diff --git a/NEWS.md b/NEWS.md index 62bee3ab2fd..3ac0a89657a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,422 +1,1780 @@ -# igraph 2.2.1.9004 +# igraph 2.1.4.9079 + +## vendor + +- Update vendored sources to igraph/igraph@6a92b9a7aedcbdf1e40ac93b88031e06cfa1a8c7 (#2044). + +- Update vendored sources to igraph/igraph@dce0a61a0bf67be4926d42bf8dd8a475a20a52a7 (#2040). + + +# igraph 2.1.4.9078 + +## Continuous integration + +- Cleanup and fix macOS (#2042). + + +# igraph 2.1.4.9077 + +## vendor + +- Update vendored sources to igraph/igraph@09bc672c2d1221c0a3a78a312584fae8da3d0af6 (#2039). + +- Update vendored sources to igraph/igraph@5ff19a9281745f8d7b39bf7b477865d3ad573729 (#2038). + +- Update vendored sources to igraph/igraph@0b3d9704f616651a4937c9a6079a5cdf36ec39e7 (#2037). + + +# igraph 2.1.4.9076 + +## Continuous integration + +- Format with air, check detritus, better handling of `extra-packages` (#2035). + +## vendor + +- Update vendored sources to igraph/igraph@d7a119ddef575026d9eba9414fedea4d8f11774b (#2034). + +- Update vendored sources to igraph/igraph@01cabca5a8c685ff263a11a6563ff42cac8572b8 (#2033). + +- Update vendored sources to igraph/igraph@f01a024b1dc6f49720cc2d089687228a55f4aa6b (#2032). + + +# igraph 2.1.4.9075 + +## vendor + +- Update vendored sources to igraph/igraph@9d9ad1935c6cea28415b8616e33d80c0c7a33c0d (#2030). + +- Update vendored sources to igraph/igraph@33be55ee088923d8b6b485e3b63352d258cde184 (#2029). + + +# igraph 2.1.4.9074 + +## vendor + +- Update vendored sources to igraph/igraph@a546942ec1d99acfd4d6b2aa35965b028a633665 (#2027). + + +# igraph 2.1.4.9073 + +## Chore + +- Adapt default path. + +## Continuous integration + +- Fix vendoring. + +- Align vendoring workflow with duckdb. + +## vendor + +- Update vendored sources to igraph/igraph@d807fc2bff14714686fa75f945772899dda8925c (#2025). + +- Update vendored sources to igraph/igraph@7788ba9623c249cd00f45f204d3aed2bfb295328 (#2024). + +- Update vendored sources to igraph/igraph@db03c3207a27a6ea5559ec79941ae2ff26a27386 (#2023). + +## Uncategorized + +- Vendor: Update vendored sources to igraph/igraph@a1c1a30aed2c4afb2892b18227e936d5b68660ca. + + +# igraph 2.1.4.9072 + +## vendor + +- Update vendored sources to igraph/igraph@a3a1271a91a476b2623275d05fd722c1fb171b00 (#2021). + +- Update vendored sources to igraph/igraph@cfb3e897a2b82fa60146325535c3d97c81c1936d (#2020). + + +# igraph 2.1.4.9071 + +## vendor + +- Update vendored sources to igraph/igraph@ba9bbc17aa56a75bd6529f3168d4dd76330689db (#2018). + +- Update vendored sources to igraph/igraph@6b59bafb6acf36a3c2ef1885927c613e80405379 (#2017). + +- Update vendored sources to igraph/igraph@232a9819f414d66c2841f7b5c8afe01ebed7374d (#2016). + +- Update vendored sources to igraph/igraph@36fec29268a872935ee0bb20727114f8bf81f7c5 (#2015). + +- Update vendored sources to igraph/igraph@0f99574f928a8463c042bf14541708def3bf4e98 (#2014). + + +# igraph 2.1.4.9070 + +## Chore + +- No `stop()` in version. + +- Don't use `stop()` in tests. + +- Improve error in stochastic_matrix. + +- Improve errors in sgm.R. + +- Improve errors in operator.R. + +- Fix cli syntax. + +- Improve error in rewire. + +- Improve errors in plot.common. + +- Improve error in `rename.attr.if.needed()`. + + +# igraph 2.1.4.9069 + +## Chore + +- Improve errors in layout.R (#2007). + +- Remove one more `stop()`. + +- Use `cli_abort()`. + +- Use `cli_abort()` instead of `stop()`. + +- Simplify error by relying on default behavior (#1997). + +- Better error in centrality (#2000). + +- Simplify error (#1999). + +- Rm useless error message (#1998). + +- Improve `igraph_match_arg()` (#1996). + + +# igraph 2.1.4.9068 + +## vendor + +- Update vendored sources to igraph/igraph@fd1d3a75efafaf57aea513e0820733c32f3ffc02 (#1994). + + +# igraph 2.1.4.9067 + +## vendor + +- Update vendored sources to igraph/igraph@0224bb3745b974fa7b6804af4ef893e85e7e1f8c (#1992). + +- Update vendored sources to igraph/igraph@f73277f19681d169d65e69d36f450b7edd7fe5a3 (#1991). + +- Update vendored sources to igraph/igraph@accada1256e859610bac5009c57de46852f7bc69 (#1990). + + +# igraph 2.1.4.9066 + +## vendor + +- Update vendored sources to igraph/igraph@8309c746e2e8aa4416c6e02b7f076738509598eb (#1988). + +- Update vendored sources to igraph/igraph@9239256bd56b19263d1cf9e16d1fa882becd7a3b (#1987). + + +# igraph 2.1.4.9065 + +## Features + +- Added weights parameter to `local_scan()` (#1082, #1448, #1982). + +## Documentation + +- Document ellipsis in `cohesion()` (#971, #1985). + +- Add 2023 preprint (#1240, #1984). + +## Testing + +- Simplify test (@1741643+krlmlr). + + +# igraph 2.1.4.9064 + +## Bug fixes + +- Adjust loop position to vertex size (#1980). + + +# igraph 2.1.4.9063 + +## Chore + +- Results for revdepchecks. + + +# igraph 2.1.4.9062 + +## Bug fixes + +- Dont rescale coordinates to `[-1,1] x [-1,1]` by default (#1492, #1956, #1962). + +- HRG printing with `type = "auto"` uses `"plain"` for large trees (#1879). + +## Features + +- Add multi attribute assignment (#55, #1916). + +- Expose `align_layout()` and add to `layout_nicely()` to align layout with axis automatically (#1907, #1957, #1958). + +## Documentation + +- Update allcontributors info (#1975). + +## Refactoring + +- Improve logic for updating edge attributes (#1332, #1915). + + +# igraph 2.1.4.9061 + +## Features + +- Add documentation of all file formats to `read_graph()` and `write_graph()` (#777, #1969). + +- Add more layouts to tkplot (#160, #1967). + + +# igraph 2.1.4.9060 + +## vendor + +- Update vendored sources to igraph/igraph@f51ea4f217a45f5895e749e7ea919040492cab5e (#1965). + +- Update vendored sources to igraph/igraph@94c0284cc6f45080cc7edb7586f137a69993ae7b (#1964). + + +# igraph 2.1.4.9059 + +## Bug fixes + +- Fail if `"layout"` attribute doesn't match the number of vertices (#1880). + + +# igraph 2.1.4.9058 + +## vendor + +- Update vendored sources to igraph/igraph@ccf3125052d65ee504abe9b29e6d089a4275b187 (#1954). + + +# igraph 2.1.4.9057 + +## vendor + +- Update vendored sources to igraph/igraph@cb8a06487520edf3c5e8d30225cfdcbc22c209df (#1952). + +- Update vendored sources to igraph/igraph@44c57191247e7fec2940db9bef2e6d07c2d88e7c (#1951). + +- Update vendored sources to igraph/igraph@46f1e12c7cd12801d62e6b712130071b4ed3d151 (#1950). + +- Update vendored sources to igraph/igraph@fbcbfb7ed47a9bd644d4c3bef3c6cac02b7a220d (#1949). + +- Update vendored sources to igraph/igraph@ae1f405faa2c0e2dfec6c7006f06486dfd4e6146 (#1948). + +- Update vendored sources to igraph/igraph@4e71883edad5f343d76954ce29374627820a28a0 (#1947). + + +# igraph 2.1.4.9056 + +## Bug fixes + +- Automatically arrange loops in `plot()` (#407, #556, #1881). + +- `NA` checking only in from/to columns of edge data.frame (#1906). + +- Vectorized drawing of arrows (#257, #1904). + +- Keep vertex attribute type for `disjoint_union()` (#1640, #1909). + +## Features + +- Support for more graph product types. + +- Added `plot(mark.lwd = )` to change line width of mark.groups (#306, #1898). + +- Add `plot(vertex.label.angle = , vertex.label.adj = )` arguments to rotate vertex labels (#106, #1899). + +## Chore + +- Auto-update from GitHub Actions (#1920). + +- Auto-update from GitHub Actions (#1918). + +## Continuous integration + +- Show Git status. + +- Fix flag. + +- Fix shell. + +- Use air. + +- Do not talk about Claude failures. + +## vendor + +- Update vendored sources to igraph/igraph@83b1d7a2cda5e0fcc3b6d04800cc96c32c47e2b3 (#1944). + +- Update vendored sources to igraph/igraph@8b0500e47f2777e1a2380cd3f9a717be1ea38881 (#1942). + +- Update vendored sources to igraph/igraph@7c967b95f62ca1a58f672a2fd9bea194334dc632 (#1941). + +- Update vendored sources to igraph/igraph@7239a13da6037e3f6b10ee19b095bca2b0a18742 (#1940). + +- Update vendored sources to igraph/igraph@65a83a4f34261a5e453cf2e5a04a0591f50d0da6 (#1939). + +- Update vendored sources to igraph/igraph@a3967d418293e382174b4e848921221b00dffb6e (#1938). + +- Update vendored sources to igraph/igraph@873aa6c8d823b7cca18fca5032c0a2487fb9d082 (#1937). + +- Update vendored sources to igraph/igraph@06074d94ffd0f8e283e079415c8e47b2eaf92cda (#1936). + +- Update vendored sources to igraph/igraph@50cf73d2844dd2ace266b38ac09ca29b627cb7ce (#1935). + +- Update vendored sources to igraph/igraph@e2a3b7c6e26683e9bb5f6a07d4e380861bd40f93 (#1934). + +- Update vendored sources to igraph/igraph@12078c2b256e7cc15404ccf32c349101ececcf56 (#1933). + +- Update vendored sources to igraph/igraph@cd62af9732e71060cc3b579fa49364bd08917175 (#1931). + +- Update vendored sources to igraph/igraph@015d34e5b6e6876d8328bf959a7c494bdd61c756 (#1930). + +- Update vendored sources to igraph/igraph@ea227139ceaa3d5525bf0ccb0656c93c6ca0b93c (#1929). + +- Update vendored sources to igraph/igraph@4b18e606d56b01d0ce7aa60063e88be3500c896e (#1928). + +- Update vendored sources (tag 0.10.16) to igraph/igraph@beebfcdcd707f50a31cf8eb3568cf09f8b7baf54 (#1927). + +- Update vendored sources to igraph/igraph@0f4e5be81a752112e828ce6614ad692cef29f5fb (#1926). + +- Update vendored sources to igraph/igraph@881c7d39b63b7986143db617afe65d4cf3b23e0e (#1925). + +- Update vendored sources to igraph/igraph@075be76c92b99ca4c95ad9207bcc1af6d471c85e (#1924). + +- Update vendored sources to igraph/igraph@06754306e700de9c6751301221744b781cdc791c (#1923). + +- Update vendored sources to igraph/igraph@ab6faf22c37cc5169063edd134193233ebab264e (#1922). + +- Update vendored sources to igraph/igraph@753afcc39f16942730913dcfd331c10668c18de1 (#1921). + +- Update vendored sources to igraph/igraph@80aea5c5897c67137872c945f684ad29408a5810 (#1919). + +- Update vendored sources to igraph/igraph@2c3cc367a24299b41cc7ae3f308781fde27950db (#1917). + +- Update vendored sources to igraph/igraph@7180ad04d0a1a3c796eb6931a21d25f5df532c7a (#1914). + +- Update vendored sources to igraph/igraph@8c1a72c8a38df0bd1337b5458f96555fbfce2778 (#1913). + +- Update vendored sources to igraph/igraph@f845707d5b35e889676821ee31b30a2cf7b670ef (#1912). + +- Update vendored sources to igraph/igraph@83f1f05905ff23f0c16e526b79ec1277f4209669 (#1911). + + +# igraph 2.1.4.9055 + +## Chore + +- Auto-update from GitHub Actions (#1901). + +- Revdepchecks, second run. + +- Ignore. + +- Revdepchecks. + +- Ignore. + +## Continuous integration + +- Ignore vendored libraries. + + +# igraph 2.1.4.9054 + +## Continuous integration + +- Fix main coverage workflow. + +- Install covr fix. + + +# igraph 2.1.4.9053 + +## Bug fixes + +- Allow more than one edge label font family (#37, #1896). + +- Pie shapes work as intended (#1882, #1883). + +## Features + +- Breaking change: change arguments default and order for `graph_from_lcf()` (#1858, #1872). + +## Chore + +- Auto-update from GitHub Actions (#1895). + +- Auto-update from GitHub Actions (#1893). + +- Auto-update from GitHub Actions (#1892). + +## Continuous integration + +- Turn off gcov. + +- More timeouts. + +- No timeout for covr. + +- Add plain covr workflow. + +- Add instructions. + +- Add Claude workflow. + +- Add description for workflow. + +## Breaking changes + +- Breaking change: change arguments default and order for `graph_from_lcf()` (#1858, #1872). + + +# igraph 2.1.4.9052 + +## Bug fixes + +- Error in bipartite projection if type is not a vertex attribute (#898, #1889). + +- Do not try to destroy non-initialized SIR objects upon error. + + see https://github.com/igraph/rigraph/issues/1888 + + +# igraph 2.1.4.9051 + +## Chore + +- Add air code formatting (#1734, #1869). + + +# igraph 2.1.4.9050 + +## Continuous integration + +- Increase timeout also for covr step. + +- Increase timeout for all builds. + +- Give more time to covr. + + +# igraph 2.1.4.9049 + +## Documentation + +- Fix indentation of `\describe{}` elements (#1867). + + +# igraph 2.1.4.9048 + +## Bug fixes + +- Added `NA` handling for matrix inputs (#917, #918, #1828). + +## Chore + +- Auto-update from GitHub Actions (#1865). + +## Documentation + +- Ensure use of `\describe{}` if using `\item{}` in return value (#1736, #1779). + +- Link to replacements of deprecated functions (#1823). + +## Refactoring + +- Use `check_string()` instead of `as.character()` (#1365). + + +# igraph 2.1.4.9047 + +## doc + +- Refer to current latest version of R in troubleshooting page. + + +# igraph 2.1.4.9046 + +## Chore + +- Auto-update from GitHub Actions (#1861). + +- Add deps file to build-ignore. + +## Continuous integration + +- Allow workflow dispatch. + +- Allow PR creation. + + +# igraph 2.1.4.9045 + +## Chore + +- Fix `devtools::load_all()` (#1857). + + +# igraph 2.1.4.9044 + +## Bug fixes + +- Added factor support for `graph_from_data_frame()` (#34, #1829). + +## Chore + +- Refer to the dev version of roxygen2 as build dependency (#1832). + +## Continuous integration + +- Fix sanitizer. + +- Permissions, better tests for missing suggests, lints (#1851). + +- Only fail covr builds if token is given (#1848). + +- Always use `_R_CHECK_FORCE_SUGGESTS_=false` (#1846). + +- Correct installation of xml2 (#1842). + +- Add xml2 for covr, print testthat results (#1840). + +- Sync (#1839). + +## Documentation + +- Clarify that `girth()` returns `Inf` for acyclic graphs (@eqmooring, #1831). + +## Testing + +- Don't `library(Matrix)` in tests (@MichaelChirico, #1833). + +## vendor + +- Update vendored sources to igraph/igraph@ca0fca2d41bfd2819e49cf98cbc69044dbca9a28 (#1854). + +- Update vendored sources to igraph/igraph@cb74a4a43c5b35ad4ec2bf2e3acbc547d23f2267 (#1853). + +- Update vendored sources to igraph/igraph@f159656faeed3ab23313fceddc17fa60cb6f2760 (#1852). + +- Update vendored sources to igraph/igraph@595b969fb1b5f206f474f0c6e4befa80f0f14fa3 (#1843). + + +# igraph 2.1.4.9043 + +## vendor + +- Update vendored sources to igraph/igraph@2d6d0abc05ac3cb53872cc3ea86b847a7556198e (#1837). + +- Update vendored sources to igraph/igraph@a899e60c8e3992f769e2159aeedf480ad46de337 (#1836). + +- Update vendored sources to igraph/igraph@145b35107659f73d85186b6a021dfe4284cf50c7 (#1835). + +- Update vendored sources to igraph/igraph@198fe3751b97bb130e724ca847d8aa5f9a58c4dc (#1834). + + +# igraph 2.1.4.9042 + +## vendor + +- Update vendored sources to igraph/igraph@05d18670f356403c1dcca4e48f78710e31b3c9b0 (#1825). + + +# igraph 2.1.4.9041 + +## Chore + +- Results from main. + +- Results from check with new arpack. + +## Documentation + +- Document return value of `make_clusters()` (#1794). + + +# igraph 2.1.4.9040 + +## Documentation + +- Add author links (#1821). + + +# igraph 2.1.4.9039 + +## Bug fixes + +- Remove string matrix support from biadjacency matrix functions (#1540, #1542, #1803). + +## Features + +- `simple_cycles()` lists all simple cycles (#1573, #1580). + +- Expose C version (#1208, #1781). + +## Chore + +- Format with air. + +## Documentation + +- Fix style (#1819). + +## Performance + +- Accelerate check if an index sequence corresponds to the entire list of vertices (#1427, #1818). + + +# igraph 2.1.4.9038 + +## Documentation + +- Correct the description of the `weights` parameter of `hits_scores()`. + +## Refactoring + +- Adapt to `cut.prob`'s new handling of NULL in the C core (#1570, #1602). + + +# igraph 2.1.4.9037 + +## vendor + +- Update vendored sources to igraph/igraph@09f6f258c4a864654ad1950e053ff2f5c507be54 (#1814). + +- Update vendored sources to igraph/igraph@d48a25ba0f6d72e447c6d17d74b667b1f21754fb (#1813). + + +# igraph 2.1.4.9036 + +## Features + +- Expose `is_complete()`, `is_clique()` and `is_ivs()` (#1316, #1388, #1581). + +## vendor + +- Update vendored sources to igraph/igraph@a68d7cafcd0935e6f229437981811e730af4f03f (#1811). + + +# igraph 2.1.4.9035 + +## vendor + +- Update vendored sources to igraph/igraph@01b15eb1f44d36418ea65394710a02887ca16857 (#1808). + +- Update vendored sources to igraph/igraph@8d5db4db95e2e80cbe8169bbe66ce64f73df7bd3 (#1807). + +- Update vendored sources to igraph/igraph@6c5b349a4b56ebee0003953ee43994d2dd93f189 (#1806). + + +# igraph 2.1.4.9034 + +## Bug fixes + +- Removed redundant inheritParams call (#1802). + +- Loops not plotted on canvas (#1799, #1800). + +- Load the Matrix package before coercing to a sparse matrix. + +- `NA` replacement for labels in plots and arrow mode (#1796, #1797). + +## Chore + +- Results from revdepcheck. + +## Testing + +- Added more weight tests to `graph_from_biadjacency_matrix()` (#1544, #1804). + + +# igraph 2.1.4.9033 + +## Features + +- Add relative size scaling to vertices in plots (@gvegayon, #172). + +## Chore + +- Render docs. + +- Updated results. + +## Documentation + +- Better describe output of `all_shortest_paths()` (#1029, #1778). + + +# igraph 2.1.4.9032 + +## vendor + +- Update vendored sources to igraph/igraph@0a22a85cb9281ce147b0db7415610e55dee2e332 (#1791). + + +# igraph 2.1.4.9031 + +## vendor + +- Update vendored sources to igraph/igraph@e5de49c7f65708763b70413dbde4ac0eba7ef5b6 (#1789). + +- Update vendored sources to igraph/igraph@7d634197abd2bb0bc3317c1216cfb82c3813d1af (#1788). + +- Update vendored sources to igraph/igraph@bc19dd7ec62ceb80409513009caefb5412c0dab1 (#1787). + + +# igraph 2.1.4.9030 + +## Documentation + +- `make_graph()` now supports `Groetzsch` as an alias of `Grotzsch`. + This change was implemented in the C core. + +## vendor + +- Update vendored sources to igraph/igraph@ead8aea0dcecf43755f9a1857d09ce092d6ff9cf (#1785). + + +# igraph 2.1.4.9029 + +## vendor + +- Update vendored sources to igraph/igraph@65cf9a269634047812afbbe966099bb6983ced68 (#1783). + + +# igraph 2.1.4.9028 + +## vendor + +- Update vendored sources to igraph/igraph@fc6860b31887b362e8ddbb07e44e6a12e9cef82d (#1776). + +- Update vendored sources to igraph/igraph@dcdad62cbb2e7969fb58429850487a5f0e00c812 (#1775). + +- Update vendored sources to igraph/igraph@1636677c821f9dd453049b86e370c0dd6477640b (#1774). + +- Update vendored sources to igraph/igraph@6d85a48755d5de8e36fa9d4e53fee891ad0428fa (#1773). + +- Update vendored sources to igraph/igraph@fe6bdb78c4a3269b542c6af7a167b9599f08173d (#1772). + +- Update vendored sources to igraph/igraph@e5e5374c55164557ba29beee4dbde1a61fa1c50b (igraph/igraph#2473, #1771). + + +# igraph 2.1.4.9027 + +## vendor + +- Update vendored sources to igraph/igraph@910770148045f66ee30bd0c519adaec0e7a7cc31 (igraph/igraph#2473, #1769). + +- Update vendored sources to igraph/igraph@10d4fc75f146f5fc8ec17d99ab808c53a3c49dae (#1768). + +- Update vendored sources to igraph/igraph@92ec35b3e427734fde7f8ebc9d978ee6fd207c68 (#1767). + + +# igraph 2.1.4.9026 + +## vendor + +- Update vendored sources to igraph/igraph@dd208201b117baecfb1f0de9018e20a6929da865 (#1765). + +- Update vendored sources to igraph/igraph@64e4649039ab5b2762068e56fd07ce4b93256767 (#1764). + +- Update vendored sources to igraph/igraph@aec39d00ee55245b368421cc3453457ac7ae737e (#1763). + + +# igraph 2.1.4.9025 + +## Features + +- Expose `find_cycle()` (#1471, #1571). + +- Split `sample_bipartite()` into two functions for the G(n, m) a… (#630, #1692). + +## Chore + +- Results from revdepcheck. + +- Update generated documentation. + +- Install build dependencies. + +## Documentation + +- Update decription of `order` parameter of `ego()` and related functions (#1746). + +## Testing + +- Snapshot updates for rcc-smoke (null) (#1738). + + +# igraph 2.1.4.9024 + +## Bug fixes + +- Integer vectors are validated before transferring them to the C library (#1434, #1582). + + +# igraph 2.1.4.9023 + +## vendor + +- Update vendored sources to igraph/igraph@b42d0101d7c2a6d31ac6568aa4b4398d5f619e2e (#1758). + +- Update vendored sources to igraph/igraph@627f71a5e0eac5c00f56499fb4457ff4f9ee315d (igraph/igraph#2710, #1757). + +- Update vendored sources to igraph/igraph@a7d22863ea48ec7b206ef6a03869ff7817cb8a5b (#1756). + + +# igraph 2.1.4.9022 + +## Chore + +- Require copyright assignment in PR template (#1747). + + +# igraph 2.1.4.9021 + +## Chore + +- Fix `Makefile-cigraph` again. + +- Deprecate `scale` argument of `centr_eigen()` and `centr_eigen_tmax()` (#1531, #1625). + +## Testing + +- Rename, add test for `laplacian_matrix()` (#1714). + +## vendor + +- Update vendored sources to igraph/igraph@662abbdfa467a6436bad650c31a8360787d75379 (#1753). + +- Update vendored sources to igraph/igraph@1a7f9b71505c8455afb836628bc133e387154118 (#1752). + +- Update vendored sources to igraph/igraph@410fc4089639fde7f2e6b42ce4588bd6af3d78de (#1751). + +- Update vendored sources to igraph/igraph@1cbe1ae2abedacb0afde1b367a788580c9810c6c (#1750). + +- Update vendored sources to igraph/igraph@5bda8315202ff0647e30da77de0d70c7f25d89bf (#1749). + +- Update vendored sources to igraph/igraph@091e2927a6acce4e89db0db37d7db8496a59f117 (#1748). + + +# igraph 2.1.4.9020 + +## Bug fixes + +- Changed base location for graph_from_graphdb and added tests (@schochastics, #1712, #1732). + +- Recycling of logical vectors when indexing into edge/vertex selectors now throws an error (@schochastics, #848, #1731). + +## Features + +- `feedback_vertex_set()` finds a minimum feedback vertex set in a graph (#1446, #1447, #1560). + +## Chore + +- Add include. + +- R 4.0 compat. + +- Remove `Rf_allocSExp()` which is no longer in R's C API (#1735). + +- Fix Stimulus (#1737). + +- Use `"parent"` instead of `"father"` in `bfs()` and `dfs()` (#880, #1523). + +## Documentation + +- Welcome Maëlle Salmon and David Schoch as authors (#1733). + +## Testing + +- Merged feedback.set tests into structural.properties (#1743). + + +# igraph 2.1.4.9019 + +## Testing + +- Added tests for untested files (@schochastics, #1728). + +- Merged and refactored other.R tests (@schochastics, #1727). + +- Merged and refactored structural.properties.R tests (@schochastics, #1726). + + +# igraph 2.1.4.9018 + +## Bug fixes + +- Use function instead of (x) in arrow.mode (@schochastics, #1722). + +## Documentation + +- Lifecycle table (#1525). + +## Refactoring + +- One less tmp use case (#1715). + +## Testing + +- Merged and refactored orphaned test files (@schochastics, #1724). + +- Merged and refactored iterators.R and operators.R tests (@schochastics, #1723). + +- Merged and refactored topology.R tests (@schochastics, #1720). + +- Merged and refactored embedding.R tests (@schochastics, #1721). + +- Merge all tests for foreign.R into one test file (#1713). + + +# igraph 2.1.4.9017 + +## Features + +- Added proper support for adding attributes via data.frames (@schochastics, #1373, #1669, #1716). + + +# igraph 2.1.4.9016 + +## doc + +- Fix typos in `laplacian_matrix` documentation. + + +# igraph 2.1.4.9015 + +## Chore + +- Run `devtools::document()` (#1710). + + +# igraph 2.1.4.9014 ## Bug fixes -- Use `"weights"` edge attribute in `modularity()` if available. +- Duplicated arrowhead drawing (@schochastics, #640, #1709). + +- Correct mapping of edge label properties in plots when loops are present (@schochastics, #157, #1706). + +- NA attribute values are replaced with default values for plotting (@schochastics, #293, #1707). + +## vendor + +- Update vendored sources to igraph/igraph@10ef19bc2a61de6c6cfe76e5a068f82b1d29fff1 (#1694). + + +# igraph 2.1.4.9013 + +## Features + +- Hrg functions check their argument (#1074, #1699). + +## Documentation + +- Replace instances of `#' if` with `#' @examplesIf` (#1134, #1698). + +- Update graph saving rec (#1242, #1700). + +## Testing + +- Improve test-dot.product.game (#1396, #1705). + + +# igraph 2.1.4.9012 -- Safer `.dd` generation. +## Chore -## Features +- Run {styler} (with {igraph.style}) (#1696). + +## Documentation -- Use snake_case in arguments to `_impl` functions (#2461, #2462). +- Add more about igraph.r2cdocs in the contributing guide (#1686, #1697). -- Add `make_wheel()` to expose `igraph_wheel()` (#1561, #2409). +## Testing -- Add `transitive_closure()` function (#1350, #2413). +- Merged and refactored conversion.R tests (@schochastics, #1701). -## Chore +- Create helpers (#1691, #1695). -- Auto-update from GitHub Actions (#2473). +- Merged and refactored make.R tests (@schochastics, #1685). -- Document `.Call()` usage \[ci skip\]. +- Merged and refactored community.R tests (@schochastics, #1689). -- Rename to `igraph_arg_match()`, instructions. +- Merged and refactored indexing.R tests (@schochastics, #1687). -- Fix autogeneration for writing functions. -- Sync autogen. +# igraph 2.1.4.9011 ## Testing -- Fix snapshots. +- Merged and refactored flow.R tests (@schochastics, #1675). + +- Merged and refactored games.R tests (@schochastics, #1682). -- Fix snapshots for `expect_snapshot_igraph_error()`. +## Uncategorized -## ai +- Refactor: consolidate graph.incidence.\* (#1483) (#1654). -- Merge \[ci skip\]. -- Tags \[ci skip\]. +# igraph 2.1.4.9010 -- Prefer `GATTR` \[ci skip\]. +## vendor +- Update vendored sources to igraph/igraph@6981deb377ddd9ca9f098d683a743c3dd793e563 (#1680). -# igraph 2.2.1.9003 +- Update vendored sources to igraph/igraph@7955e08f37feda6c61f684428063e13e5a71ff5f (#1679). -## Bug fixes -- Fix `alpha_centrality()` crash when `weights` is a custom attribute name (#915, #2403). +# igraph 2.1.4.9009 -## Features +## vendor + +- Update vendored sources to igraph/igraph@199fdbf0a511294c7444eaa25c1861e784b3aa8a (#1677). -- Add `make_full_multipartite()` and `make_turan()` graph constructors (#1562, #2406). -- Add `count_loops()` to R interface (#1379, #2414). +# igraph 2.1.4.9008 -- Add `make_circulant()` to expose `igraph_circulant()` (#1563, #2407). +## Refactoring -- Add `mean_degree()` to R (#1380, #2415). +- Enhance readability and performance of graph.adjacency.sparse (@schochastics, #1667). -- `vertices()` errors on duplicate attribute names (#1248, #2430). +## Performance -- Add `count_reachable()` function to R (#1349, #2412). +- Faster single bracket querying of a graph (@schochastics, #1465, #1658). -## Chore -- Auto-update from GitHub Actions (#2454). +# igraph 2.1.4.9007 +## vendor -# igraph 2.2.1.9002 +- Update vendored sources to igraph/igraph@27624a9b65031aabd3bb976efe944524d9e7dd43 (#1672). -## Bug fixes +## doc -- Use `LC_ALL=C` instead of `LOCALE=C` in `deps.mk` (#2446, #2447). +- Clarify weights use in `layout_with_kk()`. + + +# igraph 2.1.4.9006 + +## Continuous integration + +- Use igraph repo for vendoring. + +- Fix vendoring workflow. + +## vendor + +- Update vendored sources to igraph/igraph@2ab6b87947187a0b046fa3cbb10a30ec370843aa (#1670). + + +# igraph 2.1.4.9005 ## Features -- Add autogeneration for all C functions currently in use (#2424, #2442). +- `get_edge_ids()` accepts data frames and matrices (#1663). + + +# igraph 2.1.4.9004 + +- Refactor: forward `get.adjacency.dense()` to `get.adjacency.sparse()` if attributes are present (#1483) (#1653). + + +# igraph 2.1.4.9003 + +## Bug fixes + +- Breaking change: Subset assignment of a graph avoids addition of double edges and ignores loops unless the new `loops` argument is set to `TRUE` (@schochastics, #1662, #1661). + +## Breaking changes + +- Breaking change: Subset assignment of a graph avoids addition of double edges and ignores loops unless the new `loops` argument is set to `TRUE` (@schochastics, #1662, #1661). + + +# igraph 2.1.4.9002 + +## Bug fixes + +- Temporarily disable generating an interface for `igraph_simple_cycles_callback()`. + as the framework for handling callback functions is not yet present ## Chore -- Format. +- Breaking change: remove deprecated `neimode` parameter from `bfs()` and `dfs()` (#1105, #1526). + +- Adapt handling of optional parameters to interface definition changes in the C core (#1567). -- Ensure args are named. +- Breaking change: stricter deprecation of non-functional parameters of `layout_with_kk()` and `layout_with_fr()` (#1108, #1628). ## Continuous integration -- Fix final status as set by Copilot \[ci skip\]. +- Sync vendor workflow with duckdb. -## Documentation +## Refactoring -- More instructions \[ci skip\]. +- Prepare for C core interface standardizing 'type' -\> 'types' in igraph_is_bipartite. -## Refactoring +## Breaking changes -- Switch from `.Call()` to autogenerated `_impl` functions (#2434, #2443). +- Breaking change: remove deprecated `neimode` parameter from `bfs()` and `dfs()` (#1105, #1526). -## Testing +- Breaking change: stricter deprecation of non-functional parameters of `layout_with_kk()` and `layout_with_fr()` (#1108, #1628). -- Add structured tests alongside snapshot tests for ALL \_impl functions in test-aaa-auto.R (#2448, #2449). +## vendor -## Uncategorized +- Update vendored sources to igraph/igraph@5216243786a5368ab14db9649008d1caca75f5af. -- Merge branch 'cran-2.2.1'. + refactor: cleaner workaround in plfit for Windows 11 SDK bug where NAN is defined in a non-constant manner +- Update vendored sources to igraph/igraph@622f331dc9249b050bc6afbad2032e2c4e78de9e. -# igraph 2.2.1.9001 + fix: remove unused converage exclusion -## Bug fixes +- Update vendored sources to igraph/igraph@c675c805a6ed436887ec0e6f9c6e18ca6d13ecad. -- Fix matrix lists for output. + chore: update CodeCoverage.cmake from upstream https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake -## Features +- Update vendored sources to igraph/igraph@b25eda2dba6ccbcf5a47fe1cb77796a7f0f524d4. -- Add `invalidate_cache()` to R interface (#1387, #2416). + fix: UBSan warning about negative shift when generating Q_0 hypercube graph -- All arguments in calls to `_impl()` functions are named (#2423). +- Update vendored sources to igraph/igraph@e0dbe374e30adc654ad55a50d5aaf47ebc753908. -## Chore + chore: update plfit to 1.0.0 -- Use `Rx_` prefix for manually generated functions. +- Update vendored sources to igraph/igraph@2cdc20a37fe048143ac54a3fa8288bb017402e7c. -- Clarify error testing preference \[ci skip\]. + chore: update plfit + fuzzer: use libxml2 2.13.5 + chore(deps): bump codecov/codecov-action from 4 to 5 -- Ignore \[ci skip\]. +- Update vendored sources to igraph/igraph@082e2c6ba1a96d34d05a4e75a59c4f690aeca58d. -- Use `_impl` variants instead of inline `.Call()` for five functions with changed C signatures (#2428, #2429). + chore: update changelog \[skip ci\] -- Format \[ci skip\]. +- Update vendored sources to igraph/igraph@8d242741a1cdc2686f180838d28f80cb96985c74. -- Expand remaining `_impl` aliases (#2422). + chore: update plfit -- Remove unused `NTIMER` and `NPRINT` macro definitions (#1095, #2405). +- Update vendored sources to igraph/igraph@6c57e8c955d3c4d81160281d018dd3fa0a4052d8. -- Cleanup. + refactor: minor cleanup in maximal cliques -- Request math notation. +- Update vendored sources to igraph/igraph@d6348668ba511735110758dc4ee0423a983bf1ac. -### deps + refactor: remove extraneous whitespace before continuation backslashes in max clique template code -- Bump jinja2 from 3.1.2 to 3.1.6 in /tools/py-stimulus (#2401). +- Update vendored sources to igraph/igraph@9f06e4c34d8b1d533ba331ae581844a2ea9b565f. -- Replace `_impl` aliases in `R/flow.R` (#2347, #2379). + chore: punctuate som error messages -- Autogenerated file looks more like as if it was formatted with `air` (#2395). +- Update vendored sources to igraph/igraph@befc831fff74e4bae39743b1f83b38e6b3af0390. -## Continuous integration + fix: correct some implicit integer conversions -- Run daily vendoring to avoid noise \[ci skip\]. +- Update vendored sources to igraph/igraph@5e3c56c6a10cb954b78c7441c5460a3c6ad4f5b7. -- Snapshots \[ci skip\]. + fix: eliminate some unused parameter warnings -- Use proper actor name \[ci skip\]. +- Update vendored sources to igraph/igraph@8cdfd787c2be8886cc4eac014f3004055a8c3ca0. -- Reduce contention by running big matrices overnight. + refactor: improved const-correctness in vector implementation -- Add workflow to auto-assign to Copilot. +- Update vendored sources to igraph/igraph@ab123f04e487bc8bc1b93b9258e577e5f05d7ce9. -- Run running sanitizer only on cran branches to avoid pipeline contention. + chore: update plfit, works around non-compile-time-constant NAN bug in recent Windows 11 SDKs -## Documentation +- Update vendored sources to igraph/igraph@833672f02161051010d1b633b23be53765663372. -- More instructions \[ci skip\]. + chore: restrict workaround to CMake 3.31.0 USE_TERMINAL bug to the single affected CMake version -- More instructions \[ci skip\]. +- Update vendored sources to igraph/igraph@5e734a2c1211d017088a882ed121f25956e20189. -- More instructions \[ci skip\]. + ci: support for controlling the use of plfit and improve alpine jon -- More instructions \[ci skip\]. +- Update vendored sources to igraph/igraph@ed43183a2eeb9e604addf1dc672908b7b845cec7. -- Experimental. + refactor: some cleanup in shortest path implementations -- New code \[ci skip\]. +- Update vendored sources to igraph/igraph@2412652489721e41617e3d9719b02923da31ab0d. -- Add GitHub Copilot instructions and expand AGENTS.md (#2397, #2400). + chore: devcontainer update -## Refactoring +- Update vendored sources to igraph/igraph@48ff9407b74cca8e50f1d256b039452e40662985. -- Replace `_impl` aliases with explicit wrapper functions in `R/topology.R` (#2366, #2398). + chore: link to relevant CMake bug regarding policy CMP0175 -- Replace \_impl aliases in R/other.R (#2355, #2388). +- Update vendored sources to igraph/igraph@3631b1d5a0f3b7e49463f89cbbba762b24d9383d. + refactor: clean up igraph_path_length_hist() -# igraph 2.2.1.9000 +- Update vendored sources to igraph/igraph@6fd3903c84d741d4bed0284c85db277836a4af79. -## Chore + refactor: clean up igraph_vertex_path_from_edge_path() and clarify that it is suitable for any walk, not just paths -- New `switch_igraph_arg()` to avoid the need for default arguments. +- Update vendored sources to igraph/igraph@379ef39bb89f41ba6d0ff39a86039571796e3bde. -- Fix isomorphism callback function. + refactor: eliminate redundant pointer variable in GraphML reader -- Replace `_impl` aliases with explicit wrapper functions in `R/bipartite.R` (#2334, #2361). +- Update vendored sources to igraph/igraph@af14d843991f9e4f2894477a8644cfbd27a13d11. -- Replace \_impl aliases with explicit wrapper functions in R/centralization.R (#2336, #2360). + fix: mark global variables in GraphML parser as static -- Replace `_impl` aliases with explicit wrapper functions in `R/cliques.R` (#2337, #2363). +- Update vendored sources to igraph/igraph@05979d3b2c85c12334ce5d3508dd473cdfa3c6f5. -- Replace `_impl` function aliases with explicit wrappers in `R/centrality.R` (#2335, #2362). + doc: improve maximal clique docs -- Replace `_impl` alias with explicit wrapper in `R/coloring.R` (#2338, #2364). +- Update vendored sources to igraph/igraph@41d855d470c7e5cca40bb8a2e294656504aa2a56. -- Embed Stimulus sources, add docs. + chore: update changelog -- Replace `_impl` aliases with explicit wrappers in R/assortativity.R (#2332, #2333). +- Update vendored sources to igraph/igraph@a2109c50681c0b444285cf40d09a602047141ea1. -- Auto-update from GitHub Actions (#2331). + docs: more cross-referencing -- Auto-update from GitHub Actions (#2330). +- Update vendored sources to igraph/igraph@62881320e766e8df227839a67078dd22e909cd2d. -- Use autogen-impl functions for 3 motifs functions (#2152). + docs: fix typo -## Continuous integration +- Update vendored sources to igraph/igraph@3673a0a9c3b3604ab1975432f6bbeed697dc9f7c. -- Install air for Copilot. + doc: more cross-linking -- Update status directly for Copilot. +- Update vendored sources to igraph/igraph@e842e658993df7305aec9d805baf36008aec9e4d. -- Remove Claude assistant. + fix: compatibility with CMake 3.31 -- Avoid passing head branch for status update. +- Update vendored sources to igraph/igraph@2f0e27c9c19e8e7eb9b3b2df01ae3186f1e62470. -- Always update status after run, in some cases workflows push to the branch. + ci: use modern CMake features for CTest parallelization -- Detail. +- Update vendored sources to igraph/igraph@a16619502b6c21d4883eeee992794b271e1035d9. -- Deterministic setup for Copilot. + chore: updated changelog -- Use reviewdog only for foreign PRs. +- Update vendored sources (tag 0.10.15) to igraph/igraph@635b432eff0a89580ac9bb98068d2fbc8ef374f2. -## Documentation + chore: updated changelog -- Remove spaces from vignettes. +- Update vendored sources to igraph/igraph@563aa5e8569b85a73680752bd8ad5624575610b6. -## Refactoring + chore: run pre-commit hooks -- Replace `_impl` aliases with explicit wrapper functions in `R/triangles.R` (#2368, #2369). +- Update vendored sources to igraph/igraph@f32e621f3833556e361a3078ab9e046f6acdd9b8. -- Replace `_impl` aliases with explicit wrapper functions in `R/make.R` (#2352, #2384). + chore: bump VERSION property in shared library -- Replace `_impl` alias with explicit wrapper in `R/layout.R` (#2351, #2382). +- Update vendored sources to igraph/igraph@26d3718b364167dd0528c63a35f9e5e513df6845. -- Replace `_impl` aliases with explicit wrapper functions in `R/structural-properties.R` (#2359, #2372). + refactor: do not use vector_get() in simple cycle finder -- Replace `sir <- sir_impl` alias with explicit wrapper (#2358, #2370). +- Update vendored sources to igraph/igraph@cd7bcd9d9b9bfd9acd83dace6438507947297ce2. -- Replace `_impl` aliases with explicit wrapper functions in `R/games.R` (#2348, #2383). + refactor: cleaner parameter ordering in igraph_i_simple_cycles_circuit() -- Replace `_impl` aliases with explicit wrapper functions in `R/simple.R` (#2357, #2386). +- Update vendored sources to igraph/igraph@dafe829b811f9344fb1f5a8412a100b586817e3f. -- Replace `_impl` aliases with explicit wrappers in `R/embedding.R` (#2345, #2380). + refactor: support specifying a minimum cycle length in `igraph_simple_cycles()` -- Replace `are_adjacent` alias with explicit wrapper in `R/structure.info.R` (#2365, #2374). +- Update vendored sources to igraph/igraph@c263ce7541e904f71dbcb7e06ca0dfb08cbf2ed7. -- Replace `_impl` aliases with explicit wrappers in `R/trees.R` (#2367, #2373). + interface: loops=True default for igraph_degree() -## Testing +- Update vendored sources to igraph/igraph@f6ec07e8a9425f09259bd04b0fefe1ebdfe64067. -- Improve centralitystress test (#2214). + chore: updated contributors list +- Update vendored sources to igraph/igraph@a6441e7a00118988aeac528910d6b9d417aec364. -# igraph 2.2.1 + chore: trim trailing whitespace in interface file -## Chore +- Update vendored sources to igraph/igraph@042a2c5230e8008b976a5ad0f04fe2b3e00cde97. -- Fix ASAN checks. + interface: add missing interface for igraph_get_isomorphisms_vf2_callback() -- Add protection to fix rchk error. +- Update vendored sources to igraph/igraph@797ab4fa6c9a119ff12af1f5d6080de8d1e4f142. -## Testing + interface: mark all callback extra parameters and some callback functions as optional -- Improve centralitystress test (#2214). +- Update vendored sources to igraph/igraph@518fcc4165c420b9f4958d1496a607d325d69826. -- Fix flaky test. + interface: add default parameter values for fundamental_cycles() and minimum_cycle_basis() +- Update vendored sources to igraph/igraph@d9c328f61e31d93681e2c0894ace18ad59a5dba2. -# igraph 2.2.0 + interface: even more missing OPTIONAL markers -Update C core to version 0.10.17. See for a complete changelog, in particular the section "Breaking changes". +- Update vendored sources to igraph/igraph@3b9cb6ff078cf4e7fdb2be593811e50b97232fea. -## Features + interface: add more missing OPTIONAL markers -- Generate almost all R implementations (#2047). +- Update vendored sources to igraph/igraph@5512e864ecddc76af4a7c93b7e4ebfd7030cc404. -- Expose `align_layout()` and add to `layout_nicely()` to align layout with axis automatically (#1907, #1957, #1958). + fix: some weights parameters were incorrectly marked as OPTIONAL in functions.yaml -- Expose `simple_cycles()` which lists all simple cycles (#1573, #1580). +- Update vendored sources to igraph/igraph@4b208d877de74a730e8707e94ebad5318cf308ae. -- Expose `is_complete()`, `is_clique()` and `is_ivs()` (#1316, #1388, #1581). + fix: mark some optional weight parameters as OPTIONAL in functions.yaml -- Expose `find_cycle()` (#1471, #1571). +- Update vendored sources to igraph/igraph@d0616a433134dcb6ae6f3195c5a72e456f5a4809. -- Expose `feedback_vertex_set()` to find a minimum feedback vertex set in a graph (#1446, #1447, #1560). + fix: type -\> types in is_bipartite interface -- Add `weights` parameter to `local_scan()` (#1082, #1448, #1982). +- Update vendored sources to igraph/igraph@c3f9a823d8bc7fa210df4e1225c86226195e1f16. -- Add more layouts to `tkplot()` (#160, #1967). + fix: some BIPARTITE_TYPES parameters were incorrectly marked as optional -- Add `plot(mark.lwd = )` to change line width of mark.groups (#306, #1898). +- Update vendored sources to igraph/igraph@34f8d72f3c702aa490644244ebee98b836ac45d1. -- Add `plot(vertex.label.angle = , vertex.label.adj = )` arguments to rotate vertex labels (#106, #1899). + refactor: use OPTIONAL instead of =NULL in interfaces -- Add relative size scaling to vertices in `plot()` (@gvegayon, #172). +- Update vendored sources to igraph/igraph@5c74801197212e9908f561139af3141410cf49d2. -- Split `sample_bipartite()` into two functions for the G(n, m) and G(n, p) case (#630, #1692). + feat: functionality for listing all simple cycles -- Implement multi attribute assignment (#55, #1916) and adding attributes via data frames (#1373, #1669, #1716). Support factors in `graph_from_data_frame()` (#34, #1829). +- Update vendored sources to igraph/igraph@f5d79f2eb90c2597ea0e33c60d0e6a083efc4abc. -- All `_hrg()` functions check their argument (#1074, #1699). + interface: default OUT mode for igraph_find_cycle() -- HRG printing with `type = "auto"` uses `"plain"` for large trees (#1879). +- Update vendored sources to igraph/igraph@992f77abdbe675c2d0dd2926536c57496b720c81. -- `get_edge_ids()` accepts data frames and matrices (#1663). + refactor: better error reporting for igraph_find_cycle() -- `igraph_version()` returns version of C core in an attribute (#1208, #1781). +- Update vendored sources to igraph/igraph@207f0bb1624bb73a9d1f2f979bf2b2bfde60626f. -## Breaking changes + chore: some copyright header cleanup in public headers -- Breaking change: change arguments default and order for `graph_from_lcf()` (#1858, #1872). +- Update vendored sources to igraph/igraph@8eaa07489a27f55cdf8421bbbb8e34b60eacd1bf. + + refactor: minor readability improvements + +- Update vendored sources to igraph/igraph@5cd6552bf00d6a774cdd64b5fabf2c79524ccfc7. + + fix: add some missing IGRAPH_CHECKs + +- Update vendored sources to igraph/igraph@82d35eebd8c73a9476d5e2d205a851b4ebfc8eda. + + refactor: minor readability cleanup in matching functions + +- Update vendored sources to igraph/igraph@01db8e25a80dd8f93ccb9d7a6f39379a57fdc3ad. + + fix: `igraph_bipartite_projection_size()` now validates the bipartite `types` vector + +- Update vendored sources to igraph/igraph@7284ee015d2662ca4e1ab62e3ce17ff34df24430. + + chore: fix some spelling mistakes + +- Update vendored sources to igraph/igraph@1d6ef7c417e38c881ef325d8c553ccf767db6b6f. + + refactor: minor readability cleanup in igraph_decompose() + +- Update vendored sources to igraph/igraph@0878f577d45ff5fdc33e0ecacc542277a8024af9. + + doc: more documentation improvements + +- Update vendored sources to igraph/igraph@bd7b3a82bb9db038ebfcc046319947c5ea196660. + + doc: several documentation improvements and cross-referencing + +- Update vendored sources to igraph/igraph@764954eda823c40341d302ac290629d96d5bd9bf. + + chore: fix typo in error message + +- Update vendored sources to igraph/igraph@6c0a4310474e9935acc557673e1a2f9ec0dd6db3. + + docs: community_optimal_modulairty() does support directed graphs + +- Update vendored sources to igraph/igraph@59d71d001308d424782a386fea3069cf880d82a2. -- Breaking change: Subset assignment of a graph avoids addition of double edges and ignores loops unless the new `loops` argument is set to `TRUE` (#1662, #1661). + chore: do not warn about unknown warning options with legacy Intel compiler + +- Update vendored sources to igraph/igraph@7a0d4918abfd34c38eb2fdeec4460b2370cea1c9. + + fix: validate sample size in igraph_motifs_randesu_estimate() + +- Update vendored sources to igraph/igraph@e7820cf969a8c63d6564452f73246c044ee99ba9. + + chore: fix typo in comment + +## hack + +- Provide NULL default for types argument of `bipartite_projection_size()`. + This parameter is optional in R, but not in C. Therefore the C interface definition doesn't provide a default or OPTIONAL marker. + +## Uncategorized + +- Refactor: removed `for` loops from `get.incidence.dense()` (#1483) (#1655). + +- Vendor: Update vendored sources to igraph/igraph@ae93a3a2431bb6fd8a1feb687cac32feef63730b. + +- Vendor: Update vendored sources to igraph/igraph@e940ab737938dfdd4518164c866b2599af40856f. + +- Vendor: Update vendored sources to igraph/igraph@3ac79b81bdf835460445ca6163f25e6559ec9958. + +- Vendor: Update vendored sources to igraph/igraph@f7b77f9e9cb4d670886b7e15e876c5549250befa. + +- Vendor: Update vendored sources to igraph/igraph@a662f79d46970bbcc2888e69dce5daa3fee8906e. + +- Vendor: Update vendored sources to igraph/igraph@a1389c191ac42b5ed3fcaf341ff3235c9f6f19f3. + +- Vendor: Update vendored sources to igraph/igraph@12299c4928f9f463c06d0b46752df69a6d67c289. + + +# igraph 2.1.3.9003 + +- Refactor: removed `for` loops from `get.incidence.dense()` (#1483) (#1655). + + +# igraph 2.1.3.9002 + +## Chore + +- Breaking change: remove deprecated `neimode` parameter from `bfs()` and `dfs()` (#1105, #1526). + +- Adapt handling of optional parameters to interface definition changes in the C core (#1567). + +- Breaking change: stricter deprecation of non-functional parameters of `layout_with_kk()` and `layout_with_fr()` (#1108, #1628). + +## Breaking changes - Breaking change: remove deprecated `neimode` parameter from `bfs()` and `dfs()` (#1105, #1526). - Breaking change: stricter deprecation of non-functional parameters of `layout_with_kk()` and `layout_with_fr()` (#1108, #1628). + +# igraph 2.1.3.9001 + ## Bug fixes -- `NA` attribute values are replaced with default values in `plot()` (#293, #1707). +- Temporarily disable generating an interface for `igraph_simple_cycles_callback()`. + as the framework for handling callback functions is not yet present -- `NA` checking only in from/to columns of edge data frame (#1906). +## Refactoring -- Keep vertex attribute type for `disjoint_union()` (#1640, #1909). +- Prepare for C core interface standardizing 'type' -\> 'types' in igraph_is_bipartite. -- Error in bipartite projection if `type` is not a vertex attribute (#898, #1889). +## vendor -- Do not try to destroy non-initialized SIR objects upon error (#1888). +- Update vendored sources to igraph/igraph@5216243786a5368ab14db9649008d1caca75f5af. -- Added proper `NA` handling for matrix inputs (#917, #918, #1828). + refactor: cleaner workaround in plfit for Windows 11 SDK bug where NAN is defined in a non-constant manner -- Remove string matrix support from functions operating on biadjacency matrices (#1540, #1542, #1803). +- Update vendored sources to igraph/igraph@622f331dc9249b050bc6afbad2032e2c4e78de9e. -- Integer vectors are validated before transferring them to the C library (#1434, #1582). + fix: remove unused converage exclusion -- Changed base location for `graph_from_graphdb()` and added tests (#1712, #1732). +- Update vendored sources to igraph/igraph@c675c805a6ed436887ec0e6f9c6e18ca6d13ecad. -- Recycling of logical vectors when indexing into edge/vertex selectors now throws an error (#848, #1731). + chore: update CodeCoverage.cmake from upstream https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake -- Use `function()` instead of `(x)` in `arrow.mode` (#1722). +- Update vendored sources to igraph/igraph@b25eda2dba6ccbcf5a47fe1cb77796a7f0f524d4. -- Temporarily disable generating an interface for `igraph_simple_cycles_callback()` as the framework for handling callback functions is not yet present. + fix: UBSan warning about negative shift when generating Q_0 hypercube graph -## Plotting bug fixes +- Update vendored sources to igraph/igraph@e0dbe374e30adc654ad55a50d5aaf47ebc753908. -- Adjust loop position to vertex size in `plot()` (#1980). + chore: update plfit to 1.0.0 -- Don't rescale plot coordinates to `[-1,1] x [-1,1]` by default (#1492, #1956, #1962). +- Update vendored sources to igraph/igraph@2cdc20a37fe048143ac54a3fa8288bb017402e7c. -- Fail if `"layout"` attribute doesn't match the number of vertices (#1880). + chore: update plfit + fuzzer: use libxml2 2.13.5 + chore(deps): bump codecov/codecov-action from 4 to 5 -- Automatically arrange loops in `plot()` (#407, #556, #1881). +- Update vendored sources to igraph/igraph@082e2c6ba1a96d34d05a4e75a59c4f690aeca58d. -- Vectorized drawing of arrows in `plot()` (#257, #1904). + chore: update changelog \[skip ci\] -- Allow more than one edge label font family in `plot()` (#37, #1896). +- Update vendored sources to igraph/igraph@8d242741a1cdc2686f180838d28f80cb96985c74. -- Pie shapes now work as intended (#1882, #1883). + chore: update plfit -- Loops not plotted on canvas (#1799, #1800). +- Update vendored sources to igraph/igraph@6c57e8c955d3c4d81160281d018dd3fa0a4052d8. -- Replace `NA` values in `label` attributes in `plot()` with default values (#1796, #1797). + refactor: minor cleanup in maximal cliques -- Removed duplicated plotting of arrow heads (#640, #1709). +- Update vendored sources to igraph/igraph@d6348668ba511735110758dc4ee0423a983bf1ac. -- Correct mapping of edge label properties in plots when loops are present (#157, #1706). + refactor: remove extraneous whitespace before continuation backslashes in max clique template code -## Documentation +- Update vendored sources to igraph/igraph@9f06e4c34d8b1d533ba331ae581844a2ea9b565f. -- Welcome Maëlle Salmon and David Schoch as authors (#1733), add author links (#1821). + chore: punctuate som error messages -- Remove demos (#2008). +- Update vendored sources to igraph/igraph@befc831fff74e4bae39743b1f83b38e6b3af0390. -- Add 2023 preprint (#1240, #1984). + fix: correct some implicit integer conversions -- Update allcontributors info (#1975). +- Update vendored sources to igraph/igraph@5e3c56c6a10cb954b78c7441c5460a3c6ad4f5b7. -- Link to replacements of deprecated functions (#1823). + fix: eliminate some unused parameter warnings -- Add documentation of all file formats to `read_graph()` and `write_graph()` (#777, #1969). Recommend `saveRDS()` and `readRDS()` for saving and loading graphs (#1242, #1700). +- Update vendored sources to igraph/igraph@8cdfd787c2be8886cc4eac014f3004055a8c3ca0. -- Document return value of `make_clusters()` (#1794). + refactor: improved const-correctness in vector implementation -- Clarify that `girth()` returns `Inf` for acyclic graphs (@eqmooring, #1831). +- Update vendored sources to igraph/igraph@ab123f04e487bc8bc1b93b9258e577e5f05d7ce9. -- Clarify the use of weights in `layout_with_kk()`. + chore: update plfit, works around non-compile-time-constant NAN bug in recent Windows 11 SDKs -- Refer to current latest version of R in troubleshooting page. +- Update vendored sources to igraph/igraph@833672f02161051010d1b633b23be53765663372. -- Fix typos in `laplacian_matrix()` documentation. + chore: restrict workaround to CMake 3.31.0 USE_TERMINAL bug to the single affected CMake version -- Document ellipsis in `cohesion()` (#971, #1985). +- Update vendored sources to igraph/igraph@5e734a2c1211d017088a882ed121f25956e20189. -- Correct the description of the `weights` parameter of `hits_scores()`. + ci: support for controlling the use of plfit and improve alpine jon -- Better describe output of `all_shortest_paths()` (#1029, #1778). +- Update vendored sources to igraph/igraph@ed43183a2eeb9e604addf1dc672908b7b845cec7. -- `make_graph()` now supports `"Groetzsch"` as an alias of `"Grotzsch"`. This change was implemented in the C core. + refactor: some cleanup in shortest path implementations -- Update description of `order` parameter of `ego()` and related functions (#1746). +- Update vendored sources to igraph/igraph@2412652489721e41617e3d9719b02923da31ab0d. -- Added lifecycle table (#1525). + chore: devcontainer update -- Add more about igraph.r2cdocs in the contributing guide (#1686, #1697). +- Update vendored sources to igraph/igraph@48ff9407b74cca8e50f1d256b039452e40662985. -## Performance + chore: link to relevant CMake bug regarding policy CMP0175 -- Accelerate check if an index sequence corresponds to the entire list of vertices (#1427, #1818). +- Update vendored sources to igraph/igraph@3631b1d5a0f3b7e49463f89cbbba762b24d9383d. + + refactor: clean up igraph_path_length_hist() + +- Update vendored sources to igraph/igraph@6fd3903c84d741d4bed0284c85db277836a4af79. + + refactor: clean up igraph_vertex_path_from_edge_path() and clarify that it is suitable for any walk, not just paths + +- Update vendored sources to igraph/igraph@379ef39bb89f41ba6d0ff39a86039571796e3bde. + + refactor: eliminate redundant pointer variable in GraphML reader + +- Update vendored sources to igraph/igraph@af14d843991f9e4f2894477a8644cfbd27a13d11. + + fix: mark global variables in GraphML parser as static + +- Update vendored sources to igraph/igraph@05979d3b2c85c12334ce5d3508dd473cdfa3c6f5. + + doc: improve maximal clique docs + +- Update vendored sources to igraph/igraph@41d855d470c7e5cca40bb8a2e294656504aa2a56. + + chore: update changelog + +- Update vendored sources to igraph/igraph@a2109c50681c0b444285cf40d09a602047141ea1. + + docs: more cross-referencing + +- Update vendored sources to igraph/igraph@62881320e766e8df227839a67078dd22e909cd2d. + + docs: fix typo + +- Update vendored sources to igraph/igraph@3673a0a9c3b3604ab1975432f6bbeed697dc9f7c. + + doc: more cross-linking + +- Update vendored sources to igraph/igraph@e842e658993df7305aec9d805baf36008aec9e4d. + + fix: compatibility with CMake 3.31 + +- Update vendored sources to igraph/igraph@2f0e27c9c19e8e7eb9b3b2df01ae3186f1e62470. + + ci: use modern CMake features for CTest parallelization + +- Update vendored sources to igraph/igraph@a16619502b6c21d4883eeee992794b271e1035d9. + + chore: updated changelog + +- Update vendored sources (tag 0.10.15) to igraph/igraph@635b432eff0a89580ac9bb98068d2fbc8ef374f2. + + chore: updated changelog + +- Update vendored sources to igraph/igraph@563aa5e8569b85a73680752bd8ad5624575610b6. + + chore: run pre-commit hooks + +- Update vendored sources to igraph/igraph@f32e621f3833556e361a3078ab9e046f6acdd9b8. + + chore: bump VERSION property in shared library + +- Update vendored sources to igraph/igraph@26d3718b364167dd0528c63a35f9e5e513df6845. + + refactor: do not use vector_get() in simple cycle finder + +- Update vendored sources to igraph/igraph@cd7bcd9d9b9bfd9acd83dace6438507947297ce2. + + refactor: cleaner parameter ordering in igraph_i_simple_cycles_circuit() + +- Update vendored sources to igraph/igraph@dafe829b811f9344fb1f5a8412a100b586817e3f. + + refactor: support specifying a minimum cycle length in `igraph_simple_cycles()` + +- Update vendored sources to igraph/igraph@c263ce7541e904f71dbcb7e06ca0dfb08cbf2ed7. + + interface: loops=True default for igraph_degree() + +- Update vendored sources to igraph/igraph@f6ec07e8a9425f09259bd04b0fefe1ebdfe64067. + + chore: updated contributors list + +- Update vendored sources to igraph/igraph@a6441e7a00118988aeac528910d6b9d417aec364. + + chore: trim trailing whitespace in interface file + +- Update vendored sources to igraph/igraph@042a2c5230e8008b976a5ad0f04fe2b3e00cde97. + + interface: add missing interface for igraph_get_isomorphisms_vf2_callback() + +- Update vendored sources to igraph/igraph@797ab4fa6c9a119ff12af1f5d6080de8d1e4f142. + + interface: mark all callback extra parameters and some callback functions as optional -- Faster single bracket querying of a graph (#1465, #1658). +- Update vendored sources to igraph/igraph@518fcc4165c420b9f4958d1496a607d325d69826. + + interface: add default parameter values for fundamental_cycles() and minimum_cycle_basis() + +- Update vendored sources to igraph/igraph@d9c328f61e31d93681e2c0894ace18ad59a5dba2. + + interface: even more missing OPTIONAL markers + +- Update vendored sources to igraph/igraph@3b9cb6ff078cf4e7fdb2be593811e50b97232fea. + + interface: add more missing OPTIONAL markers + +- Update vendored sources to igraph/igraph@5512e864ecddc76af4a7c93b7e4ebfd7030cc404. + + fix: some weights parameters were incorrectly marked as OPTIONAL in functions.yaml + +- Update vendored sources to igraph/igraph@4b208d877de74a730e8707e94ebad5318cf308ae. + + fix: mark some optional weight parameters as OPTIONAL in functions.yaml + +- Update vendored sources to igraph/igraph@d0616a433134dcb6ae6f3195c5a72e456f5a4809. + + fix: type -\> types in is_bipartite interface + +- Update vendored sources to igraph/igraph@c3f9a823d8bc7fa210df4e1225c86226195e1f16. + + fix: some BIPARTITE_TYPES parameters were incorrectly marked as optional + +- Update vendored sources to igraph/igraph@34f8d72f3c702aa490644244ebee98b836ac45d1. + + refactor: use OPTIONAL instead of =NULL in interfaces + +- Update vendored sources to igraph/igraph@5c74801197212e9908f561139af3141410cf49d2. + + feat: functionality for listing all simple cycles + +- Update vendored sources to igraph/igraph@f5d79f2eb90c2597ea0e33c60d0e6a083efc4abc. + + interface: default OUT mode for igraph_find_cycle() + +- Update vendored sources to igraph/igraph@992f77abdbe675c2d0dd2926536c57496b720c81. + + refactor: better error reporting for igraph_find_cycle() + +- Update vendored sources to igraph/igraph@207f0bb1624bb73a9d1f2f979bf2b2bfde60626f. + + chore: some copyright header cleanup in public headers + +- Update vendored sources to igraph/igraph@8eaa07489a27f55cdf8421bbbb8e34b60eacd1bf. + + refactor: minor readability improvements + +- Update vendored sources to igraph/igraph@5cd6552bf00d6a774cdd64b5fabf2c79524ccfc7. + + fix: add some missing IGRAPH_CHECKs + +- Update vendored sources to igraph/igraph@82d35eebd8c73a9476d5e2d205a851b4ebfc8eda. + + refactor: minor readability cleanup in matching functions + +- Update vendored sources to igraph/igraph@01db8e25a80dd8f93ccb9d7a6f39379a57fdc3ad. + + fix: `igraph_bipartite_projection_size()` now validates the bipartite `types` vector + +- Update vendored sources to igraph/igraph@7284ee015d2662ca4e1ab62e3ce17ff34df24430. + + chore: fix some spelling mistakes + +- Update vendored sources to igraph/igraph@1d6ef7c417e38c881ef325d8c553ccf767db6b6f. + + refactor: minor readability cleanup in igraph_decompose() + +- Update vendored sources to igraph/igraph@0878f577d45ff5fdc33e0ecacc542277a8024af9. + + doc: more documentation improvements + +- Update vendored sources to igraph/igraph@bd7b3a82bb9db038ebfcc046319947c5ea196660. + + doc: several documentation improvements and cross-referencing + +- Update vendored sources to igraph/igraph@764954eda823c40341d302ac290629d96d5bd9bf. + + chore: fix typo in error message + +- Update vendored sources to igraph/igraph@6c0a4310474e9935acc557673e1a2f9ec0dd6db3. + + docs: community_optimal_modulairty() does support directed graphs + +- Update vendored sources to igraph/igraph@59d71d001308d424782a386fea3069cf880d82a2. + + chore: do not warn about unknown warning options with legacy Intel compiler + +- Update vendored sources to igraph/igraph@7a0d4918abfd34c38eb2fdeec4460b2370cea1c9. + + fix: validate sample size in igraph_motifs_randesu_estimate() + +- Update vendored sources to igraph/igraph@e7820cf969a8c63d6564452f73246c044ee99ba9. + + chore: fix typo in comment + +## hack + +- Provide NULL default for types argument of `bipartite_projection_size()`. + This parameter is optional in R, but not in C. Therefore the C interface definition doesn't provide a default or OPTIONAL marker. + +## Uncategorized + +- Vendor: Update vendored sources to igraph/igraph@ae93a3a2431bb6fd8a1feb687cac32feef63730b. + +- Vendor: Update vendored sources to igraph/igraph@e940ab737938dfdd4518164c866b2599af40856f. + +- Vendor: Update vendored sources to igraph/igraph@3ac79b81bdf835460445ca6163f25e6559ec9958. + +- Vendor: Update vendored sources to igraph/igraph@f7b77f9e9cb4d670886b7e15e876c5549250befa. + +- Vendor: Update vendored sources to igraph/igraph@a662f79d46970bbcc2888e69dce5daa3fee8906e. + +- Vendor: Update vendored sources to igraph/igraph@a1389c191ac42b5ed3fcaf341ff3235c9f6f19f3. + +- Vendor: Update vendored sources to igraph/igraph@12299c4928f9f463c06d0b46752df69a6d67c289. + + +# igraph 2.1.3.9000 + +- Switching to development version. # igraph 2.1.4 @@ -507,13 +1865,13 @@ See for a complete changelog, in particular the section "Breaking changes". -## Lifecycle +## Lifecycle ### Breaking changes - Breaking change: remove tkigraph from {igraph} proper (#1474). - Breaking change: Hard-deprecate `get.edge()` and `layout.grid.3d()` which have been deprecated for 10 years (#1398). -- Breaking change: use `rlang::arg_match()` in `igraph.match.arg()` (#1165). +- Breaking change: use `rlang::arg_match()` in `igraph_match_arg()` (#1165). ### In-progress deprecations @@ -952,7 +2310,7 @@ The internal format of graph objects has changed in a mostly backward-compatible This graph was created by an old(er) igraph version. Call upgrade_graph() on it to use with the current igraph version For now we convert it on the fly... -Error in is_directed(object) : +Error in is_directed(object) : REAL() can only be applied to a 'numeric', not a 'NULL' ``` diff --git a/R/aaa-auto.R b/R/aaa-auto.R index 1f40fa4697c..7ed4777e8aa 100644 --- a/R/aaa-auto.R +++ b/R/aaa-auto.R @@ -111,7 +111,7 @@ delete_vertices_impl <- function( res } -delete_vertices_idx_impl <- function( +delete_vertices_map_impl <- function( graph, vertices ) { @@ -122,7 +122,7 @@ delete_vertices_idx_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_delete_vertices_idx, + R_igraph_delete_vertices_map, graph, vertices - 1 ) @@ -165,7 +165,9 @@ ecount_impl <- function( neighbors_impl <- function( graph, vid, - mode = c("all", "out", "in", "total") + mode = c("all", "out", "in", "total"), + loops = c("twice", "none", "once"), + multiple = TRUE ) { # Argument checks ensure_igraph(graph) @@ -177,6 +179,8 @@ neighbors_impl <- function( ) } mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) + loops <- switch_igraph_arg(loops, "none" = 0L, "twice" = 1L, "once" = 2L) + multiple <- as.logical(multiple) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -184,7 +188,9 @@ neighbors_impl <- function( R_igraph_neighbors, graph, vid - 1, - mode + mode, + loops, + multiple ) if (igraph_opt("return.vs.es")) { res <- create_vs(graph, res) @@ -212,13 +218,13 @@ degree_impl <- function( graph, vids = V(graph), mode = c("all", "out", "in", "total"), - loops = TRUE + loops = c("twice", "none", "once") ) { # Argument checks ensure_igraph(graph) vids <- as_igraph_vs(graph, vids) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) - loops <- as.logical(loops) + loops <- switch_igraph_arg(loops, "none" = 0L, "twice" = 1L, "once" = 2L) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -235,18 +241,21 @@ degree_impl <- function( edges_impl <- function( graph, - eids + eids, + bycol = FALSE ) { # Argument checks ensure_igraph(graph) eids <- as_igraph_es(graph, eids) + bycol <- as.logical(bycol) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_edges, graph, - eids - 1 + eids - 1, + bycol ) res @@ -294,7 +303,8 @@ get_all_eids_between_impl <- function( incident_impl <- function( graph, vid, - mode = c("all", "out", "in", "total") + mode = c("all", "out", "in", "total"), + loops = c("twice", "none", "once") ) { # Argument checks ensure_igraph(graph) @@ -306,6 +316,7 @@ incident_impl <- function( ) } mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) + loops <- switch_igraph_arg(loops, "none" = 0L, "twice" = 1L, "once" = 2L) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -313,7 +324,8 @@ incident_impl <- function( R_igraph_incident, graph, vid - 1, - mode + mode, + loops ) if (igraph_opt("return.vs.es")) { res <- create_es(graph, res) @@ -645,7 +657,7 @@ famous_impl <- function( res } -lcf_vector_impl <- function( +lcf_impl <- function( n, shifts, repeats = 1 @@ -658,16 +670,12 @@ lcf_vector_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_lcf_vector, + R_igraph_lcf, n, shifts, repeats ) - if (igraph_opt("add.params")) { - res$name <- 'LCF graph' - } - res } @@ -731,7 +739,7 @@ full_bipartite_impl <- function( mode ) if (igraph_opt("add.vertex.names") && is_named(res$graph)) { - names(res$types) <- vertex_attr(res$graph, "name") + names(res$types) <- vertex_attr(res$graph, "name", V(res$graph)) } res } @@ -851,11 +859,6 @@ circulant_impl <- function( directed ) - if (igraph_opt("add.params")) { - res$name <- 'Circulant graph' - res$shifts <- shifts - } - res } @@ -907,13 +910,16 @@ erdos_renyi_game_gnp_impl <- function( n, p, directed = FALSE, - loops = FALSE + allowed_edge_types = c("simple", "loops", "multi", "all"), + edge_labeled = FALSE ) { # Argument checks n <- as.numeric(n) p <- as.numeric(p) directed <- as.logical(directed) - loops <- as.logical(loops) + allowed_edge_types <- switch_igraph_arg(allowed_edge_types, + "simple" = 0L, "loop" = 1L, "loops" = 1L, "multi" = 6L, "multiple" = 6L, "all" = 7L) + edge_labeled <- as.logical(edge_labeled) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -922,13 +928,43 @@ erdos_renyi_game_gnp_impl <- function( n, p, directed, - loops + allowed_edge_types, + edge_labeled ) res } erdos_renyi_game_gnm_impl <- function( + n, + m, + directed = FALSE, + allowed_edge_types = c("simple", "loops", "multi", "all"), + edge_labeled = FALSE +) { + # Argument checks + n <- as.numeric(n) + m <- as.numeric(m) + directed <- as.logical(directed) + allowed_edge_types <- switch_igraph_arg(allowed_edge_types, + "simple" = 0L, "loop" = 1L, "loops" = 1L, "multi" = 6L, "multiple" = 6L, "all" = 7L) + edge_labeled <- as.logical(edge_labeled) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_erdos_renyi_game_gnm, + n, + m, + directed, + allowed_edge_types, + edge_labeled + ) + + res +} + +iea_game_impl <- function( n, m, directed = FALSE, @@ -943,7 +979,7 @@ erdos_renyi_game_gnm_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_erdos_renyi_game_gnm, + R_igraph_iea_game, n, m, directed, @@ -1054,14 +1090,13 @@ asymmetric_preference_game_impl <- function( rewire_edges_impl <- function( graph, prob, - loops = FALSE, - multiple = FALSE + allowed_edge_types = c("simple", "loops", "multi", "all") ) { # Argument checks ensure_igraph(graph) prob <- as.numeric(prob) - loops <- as.logical(loops) - multiple <- as.logical(multiple) + allowed_edge_types <- switch_igraph_arg(allowed_edge_types, + "simple" = 0L, "loop" = 1L, "loops" = 1L, "multi" = 6L, "multiple" = 6L, "all" = 7L) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -1069,8 +1104,7 @@ rewire_edges_impl <- function( R_igraph_rewire_edges, graph, prob, - loops, - multiple + allowed_edge_types ) res @@ -1205,15 +1239,14 @@ static_fitness_game_impl <- function( no_of_edges, fitness_out, fitness_in = NULL, - loops = FALSE, - multiple = FALSE + allowed_edge_types = c("simple", "loops", "multi", "all") ) { # Argument checks no_of_edges <- as.numeric(no_of_edges) fitness_out <- as.numeric(fitness_out) if (!is.null(fitness_in)) fitness_in <- as.numeric(fitness_in) - loops <- as.logical(loops) - multiple <- as.logical(multiple) + allowed_edge_types <- switch_igraph_arg(allowed_edge_types, + "simple" = 0L, "loop" = 1L, "loops" = 1L, "multi" = 6L, "multiple" = 6L, "all" = 7L) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -1222,8 +1255,7 @@ static_fitness_game_impl <- function( no_of_edges, fitness_out, fitness_in, - loops, - multiple + allowed_edge_types ) if (igraph_opt("add.params")) { @@ -1240,8 +1272,7 @@ static_power_law_game_impl <- function( no_of_edges, exponent_out, exponent_in = -1, - loops = FALSE, - multiple = FALSE, + allowed_edge_types = c("simple", "loops", "multi", "all"), finite_size_correction = TRUE ) { # Argument checks @@ -1249,8 +1280,8 @@ static_power_law_game_impl <- function( no_of_edges <- as.numeric(no_of_edges) exponent_out <- as.numeric(exponent_out) exponent_in <- as.numeric(exponent_in) - loops <- as.logical(loops) - multiple <- as.logical(multiple) + allowed_edge_types <- switch_igraph_arg(allowed_edge_types, + "simple" = 0L, "loop" = 1L, "loops" = 1L, "multi" = 6L, "multiple" = 6L, "all" = 7L) finite_size_correction <- as.logical(finite_size_correction) on.exit(.Call(R_igraph_finalizer)) @@ -1261,8 +1292,7 @@ static_power_law_game_impl <- function( no_of_edges, exponent_out, exponent_in, - loops, - multiple, + allowed_edge_types, finite_size_correction ) @@ -1270,8 +1300,6 @@ static_power_law_game_impl <- function( res$name <- 'Static power law model' res$exponent_out <- exponent_out res$exponent_in <- exponent_in - res$loops <- loops - res$multiple <- multiple res$finite_size_correction <- finite_size_correction } @@ -1309,28 +1337,26 @@ k_regular_game_impl <- function( } sbm_game_impl <- function( - n, pref_matrix, block_sizes, directed = FALSE, - loops = FALSE + allowed_edge_types = c("simple", "loops", "multi", "all") ) { # Argument checks - n <- as.numeric(n) pref_matrix[] <- as.numeric(pref_matrix) block_sizes <- as.numeric(block_sizes) directed <- as.logical(directed) - loops <- as.logical(loops) + allowed_edge_types <- switch_igraph_arg(allowed_edge_types, + "simple" = 0L, "loop" = 1L, "loops" = 1L, "multi" = 6L, "multiple" = 6L, "all" = 7L) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_sbm_game, - n, pref_matrix, block_sizes, directed, - loops + allowed_edge_types ) if (igraph_opt("add.params")) { @@ -1486,75 +1512,6 @@ dot_product_game_impl <- function( res } -sample_sphere_surface_impl <- function( - dim, - n = 1, - radius = 1, - positive = TRUE -) { - # Argument checks - dim <- as.numeric(dim) - n <- as.numeric(n) - radius <- as.numeric(radius) - positive <- as.logical(positive) - - on.exit(.Call(R_igraph_finalizer)) - # Function call - res <- .Call( - R_igraph_sample_sphere_surface, - dim, - n, - radius, - positive - ) - - res -} - -sample_sphere_volume_impl <- function( - dim, - n = 1, - radius = 1, - positive = TRUE -) { - # Argument checks - dim <- as.numeric(dim) - n <- as.numeric(n) - radius <- as.numeric(radius) - positive <- as.logical(positive) - - on.exit(.Call(R_igraph_finalizer)) - # Function call - res <- .Call( - R_igraph_sample_sphere_volume, - dim, - n, - radius, - positive - ) - - res -} - -sample_dirichlet_impl <- function( - n, - alpha -) { - # Argument checks - n <- as.numeric(n) - alpha <- as.numeric(alpha) - - on.exit(.Call(R_igraph_finalizer)) - # Function call - res <- .Call( - R_igraph_sample_dirichlet, - n, - alpha - ) - - res -} - are_adjacent_impl <- function( graph, v1, @@ -1589,6 +1546,38 @@ are_adjacent_impl <- function( res } +diameter_impl <- function( + graph, + weights = NULL, + directed = TRUE, + unconnected = TRUE +) { + # Argument checks + ensure_igraph(graph) + if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { + weights <- E(graph)$weight + } + if (!is.null(weights) && !all(is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } + directed <- as.logical(directed) + unconnected <- as.logical(unconnected) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_diameter, + graph, + weights, + directed, + unconnected + ) + + res +} + closeness_impl <- function( graph, vids = V(graph), @@ -1632,7 +1621,7 @@ closeness_cutoff_impl <- function( mode = c("out", "in", "all", "total"), weights = NULL, normalized = FALSE, - cutoff = -1 + cutoff = UNLIMITED ) { # Argument checks ensure_igraph(graph) @@ -1668,12 +1657,21 @@ closeness_cutoff_impl <- function( get_shortest_path_impl <- function( graph, + weights = NULL, from, to, mode = c("out", "in", "all", "total") ) { # Argument checks ensure_igraph(graph) + if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { + weights <- E(graph)$weight + } + if (!is.null(weights) && !all(is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } from <- as_igraph_vs(graph, from) if (length(from) == 0) { cli::cli_abort( @@ -1695,6 +1693,7 @@ get_shortest_path_impl <- function( res <- .Call( R_igraph_get_shortest_path, graph, + weights, from - 1, to - 1, mode @@ -1814,12 +1813,21 @@ get_shortest_path_dijkstra_impl <- function( get_all_shortest_paths_impl <- function( graph, + weights = NULL, from, to, mode = c("out", "in", "all", "total") ) { # Argument checks ensure_igraph(graph) + if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { + weights <- E(graph)$weight + } + if (!is.null(weights) && !all(is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } from <- as_igraph_vs(graph, from) if (length(from) == 0) { cli::cli_abort( @@ -1835,16 +1843,12 @@ get_all_shortest_paths_impl <- function( res <- .Call( R_igraph_get_all_shortest_paths, graph, + weights, from - 1, to - 1, mode ) - if (igraph_opt("return.vs.es")) { - res$vpaths <- lapply(res$vpaths, unsafe_create_vs, graph = graph, verts = V(graph)) - } - if (igraph_opt("return.vs.es")) { - res$epaths <- lapply(res$epaths, unsafe_create_es, graph = graph, es = E(graph)) - } + res } @@ -1885,12 +1889,7 @@ get_all_shortest_paths_dijkstra_impl <- function( weights, mode ) - if (igraph_opt("return.vs.es")) { - res$vpaths <- lapply(res$vpaths, unsafe_create_vs, graph = graph, verts = V(graph)) - } - if (igraph_opt("return.vs.es")) { - res$epaths <- lapply(res$epaths, unsafe_create_es, graph = graph, es = E(graph)) - } + res } @@ -1935,8 +1934,10 @@ get_all_simple_paths_impl <- function( graph, from, to = V(graph), - cutoff = -1, - mode = c("out", "in", "all", "total") + mode = c("out", "in", "all", "total"), + minlen = UNLIMITED, + maxlen = UNLIMITED, + max_results = UNLIMITED ) { # Argument checks ensure_igraph(graph) @@ -1948,8 +1949,10 @@ get_all_simple_paths_impl <- function( ) } to <- as_igraph_vs(graph, to) - cutoff <- as.numeric(cutoff) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) + minlen <- as.numeric(minlen) + maxlen <- as.numeric(maxlen) + max_results <- as.numeric(max_results) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -1958,12 +1961,12 @@ get_all_simple_paths_impl <- function( graph, from - 1, to - 1, - cutoff, - mode + mode, + minlen, + maxlen, + max_results ) - if (igraph_opt("return.vs.es")) { - res <- create_vs(graph, res) - } + res } @@ -2015,12 +2018,7 @@ get_k_shortest_paths_impl <- function( to - 1, mode ) - if (igraph_opt("return.vs.es")) { - res$vpaths <- lapply(res$vpaths, unsafe_create_vs, graph = graph, verts = V(graph)) - } - if (igraph_opt("return.vs.es")) { - res$epaths <- lapply(res$epaths, unsafe_create_es, graph = graph, es = E(graph)) - } + res } @@ -2028,7 +2026,7 @@ get_widest_path_impl <- function( graph, from, to, - weights = NULL, + weights, mode = c("out", "in", "all", "total") ) { # Argument checks @@ -2080,7 +2078,7 @@ get_widest_paths_impl <- function( graph, from, to = V(graph), - weights = NULL, + weights, mode = c("out", "in", "all", "total") ) { # Argument checks @@ -2113,12 +2111,7 @@ get_widest_paths_impl <- function( weights, mode ) - if (igraph_opt("return.vs.es")) { - res$vertices <- lapply(res$vertices, unsafe_create_vs, graph = graph, verts = V(graph)) - } - if (igraph_opt("return.vs.es")) { - res$edges <- lapply(res$edges, unsafe_create_es, graph = graph, es = E(graph)) - } + res } @@ -2126,7 +2119,7 @@ widest_path_widths_dijkstra_impl <- function( graph, from = V(graph), to = V(graph), - weights = NULL, + weights, mode = c("out", "in", "all", "total") ) { # Argument checks @@ -2161,7 +2154,7 @@ widest_path_widths_floyd_warshall_impl <- function( graph, from = V(graph), to = V(graph), - weights = NULL, + weights, mode = c("out", "in", "all", "total") ) { # Argument checks @@ -2225,15 +2218,14 @@ spanner_impl <- function( betweenness_cutoff_impl <- function( graph, + weights = NULL, vids = V(graph), directed = TRUE, - weights = NULL, - cutoff = -1 + normalized = FALSE, + cutoff = UNLIMITED ) { # Argument checks ensure_igraph(graph) - vids <- as_igraph_vs(graph, vids) - directed <- as.logical(directed) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -2242,6 +2234,9 @@ betweenness_cutoff_impl <- function( } else { weights <- NULL } + vids <- as_igraph_vs(graph, vids) + directed <- as.logical(directed) + normalized <- as.logical(normalized) cutoff <- as.numeric(cutoff) on.exit(.Call(R_igraph_finalizer)) @@ -2249,9 +2244,10 @@ betweenness_cutoff_impl <- function( res <- .Call( R_igraph_betweenness_cutoff, graph, + weights, vids - 1, directed, - weights, + normalized, cutoff ) if (igraph_opt("add.vertex.names") && is_named(graph)) { @@ -2262,18 +2258,15 @@ betweenness_cutoff_impl <- function( betweenness_subset_impl <- function( graph, + weights = NULL, vids = V(graph), - directed = TRUE, sources = V(graph), targets = V(graph), - weights = NULL + directed = TRUE, + normalized = FALSE ) { # Argument checks ensure_igraph(graph) - vids <- as_igraph_vs(graph, vids) - directed <- as.logical(directed) - sources <- as_igraph_vs(graph, sources) - targets <- as_igraph_vs(graph, targets) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -2282,17 +2275,23 @@ betweenness_subset_impl <- function( } else { weights <- NULL } + vids <- as_igraph_vs(graph, vids) + sources <- as_igraph_vs(graph, sources) + targets <- as_igraph_vs(graph, targets) + directed <- as.logical(directed) + normalized <- as.logical(normalized) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_betweenness_subset, graph, + weights, vids - 1, - directed, sources - 1, targets - 1, - weights + directed, + normalized ) if (igraph_opt("add.vertex.names") && is_named(graph)) { names(res) <- vertex_attr(graph, "name", vids) @@ -2302,12 +2301,13 @@ betweenness_subset_impl <- function( edge_betweenness_impl <- function( graph, + weights = NULL, + eids = E(graph), directed = TRUE, - weights = NULL + normalized = FALSE ) { # Argument checks ensure_igraph(graph) - directed <- as.logical(directed) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -2316,14 +2316,19 @@ edge_betweenness_impl <- function( } else { weights <- NULL } + eids <- as_igraph_es(graph, eids) + directed <- as.logical(directed) + normalized <- as.logical(normalized) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_edge_betweenness, graph, + weights, + eids - 1, directed, - weights + normalized ) res @@ -2331,13 +2336,14 @@ edge_betweenness_impl <- function( edge_betweenness_cutoff_impl <- function( graph, - directed = TRUE, weights = NULL, - cutoff = -1 + eids = E(graph), + directed = TRUE, + normalized = FALSE, + cutoff = UNLIMITED ) { # Argument checks ensure_igraph(graph) - directed <- as.logical(directed) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -2346,6 +2352,9 @@ edge_betweenness_cutoff_impl <- function( } else { weights <- NULL } + eids <- as_igraph_es(graph, eids) + directed <- as.logical(directed) + normalized <- as.logical(normalized) cutoff <- as.numeric(cutoff) on.exit(.Call(R_igraph_finalizer)) @@ -2353,8 +2362,10 @@ edge_betweenness_cutoff_impl <- function( res <- .Call( R_igraph_edge_betweenness_cutoff, graph, - directed, weights, + eids - 1, + directed, + normalized, cutoff ) @@ -2363,18 +2374,15 @@ edge_betweenness_cutoff_impl <- function( edge_betweenness_subset_impl <- function( graph, - eids = E(graph), - directed = TRUE, + weights = NULL, sources = V(graph), targets = V(graph), - weights = NULL + eids = E(graph), + directed = TRUE, + normalized = FALSE ) { # Argument checks ensure_igraph(graph) - eids <- as_igraph_es(graph, eids) - directed <- as.logical(directed) - sources <- as_igraph_vs(graph, sources) - targets <- as_igraph_vs(graph, targets) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -2383,17 +2391,23 @@ edge_betweenness_subset_impl <- function( } else { weights <- NULL } + sources <- as_igraph_vs(graph, sources) + targets <- as_igraph_vs(graph, targets) + eids <- as_igraph_es(graph, eids) + directed <- as.logical(directed) + normalized <- as.logical(normalized) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_edge_betweenness_subset, graph, - eids - 1, - directed, + weights, sources - 1, targets - 1, - weights + eids - 1, + directed, + normalized ) res @@ -2405,7 +2419,7 @@ harmonic_centrality_cutoff_impl <- function( mode = c("out", "in", "all", "total"), weights = NULL, normalized = FALSE, - cutoff = -1 + cutoff = UNLIMITED ) { # Argument checks ensure_igraph(graph) @@ -2441,21 +2455,16 @@ harmonic_centrality_cutoff_impl <- function( personalized_pagerank_impl <- function( graph, - algo = c("prpack", "arpack"), - vids = V(graph), - directed = TRUE, - damping = 0.85, - personalized = NULL, weights = NULL, + reset = NULL, + damping = 0.85, + directed = TRUE, + vids = V(graph), + algo = c("prpack", "arpack"), options = NULL ) { # Argument checks ensure_igraph(graph) - algo <- switch_igraph_arg(algo, "arpack" = 1L, "prpack" = 2L) - vids <- as_igraph_vs(graph, vids) - directed <- as.logical(directed) - damping <- as.numeric(damping) - if (!is.null(personalized)) personalized <- as.numeric(personalized) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -2464,6 +2473,11 @@ personalized_pagerank_impl <- function( } else { weights <- NULL } + if (!is.null(reset)) reset <- as.numeric(reset) + damping <- as.numeric(damping) + directed <- as.logical(directed) + vids <- as_igraph_vs(graph, vids) + algo <- switch_igraph_arg(algo, "arpack" = 1L, "prpack" = 2L) if (is.null(options)) { if (algo == 0L) { options <- list(niter=1000, eps=0.001) @@ -2479,12 +2493,12 @@ personalized_pagerank_impl <- function( res <- .Call( R_igraph_personalized_pagerank, graph, - algo, - vids - 1, - directed, - damping, - personalized, weights, + reset, + damping, + directed, + vids - 1, + algo, options ) if (igraph_opt("add.vertex.names") && is_named(graph)) { @@ -2495,22 +2509,17 @@ personalized_pagerank_impl <- function( personalized_pagerank_vs_impl <- function( graph, - algo = c("prpack", "arpack"), - vids = V(graph), - directed = TRUE, - damping = 0.85, - reset_vids, weights = NULL, + reset_vids, + damping = 0.85, + directed = TRUE, + vids = V(graph), + algo = c("prpack", "arpack"), options = NULL, details = FALSE ) { # Argument checks ensure_igraph(graph) - algo <- switch_igraph_arg(algo, "arpack" = 1L, "prpack" = 2L) - vids <- as_igraph_vs(graph, vids) - directed <- as.logical(directed) - damping <- as.numeric(damping) - reset_vids <- as_igraph_vs(graph, reset_vids) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -2519,6 +2528,11 @@ personalized_pagerank_vs_impl <- function( } else { weights <- NULL } + reset_vids <- as_igraph_vs(graph, reset_vids) + damping <- as.numeric(damping) + directed <- as.logical(directed) + vids <- as_igraph_vs(graph, vids) + algo <- switch_igraph_arg(algo, "arpack" = 1L, "prpack" = 2L) if (is.null(options)) { if (algo == 0L) { options <- list(niter=1000, eps=0.001) @@ -2534,12 +2548,12 @@ personalized_pagerank_vs_impl <- function( res <- .Call( R_igraph_personalized_pagerank_vs, graph, - algo, - vids - 1, - directed, - damping, - reset_vids - 1, weights, + reset_vids - 1, + damping, + directed, + vids - 1, + algo, options ) if (igraph_opt("add.vertex.names") && is_named(graph)) { @@ -2554,12 +2568,13 @@ personalized_pagerank_vs_impl <- function( rewire_impl <- function( rewire, n, - mode = c("simple", "simple_loops") + allowed_edge_types = c("simple", "loops", "multi", "all") ) { # Argument checks ensure_igraph(rewire) n <- as.numeric(n) - mode <- switch_igraph_arg(mode, "simple" = 0L, "simple_loops" = 1L) + allowed_edge_types <- switch_igraph_arg(allowed_edge_types, + "simple" = 0L, "loop" = 1L, "loops" = 1L, "multi" = 6L, "multiple" = 6L, "all" = 7L) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -2567,7 +2582,7 @@ rewire_impl <- function( R_igraph_rewire, rewire, n, - mode + allowed_edge_types ) res @@ -2636,11 +2651,11 @@ reverse_edges_impl <- function( res } -average_path_length_dijkstra_impl <- function( +average_path_length_impl <- function( graph, weights = NULL, directed = TRUE, - unconnected = TRUE, + unconn = TRUE, details = FALSE ) { # Argument checks @@ -2654,16 +2669,16 @@ average_path_length_dijkstra_impl <- function( weights <- NULL } directed <- as.logical(directed) - unconnected <- as.logical(unconnected) + unconn <- as.logical(unconn) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_average_path_length_dijkstra, + R_igraph_average_path_length, graph, weights, directed, - unconnected + unconn ) if (!details) { res <- res$res @@ -2891,14 +2906,14 @@ maxdegree_impl <- function( ..., v = V(graph), mode = c("all", "out", "in", "total"), - loops = TRUE + loops = c("twice", "none", "once") ) { # Argument checks check_dots_empty() ensure_igraph(graph) v <- as_igraph_vs(graph, v) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) - loops <- as.logical(loops) + loops <- switch_igraph_arg(loops, "none" = 0L, "twice" = 1L, "once" = 2L) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -2915,10 +2930,19 @@ maxdegree_impl <- function( density_impl <- function( graph, + weights = NULL, loops = FALSE ) { # Argument checks ensure_igraph(graph) + if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { + weights <- E(graph)$weight + } + if (!is.null(weights) && !all(is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } loops <- as.logical(loops) on.exit(.Call(R_igraph_finalizer)) @@ -2926,6 +2950,7 @@ density_impl <- function( res <- .Call( R_igraph_density, graph, + weights, loops ) @@ -3084,16 +3109,19 @@ is_acyclic_impl <- function( } is_simple_impl <- function( - graph + graph, + directed = TRUE ) { # Argument checks ensure_igraph(graph) + directed <- as.logical(directed) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_is_simple, - graph + graph, + directed ) res @@ -3198,7 +3226,7 @@ girth_impl <- function( graph ) if (igraph_opt("return.vs.es")) { - res$circle <- create_vs(graph, res$circle) + res$cycle <- create_vs(graph, res$cycle) } res } @@ -3221,15 +3249,13 @@ is_perfect_impl <- function( eigenvector_centrality_impl <- function( graph, - directed = FALSE, - scale = TRUE, + mode = c("out", "in", "all", "total"), weights = NULL, options = arpack_defaults() ) { # Argument checks ensure_igraph(graph) - directed <- as.logical(directed) - scale <- as.logical(scale) + mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -3245,26 +3271,23 @@ eigenvector_centrality_impl <- function( res <- .Call( R_igraph_eigenvector_centrality, graph, - directed, - scale, + mode, weights, options ) if (igraph_opt("add.vertex.names") && is_named(graph)) { - names(res$vector) <- vertex_attr(graph, "name", V(graph)) + names(res$vector) <- vertex_attr(graph, "name") } res } hub_and_authority_scores_impl <- function( graph, - scale = TRUE, weights = NULL, options = arpack_defaults() ) { # Argument checks ensure_igraph(graph) - scale <- as.logical(scale) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -3280,15 +3303,14 @@ hub_and_authority_scores_impl <- function( res <- .Call( R_igraph_hub_and_authority_scores, graph, - scale, weights, options ) if (igraph_opt("add.vertex.names") && is_named(graph)) { - names(res$hub) <- vertex_attr(graph, "name", V(graph)) + names(res$hub_vector) <- vertex_attr(graph, "name") } if (igraph_opt("add.vertex.names") && is_named(graph)) { - names(res$authority) <- vertex_attr(graph, "name", V(graph)) + names(res$authority_vector) <- vertex_attr(graph, "name") } res } @@ -3488,14 +3510,14 @@ strength_impl <- function( graph, vids = V(graph), mode = c("all", "out", "in", "total"), - loops = TRUE, + loops = c("twice", "none", "once"), weights = NULL ) { # Argument checks ensure_igraph(graph) vids <- as_igraph_vs(graph, vids) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) - loops <- as.logical(loops) + loops <- switch_igraph_arg(loops, "none" = 0L, "twice" = 1L, "once" = 2L) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -3546,13 +3568,13 @@ centralization_impl <- function( centralization_degree_impl <- function( graph, mode = c("all", "out", "in", "total"), - loops = TRUE, + loops = c("twice", "none", "once"), normalized = TRUE ) { # Argument checks ensure_igraph(graph) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) - loops <- as.logical(loops) + loops <- switch_igraph_arg(loops, "none" = 0L, "twice" = 1L, "once" = 2L) normalized <- as.logical(normalized) on.exit(.Call(R_igraph_finalizer)) @@ -3578,7 +3600,7 @@ centralization_degree_tmax_impl <- function( if (!is.null(graph)) ensure_igraph(graph) nodes <- as.numeric(nodes) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) - loops <- as.logical(loops) + loops <- switch_igraph_arg(loops, "none" = 0L, "twice" = 1L, "once" = 2L) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -3683,15 +3705,13 @@ centralization_closeness_tmax_impl <- function( centralization_eigenvector_centrality_impl <- function( graph, - directed = FALSE, - scale = TRUE, + mode = c("out", "in", "all", "total"), options = arpack_defaults(), normalized = TRUE ) { # Argument checks ensure_igraph(graph) - directed <- as.logical(directed) - scale <- as.logical(scale) + mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) options <- modify_list(arpack_defaults(), options) normalized <- as.logical(normalized) @@ -3700,8 +3720,7 @@ centralization_eigenvector_centrality_impl <- function( res <- .Call( R_igraph_centralization_eigenvector_centrality, graph, - directed, - scale, + mode, options, normalized ) @@ -3712,14 +3731,12 @@ centralization_eigenvector_centrality_impl <- function( centralization_eigenvector_centrality_tmax_impl <- function( graph = NULL, nodes = 0, - directed = FALSE, - scale = TRUE + mode = c("out", "in", "all", "total") ) { # Argument checks if (!is.null(graph)) ensure_igraph(graph) nodes <- as.numeric(nodes) - directed <- as.logical(directed) - scale <- as.logical(scale) + mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -3727,8 +3744,7 @@ centralization_eigenvector_centrality_tmax_impl <- function( R_igraph_centralization_eigenvector_centrality_tmax, graph, nodes, - directed, - scale + mode ) res @@ -3736,12 +3752,21 @@ centralization_eigenvector_centrality_tmax_impl <- function( assortativity_nominal_impl <- function( graph, + weights = NULL, types, directed = TRUE, normalized = TRUE ) { # Argument checks ensure_igraph(graph) + if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { + weights <- E(graph)$weight + } + if (!is.null(weights) && !all(is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } types <- as.numeric(types)-1 directed <- as.logical(directed) normalized <- as.logical(normalized) @@ -3751,6 +3776,7 @@ assortativity_nominal_impl <- function( res <- .Call( R_igraph_assortativity_nominal, graph, + weights, types, directed, normalized @@ -3761,6 +3787,7 @@ assortativity_nominal_impl <- function( assortativity_impl <- function( graph, + weights = NULL, values, values_in = NULL, directed = TRUE, @@ -3768,6 +3795,14 @@ assortativity_impl <- function( ) { # Argument checks ensure_igraph(graph) + if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { + weights <- E(graph)$weight + } + if (!is.null(weights) && !all(is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } values <- as.numeric(values) if (!is.null(values_in)) values_in <- as.numeric(values_in) directed <- as.logical(directed) @@ -3778,6 +3813,7 @@ assortativity_impl <- function( res <- .Call( R_igraph_assortativity, graph, + weights, values, values_in, directed, @@ -3809,8 +3845,8 @@ assortativity_degree_impl <- function( joint_degree_matrix_impl <- function( graph, weights = NULL, - max_out_degree = -1, - max_in_degree = -1 + max_out_degree = UNLIMITED, + max_in_degree = UNLIMITED ) { # Argument checks ensure_igraph(graph) @@ -3845,8 +3881,8 @@ joint_degree_distribution_impl <- function( to_mode = c("in", "out", "all", "total"), directed_neighbors = TRUE, normalized = TRUE, - max_from_degree = -1, - max_to_degree = -1 + max_from_degree = UNLIMITED, + max_to_degree = UNLIMITED ) { # Argument checks ensure_igraph(graph) @@ -3942,15 +3978,13 @@ contract_vertices_impl <- function( res } -eccentricity_dijkstra_impl <- function( +eccentricity_impl <- function( graph, - vids = V(graph), - ..., weights = NULL, + vids = V(graph), mode = c("all", "out", "in", "total") ) { # Argument checks - check_dots_empty() ensure_igraph(graph) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight @@ -3966,7 +4000,7 @@ eccentricity_dijkstra_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_eccentricity_dijkstra, + R_igraph_eccentricity, graph, weights, vids - 1, @@ -3978,14 +4012,12 @@ eccentricity_dijkstra_impl <- function( res } -graph_center_dijkstra_impl <- function( +graph_center_impl <- function( graph, - ..., weights = NULL, mode = c("all", "out", "in", "total") ) { # Argument checks - check_dots_empty() ensure_igraph(graph) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight @@ -4000,7 +4032,7 @@ graph_center_dijkstra_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_graph_center_dijkstra, + R_igraph_graph_center, graph, weights, mode @@ -4011,14 +4043,12 @@ graph_center_dijkstra_impl <- function( res } -radius_dijkstra_impl <- function( +radius_impl <- function( graph, - ..., weights = NULL, mode = c("all", "out", "in", "total") ) { # Argument checks - check_dots_empty() ensure_igraph(graph) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight @@ -4033,7 +4063,7 @@ radius_dijkstra_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_radius_dijkstra, + R_igraph_radius, graph, weights, mode @@ -4043,37 +4073,6 @@ radius_dijkstra_impl <- function( } pseudo_diameter_impl <- function( - graph, - start_vid, - directed = TRUE, - unconnected = TRUE -) { - # Argument checks - ensure_igraph(graph) - start_vid <- as_igraph_vs(graph, start_vid) - if (length(start_vid) == 0) { - cli::cli_abort( - "{.arg start_vid} must specify at least one vertex", - call = rlang::caller_env() - ) - } - directed <- as.logical(directed) - unconnected <- as.logical(unconnected) - - on.exit(.Call(R_igraph_finalizer)) - # Function call - res <- .Call( - R_igraph_pseudo_diameter, - graph, - start_vid - 1, - directed, - unconnected - ) - - res -} - -pseudo_diameter_dijkstra_impl <- function( graph, weights = NULL, start_vid, @@ -4103,7 +4102,7 @@ pseudo_diameter_dijkstra_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_pseudo_diameter_dijkstra, + R_igraph_pseudo_diameter, graph, weights, start_vid - 1, @@ -4225,14 +4224,13 @@ global_efficiency_impl <- function( local_efficiency_impl <- function( graph, - vids = V(graph), weights = NULL, + vids = V(graph), directed = TRUE, mode = c("all", "out", "in", "total") ) { # Argument checks ensure_igraph(graph) - vids <- as_igraph_vs(graph, vids) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -4241,6 +4239,7 @@ local_efficiency_impl <- function( } else { weights <- NULL } + vids <- as_igraph_vs(graph, vids) directed <- as.logical(directed) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) @@ -4249,8 +4248,8 @@ local_efficiency_impl <- function( res <- .Call( R_igraph_local_efficiency, graph, - vids - 1, weights, + vids - 1, directed, mode ) @@ -4292,7 +4291,7 @@ average_local_efficiency_impl <- function( res } -transitive_closure_dag_impl <- function( +transitive_closure_impl <- function( graph ) { # Argument checks @@ -4301,14 +4300,14 @@ transitive_closure_dag_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_transitive_closure_dag, + R_igraph_transitive_closure, graph ) res } -transitive_closure_impl <- function( +trussness_impl <- function( graph ) { # Argument checks @@ -4317,23 +4316,7 @@ transitive_closure_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_transitive_closure, - graph - ) - - res -} - -trussness_impl <- function( - graph -) { - # Argument checks - ensure_igraph(graph) - - on.exit(.Call(R_igraph_finalizer)) - # Function call - res <- .Call( - R_igraph_trussness, + R_igraph_trussness, graph ) @@ -4412,14 +4395,36 @@ bipartite_projection_size_impl <- function( res } +create_bipartite_impl <- function( + types, + edges, + directed = FALSE +) { + # Argument checks + types <- handle_vertex_type_arg(types, graph) + edges <- as.numeric(edges) + directed <- as.logical(directed) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_create_bipartite, + types, + edges, + directed + ) + + res +} + biadjacency_impl <- function( - incidence, + biadjmatrix, directed = FALSE, mode = c("all", "out", "in", "total"), multiple = FALSE ) { # Argument checks - incidence[] <- as.numeric(incidence) + biadjmatrix[] <- as.numeric(biadjmatrix) directed <- as.logical(directed) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) multiple <- as.logical(multiple) @@ -4428,7 +4433,7 @@ biadjacency_impl <- function( # Function call res <- .Call( R_igraph_biadjacency, - incidence, + biadjmatrix, directed, mode, multiple @@ -4439,20 +4444,54 @@ biadjacency_impl <- function( res } +weighted_biadjacency_impl <- function( + biadjmatrix, + directed = FALSE, + mode = c("all", "out", "in", "total") +) { + # Argument checks + biadjmatrix[] <- as.numeric(biadjmatrix) + directed <- as.logical(directed) + mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_weighted_biadjacency, + biadjmatrix, + directed, + mode + ) + if (igraph_opt("add.vertex.names") && is_named(res$graph)) { + names(res$types) <- vertex_attr(res$graph, "name", V(res$graph)) + } + res +} + get_biadjacency_impl <- function( graph, - types + types, + weights = NULL ) { # Argument checks ensure_igraph(graph) types <- handle_vertex_type_arg(types, graph) + if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { + weights <- E(graph)$weight + } + if (!is.null(weights) && !all(is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_get_biadjacency, graph, - types + types, + weights ) res @@ -4481,7 +4520,9 @@ bipartite_game_gnp_impl <- function( n2, p, directed = FALSE, - mode = c("all", "out", "in", "total") + mode = c("all", "out", "in", "total"), + allowed_edge_types = c("simple", "loops", "multi", "all"), + edge_labeled = FALSE ) { # Argument checks n1 <- as.numeric(n1) @@ -4489,6 +4530,9 @@ bipartite_game_gnp_impl <- function( p <- as.numeric(p) directed <- as.logical(directed) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) + allowed_edge_types <- switch_igraph_arg(allowed_edge_types, + "simple" = 0L, "loop" = 1L, "loops" = 1L, "multi" = 6L, "multiple" = 6L, "all" = 7L) + edge_labeled <- as.logical(edge_labeled) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -4498,9 +4542,13 @@ bipartite_game_gnp_impl <- function( n2, p, directed, - mode + mode, + allowed_edge_types, + edge_labeled ) - + if (igraph_opt("add.vertex.names") && is_named(res$graph)) { + names(res$types) <- vertex_attr(res$graph, "name", V(res$graph)) + } res } @@ -4509,7 +4557,9 @@ bipartite_game_gnm_impl <- function( n2, m, directed = FALSE, - mode = c("all", "out", "in", "total") + mode = c("all", "out", "in", "total"), + allowed_edge_types = c("simple", "loops", "multi", "all"), + edge_labeled = FALSE ) { # Argument checks n1 <- as.numeric(n1) @@ -4517,6 +4567,9 @@ bipartite_game_gnm_impl <- function( m <- as.numeric(m) directed <- as.logical(directed) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) + allowed_edge_types <- switch_igraph_arg(allowed_edge_types, + "simple" = 0L, "loop" = 1L, "loops" = 1L, "multi" = 6L, "multiple" = 6L, "all" = 7L) + edge_labeled <- as.logical(edge_labeled) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -4526,9 +4579,43 @@ bipartite_game_gnm_impl <- function( n2, m, directed, - mode + mode, + allowed_edge_types, + edge_labeled ) + if (igraph_opt("add.vertex.names") && is_named(res$graph)) { + names(res$types) <- vertex_attr(res$graph, "name", V(res$graph)) + } + res +} + +bipartite_iea_game_impl <- function( + n1, + n2, + m, + directed = FALSE, + mode = c("all", "out", "in", "total") +) { + # Argument checks + n1 <- as.numeric(n1) + n2 <- as.numeric(n2) + m <- as.numeric(m) + directed <- as.logical(directed) + mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_bipartite_iea_game, + n1, + n2, + m, + directed, + mode + ) + if (igraph_opt("add.vertex.names") && is_named(res$graph)) { + names(res$types) <- vertex_attr(res$graph, "name", V(res$graph)) + } res } @@ -4667,15 +4754,6 @@ biconnected_components_impl <- function( R_igraph_biconnected_components, graph ) - if (igraph_opt("return.vs.es")) { - res$tree_edges <- lapply(res$tree_edges, unsafe_create_es, graph = graph, es = E(graph)) - } - if (igraph_opt("return.vs.es")) { - res$component_edges <- lapply(res$component_edges, unsafe_create_es, graph = graph, es = E(graph)) - } - if (igraph_opt("return.vs.es")) { - res$components <- lapply(res$components, unsafe_create_vs, graph = graph, verts = V(graph)) - } if (igraph_opt("return.vs.es")) { res$articulation_points <- create_vs(graph, res$articulation_points) } @@ -4813,13 +4891,15 @@ is_clique_impl <- function( cliques_impl <- function( graph, - min = 0, - max = 0 + min = UNLIMITED, + max = UNLIMITED, + max_results = UNLIMITED ) { # Argument checks ensure_igraph(graph) min <- as.numeric(min) max <- as.numeric(max) + max_results <- as.numeric(max_results) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -4827,11 +4907,10 @@ cliques_impl <- function( R_igraph_cliques, graph, min, - max + max, + max_results ) - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -4869,9 +4948,7 @@ largest_cliques_impl <- function( R_igraph_largest_cliques, graph ) - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -4938,9 +5015,10 @@ clique_number_impl <- function( weighted_cliques_impl <- function( graph, vertex_weights = NULL, - min_weight = 0, - max_weight = 0, - maximal = FALSE + maximal = FALSE, + min_weight = UNLIMITED, + max_weight = UNLIMITED, + max_results = UNLIMITED ) { # Argument checks ensure_igraph(graph) @@ -4952,9 +5030,10 @@ weighted_cliques_impl <- function( } else { vertex_weights <- NULL } + maximal <- as.logical(maximal) min_weight <- as.numeric(min_weight) max_weight <- as.numeric(max_weight) - maximal <- as.logical(maximal) + max_results <- as.numeric(max_results) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -4962,13 +5041,12 @@ weighted_cliques_impl <- function( R_igraph_weighted_cliques, graph, vertex_weights, + maximal, min_weight, max_weight, - maximal + max_results ) - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -4994,9 +5072,7 @@ largest_weighted_cliques_impl <- function( graph, vertex_weights ) - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -5057,27 +5133,32 @@ largest_independent_vertex_sets_impl <- function( R_igraph_largest_independent_vertex_sets, graph ) - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } maximal_independent_vertex_sets_impl <- function( - graph + graph, + min_size = UNLIMITED, + max_size = UNLIMITED, + max_results = UNLIMITED ) { # Argument checks ensure_igraph(graph) + min_size <- as.numeric(min_size) + max_size <- as.numeric(max_size) + max_results <- as.numeric(max_results) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_maximal_independent_vertex_sets, - graph + graph, + min_size, + max_size, + max_results ) - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -5256,6 +5337,76 @@ layout_sphere_impl <- function( res } +layout_drl_impl <- function( + graph, + res, + use_seed = FALSE, + options = drl_defaults$default, + weights = NULL +) { + # Argument checks + ensure_igraph(graph) + res[] <- as.numeric(res) + use_seed <- as.logical(use_seed) + options <- modify_list(drl_defaults$default, options) + if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { + weights <- E(graph)$weight + } + if (!is.null(weights) && !all(is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_layout_drl, + graph, + res, + use_seed, + options, + weights + ) + + res +} + +layout_drl_3d_impl <- function( + graph, + res, + use_seed = FALSE, + options = drl_defaults$default, + weights = NULL +) { + # Argument checks + ensure_igraph(graph) + res[] <- as.numeric(res) + use_seed <- as.logical(use_seed) + options <- modify_list(drl_defaults$default, options) + if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { + weights <- E(graph)$weight + } + if (!is.null(weights) && !all(is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_layout_drl_3d, + graph, + res, + use_seed, + options, + weights + ) + + res +} + layout_sugiyama_impl <- function( graph, layers = NULL, @@ -5573,13 +5724,15 @@ bibcoupling_impl <- function( similarity_dice_impl <- function( graph, - vids = V(graph), + from = V(graph), + to = V(graph), mode = c("all", "out", "in", "total"), loops = FALSE ) { # Argument checks ensure_igraph(graph) - vids <- as_igraph_vs(graph, vids) + from <- as_igraph_vs(graph, from) + to <- as_igraph_vs(graph, to) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) loops <- as.logical(loops) @@ -5588,7 +5741,8 @@ similarity_dice_impl <- function( res <- .Call( R_igraph_similarity_dice, graph, - vids - 1, + from - 1, + to - 1, mode, loops ) @@ -5669,13 +5823,15 @@ similarity_inverse_log_weighted_impl <- function( similarity_jaccard_impl <- function( graph, - vids = V(graph), + from = V(graph), + to = V(graph), mode = c("all", "out", "in", "total"), loops = FALSE ) { # Argument checks ensure_igraph(graph) - vids <- as_igraph_vs(graph, vids) + from <- as_igraph_vs(graph, from) + to <- as_igraph_vs(graph, to) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) loops <- as.logical(loops) @@ -5684,7 +5840,8 @@ similarity_jaccard_impl <- function( res <- .Call( R_igraph_similarity_jaccard, graph, - vids - 1, + from - 1, + to - 1, mode, loops ) @@ -5854,7 +6011,8 @@ community_label_propagation_impl <- function( mode = c("all", "out", "in", "total"), weights = NULL, initial = NULL, - fixed = NULL + fixed = NULL, + lpa_variant = c("dominance", "retention", "fast") ) { # Argument checks ensure_igraph(graph) @@ -5869,6 +6027,8 @@ community_label_propagation_impl <- function( } if (!is.null(initial)) initial <- as.numeric(initial)-1 if (!is.null(fixed)) fixed <- as.logical(fixed) + lpa_variant <- switch_igraph_arg(lpa_variant, + "dominance" = 0L, "retention" = 1L, "fast" = 2L) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -5878,7 +6038,8 @@ community_label_propagation_impl <- function( mode, weights, initial, - fixed + fixed, + lpa_variant ) res @@ -5915,7 +6076,8 @@ community_multilevel_impl <- function( community_optimal_modularity_impl <- function( graph, - weights = NULL + weights = NULL, + resolution = 1.0 ) { # Argument checks ensure_igraph(graph) @@ -5927,13 +6089,15 @@ community_optimal_modularity_impl <- function( } else { weights <- NULL } + resolution <- as.numeric(resolution) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_community_optimal_modularity, graph, - weights + weights, + resolution ) res @@ -5942,10 +6106,11 @@ community_optimal_modularity_impl <- function( community_leiden_impl <- function( graph, weights = NULL, - vertex_weights = NULL, + vertex_out_weights = NULL, + vertex_in_weights = NULL, resolution, beta = 0.01, - start, + start = FALSE, n_iterations = 2, membership = NULL ) { @@ -5959,13 +6124,21 @@ community_leiden_impl <- function( } else { weights <- NULL } - if (is.null(vertex_weights) && "weight" %in% vertex_attr_names(graph)) { - vertex_weights <- V(graph)$weight + if (is.null(vertex_out_weights) && "weight" %in% vertex_attr_names(graph)) { + vertex_out_weights <- V(graph)$weight } - if (!is.null(vertex_weights) && !all(is.na(vertex_weights))) { - vertex_weights <- as.numeric(vertex_weights) + if (!is.null(vertex_out_weights) && !all(is.na(vertex_out_weights))) { + vertex_out_weights <- as.numeric(vertex_out_weights) } else { - vertex_weights <- NULL + vertex_out_weights <- NULL + } + if (is.null(vertex_in_weights) && "weight" %in% vertex_attr_names(graph)) { + vertex_in_weights <- V(graph)$weight + } + if (!is.null(vertex_in_weights) && !all(is.na(vertex_in_weights))) { + vertex_in_weights <- as.numeric(vertex_in_weights) + } else { + vertex_in_weights <- NULL } resolution <- as.numeric(resolution) beta <- as.numeric(beta) @@ -5979,7 +6152,8 @@ community_leiden_impl <- function( R_igraph_community_leiden, graph, weights, - vertex_weights, + vertex_out_weights, + vertex_in_weights, resolution, beta, start, @@ -5990,15 +6164,58 @@ community_leiden_impl <- function( res } -split_join_distance_impl <- function( - comm1, - comm2 -) { - # Argument checks - comm1 <- as.numeric(comm1) - comm2 <- as.numeric(comm2) - - on.exit(.Call(R_igraph_finalizer)) +community_leiden_simple_impl <- function( + graph, + weights = NULL, + objective, + resolution, + beta = 0.01, + start = FALSE, + n_iterations = 2, + membership = NULL +) { + # Argument checks + ensure_igraph(graph) + if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { + weights <- E(graph)$weight + } + if (!is.null(weights) && !all(is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } + resolution <- as.numeric(resolution) + beta <- as.numeric(beta) + start <- as.logical(start) + n_iterations <- as.numeric(n_iterations) + if (!is.null(membership)) membership <- as.numeric(membership) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_community_leiden_simple, + graph, + weights, + objective, + resolution, + beta, + start, + n_iterations, + membership + ) + + res +} + +split_join_distance_impl <- function( + comm1, + comm2 +) { + # Argument checks + comm1 <- as.numeric(comm1) + comm2 <- as.numeric(comm2) + + on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_split_join_distance, @@ -6011,38 +6228,44 @@ split_join_distance_impl <- function( community_infomap_impl <- function( graph, - e_weights = NULL, - v_weights = NULL, - nb_trials = 10 + edge_weights = NULL, + vertex_weights = NULL, + nb_trials = 10, + is_regularized = FALSE, + regularization_strength = 1 ) { # Argument checks ensure_igraph(graph) - if (is.null(e_weights) && "weight" %in% edge_attr_names(graph)) { - e_weights <- E(graph)$weight + if (is.null(edge_weights) && "weight" %in% edge_attr_names(graph)) { + edge_weights <- E(graph)$weight } - if (!is.null(e_weights) && !all(is.na(e_weights))) { - e_weights <- as.numeric(e_weights) + if (!is.null(edge_weights) && !all(is.na(edge_weights))) { + edge_weights <- as.numeric(edge_weights) } else { - e_weights <- NULL + edge_weights <- NULL } - if (is.null(v_weights) && "weight" %in% vertex_attr_names(graph)) { - v_weights <- V(graph)$weight + if (is.null(vertex_weights) && "weight" %in% vertex_attr_names(graph)) { + vertex_weights <- V(graph)$weight } - if (!is.null(v_weights) && !all(is.na(v_weights))) { - v_weights <- as.numeric(v_weights) + if (!is.null(vertex_weights) && !all(is.na(vertex_weights))) { + vertex_weights <- as.numeric(vertex_weights) } else { - v_weights <- NULL + vertex_weights <- NULL } nb_trials <- as.numeric(nb_trials) + is_regularized <- as.logical(is_regularized) + regularization_strength <- as.numeric(regularization_strength) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_community_infomap, graph, - e_weights, - v_weights, - nb_trials + edge_weights, + vertex_weights, + nb_trials, + is_regularized, + regularization_strength ) res @@ -6073,9 +6296,7 @@ graphlets_impl <- function( weights, niter ) - if (igraph_opt("return.vs.es")) { - res$cliques <- lapply(res$cliques, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -6101,9 +6322,7 @@ graphlets_candidate_basis_impl <- function( graph, weights ) - if (igraph_opt("return.vs.es")) { - res$cliques <- lapply(res$cliques, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -6135,7 +6354,7 @@ graphlets_project_impl <- function( R_igraph_graphlets_project, graph, weights, - lapply(cliques, function(.x) .x - 1), + cliques, Muc, startMu, niter @@ -7095,7 +7314,7 @@ local_scan_neighborhood_ecount_impl <- function( R_igraph_local_scan_neighborhood_ecount, graph, weights, - lapply(neighborhoods, function(.x) .x - 1) + neighborhoods ) res @@ -7123,7 +7342,7 @@ local_scan_subset_ecount_impl <- function( R_igraph_local_scan_subset_ecount, graph, weights, - lapply(subsets, function(.x) .x - 1) + subsets ) res @@ -7380,7 +7599,7 @@ gomory_hu_tree_impl <- function( if (is.null(capacity) && "capacity" %in% edge_attr_names(graph)) { capacity <- E(graph)$capacity } - if (!is.null(capacity) && !all(is.na(capacity))) { + if (!is.null(capacity) && any(!is.na(capacity))) { capacity <- as.numeric(capacity) } else { capacity <- NULL @@ -7422,7 +7641,7 @@ maxflow_impl <- function( if (is.null(capacity) && "capacity" %in% edge_attr_names(graph)) { capacity <- E(graph)$capacity } - if (!is.null(capacity) && !all(is.na(capacity))) { + if (!is.null(capacity) && any(!is.na(capacity))) { capacity <- as.numeric(capacity) } else { capacity <- NULL @@ -7458,7 +7677,7 @@ mincut_impl <- function( if (is.null(capacity) && "capacity" %in% edge_attr_names(graph)) { capacity <- E(graph)$capacity } - if (!is.null(capacity) && !all(is.na(capacity))) { + if (!is.null(capacity) && any(!is.na(capacity))) { capacity <- as.numeric(capacity) } else { capacity <- NULL @@ -7492,7 +7711,7 @@ mincut_value_impl <- function( if (is.null(capacity) && "capacity" %in% edge_attr_names(graph)) { capacity <- E(graph)$capacity } - if (!is.null(capacity) && !all(is.na(capacity))) { + if (!is.null(capacity) && any(!is.na(capacity))) { capacity <- as.numeric(capacity) } else { capacity <- NULL @@ -7519,7 +7738,7 @@ residual_graph_impl <- function( if (is.null(capacity) && "capacity" %in% edge_attr_names(graph)) { capacity <- E(graph)$capacity } - if (!is.null(capacity) && !all(is.na(capacity))) { + if (!is.null(capacity) && any(!is.na(capacity))) { capacity <- as.numeric(capacity) } else { capacity <- NULL @@ -7548,7 +7767,7 @@ reverse_residual_graph_impl <- function( if (is.null(capacity) && "capacity" %in% edge_attr_names(graph)) { capacity <- E(graph)$capacity } - if (!is.null(capacity) && !all(is.na(capacity))) { + if (!is.null(capacity) && any(!is.na(capacity))) { capacity <- as.numeric(capacity) } else { capacity <- NULL @@ -7592,7 +7811,7 @@ st_mincut_impl <- function( if (is.null(capacity) && "capacity" %in% edge_attr_names(graph)) { capacity <- E(graph)$capacity } - if (!is.null(capacity) && !all(is.na(capacity))) { + if (!is.null(capacity) && any(!is.na(capacity))) { capacity <- as.numeric(capacity) } else { capacity <- NULL @@ -7755,12 +7974,7 @@ all_st_cuts_impl <- function( source - 1, target - 1 ) - if (igraph_opt("return.vs.es")) { - res$cuts <- lapply(res$cuts, unsafe_create_es, graph = graph, es = E(graph)) - } - if (igraph_opt("return.vs.es")) { - res$partition1s <- lapply(res$partition1s, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -7789,7 +8003,7 @@ all_st_mincuts_impl <- function( if (is.null(capacity) && "capacity" %in% edge_attr_names(graph)) { capacity <- E(graph)$capacity } - if (!is.null(capacity) && !all(is.na(capacity))) { + if (!is.null(capacity) && any(!is.na(capacity))) { capacity <- as.numeric(capacity) } else { capacity <- NULL @@ -7804,12 +8018,7 @@ all_st_mincuts_impl <- function( target - 1, capacity ) - if (igraph_opt("return.vs.es")) { - res$cuts <- lapply(res$cuts, unsafe_create_es, graph = graph, es = E(graph)) - } - if (igraph_opt("return.vs.es")) { - res$partition1s <- lapply(res$partition1s, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -7879,9 +8088,7 @@ all_minimal_st_separators_impl <- function( R_igraph_all_minimal_st_separators, graph ) - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -7897,9 +8104,7 @@ minimum_size_separators_impl <- function( R_igraph_minimum_size_separators, graph ) - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) - } + res } @@ -7915,9 +8120,7 @@ cohesive_blocks_impl <- function( R_igraph_cohesive_blocks, graph ) - if (igraph_opt("return.vs.es")) { - res$blocks <- lapply(res$blocks, unsafe_create_vs, graph = graph, verts = V(graph)) - } + class(res) <- "cohesiveBlocks" res } @@ -7976,20 +8179,76 @@ isomorphic_impl <- function( res } +automorphism_group_impl <- function( + graph, + colors = NULL +) { + # Argument checks + ensure_igraph(graph) + if (is_missing(colors)) { + if ("color" %in% vertex_attr_names(graph)) { + colors <- V(graph)$color + } else { + colors <- NULL + } + } + if (!is.null(colors)) { + colors <- as.numeric(colors)-1 + } + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_automorphism_group, + graph, + colors + ) + + res +} + +count_automorphisms_impl <- function( + graph, + colors = NULL +) { + # Argument checks + ensure_igraph(graph) + if (is_missing(colors)) { + if ("color" %in% vertex_attr_names(graph)) { + colors <- V(graph)$color + } else { + colors <- NULL + } + } + if (!is.null(colors)) { + colors <- as.numeric(colors)-1 + } + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_count_automorphisms, + graph, + colors + ) + + res +} + isoclass_subgraph_impl <- function( graph, vids ) { # Argument checks ensure_igraph(graph) - vids <- as.numeric(vids) + vids <- as_igraph_vs(graph, vids) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_isoclass_subgraph, graph, - vids + vids - 1 ) res @@ -8506,6 +8765,34 @@ get_subisomorphisms_vf2_impl <- function( } canonical_permutation_impl <- function( + graph, + colors = NULL +) { + # Argument checks + ensure_igraph(graph) + if (is_missing(colors)) { + if ("color" %in% vertex_attr_names(graph)) { + colors <- V(graph)$color + } else { + colors <- NULL + } + } + if (!is.null(colors)) { + colors <- as.numeric(colors)-1 + } + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_canonical_permutation, + graph, + colors + ) + + res +} + +canonical_permutation_bliss_impl <- function( graph, colors = NULL, sh = c("fm", "f", "fs", "fl", "flm", "fsm") @@ -8527,7 +8814,7 @@ canonical_permutation_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_canonical_permutation, + R_igraph_canonical_permutation_bliss, graph, colors, sh @@ -8601,7 +8888,7 @@ isomorphic_bliss_impl <- function( res } -count_automorphisms_impl <- function( +count_automorphisms_bliss_impl <- function( graph, colors = NULL, sh = c("fm", "f", "fs", "fl", "flm", "fsm") @@ -8623,7 +8910,7 @@ count_automorphisms_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_count_automorphisms, + R_igraph_count_automorphisms_bliss, graph, colors, sh @@ -8632,7 +8919,7 @@ count_automorphisms_impl <- function( res } -automorphism_group_impl <- function( +automorphism_group_bliss_impl <- function( graph, colors = NULL, sh = c("fm", "f", "fs", "fl", "flm", "fsm"), @@ -8655,14 +8942,11 @@ automorphism_group_impl <- function( on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_automorphism_group, + R_igraph_automorphism_group_bliss, graph, colors, sh ) - if (igraph_opt("return.vs.es")) { - res$generators <- lapply(res$generators, unsafe_create_vs, graph = graph, verts = V(graph)) - } if (!details) { res <- res$generators } @@ -9038,14 +9322,16 @@ find_cycle_impl <- function( simple_cycles_impl <- function( graph, mode = c("out", "in", "all", "total"), - min_cycle_length = -1, - max_cycle_length = -1 + min_cycle_length = UNLIMITED, + max_cycle_length = UNLIMITED, + max_results = UNLIMITED ) { # Argument checks ensure_igraph(graph) mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) min_cycle_length <- as.numeric(min_cycle_length) max_cycle_length <- as.numeric(max_cycle_length) + max_results <- as.numeric(max_results) on.exit(.Call(R_igraph_finalizer)) # Function call @@ -9054,14 +9340,10 @@ simple_cycles_impl <- function( graph, mode, min_cycle_length, - max_cycle_length + max_cycle_length, + max_results ) - if (igraph_opt("return.vs.es")) { - res$vertices <- lapply(res$vertices, unsafe_create_vs, graph = graph, verts = V(graph)) - } - if (igraph_opt("return.vs.es")) { - res$edges <- lapply(res$edges, unsafe_create_es, graph = graph, es = E(graph)) - } + res } @@ -9125,20 +9407,12 @@ eulerian_cycle_impl <- function( fundamental_cycles_impl <- function( graph, - start = NULL, - bfs_cutoff = -1, - weights = NULL + weights = NULL, + start = -1, + bfs_cutoff = UNLIMITED ) { # Argument checks ensure_igraph(graph) - if (!is.null(start)) start <- as_igraph_vs(graph, start) - if (length(start) == 0) { - cli::cli_abort( - "{.arg start} must specify at least one vertex", - call = rlang::caller_env() - ) - } - bfs_cutoff <- as.numeric(bfs_cutoff) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -9147,34 +9421,37 @@ fundamental_cycles_impl <- function( } else { weights <- NULL } + if (!is.null(start)) start <- as_igraph_vs(graph, start) + if (length(start) == 0) { + cli::cli_abort( + "{.arg start} must specify at least one vertex", + call = rlang::caller_env() + ) + } + bfs_cutoff <- as.numeric(bfs_cutoff) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_fundamental_cycles, graph, + weights, start - 1, - bfs_cutoff, - weights + bfs_cutoff ) - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_es, graph = graph, es = E(graph)) - } + res } minimum_cycle_basis_impl <- function( graph, - bfs_cutoff = -1, + weights = NULL, + bfs_cutoff = UNLIMITED, complete = TRUE, - use_cycle_order = TRUE, - weights = NULL + use_cycle_order = TRUE ) { # Argument checks ensure_igraph(graph) - bfs_cutoff <- as.numeric(bfs_cutoff) - complete <- as.logical(complete) - use_cycle_order <- as.logical(use_cycle_order) if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { weights <- E(graph)$weight } @@ -9183,20 +9460,21 @@ minimum_cycle_basis_impl <- function( } else { weights <- NULL } + bfs_cutoff <- as.numeric(bfs_cutoff) + complete <- as.logical(complete) + use_cycle_order <- as.logical(use_cycle_order) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( R_igraph_minimum_cycle_basis, graph, + weights, bfs_cutoff, complete, - use_cycle_order, - weights + use_cycle_order ) - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_es, graph = graph, es = E(graph)) - } + res } @@ -9322,25 +9600,10 @@ is_complete_impl <- function( res } -minimum_spanning_tree_unweighted_impl <- function( - graph -) { - # Argument checks - ensure_igraph(graph) - - on.exit(.Call(R_igraph_finalizer)) - # Function call - res <- .Call( - R_igraph_minimum_spanning_tree_unweighted, - graph - ) - - res -} - -minimum_spanning_tree_prim_impl <- function( +minimum_spanning_tree_impl <- function( graph, - weights + weights = NULL, + method = c("automatic", "unweighted", "prim", "kruskal") ) { # Argument checks ensure_igraph(graph) @@ -9352,21 +9615,25 @@ minimum_spanning_tree_prim_impl <- function( } else { weights <- NULL } + method <- switch_igraph_arg(method, "automatic" = 0L, "unweighted" = 1L, "prim" = 2L, "kruskal" = 3L) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_minimum_spanning_tree_prim, + R_igraph_minimum_spanning_tree, graph, - weights + weights, + method ) - + if (igraph_opt("return.vs.es")) { + res <- create_es(graph, res) + } res } random_spanning_tree_impl <- function( graph, - vid = 0 + vid = -1 ) { # Argument checks ensure_igraph(graph) @@ -9413,6 +9680,159 @@ tree_game_impl <- function( res } +nearest_neighbor_graph_impl <- function( + points, + metric, + neighbors, + cutoff, + directed +) { + # Argument checks + points[] <- as.numeric(points) + neighbors <- as.numeric(neighbors) + cutoff <- as.numeric(cutoff) + directed <- as.logical(directed) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_nearest_neighbor_graph, + points, + metric, + neighbors, + cutoff, + directed + ) + + res +} + +delaunay_graph_impl <- function( + points +) { + # Argument checks + points[] <- as.numeric(points) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_delaunay_graph, + points + ) + + res +} + +gabriel_graph_impl <- function( + points +) { + # Argument checks + points[] <- as.numeric(points) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_gabriel_graph, + points + ) + + res +} + +relative_neighborhood_graph_impl <- function( + points +) { + # Argument checks + points[] <- as.numeric(points) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_relative_neighborhood_graph, + points + ) + + res +} + +lune_beta_skeleton_impl <- function( + points, + beta = 1 +) { + # Argument checks + points[] <- as.numeric(points) + beta <- as.numeric(beta) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_lune_beta_skeleton, + points, + beta + ) + + res +} + +circle_beta_skeleton_impl <- function( + points, + beta = 1 +) { + # Argument checks + points[] <- as.numeric(points) + beta <- as.numeric(beta) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_circle_beta_skeleton, + points, + beta + ) + + res +} + +beta_weighted_gabriel_graph_impl <- function( + points, + max_beta = UNLIMITED +) { + # Argument checks + points[] <- as.numeric(points) + max_beta <- as.numeric(max_beta) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_beta_weighted_gabriel_graph, + points, + max_beta + ) + + res +} + +spatial_edge_lengths_impl <- function( + graph, + points, + METRIC +) { + # Argument checks + ensure_igraph(graph) + points[] <- as.numeric(points) + + on.exit(.Call(R_igraph_finalizer)) + # Function call + res <- .Call( + R_igraph_spatial_edge_lengths, + graph, + points, + METRIC + ) + + res +} + vertex_coloring_greedy_impl <- function( graph, heuristic = c("colored_neighbors", "dsatur") @@ -9510,207 +9930,100 @@ is_edge_coloring_impl <- function( res } -deterministic_optimal_imitation_impl <- function( - graph, - vid, - optimality = c("maximum", "minimum"), - quantities, - strategies, - mode = c("out", "in", "all", "total") +invalidate_cache_impl <- function( + graph ) { # Argument checks ensure_igraph(graph) - vid <- as_igraph_vs(graph, vid) - if (length(vid) == 0) { - cli::cli_abort( - "{.arg vid} must specify at least one vertex", - call = rlang::caller_env() - ) - } - optimality <- switch_igraph_arg(optimality, "minimum" = 0L, "maximum" = 1L) - strategies <- as.numeric(strategies) - mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_deterministic_optimal_imitation, - graph, - vid - 1, - optimality, - quantities, - strategies, - mode + R_igraph_invalidate_cache, + graph ) res } -moran_process_impl <- function( - graph, - weights = NULL, - quantities, - strategies, - mode = c("out", "in", "all", "total") +version_impl <- function( ) { # Argument checks - ensure_igraph(graph) - if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { - weights <- E(graph)$weight - } - if (!is.null(weights) && !all(is.na(weights))) { - weights <- as.numeric(weights) - } else { - weights <- NULL - } - strategies <- as.numeric(strategies) - mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) - on.exit(.Call(R_igraph_finalizer)) - # Function call - res <- .Call( - R_igraph_moran_process, - graph, - weights, - quantities, - strategies, - mode - ) - if (igraph_opt("add.vertex.names") && is_named(graph)) { - names(res$quantities) <- vertex_attr(graph, "name", V(graph)) - } - res -} - -roulette_wheel_imitation_impl <- function( - graph, - vid, - is_local, - quantities, - strategies, - mode = c("out", "in", "all", "total") -) { - # Argument checks - ensure_igraph(graph) - vid <- as_igraph_vs(graph, vid) - if (length(vid) == 0) { - cli::cli_abort( - "{.arg vid} must specify at least one vertex", - call = rlang::caller_env() - ) - } - is_local <- as.logical(is_local) - strategies <- as.numeric(strategies) - mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_roulette_wheel_imitation, - graph, - vid - 1, - is_local, - quantities, - strategies, - mode + R_igraph_version ) res } -stochastic_imitation_impl <- function( - graph, - vid, - algo, - quantities, - strategies, - mode = c("out", "in", "all", "total") +sample_sphere_surface_impl <- function( + dim, + n = 1, + radius = 1, + positive = TRUE ) { # Argument checks - ensure_igraph(graph) - vid <- as_igraph_vs(graph, vid) - if (length(vid) == 0) { - cli::cli_abort( - "{.arg vid} must specify at least one vertex", - call = rlang::caller_env() - ) - } - strategies <- as.numeric(strategies) - mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) + dim <- as.numeric(dim) + n <- as.numeric(n) + radius <- as.numeric(radius) + positive <- as.logical(positive) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_stochastic_imitation, - graph, - vid - 1, - algo, - quantities, - strategies, - mode + R_igraph_sample_sphere_surface, + dim, + n, + radius, + positive ) res } -invalidate_cache_impl <- function( - graph +sample_sphere_volume_impl <- function( + dim, + n = 1, + radius = 1, + positive = TRUE ) { # Argument checks - ensure_igraph(graph) + dim <- as.numeric(dim) + n <- as.numeric(n) + radius <- as.numeric(radius) + positive <- as.logical(positive) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_invalidate_cache, - graph + R_igraph_sample_sphere_volume, + dim, + n, + radius, + positive ) res } -vertex_path_from_edge_path_impl <- function( - graph, - start = NULL, - edge_path, - mode = c("out", "in", "all", "total") -) { - # Argument checks - ensure_igraph(graph) - if (!is.null(start)) start <- as_igraph_vs(graph, start) - if (length(start) == 0) { - cli::cli_abort( - "{.arg start} must specify at least one vertex", - call = rlang::caller_env() - ) - } - edge_path <- as_igraph_es(graph, edge_path) - mode <- switch_igraph_arg(mode, "out" = 1L, "in" = 2L, "all" = 3L, "total" = 3L) - - on.exit(.Call(R_igraph_finalizer)) - # Function call - res <- .Call( - R_igraph_vertex_path_from_edge_path, - graph, - start - 1, - edge_path - 1, - mode - ) - if (igraph_opt("return.vs.es")) { - res <- create_vs(graph, res) - } - res -} - -version_impl <- function( +sample_dirichlet_impl <- function( + n, + alpha ) { # Argument checks - + n <- as.numeric(n) + alpha <- as.numeric(alpha) on.exit(.Call(R_igraph_finalizer)) # Function call res <- .Call( - R_igraph_version + R_igraph_sample_dirichlet, + n, + alpha ) res diff --git a/R/centrality.R b/R/centrality.R index 5cebcee7db8..eb39ea501a9 100644 --- a/R/centrality.R +++ b/R/centrality.R @@ -184,6 +184,8 @@ graph.diversity <- function(graph, weights = NULL, vids = V(graph)) { #' `evcent()` was renamed to [eigen_centrality()] to create a more #' consistent API. #' @inheritParams eigen_centrality +#' @param directed Logical scalar, whether to consider direction of the edges +#' in directed graphs. It is ignored for undirected graphs. #' @keywords internal #' @export evcent <- function( @@ -446,11 +448,12 @@ betweenness <- function( ) { res <- betweenness_cutoff_impl( graph = graph, + weights = weights, vids = v, directed = directed, - weights = weights, cutoff = cutoff ) + if (normalized) { vc <- as.numeric(vcount(graph)) if (is_directed(graph) && directed) { @@ -475,10 +478,11 @@ edge_betweenness <- function( e <- as_igraph_es(graph, e) res <- edge_betweenness_cutoff_impl( graph = graph, - directed = directed, weights = weights, + directed = directed, cutoff = cutoff ) + res[as.numeric(e)] } @@ -1248,7 +1252,7 @@ eigen_defaults <- function() { #' computation, see [arpack()] for more about ARPACK in igraph. #' #' @param graph Graph to be analyzed. -#' @param directed Logical scalar, whether to consider direction of the edges +#' @param directed `r lifecycle::badge("deprecated")` Logical scalar, whether to consider direction of the edges #' in directed graphs. It is ignored for undirected graphs. #' @param scale `r lifecycle::badge("deprecated")` Normalization will always take #' place. @@ -1265,6 +1269,17 @@ eigen_defaults <- function() { #' weights spread the centrality better. #' @param options A named list, to override some ARPACK options. See #' [arpack()] for details. +#' @param mode How to consider edge directions in directed graphs. +#' It is ignored for undirected graphs. +#' Possible values: +#' - `"out"` the left eigenvector of the adjacency matrix is calculated, +#' i.e. the centrality of a vertex is proportional to the sum of centralities +#' of vertices pointing to it. This is the standard eigenvector centrality. +#' - `"in"` the right eigenvector of the adjacency matrix is calculated, +#' i.e. the centrality of a vertex is proportional to the sum of centralities +#' of vertices it points to. +#' - `"all"` edge directions are ignored, +#' and the unweighted eigenvector centrality is calculated. #' @return A named list with components: #' \describe{ #' \item{vector}{ @@ -1294,10 +1309,11 @@ eigen_defaults <- function() { #' @cdocs igraph_eigenvector_centrality eigen_centrality <- function( graph, - directed = FALSE, + directed = deprecated(), scale = deprecated(), weights = NULL, - options = arpack_defaults() + options = arpack_defaults(), + mode = c("out", "in", "all") ) { if (is.function(options)) { lifecycle::deprecate_soft( @@ -1326,10 +1342,33 @@ eigen_centrality <- function( } } + mode <- igraph_match_arg(mode) + + if (lifecycle::is_present(directed)) { + if (directed) { + lifecycle::deprecate_soft( + "2.2.0", + "eigen_centrality(directed)", + details = "Use the mode argument." + ) + if (!lifecycle::is_present(mode)) { + mode <- "out" + } + } else { + lifecycle::deprecate_soft( + "2.2.0", + "eigen_centrality(directed)", + details = "Use the mode argument." + ) + if (!lifecycle::is_present(mode)) { + mode <- "all" + } + } + } + eigenvector_centrality_impl( graph = graph, - directed = directed, - scale = TRUE, + mode = mode, weights = weights, options = options ) @@ -1453,9 +1492,7 @@ diversity <- function(graph, weights = NULL, vids = V(graph)) { #' scores are the same as authority scores. #' #' @param graph The input graph. -#' @param scale Logical scalar, whether to scale the result to have a maximum -#' score of one. If no scaling is used then the result vector has unit length -#' in the Euclidean norm. +#' @param scale `r lifecycle::badge("deprecated")` Ignored, always scaled. #' @param weights Optional positive weight vector for calculating weighted #' scores. If the graph has a `weight` edge attribute, then this is used #' by default. Pass `NA` to ignore the weight attribute. This function @@ -1501,15 +1538,22 @@ diversity <- function(graph, weights = NULL, vids = V(graph)) { hits_scores <- function( graph, ..., - scale = TRUE, + scale = deprecated(), weights = NULL, options = arpack_defaults() ) { rlang::check_dots_empty() + if (lifecycle::is_present(scale)) { + lifecycle::deprecate_soft( + "2.1.5", + "hits_scores(scale = )", + details = "The function always behaves as if `scale = TRUE`. + The argument will be removed in the future." + ) + } hub_and_authority_scores_impl( graph = graph, - scale = scale, weights = weights, options = options ) @@ -1545,7 +1589,8 @@ authority_score <- function( weights = weights, options = options ) - scores$hub <- NULL + scores[["hub_vector"]] <- NULL + rlang::set_names(scores, c("vector", "value", "options")) } @@ -1590,7 +1635,7 @@ hub_score <- function( weights = weights, options = options ) - scores$authority <- NULL + scores[["authority_vector"]] <- NULL rlang::set_names(scores, c("vector", "value", "options")) } diff --git a/R/centralization.R b/R/centralization.R index aa9226034fb..2b38ba932eb 100644 --- a/R/centralization.R +++ b/R/centralization.R @@ -56,6 +56,8 @@ centralization.evcent.tmax <- function( #' `centralization.evcent()` was renamed to [centr_eigen()] to create a more #' consistent API. #' @inheritParams centr_eigen +#' @param directed logical scalar, whether to use directed shortest paths for +#' calculating eigenvector centrality. #' @keywords internal #' @export centralization.evcent <- function( @@ -306,7 +308,7 @@ NULL #' #' # Calculate centralization from pre-computed scores #' deg <- degree(g) -#' tmax <- centr_degree_tmax(g, loops = FALSE) +#' tmax <- centr_degree_tmax(g, loops = "none") #' centralize(deg, tmax) #' #' # The most centralized graph according to eigenvector centrality @@ -385,8 +387,11 @@ centr_degree <- function( #' @param nodes The number of vertices. This is ignored if the graph is given. #' @param mode This is the same as the `mode` argument of `degree()`. Ignored #' if `graph` is given and the graph is undirected. -#' @param loops Logical scalar, whether to consider loops edges when -#' calculating the degree. +#' @param loops Character string, +#' `"none"` (the default) ignores loop edges; +#' `"once"` counts each loop edge only once; +#' `"twice"` counts each loop edge twice in undirected graphs. +#' and once in directed graphs. #' @return Real scalar, the theoretical maximum (unnormalized) graph degree #' centrality score for graphs with given order and other parameters. #' @@ -397,8 +402,8 @@ centr_degree <- function( #' @examples #' # A BA graph is quite centralized #' g <- sample_pa(1000, m = 4) -#' centr_degree(g, normalized = FALSE)$centralization %>% -#' `/`(centr_degree_tmax(g, loops = FALSE)) +#' centr_degree(g, normalized = FALSE)$centralization / +#' centr_degree_tmax(g, loops = "twice") #' centr_degree(g, normalized = TRUE)$centralization centr_degree_tmax <- function( graph = NULL, @@ -412,7 +417,7 @@ centr_degree_tmax <- function( what = "centr_degree_tmax(loops = 'must be explicit')", details = "The default value (currently `FALSE`) will be dropped in the next release. Add an explicit value for the `loops` argument." ) - loops <- FALSE + loops <- "none" } # Argument checks @@ -420,8 +425,6 @@ centr_degree_tmax <- function( nodes <- as.numeric(nodes) - loops <- as.logical(loops) - # Function call res <- centralization_degree_tmax_impl( graph = graph, @@ -614,12 +617,22 @@ centr_clo_tmax <- function( #' See [centralize()] for a summary of graph centralization. #' #' @param graph The input graph. -#' @param directed logical scalar, whether to use directed shortest paths for -#' calculating eigenvector centrality. +#' @param directed `r lifecycle::badge("deprecated")` Use `mode` instead. #' @param scale `r lifecycle::badge("deprecated")` Ignored. Computing #' eigenvector centralization requires normalized eigenvector centrality scores. #' @param options This is passed to [eigen_centrality()], the options #' for the ARPACK eigensolver. +#' @param mode How to consider edge directions in directed graphs. +#' It is ignored for undirected graphs. +#' Possible values: +#' - `"out"` the left eigenvector of the adjacency matrix is calculated, +#' i.e. the centrality of a vertex is proportional to the sum of centralities +#' of vertices pointing to it. This is the standard eigenvector centrality. +#' - `"in"` the right eigenvector of the adjacency matrix is calculated, +#' i.e. the centrality of a vertex is proportional to the sum of centralities +#' of vertices it points to. +#' - `"all"` edge directions are ignored, +#' and the unweighted eigenvector centrality is calculated. #' @param normalized Logical scalar. Whether to normalize the graph level #' centrality score by dividing by the theoretical maximum. #' @return A named list with the following components: @@ -662,10 +675,11 @@ centr_clo_tmax <- function( #' @cdocs igraph_centralization_eigenvector_centrality centr_eigen <- function( graph, - directed = FALSE, + directed = deprecated(), scale = deprecated(), options = arpack_defaults(), - normalized = TRUE + normalized = TRUE, + mode = c("out", "in", "all") ) { if (lifecycle::is_present(scale)) { lifecycle::deprecate_soft( @@ -676,10 +690,33 @@ centr_eigen <- function( ) } + mode <- igraph_match_arg(mode) + + if (lifecycle::is_present(directed)) { + if (directed) { + lifecycle::deprecate_soft( + "2.2.0", + "eigen_centrality(directed)", + details = "Use the mode argument." + ) + if (!lifecycle::is_present(mode)) { + mode <- "out" + } + } else { + lifecycle::deprecate_soft( + "2.2.0", + "eigen_centrality(directed)", + details = "Use the mode argument." + ) + if (!lifecycle::is_present(mode)) { + mode <- "all" + } + } + } + centralization_eigenvector_centrality_impl( graph = graph, - directed = directed, - scale = TRUE, + mode = mode, options = options, normalized = normalized ) @@ -696,7 +733,9 @@ centr_eigen <- function( #' @param directed logical scalar, whether to consider edge directions #' during the calculation. Ignored in undirected graphs. #' @param scale `r lifecycle::badge("deprecated")` Ignored. Computing -#' eigenvector centralization requires normalized eigenvector centrality scores. +#' eigenvector centralization requires normalized eigenvector centrality scores. +#' @param mode This is the same as the `mode` argument of +#' `degree()`. #' @return Real scalar, the theoretical maximum (unnormalized) graph #' eigenvector centrality score for graphs with given vertex count and #' other parameters. @@ -715,8 +754,9 @@ centr_eigen <- function( centr_eigen_tmax <- function( graph = NULL, nodes = 0, - directed = FALSE, - scale = deprecated() + directed = deprecated(), + scale = deprecated(), + mode = c("out", "in", "all") ) { if (lifecycle::is_present(scale)) { lifecycle::deprecate_soft( @@ -726,11 +766,33 @@ centr_eigen_tmax <- function( The argument will be removed in the future." ) } + mode <- igraph_match_arg(mode) + + if (lifecycle::is_present(directed)) { + if (directed) { + lifecycle::deprecate_soft( + "2.2.0", + "eigen_centrality(directed)", + details = "Use the mode argument." + ) + if (!lifecycle::is_present(mode)) { + mode <- "out" + } + } else { + lifecycle::deprecate_soft( + "2.2.0", + "eigen_centrality(directed)", + details = "Use the mode argument." + ) + if (!lifecycle::is_present(mode)) { + mode <- "all" + } + } + } centralization_eigenvector_centrality_tmax_impl( graph = graph, nodes = nodes, - directed = directed, - scale = TRUE + mode = mode ) } diff --git a/R/cliques.R b/R/cliques.R index 5c2a190587c..9f2c8fc5b82 100644 --- a/R/cliques.R +++ b/R/cliques.R @@ -428,10 +428,10 @@ weighted_cliques <- function( ) { weighted_cliques_impl( graph = graph, - vertex_weights = vertex.weights, - min_weight = min.weight, - max_weight = max.weight, - maximal = maximal + vertex.weights = vertex.weights, + maximal = maximal, + min.weight = min.weight, + max.weight = max.weight ) } #' @export diff --git a/R/community.R b/R/community.R index 4e5e0c3b035..8fef812b2ee 100644 --- a/R/community.R +++ b/R/community.R @@ -2326,6 +2326,10 @@ cluster_leading_eigen <- function( #' @param fixed Logical vector denoting which labels are fixed. Of course this #' makes sense only if you provided an initial state, otherwise this element #' will be ignored. Also note that vertices without labels cannot be fixed. +#' @param lpa_variant Which variant of the label propagation algorithm to run. +#' - `"dominance"` (default) check for dominance of all nodes after each iteration. +#' - `"retention"` keep current label if among dominant labels, only check if labels changed. +#' - `"fast"` sample from dominant labels, only check neighbors. #' @return `cluster_label_prop()` returns a #' [communities()] object, please see the [communities()] #' manual page for details. @@ -2354,7 +2358,8 @@ cluster_label_prop <- function( ..., mode = c("out", "in", "all"), initial = NULL, - fixed = NULL + fixed = NULL, + lpa_variant = c("dominance", "retention", "fast") ) { if (...length() > 0) { lifecycle::deprecate_soft( @@ -2376,7 +2381,7 @@ cluster_label_prop <- function( return(inject(cluster_label_prop0(!!!dots))) } - cluster_label_prop0(graph, weights, mode, initial, fixed) + cluster_label_prop0(graph, weights, mode, initial, fixed, lpa_variant) } cluster_label_prop0 <- function( @@ -2384,13 +2389,15 @@ cluster_label_prop0 <- function( weights = NULL, mode = c("out", "in", "all"), initial = NULL, - fixed = NULL + fixed = NULL, + lpa_variant = c("dominance", "retention", "fast") ) { # Argument checks ensure_igraph(graph) # Necessary because evaluated later mode <- igraph_match_arg(mode) + lpa_variant <- igraph_match_arg(lpa_variant) # Function call membership <- community_label_propagation_impl( @@ -2398,7 +2405,8 @@ cluster_label_prop0 <- function( mode = mode, weights = weights, initial = initial, - fixed = fixed + fixed = fixed, + lpa.variant = lpa_variant ) res <- list() diff --git a/R/console.R b/R/console.R index 882e7d3b6b1..47e748b3402 100644 --- a/R/console.R +++ b/R/console.R @@ -95,18 +95,26 @@ console <- function() { #' @inheritParams .igraph.progress #' @dev .igraph.status <- function(message) { - type <- igraph_opt("verbose") - if (is.logical(type) && type) { - message(message, appendLF = FALSE) - } else { - switch( - type, - "tk" = message(message, appendLF = FALSE), - "tkconsole" = .igraph.progress.tkconsole.message(message, start = TRUE), - stop("Cannot interpret 'verbose' option, this should not happen") - ) - } - 0L + # Catch all errors + tryCatch( + { + type <- igraph::igraph_opt("verbose") + if (is.logical(type) && type) { + message(message, appendLF = FALSE) + } else { + switch( + type, + "tk" = message(message, appendLF = FALSE), + "tkconsole" = .igraph.progress.tkconsole.message( + message, + start = TRUE + ), + stop("Cannot interpret 'verbose' option, this should not happen") + ) + } + }, + error = function(e) {} + ) } #' @importFrom utils txtProgressBar setTxtProgressBar diff --git a/R/efficiency.R b/R/efficiency.R index bb7e7a0df23..2d456340948 100644 --- a/R/efficiency.R +++ b/R/efficiency.R @@ -87,8 +87,8 @@ local_efficiency <- function( ) { local_efficiency_impl( graph = graph, - vids = vids, weights = weights, + vids = vids, directed = directed, mode = mode ) diff --git a/R/eulerian.R b/R/eulerian.R index 592209653b6..5209d10e7f6 100644 --- a/R/eulerian.R +++ b/R/eulerian.R @@ -71,6 +71,7 @@ has_eulerian_path <- function(graph) { res <- is_eulerian_impl( graph = graph ) + res$has_path } @@ -81,6 +82,7 @@ has_eulerian_cycle <- function(graph) { res <- is_eulerian_impl( graph = graph ) + res$has_cycle } diff --git a/R/games.R b/R/games.R index daab133a83c..d25f2464ef6 100644 --- a/R/games.R +++ b/R/games.R @@ -938,10 +938,6 @@ sample_pa <- function( )) } - if (is.null(out.seq)) { - out.seq <- numeric() - } - algorithm <- igraph_match_arg(algorithm) algorithm1 <- switch( algorithm, @@ -3087,20 +3083,18 @@ sample_fitness_pl <- function( finite.size.correction = TRUE ) { res <- static_power_law_game_impl( - no_of_nodes = no.of.nodes, - no_of_edges = no.of.edges, - exponent_out = exponent.out, - exponent_in = exponent.in, + no.of.nodes = no.of.nodes, + no.of.edges = no.of.edges, + exponent.out = exponent.out, + exponent.in = exponent.in, loops = loops, multiple = multiple, finite_size_correction = finite.size.correction ) - # Add backward-compatible dotted names if (igraph_opt("add.params")) { - res$exponent.out <- res$exponent_out - res$exponent.in <- res$exponent_in - res$finite.size.correction <- res$finite_size_correction + res$loops <- loops + res$multiple <- multiple } res diff --git a/R/interface.R b/R/interface.R index 3831da207a4..faf882e3ac2 100644 --- a/R/interface.R +++ b/R/interface.R @@ -370,6 +370,13 @@ neighbors <- function(graph, v, mode = c("out", "in", "all", "total")) { #' @param mode Whether to query outgoing (\sQuote{out}), incoming #' (\sQuote{in}) edges, or both types (\sQuote{all}). This is #' ignored for undirected graphs. +#' @param loops Specifies how to treat loop edges. +#' `"none"` removes loop edges from the result. +#' `"once"` makes each loop edge appear only once in the result. +#' `"twice"` makes loop edges appear twice in the result +#' if the graph is undirected or `mode` is set to `"all"` +#' (and once otherwise as returning them twice +#' does not make sense for directed graphs). #' @return An edge sequence containing the incident edges of #' the input vertex. #' @@ -380,26 +387,30 @@ neighbors <- function(graph, v, mode = c("out", "in", "all", "total")) { #' g <- make_graph("Zachary") #' incident(g, 1) #' incident(g, 34) -incident <- function(graph, v, mode = c("all", "out", "in", "total")) { +incident <- function( + graph, + v, + mode = c("all", "out", "in", "total"), + loops = c("twice", "none", "once") +) { ensure_igraph(graph) if (is_directed(graph)) { mode <- igraph_match_arg(mode) - mode <- switch(mode, "out" = 1, "in" = 2, "all" = 3, "total" = 3) } else { - mode <- 1 + mode <- "out" } + loops <- igraph_match_arg(loops) v <- as_igraph_vs(graph, v) if (length(v) == 0) { stop("No vertex was specified") } - on.exit(.Call(R_igraph_finalizer)) - res <- .Call(Rx_igraph_incident, graph, v - 1, as.numeric(mode)) + 1L - - if (igraph_opt("return.vs.es")) { - res <- create_es(graph, res) - } - res + incident_impl( + graph = graph, + vid = v, + mode = mode, + loops = loops + ) } #' Check whether a graph is directed diff --git a/R/make.R b/R/make.R index db350e1dc30..8fb34a1dccd 100644 --- a/R/make.R +++ b/R/make.R @@ -385,7 +385,7 @@ graph.lcf <- function(n, shifts, repeats = 1) { # nocov start lifecycle::deprecate_soft("2.1.0", "graph.lcf()", "graph_from_lcf()") # Use the _impl function - lcf_vector_impl( + lcf_impl( n = n, shifts = shifts, repeats = repeats @@ -2859,7 +2859,7 @@ full_citation_graph <- function(...) { #' g2 <- make_graph("Franklin") #' isomorphic(g1, g2) #' @export -#' @cdocs igraph_lcf_vector +#' @cdocs igraph_lcf graph_from_lcf <- function( shifts, ..., @@ -2887,7 +2887,7 @@ graph_from_lcf <- function( ) } - lcf_vector_impl( + lcf_impl( n = n, shifts = shifts, repeats = repeats diff --git a/R/minimum.spanning.tree.R b/R/minimum.spanning.tree.R index 0ab3b564836..7ed253c96fe 100644 --- a/R/minimum.spanning.tree.R +++ b/R/minimum.spanning.tree.R @@ -58,7 +58,7 @@ minimum.spanning.tree <- function( #' distances. #' @param algorithm The algorithm to use for calculation. `unweighted` can #' be used for unweighted graphs, and `prim` runs Prim's algorithm for -#' weighted graphs. If this is `NULL` then igraph will select the +#' weighted graphs. By default igraph will select the #' algorithm automatically: if the graph has an edge attribute called #' `weight` or the `weights` argument is not `NULL` then Prim's #' algorithm is chosen, otherwise the unweighted algorithm is used. @@ -79,29 +79,17 @@ minimum.spanning.tree <- function( #' g <- sample_gnp(100, 3 / 100) #' g_mst <- mst(g) #' -mst <- function(graph, weights = NULL, algorithm = NULL, ...) { +mst <- function( + graph, + weights = NULL, + algorithm = c("automatic", "unweighted", "prim", "kruskal"), + ... +) { ensure_igraph(graph) - - if (is.null(algorithm)) { - if (!is.null(weights) || "weight" %in% edge_attr_names(graph)) { - algorithm <- "prim" - } else { - algorithm <- "unweighted" - } - } - - if (algorithm == "unweighted") { - on.exit(.Call(R_igraph_finalizer)) - .Call(Rx_igraph_minimum_spanning_tree_unweighted, graph) - } else if (algorithm == "prim") { - if (is.null(weights) && !"weight" %in% edge_attr_names(graph)) { - cli::cli_abort("edges weights must be supplied for Prim's algorithm.") - } else if (is.null(weights)) { - weights <- E(graph)$weight - } - on.exit(.Call(R_igraph_finalizer)) - .Call(Rx_igraph_minimum_spanning_tree_prim, graph, as.numeric(weights)) - } else { - cli::cli_abort("Invalid {.arg algorithm}.") - } + algorithm <- igraph_match_arg(algorithm) + minimum_spanning_tree_impl( + graph = graph, + weights = weights, + method = algorithm + ) } diff --git a/R/other.R b/R/other.R index 4eff3d52685..9d5b42aaf5a 100644 --- a/R/other.R +++ b/R/other.R @@ -222,7 +222,7 @@ igraph.i.spMatrix <- function(M) { #' convex_hull(M) #' @family other #' @export -#' @cdocs igraph_convex_hull +#' @cdocs igraph_convex_hull_2d convex_hull <- function(data) { convex_hull_2d_impl( data = data diff --git a/R/paths.R b/R/paths.R index 972bcc136b7..305e321393e 100644 --- a/R/paths.R +++ b/R/paths.R @@ -127,7 +127,6 @@ all_simple_paths <- function( mode = mode ) ) - res <- get.all.simple.paths.pp(res) if (igraph_opt("return.vs.es")) { res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) @@ -282,7 +281,7 @@ max_cardinality <- function(graph) { #' eccentricity(g) #' @family paths #' @export -#' @cdocs igraph_eccentricity_dijkstra +#' @cdocs igraph_eccentricity eccentricity <- function( graph, vids = V(graph), @@ -306,10 +305,10 @@ eccentricity <- function( } } - eccentricity_dijkstra_impl( + eccentricity_impl( graph = graph, - vids = vids, weights = weights, + vids = vids, mode = mode ) } @@ -342,7 +341,7 @@ eccentricity <- function( #' radius(g) #' @family paths #' @export -#' @cdocs igraph_radius_dijkstra +#' @cdocs igraph_radius radius <- function( graph, ..., @@ -365,7 +364,7 @@ radius <- function( } } - radius_dijkstra_impl( + radius_impl( graph = graph, weights = weights, mode = mode @@ -398,14 +397,14 @@ radius <- function( #' graph_center(ring) #' #' @export -#' @cdocs igraph_graph_center_dijkstra +#' @cdocs igraph_graph_center graph_center <- function( graph, ..., weights = NULL, mode = c("all", "out", "in", "total") ) { - graph_center_dijkstra_impl( + graph_center_impl( graph = graph, weights = weights, mode = mode diff --git a/R/pp.R b/R/pp.R deleted file mode 100644 index a412f1d434a..00000000000 --- a/R/pp.R +++ /dev/null @@ -1,24 +0,0 @@ -# IGraph R package -# Copyright (C) 2014 Gabor Csardi -# 334 Harvard street, Cambridge, MA 02139 USA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 USA -# -################################################################### - -get.all.simple.paths.pp <- function(vect) { - .Call(Rx_igraph_get_all_simple_paths_pp, vect) -} diff --git a/R/similarity.R b/R/similarity.R index 870d57cbcaf..d3edeeb0bc6 100644 --- a/R/similarity.R +++ b/R/similarity.R @@ -26,7 +26,11 @@ #' 25(3):211-230, 2003. #' #' @param graph The input graph. -#' @param vids The vertex ids for which the similarity is calculated. +#' @param vids lifecycle::badge("deprecated") +#' @param vids_from The vertex IDs of the first set of vertices of the pairs +#' for which the calculation will be done. +#' @param vids_to The vertex IDs of the second set of vertices of the pairs +#' for which the calculation will be done. #' @param mode The type of neighboring vertices to use for the calculation, #' possible values: \sQuote{`out`}, \sQuote{`in`}, #' \sQuote{`all`}. @@ -52,7 +56,7 @@ #' similarity(g, method = "jaccard") similarity <- function( graph, - vids = V(graph), + vids = deprecated(), mode = c( "all", "out", @@ -64,30 +68,47 @@ similarity <- function( "jaccard", "dice", "invlogweighted" - ) + ), + vids_from = V(graph), + vids_to = vids_from ) { + if (lifecycle::is_present(vids)) { + lifecycle::deprecate_soft( + "similarity(vids =)", + I("similarity(vids_from =, vids_to =)"), + when = "3.0.0" + ) + if (!lifecycle::is_present(vids_from)) { + vids_from <- vids + vids_to <- vids_from + } + } + method <- igraph_match_arg(method) - if (method == "jaccard") { - similarity_jaccard_impl( - graph = graph, - vids = vids, + + switch( + method, + jaccard = similarity_jaccard_impl( + graph, + vit.from = vids_from, + vit.to = vids_to, mode = mode, loops = loops - ) - } else if (method == "dice") { - similarity_dice_impl( - graph = graph, - vids = vids, + ), + dice = similarity_dice_impl( + graph, + vit.from = vids_from, + vit.to = vids_to, mode = mode, loops = loops - ) - } else if (method == "invlogweighted") { - similarity_inverse_log_weighted_impl( - graph = graph, - vids = vids, + ), + invlogweighted = similarity_inverse_log_weighted_impl( + graph, + vit.from = vids_from, + vit.to = vids_to, mode = mode ) - } + ) } #' Similarity measures of two vertices (Jaccard) @@ -97,6 +118,7 @@ similarity <- function( #' #' Please use [similarity()] with `method = "jaccard"` instead. #' @inheritParams similarity +#' @param vids The vertex ids for which the similarity is calculated. #' @keywords internal #' @export similarity.jaccard <- function( @@ -128,6 +150,7 @@ similarity.jaccard <- function( #' #' Please use [similarity()] with `method = "dice"` instead. #' @inheritParams similarity +#' @param vids The vertex ids for which the similarity is calculated. #' @keywords internal #' @export similarity.dice <- function( @@ -159,6 +182,7 @@ similarity.dice <- function( #' #' Please use [similarity()] with `method = "invlogweighted"` instead. #' @inheritParams similarity +#' @param vids The vertex ids for which the similarity is calculated. #' @keywords internal #' @export similarity.invlogweighted <- function( diff --git a/R/simple.R b/R/simple.R index 65bd13d9ea9..8711dda943c 100644 --- a/R/simple.R +++ b/R/simple.R @@ -71,6 +71,11 @@ is.simple <- function(graph) { #' `remove.multiple=TRUE`. In this case many edges might be mapped to a #' single one in the new graph, and their attributes are combined. Please see #' [attribute.combination()] for details on this. +#' @param directed Boolean.Whether to consider the directions of edges. +#' The default, `TRUE` means that edge directions will be considered. +#' `FALSE` means that edge directions will be ignored and a directed graph +#' with at least one mutual edge pair will be considered non-simple. +#' Ignored for undirected graphs. #' @return a new graph object with the edges deleted. #' @author Gabor Csardi \email{csardi.gabor@@gmail.com} #' @seealso [which_loop()], [which_multiple()] and @@ -84,6 +89,11 @@ is.simple <- function(graph) { #' is_simple(simplify(g, remove.loops = FALSE)) #' is_simple(simplify(g, remove.multiple = FALSE)) #' is_simple(simplify(g)) +#' +#' # directed argument +#' g <- graph_from_literal(1 +-+ 2 -+ 3) +#' is_simple(g) +#' is_simple(g, directed = FALSE) #' @family simple #' @family functions for manipulating graph structure #' @family isomorphism diff --git a/R/structural-properties.R b/R/structural-properties.R index d3e4298584f..0b0998a645c 100644 --- a/R/structural-properties.R +++ b/R/structural-properties.R @@ -758,23 +758,14 @@ diameter <- function( ) { ensure_igraph(graph) - if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { - weights <- E(graph)$weight - } - if (!is.null(weights) && any(!is.na(weights))) { - weights <- as.numeric(weights) - } else { - weights <- NULL - } - - on.exit(.Call(R_igraph_finalizer)) - .Call( - R_igraph_diameter, - graph, - as.logical(directed), - as.logical(unconnected), - weights + res <- diameter_impl( + graph = graph, + weights = weights, + directed = directed, + unconnected = unconnected ) + + res$res } #' @rdname diameter @@ -851,7 +842,7 @@ farthest_vertices <- function( #' @export #' @rdname distances -#' @cdocs igraph_average_path_length_dijkstra +#' @cdocs igraph_average_path_length mean_distance <- function( graph, weights = NULL, @@ -859,13 +850,20 @@ mean_distance <- function( unconnected = TRUE, details = FALSE ) { - average_path_length_dijkstra_impl( + res <- average_path_length_impl( graph = graph, weights = weights, directed = directed, - unconnected = unconnected, + unconn = unconnected, details = details ) + + if (details) { + res$unconnected <- res$unconn_pair + res$unconn_pair <- NULL + } + + res } #' Degree and degree distribution of the vertices @@ -879,7 +877,11 @@ mean_distance <- function( #' @param mode Character string, \dQuote{out} for out-degree, \dQuote{in} for #' in-degree or \dQuote{total} for the sum of the two. For undirected graphs #' this argument is ignored. \dQuote{all} is a synonym of \dQuote{total}. -#' @param loops Logical; whether the loop edges are also counted. +#' @param loops Character string, +#' `"none"` ignores loop edges; +#' `"once"` counts each loop edge only once; +#' `"twice"` (the default) counts each loop edge twice in undirected graphs +#' and once in directed graphs. #' @param normalized Logical scalar, whether to normalize the degree. If #' `TRUE` then the result is divided by \eqn{n-1}, where \eqn{n} is the #' number of vertices in the graph. @@ -915,13 +917,26 @@ degree <- function( graph, v = V(graph), mode = c("all", "out", "in", "total"), - loops = TRUE, + loops = c("twice", "none", "once"), normalized = FALSE ) { ensure_igraph(graph) - v <- as_igraph_vs(graph, v) mode <- igraph_match_arg(mode) + if (is.logical(loops)) { + lifecycle::deprecate_soft( + "2.2.0", + "degree(loops = 'must be a character string')" + ) + if (loops) { + loops <- "twice" + } else { + loops <- "none" + } + } + + loops <- igraph_match_arg(loops) + res <- degree_impl( graph = graph, vids = v, @@ -946,8 +961,24 @@ max_degree <- function( ..., v = V(graph), mode = c("all", "out", "in", "total"), - loops = TRUE + loops = c("twice", "none", "once") ) { + ensure_igraph(graph) + mode <- igraph_match_arg(mode) + + if (is.logical(loops)) { + lifecycle::deprecate_soft( + "2.2.0", + "max_degree(loops = 'must be a character string')" + ) + if (loops) { + loops <- "twice" + } else { + loops <- "none" + } + } + loops <- igraph_match_arg(loops) + maxdegree_impl( graph = graph, v = v, @@ -955,7 +986,6 @@ max_degree <- function( loops = loops ) } - #' @rdname degree #' @export #' @cdocs igraph_mean_degree diff --git a/R/topology.R b/R/topology.R index ea43b221a26..d65667a78de 100644 --- a/R/topology.R +++ b/R/topology.R @@ -1034,7 +1034,7 @@ canonical_permutation <- function( colors = NULL, sh = c("fm", "f", "fs", "fl", "flm", "fsm") ) { - canonical_permutation_impl( + canonical_permutation_bliss_impl( graph = graph, colors = if (missing(colors)) missing_arg() else colors, sh = sh @@ -1186,7 +1186,7 @@ count_automorphisms <- function( colors = NULL, sh = c("fm", "f", "fs", "fl", "flm", "fsm") ) { - count_automorphisms_impl( + count_automorphisms_bliss_impl( graph = graph, colors = if (missing(colors)) missing_arg() else colors, sh = sh @@ -1217,24 +1217,6 @@ count_automorphisms <- function( #' vertices, or, if there is no such vertex attribute, it simply assumes that #' all vertices have the same color. Pass NULL explicitly if the graph has a #' `color` vertex attribute but you do not want to use it. -#' @param sh The splitting heuristics for the BLISS algorithm. Possible values -#' are: -#' \sQuote{`f`}: -#' first non-singleton cell, -#' \sQuote{`fl`}: -#' first largest non-singleton cell, -#' \sQuote{`fs`}: -#' first smallest non-singleton cell, -#' \sQuote{`fm`}: -#' first maximally non-trivially connected -#' non-singleton cell, -#' \sQuote{`flm`}: -#' first largest maximally -#' non-trivially connected non-singleton cell, -#' \sQuote{`fsm`}: -#' first smallest maximally non-trivially connected non-singleton cell. -#' @param details Specifies whether to provide additional details about the -#' BLISS internals in the result. #' @return When `details` is `FALSE`, a list of vertex permutations #' that form a generating set of the automorphism group of the input graph. #' When `details` is `TRUE`, a named list with two members: diff --git a/R/trees.R b/R/trees.R index 03adbc86ee3..1c186395cdb 100644 --- a/R/trees.R +++ b/R/trees.R @@ -152,7 +152,7 @@ to_prufer <- function(graph) { #' @param graph The input graph to sample from. Edge directions are ignored if #' the graph is directed. #' @param vid When the graph is disconnected, this argument specifies how to -#' handle the situation. When the argument is zero (the default), the sampling +#' handle the situation. When the argument is `NULL` (the default), the sampling #' will be performed component-wise, and the result will be a spanning forest. #' When the argument contains a vertex ID, only the component containing the #' given vertex will be processed, and the result will be a spanning tree of the @@ -171,7 +171,8 @@ to_prufer <- function(graph) { #' @family trees #' @export #' @cdocs igraph_random_spanning_tree -sample_spanning_tree <- function(graph, vid = 0) { +sample_spanning_tree <- function(graph, vid = NULL) { + vid <- vid %||% 0 random_spanning_tree_impl( graph = graph, vid = vid diff --git a/R/triangles.R b/R/triangles.R index 8321e044795..1745ab62254 100644 --- a/R/triangles.R +++ b/R/triangles.R @@ -97,7 +97,7 @@ triangles <- function(graph) { #' @export #' @rdname count_triangles -#' @cdocs igraph_adjacent_triangles +#' @cdocs igraph_count_adjacent_triangles count_triangles <- function(graph, vids = V(graph)) { count_adjacent_triangles_impl( graph = graph, diff --git a/R/versions.R b/R/versions.R index b4a3b4696fe..dc4336fbf7d 100644 --- a/R/versions.R +++ b/R/versions.R @@ -243,5 +243,7 @@ print.igraph_version <- function(x, ...) { } c_version <- function() { - version_impl()[["version_string"]] + version <- version_impl() + + version[["version_string"]] } diff --git a/cran-comments.md b/cran-comments.md index 0f029c4f4d0..6ea8a5424c5 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,4 +1,4 @@ -igraph 2.2.1 +igraph 2.1.99.9900 ## Cran Repository Policy diff --git a/inst/CHANGELOG-C-DELETEME.md b/inst/CHANGELOG-C-DELETEME.md new file mode 100644 index 00000000000..1f383ade983 --- /dev/null +++ b/inst/CHANGELOG-C-DELETEME.md @@ -0,0 +1,213 @@ +# igraph C library changelog + +## [develop] + +### Breaking changes + +This section gives detailed on breaking changes you need to consider when updating code written for igraph 0.10.x. + +#### General changes + + - igraph now requires a C++ compiler that supports the C++14 standard. + - `igraph_setup()` is now recommended to be called before using the library. This function may gain essential functions in the future. See below for details. + - `igraph_rng_set_default()` now returns a pointer to the previous RNG. Furthermore, this function now only stores a pointer to the `igraph_rng_t` struct passed to it, instead of copying the struct. Thus the `igraph_rng_t` must continue to exist for as long as it is used as the default RNG. + - Interruption handlers do not take a `void*` argument any more; this is relevant to maintainers of higher-level interfaces only. + - Interruption handlers now return an `igraph_bool_t` instead of an `igraph_error_t`; the returned value must be true if the calculation has to be interrupted and false otherwise. + - `igraph_status()`, `igraph_statusf()` and their macro versions (`IGRAPH_STATUS()` and `IGRAPH_STATUSF()`) do not convert error codes to `IGRAPH_INTERRUPTED` any more. Any error code returned from the status handler function is forwarded intact to the caller. If you want to trigger the interruption of the current calculation from the status handler without reporting an error, report `IGRAPH_INTERRUPTED` explicitly. It is the responsibility of higher-level interfaces to handle this error code appropriately. + - The `RNG_BEGIN()` and `RNG_END()` macros were removed. You are now responsible for seeding the RNG before using any igraph function that may use random numbers by calling `igraph_rng_seed(igraph_rng_default(), ...)`, or by simply ensuring that `igraph_setup()` was called before the first use of the library. + +#### Error codes + + - The `IGRAPH_EINVEVECTOR` error code was removed; `igraph_create()` and `igraph_add_edges()` that used to return this error code for invalid edge vectors will now return `IGRAPH_EINVAL` instead. + - The `IGRAPH_NONSQUARE` error code was removed; functions that used this error code now return `IGRAPH_EINVAL` instead when encountering a non-square matrix. + - The `IGRAPH_EGLP` error code and all other GLP-specific error codes (starting with `IGRAPH_GLP_`) were removed; functions that used this error code now return `IGRAPH_FAILURE` instead, providing more details in the message associated to the error code. + - The `IGRAPH_ELAPACK` error code was removed; functions that used this error code now return `IGRAPH_FAILURE` instead, providing more details in the message associated to the error code. + - The `IGRAPH_CPUTIME` error code was removed in favour of the interruption mechanism built into igraph. + - The unused `IGRAPH_EDIVZERO` and `IGRAPH_EATTRIBUTES` error codes were removed with no replacement. + - The deprecated error code `IGRAPH_ENEGLOOP` was removed. Use `IGRAPH_ENEGCYCLE` instead. The underlying numerical value is the same as it was for `IGRAPH_ENEGLOOP`. + - ARPACK-specific error codes (starting with `IGRAPH_ARPACK_...`) were replaced with a single `IGRAPH_EARPACK` error code. Details about the underlying ARPACK failure are provided in the error message. + - A new error code called `IGRAPH_EINVEID` was added for cases when an invalid edge ID was encountered in an edge ID vector. + +#### Core data structures + + - `igraph_strvector_push_back_len()` now takes a length parameter of `size_t` instead of `igraph_integer_t`. + - `igraph_strvector_print()` no longer takes a file parameter. Use `igraph_strvector_fprint()` to print to a file. + - `igraph_vector_reverse()` no longer returns an error code. + - `igraph_vector_shuffle()` no longer returns an error code. + - `igraph_vector_swap()` and `igraph_matrix_swap()` no longer return an error code. + - `igraph_vector_list_swap()` and `igraph_graph_list_swap()` no longer return an error code. + - `igraph_vector_swap_elements()` no longer returns an error code. + - `igraph_vector_list_swap_elements()` and `igraph_graph_list_swap_elements()` no longer return an error code. + - `igraph_matrix_copy_to()` gained an `igraph_matrix_storage_t storage` parameter that specifies whether the data should be written in column-major or row-major format. + +#### Attribute handling + + - `igraph_attribute_handler_t` members that formerly took an untyped `igraph_vector_ptr_t` argument are now taking a typed `igraph_attribute_record_list_t` argument instead. + - The deprecated `IGRAPH_ATTRIBUTE_DEFAULT` value of the `igraph_attribute_type_t` enum was removed. + - The `gettype` member of `igraph_attribute_table_t` was renamed to `get_type` for sake of consistency with the naming scheme of other struct members. + - Attribute table members that retrieve graph, vertex or edge attributes must not clear the incoming result vector any more; results must be appended to the end of the provided result vector instead. + - The `value` member of `igraph_attribute_record_t` is now a union that can be used to formally treat the associated pointer as an `igraph_vector_t *`, `igraph_strvector_t *` or `igraph_vector_bool_t *`. + +#### Core graph manipulation + + - `igraph_delete_vertices_map()` (formerly called `igraph_delete_vertices_idx()`) and `igraph_induced_subgraph_map()` now use `-1` to represent unmapped vertices in the returned forward mapping vector and they do not offset vertex indices by 1 any more. (Note that the inverse map always behaved this way, this change makes the two mappings consistent). + - `igraph_edges()` gained a new `bycol` argument that determines the order in which the edges are returned. `bycol = false` reproduces the existing behaviour, while `bycol = true` returns the edges suitable for a matrix stored in column-wise order. + - `igraph_neighbors()` and `igraph_vs_adj()` gained two extra arguments to specify what to do with loop and multiple edges. This makes their interfaces consistent with `igraph_adjlist_init()`. + - `igraph_incident()` and `igraph_es_incident()` gained an extra arguments to specify what to do with loop edges. This makes their interfaces consistent with `igraph_inclist_init()`. + - `igraph_multiple_t` was removed from the public API as it is essentially a boolean. The symbolic constants `IGRAPH_MULTIPLE` and `IGRAPH_NO_MULTIPLE` were kept to improve readability of code written directly in C. + +#### Basic graph properties + + - `igraph_density()` now takes an optional `weights` parameter. + - `igraph_is_simple()` gained an extra `igraph_bool_t` argument that decides whether edge directions should be considered. Directed graphs with a mutual edge pair are treated as non-simple if this argument is set to `IGRAPH_UNDIRECTED` (which treats the graph as if it was undirected). + - The type of the `loops` argument of `igraph_adjlist_init_complementer()`, `igraph_centralization_degree()`, `igraph_centralization_degree_tmax()`, `igraph_degree()`, `igraph_maxdegree()`, `igraph_sort_vertex_ids_by_degree()` and `igraph_strength()` was changed to `igraph_loops_t` from `igraph_bool_t`, allowing finer-grained control about how loop edges are treated. + - `igraph_get_biadjacency()` now takes a `weights` parameter, and can optionally create weighted biadjacency matrices. + - `igraph_adjacency()` now treats `IGRAPH_LOOPS_TWICE` as `IGRAPH_LOOPS_ONCE` when the mode is `IGRAPH_ADJ_DIRECTED`, `IGRAPH_ADJ_UPPER` or `IGRAPH_ADJ_LOWER`. For directed graphs, this is for the sake of consistency with the rest of the library where `IGRAPH_LOOPS_TWICE` is considered for undirected graphs only. For the "upper" and "lower" modes, double-counting the diagonal makes no sense because the double-counting artifact appears when you add the _transpose_ of an upper (or lower) diagonal matrix on top of the matrix itself. See Github issue #2501 for more context. + +#### Graph generators + + - `igraph_barabasi_game()`, `igraph_barabasi_aging_game()`, `igraph_recent_degree_game()` and `igraph_recent_degree_aging_game()` no longer interprets an empty `outseq` vector as a missing out-degree sequence. Pass `NULL` if you don't wish to specify an out-degree sequence. + - `igraph_degree_sequence_game()` no longer interprets an empty in-degree vector as a request for generating undirected graphs. To generate undirected graphs, pass `NULL` for in-degrees. + - `igraph_lcf()` was renamed to `igraph_lcf_small()` and `igraph_lcf_vector()` was renamed to `igraph_lcf()`. Now `igraph_lcf()` takes shifts as a vector input, while `igraph_lcf_small()` accepts a shorthand notation where shifts are given as a variable number of function arguments. + - `igraph_sbm_game()` gained a `multiple` parameter and now supports generating multigraph with prescribed expected edge multiplicities. The parameter determining the total number of vertices (`n`) was removed as it was redundant. + +#### Shortest paths + + - `igraph_distances()`, `igraph_distances_cutoff()`, `igraph_get_shortest_path()`, `igraph_get_shortest_paths()` and `igraph_get_all_shortest_paths()` gained a `weights` argument. The functions now automatically select the appropriate implementation (unweighted, Dijkstra, Bellman-Ford or Johnson) algorithm based on whether weights are present and whether there are negative weights or not. You can still call the individual methods by their more specific names. + - `igraph_distances_johnson()` now takes a mode parameter to determine in which direction paths should be followed. + - `igraph_similarity_jaccard()` and `igraph_similarity_dice()` now take two sets of vertices to create vertex pairs of, instead of one. + - The weighted variants of `igraph_diameter()`, `igraph_pseudo_diameter()`, `igraph_radius()`, `igraph_graph_center()`, `igraph_eccentricity()` and `igraph_average_path_length()` were merged into the undirected ones by adding a new argument named `weights` in the second position. + - The `weights` parameter of `igraph_average_path_length()`, `igraph_global_efficiency()`, `igraph_local_efficiency()` and `igraph_average_local_efficiency()` were moved to the second position, after the `graph` itself, for sake of consistency with other functions. + - `igraph_get_all_simple_paths()` returns its results in an integer vector list (`igraph_vector_int_list_t`) instead of a single integer vector. + - `igraph_get_all_simple_paths()` now has an additional parameter that allows restricting paths by minimum length as well. + +#### Community detection + + - `igraph_community_edge_betweenness()` now takes both a `weights` and a `lengths` parameter. Egde weights (interpreted as connection strengths) are used to divide betweenness scores before selecting them for removal as well as for the modularity computation. Edge lengths are used for defining shortest path lengths during the betweenness computation. This fixes issues #2229 and #1040. + - `igraph_community_infomap()` now supports regularization and gained the `is_regularized` and `regularization_strength` parameters. + - `igraph_community_label_propagation()` changed signature to allow specification of label propagation algorithm (LPA) variants. A new fast label propagation variant was added. + - `igraph_community_leiden()` now takes two `vertex_out_weights` and `vertex_in_weights` parameters in order to support directed graphs, instead of the previous single `node_weights` parameter. To obtain the old behavior for undirected graphs, pass the vertex weights as `vertex_out_weights` and set `vertex_in_weights` to `NULL`. + - The `history` parameter of `igraph_community_leading_eigenvector()` is now a pointer to an `igraph_vector_int_t` instead of an `igraph_vector_t`. + - `igraph_community_optimal_modularity()` now takes a `resolution` parameter and its `weight` parameter was moved to the second place. + - `igraph_community_spinglass_single()` now uses `igraph_real_t` for its `inner_links` and `outer_links` output parameters, as these return not simply edge counts, but the sum of the weights of some edges. + +#### Isomorphism functions and permutations + + - `igraph_count_automorphisms()` has been renamed to `igraph_count_automorphisms_bliss()` because it has a BLISS-specific interface. A new `igraph_count_automorphisms()` function was added with a simplified interface that does not depend on BLISS. + - `igraph_automorphism_group()` has been renamed to `igraph_automorphism_group_bliss()` because it has a BLISS-specific interface. A new `igraph_automorphism_group()` function was added with a simplified interface that does not depend on BLISS. + - `igraph_canonical_permutation()` has been renamed to `igraph_canonical_permutation_bliss()` because it has a BLISS-specific interface. A new `igraph_canonical_permutation()` function was added with a simplified interface that does not depend on BLISS. + - `igraph_subisomorphic_lad()` does not have a CPU time limit parameter any more. If you wish to stop the calculation from another thread or a higher level interface, use igraph's interruption mechanism. + - The semantics of the `igraph_permute_vertices()` permutation argument has changed: the i-th element of the vector now contains the index of the _original_ vertex that will be mapped to the i-th vertex in the new graph. This is now consistent with how other igraph functions treat permutations and vertex index vectors; for instance, you can now pass the result of `igraph_topological_sorting()` directly to `igraph_permute_vertices()` to obtain a new graph where the vertices are sorted topologically. + - As a consequence to the change in the semantics of the `igraph_permute_vertices()` permutation argument, the semantics of the permutations returned from `igraph_canonical_permutation()` and `igraph_canonical_permutation_bliss()` have also been inverted to maintain the invariant that the output of these functions can be fed into `igraph_permute_vertices()` directly. + +#### Centralities + + - All betweenness functions got `normalized` parameter to support normalizing the result by the number of vertex pairs in the graph. At the same time, parameter ordering was standardized. The following functions are affected: `igraph_betweenness()`, `igraph_betweenness_cutoff()`, `igraph_edge_betweenness()`, `igraph_edge_betweenness_cutoff()`, `igraph_betweenness_subset()`, `igraph_edge_betweenness_subset()`. + - `igraph_edge_betweenness()` and `igraph_edge_betweenness_cutoff()` now have an `eids` parameter to return only a subset of results. This makes their interface consistent with other betweenness functions. + - `igraph_eigenvector_centrality()`, `igraph_centralization_eigenvector_centrality()` and `igraph_centralization_eigenvector_centrality_tmax()` now use a `mode` parameter with possible values `IGRAPH_OUT`, `IGRAPH_IN` or `IGRAPH_ALL` to control how edge directions are considered. Previously they used a boolean `directed` parameter. + - `igraph_eigenvector_centrality()`, `igraph_centralization_eigenvector_centrality()` and `igraph_centralization_eigenvector_centrality_tmax()` no longer have a `scale` parameter. The result is now always scaled so that the largest centrality value is 1. + - `igraph_hub_and_authority_scores()` no longer has a `scale` parameter. The result is now always scaled so that the largest hub and authority scores are each 1. + - `igraph_pagerank()`, `igraph_personalized_pagerank()` and `igraph_personalized_pagerank_vs()` had their parameter ordering standardized. + +#### Other network analysis + + - `igraph_minimum_spanning_tree()` takes a new `method` parameter that controls the algorithm used for finding the spanning tree. Kruskal's algorithm was added. + - The deprecated `igraph_rng_get_dirichlet()` function was removed. + - `igraph_motifs_randesu_no()` and `igraph_motifs_randesu_estimate()` now take an `igraph_real_t` as their `result` argument to prevent overflows when igraph is compiled with 32-bit integers. + - The experimental functions `igraph_fundamental_cycles()` and `igraph_minimum_cycle_basis()` now use the type `igraph_real_t` for their `bfs_cutoff` parameter, and had their `weights` parameter moved to the 2nd position. + - `igraph_rewire()` now takes an `igraph_edge_type_sw_t` parameter to specify whether to create self-loops. The `igraph_rewiring_t` enum type was removed. Instead of the old `IGRAPH_REWIRING_SIMPLE`, use `IGRAPH_SIMPLE_SW`. Instead of the old `IGRAPH_REWIRING_SIMPLE_LOOPS`, use `IGRAPH_LOOPS_SW`. + +#### Foreign formats + + - `igraph_read_graph_ncol()` and `igraph_read_graph_lgl()` now uses a default edge weight of 1 instead of 0 for files that do not contain edge weights for at least some of the edges. + +### Added + + - `igraph_setup()` performs all initialization tasks that are recommended before using the igraph library. Right now this function only initializes igraph's internal random number generator with a practically random seed, but it may also perform other tasks in the future. It is recommended to call this function before using any other function from the library (although most of the functions will work fine now even if this function is not called). + - `igraph_int_t` may now be used as an alias to `igraph_integer_t`. + - `igraph_erdos_renyi_game_gnm()` gained a `multiple` Boolean argument to uniformly sample G(n,m) graphs with multi-edges. + - `igraph_bipartite_game_gnm()` gained a `multiple` Boolean argument to uniformly sample bipartite G(n,m) graphs with multi-edges. + - `igraph_iea_game()` samples random multigraphs through independent edge assignment. + - `igraph_bipartite_iea_game()` samples random bipartite multigraph through independent edge assignment. + - `igraph_weighted_biadjacency()` creates a weighted graph from a bipartite adjacency matrix. + - `igraph_vector_ptr_capacity()` returns the allocated capacity of a pointer vector. + - `igraph_vector_ptr_resize_min()` deallocates unused capacity of a pointer vector. + - `igraph_strvector_fprint()` prints a string vector to a file. + - `igraph_rng_sample_dirichlet()`, `igraph_rng_sample_sphere_volume()` and `igraph_rng_sample_sphere_surface()` samples vectors from a Dirichlet distribution or from the volume or surface of a sphere while allowing the user to specify the random number generator to use. + - `igraph_nearest_neighbor_graph()` computes a neighborhood graph of spatial points based on a neighbor count, cutoff distance, and chosen metric (experimental function). Thanks to Arnór Friðriksson @Zepeacedust for implementing this in #2788! + - `igraph_delaunay_graph()` computes a Delaunay graph of a spatial point set (experimental function). Thanks to Arnór Friðriksson @Zepeacedust for implementing this in #2806! + - `igraph_spatial_edge_lengths()` computes edges lengths based on spatial vertex coordinates (experimental function). + - `igraph_community_leiden_simple()` is a simplified interface to `igraph_community_leiden()` that allows selecting the objective function to maximize directly. + - `igraph_vector_difference_and_intersection_sorted()` calculates the intersection and the differences of two vectors simultaneously. + +### Changed + + - The Pajek format reader and writer now map vertex labels to the `name` vertex attribute in igraph. The `id` attribute is no longer used. + - `igraph_minimum_size_separators()` no longer returns any separating vertex sets for complete graphs. Prior to igraph 1.0, it would return all `n - 1` size vertex subsets where `n` is the vertex count. + - `igraph_community_edge_betweenness()` now treats edges with large weights as strong connections. + - `igraph_biadjacency()` now truncates non-integer matrix entries to their integer part instead of rounding them up. This brings consistency with related functions such as `igraph_adjacency()`. + - The order of edges in the graph returned by `igraph_(weighted_)adjacency()` and `igraph_biadjacency()` has changed. Note that these functions do not guarantee any specific edge order. + - `igraph_eigenvector_centrality()` now warns about eigenvector centralities equal to zero, as these indicate a disconnected graph, for which eigenvector centrality is not meaningful. + - `igraph_hub_and_authority_scores()` now warns when a large fraction of centrality scores are zero, as this indicates a non-unique solution, and thus the returned result may not be meaningful. + - `igraph_hub_and_authority_scores()` now warns when providing an undirected graph as input, and falls back to the equivalent eigenvector centrality computation. + - `igraph_get_stochastic_sparse()` no longer throws an error when some row or column sums are zero. This brings its behaviour in line with `igraph_get_stochastic()`. + - `igraph_vector_append()`, `igraph_strvector_append()` and `igraph_vector_ptr_append()` now use a different allocation strategy: if the `to` vector has insufficient capacity, they double its capacity. Previously they reserved precisely as much capacity as needed for appending the `from` vector. + - The implementation of the Infomap algorithm behind `igraph_community_infomap()` has been updated with a more recent version (2.8.0). Isolated vertices are now supported. + - `igraph_vector_difference_sorted()` now handles multisets properly (and documents how the multiplicities are handled). + +### Finalized experimental functions + + - The following functions are not experimental any more: `igraph_count_loops()`, `igraph_count_reachable()`, `igraph_distances_cutoff()`, `igraph_distances_floyd_warshall()`, `igraph_distances_dijkstra_cutoff()`, `igraph_ecc()`, `igraph_enter_safelocale()`, `igraph_exit_safelocale()`, `igraph_feedback_vertex_set()`, `igraph_find_cycle()`, `igraph_get_shortest_path_astar()`, `igraph_graph_power()`, `igraph_hexagonal_lattice()`, `igraph_hypercube()`, `igraph_is_clique()`, `igraph_is_complete()`, `igraph_is_edge_coloring()`, `igraph_is_vertex_coloring()`, `igraph_is_independent_vertex_set()`, `igraph_join()`,`igraph_joint_degree_distribution()`, `igraph_joint_degree_matrix()`, `igraph_joint_type_distribution()`, `igraph_layout_align()`, `igraph_layout_merge_dla()`, `igraph_mean_degree()`, `igraph_radius()`, `igraph_realize_bipartite_degree_sequence()`, `igraph_reachability()`, `igraph_transitive_closure()`, `igraph_tree_from_parent_vector()`, `igraph_triangular_lattice()`, `igraph_vector_intersection_size_sorted()`, `igraph_voronoi()`. + +### Fixed + + - `igraph_community_spinglass_single()` now uses `igraph_real_t` for its `inner_links` and `outer_links` output parameters, as these return not simply edge counts, but the sum of the weights of some edges. Thus these results are no longer incorrectly rounded. + +### Removed + + - Removed `igraph_Calloc()`, `igraph_Realloc()` and `igraph_Free()`. Use `IGRAPH_CALLOC()`, `IGRAPH_REALLOC()` and `IGRAPH_FREE()` instead. + - The deprecated `igraph_adjacent_triangles()` was removed. Use `igraph_count_adjacent_triangles()` instead. + - The deprecated `igraph_are_connected()` was removed. Use `igraph_are_adjacent()` instead. + - The deprecated `igraph_automorphisms()` was removed. Use `igraph_count_automorphisms()` or `igraph_count_automorphisms_bliss()` instead. + - The deprecated `igraph_convex_hull()` was removed. Use `igraph_convex_hull_2d()` instead. + - The deprecated `igraph_decompose_destroy()` was removed. + - The deprecated `igraph_hub_score()` and `igraph_authority_score()` were removed. + - The deprecated `igraph_vs_seq()`, `igraph_vss_seq()`, `igraph_es_seq()`, `igraph_ess_range()`, and `igraph_vector_init_seq()` were removed. Use the `range` alternatives instead of the old `seq` ones. + - The deprecated `igraph_erdos_renyi_game()` and `igraph_bipartite_game()` were removed. Use the corresponding functions with `_gnm()` and `_gnp()` in the name instead. + - The deprecated `igraph_tree()` was removed. Use `igraph_kary_tree()` instead. + - The deprecated `igraph_lattice()` was removed. Use `igraph_square_lattice()` instead. + - The deprecated `igraph_minimum_spanning_tree_prim()` was removed. Use `igraph_minimum_spanning_tree()` in conjunction with `igraph_subgraph_from_edges()` instead. + - The deprecated `igraph_minimum_spanning_tree_unweighted()` was removed. Use `igraph_minimum_spanning_tree()` in conjunction with `igraph_subgraph_from_edges()` instead. + - The deprecated `igraph_get_sparsemat()` was removed. Use `igraph_get_adjacency_sparse()` instead. + - The deprecated `igraph_get_stochastic_sparsemat()` was removed. Use `igraph_get_stochastic_sparse()` instead. + - The deprecated `igraph_laplacian()` was removed. Use `igraph_get_laplacian()` or `igraph_get_laplacian_sparse()` instead. + - The deprecated `igraph_subgraph_edges()` was removed. Use `igraph_subgraph_from_edges()` instead. + - The deprecated `igraph_read_graph_dimacs()` and `igraph_write_graph_dimacs()` were removed. These names may be re-used in the future. Use `igraph_read_graph_dimacs_flow()` and `igraph_write_graph_dimacs_flow()` instead. + - The deprecated `igraph_isomorphic_function_vf2()` was removed. Use `igraph_get_isomorphisms_vf2_callback()` instead. + - The deprecated `igraph_subisomorphic_function_vf2()` was removed. Use `igraph_get_subisomorphisms_vf2_callback()` instead. + - The deprecated `igraph_isomorphic_34()` was removed. Its functionality is accessible through `igraph_isomorphic()`. + - The deprecated `igraph_transitive_closure_dag()` was removed. Use `igraph_transitive_closure()` instead, which works for all graphs, not just DAGs. + - The deprecated `igraph_sparsemat_copy()` was removed. Use `igraph_sparsemat_init_copy()` instead. + - The deprecated `igraph_sparsemat_eye()` was removed. Use `igraph_sparsemat_init_eye()` instead. + - The deprecated `igraph_sparsemat_diag()` was removed. Use `igraph_sparsemat_init_diag()` instead. + - The deprecated `igraph_sparsemat()` and `igraph_weighted_sparsemat()` functions were removed; use `igraph_get_adjacency_sparse()` instead. + - The deprecated `igraph_random_edge_walk()` was removed. Its functionality is incorporated in `igraph_random_walk()`. + - The deprecated `igraph_vector_qsort_ind()` was removed. Use `igraph_vector_sort_ind()` instead. + - The deprecated `igraph_vector_binsearch2()` was removed. Use `igraph_vector_contains_sorted()` instead. + - The deprecated `igraph_vector_copy()` and `igraph_matrix_copy()` were removed. Use `igraph_vector_init_copy()` and `igraph_matrix_init_copy()` instead. + - The deprecated `igraph_vector_e()`, `igraph_vector_e_ptr()`, `igraph_matrix_e()` and `igraph_matrix_e_ptr()` were removed. Use the alternatives ending in `_get()` and `_get_ptr()` instead. + - The deprecated `igraph_vector_move_interval2()` was removed. + - The deprecated `igraph_zeroin()` was removed. + - The deprecated `igraph_deterministic_optimal_imitation()`, `igraph_moran_process()`, `igraph_roulette_wheel_imitation()` and `igraph_stochastic_imitation()` functions were removed. + - `igraph_sample_dirichlet()`, `igraph_sample_sphere_surface()` and `igraph_sample_sphere_volume()` were removed in favour of `igraph_rng_sample_dirichlet()`, `igraph_rng_sample_sphere_surface()` and `igraph_rng_sample_sphere_volume()`, which allow the user to specify the random number generator to use. + - The unused enum type `igraph_fileformat_type_t` was removed. + - The macros `IGRAPH_POSINFINITY` and `IGRAPH_NEGINFINITY` were removed. Use `IGRAPH_INFINITY` and `-IGRAPH_INFINITY` instead. + +### Deprecated + +- `igraph_delete_vertices_idx()` is now deprecated in favour of `igraph_delete_vertices_map()`, which is functionally equivalent but has a name that is consistent with `igraph_induced_subgraph_map()`. + +### Other + + - Documentation improvements. + - Improved performance when creating graphs from dense adjacency matrices (`igraph_adjacency()` and `igraph_weighted_adjacency()`). \ No newline at end of file diff --git a/man/automorphism_group.Rd b/man/automorphism_group.Rd index ab8b25f3ca6..b4810c1e3d6 100644 --- a/man/automorphism_group.Rd +++ b/man/automorphism_group.Rd @@ -20,26 +20,6 @@ automorphism. When omitted, igraph uses the \code{color} attribute of the vertices, or, if there is no such vertex attribute, it simply assumes that all vertices have the same color. Pass NULL explicitly if the graph has a \code{color} vertex attribute but you do not want to use it.} - -\item{sh}{The splitting heuristics for the BLISS algorithm. Possible values -are: -\sQuote{\code{f}}: -first non-singleton cell, -\sQuote{\code{fl}}: -first largest non-singleton cell, -\sQuote{\code{fs}}: -first smallest non-singleton cell, -\sQuote{\code{fm}}: -first maximally non-trivially connected -non-singleton cell, -\sQuote{\code{flm}}: -first largest maximally -non-trivially connected non-singleton cell, -\sQuote{\code{fsm}}: -first smallest maximally non-trivially connected non-singleton cell.} - -\item{details}{Specifies whether to provide additional details about the -BLISS internals in the result.} } \value{ When \code{details} is \code{FALSE}, a list of vertex permutations diff --git a/man/centr_degree_tmax.Rd b/man/centr_degree_tmax.Rd index edb61533072..274ea5b5a05 100644 --- a/man/centr_degree_tmax.Rd +++ b/man/centr_degree_tmax.Rd @@ -19,8 +19,11 @@ centr_degree_tmax( \item{mode}{This is the same as the \code{mode} argument of \code{degree()}. Ignored if \code{graph} is given and the graph is undirected.} -\item{loops}{Logical scalar, whether to consider loops edges when -calculating the degree.} +\item{loops}{Character string, +\code{"none"} (the default) ignores loop edges; +\code{"once"} counts each loop edge only once; +\code{"twice"} counts each loop edge twice in undirected graphs. +and once in directed graphs.} } \value{ Real scalar, the theoretical maximum (unnormalized) graph degree @@ -32,8 +35,8 @@ See \code{\link[=centralize]{centralize()}} for a summary of graph centralizatio \examples{ # A BA graph is quite centralized g <- sample_pa(1000, m = 4) -centr_degree(g, normalized = FALSE)$centralization \%>\% - `/`(centr_degree_tmax(g, loops = FALSE)) +centr_degree(g, normalized = FALSE)$centralization / + centr_degree_tmax(g, loops = "twice") centr_degree(g, normalized = TRUE)$centralization } \seealso{ diff --git a/man/centr_eigen.Rd b/man/centr_eigen.Rd index e418e792712..6df0134744f 100644 --- a/man/centr_eigen.Rd +++ b/man/centr_eigen.Rd @@ -6,17 +6,17 @@ \usage{ centr_eigen( graph, - directed = FALSE, + directed = deprecated(), scale = deprecated(), options = arpack_defaults(), - normalized = TRUE + normalized = TRUE, + mode = c("out", "in", "all") ) } \arguments{ \item{graph}{The input graph.} -\item{directed}{logical scalar, whether to use directed shortest paths for -calculating eigenvector centrality.} +\item{directed}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Use \code{mode} instead.} \item{scale}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Ignored. Computing eigenvector centralization requires normalized eigenvector centrality scores.} @@ -26,6 +26,20 @@ for the ARPACK eigensolver.} \item{normalized}{Logical scalar. Whether to normalize the graph level centrality score by dividing by the theoretical maximum.} + +\item{mode}{How to consider edge directions in directed graphs. +It is ignored for undirected graphs. +Possible values: +\itemize{ +\item \code{"out"} the left eigenvector of the adjacency matrix is calculated, +i.e. the centrality of a vertex is proportional to the sum of centralities +of vertices pointing to it. This is the standard eigenvector centrality. +\item \code{"in"} the right eigenvector of the adjacency matrix is calculated, +i.e. the centrality of a vertex is proportional to the sum of centralities +of vertices it points to. +\item \code{"all"} edge directions are ignored, +and the unweighted eigenvector centrality is calculated. +}} } \value{ A named list with the following components: diff --git a/man/centr_eigen_tmax.Rd b/man/centr_eigen_tmax.Rd index 143d51252df..b8d6a39f0f9 100644 --- a/man/centr_eigen_tmax.Rd +++ b/man/centr_eigen_tmax.Rd @@ -7,8 +7,9 @@ centr_eigen_tmax( graph = NULL, nodes = 0, - directed = FALSE, - scale = deprecated() + directed = deprecated(), + scale = deprecated(), + mode = c("out", "in", "all") ) } \arguments{ @@ -23,6 +24,9 @@ during the calculation. Ignored in undirected graphs.} \item{scale}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Ignored. Computing eigenvector centralization requires normalized eigenvector centrality scores.} + +\item{mode}{This is the same as the \code{mode} argument of +\code{degree()}.} } \value{ Real scalar, the theoretical maximum (unnormalized) graph diff --git a/man/centralization.degree.tmax.Rd b/man/centralization.degree.tmax.Rd index fa664f658f5..f5cfa9a37df 100644 --- a/man/centralization.degree.tmax.Rd +++ b/man/centralization.degree.tmax.Rd @@ -19,8 +19,11 @@ centralization.degree.tmax( \item{mode}{This is the same as the \code{mode} argument of \code{degree()}. Ignored if \code{graph} is given and the graph is undirected.} -\item{loops}{Logical scalar, whether to consider loops edges when -calculating the degree.} +\item{loops}{Character string, +\code{"none"} (the default) ignores loop edges; +\code{"once"} counts each loop edge only once; +\code{"twice"} counts each loop edge twice in undirected graphs. +and once in directed graphs.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} diff --git a/man/centralize.Rd b/man/centralize.Rd index 134db123a5b..e9969cb9238 100644 --- a/man/centralize.Rd +++ b/man/centralize.Rd @@ -56,7 +56,7 @@ centr_eigen(g, directed = FALSE)$centralization # Calculate centralization from pre-computed scores deg <- degree(g) -tmax <- centr_degree_tmax(g, loops = FALSE) +tmax <- centr_degree_tmax(g, loops = "none") centralize(deg, tmax) # The most centralized graph according to eigenvector centrality diff --git a/man/cluster_label_prop.Rd b/man/cluster_label_prop.Rd index 86ec14c870f..d092ca9a061 100644 --- a/man/cluster_label_prop.Rd +++ b/man/cluster_label_prop.Rd @@ -10,7 +10,8 @@ cluster_label_prop( ..., mode = c("out", "in", "all"), initial = NULL, - fixed = NULL + fixed = NULL, + lpa_variant = c("dominance", "retention", "fast") ) } \arguments{ @@ -43,6 +44,13 @@ entries denote vertices without labels.} \item{fixed}{Logical vector denoting which labels are fixed. Of course this makes sense only if you provided an initial state, otherwise this element will be ignored. Also note that vertices without labels cannot be fixed.} + +\item{lpa_variant}{Which variant of the label propagation algorithm to run. +\itemize{ +\item \code{"dominance"} (default) check for dominance of all nodes after each iteration. +\item \code{"retention"} keep current label if among dominant labels, only check if labels changed. +\item \code{"fast"} sample from dominant labels, only check neighbors. +}} } \value{ \code{cluster_label_prop()} returns a diff --git a/man/convex_hull.Rd b/man/convex_hull.Rd index b500ab2615e..45a17e0fb2a 100644 --- a/man/convex_hull.Rd +++ b/man/convex_hull.Rd @@ -45,5 +45,5 @@ Tamas Nepusz \email{ntamas@gmail.com} } \concept{other} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Nongraph.html#igraph_convex_hull}{\code{convex_hull()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Spatial.html#igraph_convex_hull_2d}{\code{convex_hull_2d()}}.} diff --git a/man/count_triangles.Rd b/man/count_triangles.Rd index 8db87f9e930..46764c13d21 100644 --- a/man/count_triangles.Rd +++ b/man/count_triangles.Rd @@ -63,5 +63,5 @@ Gabor Csardi \email{csardi.gabor@gmail.com} } \concept{triangles} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Motifs.html#igraph_list_triangles}{\code{list_triangles()}}, \href{https://igraph.org/c/html/latest/igraph-Motifs.html#igraph_adjacent_triangles}{\code{adjacent_triangles()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Motifs.html#igraph_list_triangles}{\code{list_triangles()}}, \href{https://igraph.org/c/html/latest/igraph-Motifs.html#igraph_count_adjacent_triangles}{\code{count_adjacent_triangles()}}.} diff --git a/man/degree.Rd b/man/degree.Rd index 2bd19522f86..4e4f1014847 100644 --- a/man/degree.Rd +++ b/man/degree.Rd @@ -11,7 +11,7 @@ degree( graph, v = V(graph), mode = c("all", "out", "in", "total"), - loops = TRUE, + loops = c("twice", "none", "once"), normalized = FALSE ) @@ -20,7 +20,7 @@ max_degree( ..., v = V(graph), mode = c("all", "out", "in", "total"), - loops = TRUE + loops = c("twice", "none", "once") ) mean_degree(graph, loops = TRUE) @@ -36,7 +36,11 @@ degree_distribution(graph, cumulative = FALSE, ...) in-degree or \dQuote{total} for the sum of the two. For undirected graphs this argument is ignored. \dQuote{all} is a synonym of \dQuote{total}.} -\item{loops}{Logical; whether the loop edges are also counted.} +\item{loops}{Character string, +\code{"none"} ignores loop edges; +\code{"once"} counts each loop edge only once; +\code{"twice"} (the default) counts each loop edge twice in undirected graphs +and once in directed graphs.} \item{normalized}{Logical scalar, whether to normalize the degree. If \code{TRUE} then the result is divided by \eqn{n-1}, where \eqn{n} is the diff --git a/man/distances.Rd b/man/distances.Rd index 96ffa1c2860..a9ebe93a875 100644 --- a/man/distances.Rd +++ b/man/distances.Rd @@ -328,5 +328,5 @@ Gabor Csardi \email{csardi.gabor@gmail.com} \concept{paths} \concept{structural.properties} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_path_length_hist}{\code{path_length_hist()}}, \href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_average_path_length_dijkstra}{\code{average_path_length_dijkstra()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_path_length_hist}{\code{path_length_hist()}}, \href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_average_path_length}{\code{average_path_length()}}.} diff --git a/man/eccentricity.Rd b/man/eccentricity.Rd index a4678a78d2d..19a64315619 100644 --- a/man/eccentricity.Rd +++ b/man/eccentricity.Rd @@ -68,5 +68,5 @@ Other paths: \code{\link{radius}()} } \concept{paths} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_eccentricity_dijkstra}{\code{eccentricity_dijkstra()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_eccentricity}{\code{eccentricity()}}.} diff --git a/man/eigen_centrality.Rd b/man/eigen_centrality.Rd index 43b3c7092c6..2b0320a800a 100644 --- a/man/eigen_centrality.Rd +++ b/man/eigen_centrality.Rd @@ -6,16 +6,17 @@ \usage{ eigen_centrality( graph, - directed = FALSE, + directed = deprecated(), scale = deprecated(), weights = NULL, - options = arpack_defaults() + options = arpack_defaults(), + mode = c("out", "in", "all") ) } \arguments{ \item{graph}{Graph to be analyzed.} -\item{directed}{Logical scalar, whether to consider direction of the edges +\item{directed}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Logical scalar, whether to consider direction of the edges in directed graphs. It is ignored for undirected graphs.} \item{scale}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Normalization will always take @@ -35,6 +36,20 @@ weights spread the centrality better.} \item{options}{A named list, to override some ARPACK options. See \code{\link[=arpack]{arpack()}} for details.} + +\item{mode}{How to consider edge directions in directed graphs. +It is ignored for undirected graphs. +Possible values: +\itemize{ +\item \code{"out"} the left eigenvector of the adjacency matrix is calculated, +i.e. the centrality of a vertex is proportional to the sum of centralities +of vertices pointing to it. This is the standard eigenvector centrality. +\item \code{"in"} the right eigenvector of the adjacency matrix is calculated, +i.e. the centrality of a vertex is proportional to the sum of centralities +of vertices it points to. +\item \code{"all"} edge directions are ignored, +and the unweighted eigenvector centrality is calculated. +}} } \value{ A named list with components: diff --git a/man/feedback_arc_set.Rd b/man/feedback_arc_set.Rd index 59a41641f6a..ebf760a59d3 100644 --- a/man/feedback_arc_set.Rd +++ b/man/feedback_arc_set.Rd @@ -88,5 +88,5 @@ Graph cycles \concept{cycles} \concept{structural.properties} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_feedback_arc_set}{\code{feedback_arc_set()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Cycles.html#igraph_feedback_arc_set}{\code{feedback_arc_set()}}.} diff --git a/man/feedback_vertex_set.Rd b/man/feedback_vertex_set.Rd index 06f635f7ee5..e9039b29160 100644 --- a/man/feedback_vertex_set.Rd +++ b/man/feedback_vertex_set.Rd @@ -74,5 +74,5 @@ Graph cycles \concept{cycles} \concept{structural.properties} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_feedback_vertex_set}{\code{feedback_vertex_set()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Cycles.html#igraph_feedback_vertex_set}{\code{feedback_vertex_set()}}.} diff --git a/man/graph_center.Rd b/man/graph_center.Rd index edaa1075a6e..eb505c7da0f 100644 --- a/man/graph_center.Rd +++ b/man/graph_center.Rd @@ -57,5 +57,5 @@ Other paths: \code{\link{radius}()} } \concept{paths} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_graph_center_dijkstra}{\code{graph_center_dijkstra()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_graph_center}{\code{graph_center()}}.} diff --git a/man/graph_from_lcf.Rd b/man/graph_from_lcf.Rd index 41ac2b6c9d6..b2a5618baed 100644 --- a/man/graph_from_lcf.Rd +++ b/man/graph_from_lcf.Rd @@ -42,5 +42,5 @@ functions on the its manual page for creating special graphs. Gabor Csardi \email{csardi.gabor@gmail.com} } \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_lcf_vector}{\code{lcf_vector()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_lcf}{\code{lcf()}}.} diff --git a/man/hits_scores.Rd b/man/hits_scores.Rd index ad304438ecd..ca324679740 100644 --- a/man/hits_scores.Rd +++ b/man/hits_scores.Rd @@ -7,7 +7,7 @@ hits_scores( graph, ..., - scale = TRUE, + scale = deprecated(), weights = NULL, options = arpack_defaults() ) @@ -17,9 +17,7 @@ hits_scores( \item{...}{These dots are for future extensions and must be empty.} -\item{scale}{Logical scalar, whether to scale the result to have a maximum -score of one. If no scaling is used then the result vector has unit length -in the Euclidean norm.} +\item{scale}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Ignored, always scaled.} \item{weights}{Optional positive weight vector for calculating weighted scores. If the graph has a \code{weight} edge attribute, then this is used diff --git a/man/incident.Rd b/man/incident.Rd index b69fb6b753c..1a7e809f67d 100644 --- a/man/incident.Rd +++ b/man/incident.Rd @@ -4,7 +4,12 @@ \alias{incident} \title{Incident edges of a vertex in a graph} \usage{ -incident(graph, v, mode = c("all", "out", "in", "total")) +incident( + graph, + v, + mode = c("all", "out", "in", "total"), + loops = c("twice", "none", "once") +) } \arguments{ \item{graph}{The input graph.} @@ -14,6 +19,14 @@ incident(graph, v, mode = c("all", "out", "in", "total")) \item{mode}{Whether to query outgoing (\sQuote{out}), incoming (\sQuote{in}) edges, or both types (\sQuote{all}). This is ignored for undirected graphs.} + +\item{loops}{Specifies how to treat loop edges. +\code{"none"} removes loop edges from the result. +\code{"once"} makes each loop edge appear only once in the result. +\code{"twice"} makes loop edges appear twice in the result +if the graph is undirected or \code{mode} is set to \code{"all"} +(and once otherwise as returning them twice +does not make sense for directed graphs).} } \value{ An edge sequence containing the incident edges of diff --git a/man/is_acyclic.Rd b/man/is_acyclic.Rd index 21a8b7dc86d..6881e4e95b0 100644 --- a/man/is_acyclic.Rd +++ b/man/is_acyclic.Rd @@ -67,5 +67,5 @@ Other structural.properties: \concept{cycles} \concept{structural.properties} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_is_acyclic}{\code{is_acyclic()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Cycles.html#igraph_is_acyclic}{\code{is_acyclic()}}.} diff --git a/man/is_dag.Rd b/man/is_dag.Rd index 0c651de7b3e..08c2a30d9f8 100644 --- a/man/is_dag.Rd +++ b/man/is_dag.Rd @@ -71,5 +71,5 @@ Tamas Nepusz \email{ntamas@gmail.com} for the C code, Gabor Csardi \concept{cycles} \concept{structural.properties} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_is_dag}{\code{is_dag()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Cycles.html#igraph_is_dag}{\code{is_dag()}}.} diff --git a/man/min_st_separators.Rd b/man/min_st_separators.Rd index 6a1924654d3..cd36e3839dc 100644 --- a/man/min_st_separators.Rd +++ b/man/min_st_separators.Rd @@ -38,16 +38,13 @@ min_st_separators(g) }\if{html}{\out{}} \if{html}{\out{
}}\preformatted{#> [[1]] -#> + 1/5 vertex, named: -#> [1] 1 +#> [1] 2 #> #> [[2]] -#> + 2/5 vertices, named: -#> [1] 2 4 +#> [1] 3 5 #> #> [[3]] -#> + 2/5 vertices, named: -#> [1] 1 3 +#> [1] 2 4 }\if{html}{\out{
}} } diff --git a/man/minimum.spanning.tree.Rd b/man/minimum.spanning.tree.Rd index 79dc14a82d9..fcef3779db3 100644 --- a/man/minimum.spanning.tree.Rd +++ b/man/minimum.spanning.tree.Rd @@ -16,7 +16,7 @@ distances.} \item{algorithm}{The algorithm to use for calculation. \code{unweighted} can be used for unweighted graphs, and \code{prim} runs Prim's algorithm for -weighted graphs. If this is \code{NULL} then igraph will select the +weighted graphs. By default igraph will select the algorithm automatically: if the graph has an edge attribute called \code{weight} or the \code{weights} argument is not \code{NULL} then Prim's algorithm is chosen, otherwise the unweighted algorithm is used.} diff --git a/man/mst.Rd b/man/mst.Rd index 686678e50e3..7f7335ab1b7 100644 --- a/man/mst.Rd +++ b/man/mst.Rd @@ -4,7 +4,12 @@ \alias{mst} \title{Minimum spanning tree} \usage{ -mst(graph, weights = NULL, algorithm = NULL, ...) +mst( + graph, + weights = NULL, + algorithm = c("automatic", "unweighted", "prim", "kruskal"), + ... +) } \arguments{ \item{graph}{The graph object to analyze.} @@ -16,7 +21,7 @@ distances.} \item{algorithm}{The algorithm to use for calculation. \code{unweighted} can be used for unweighted graphs, and \code{prim} runs Prim's algorithm for -weighted graphs. If this is \code{NULL} then igraph will select the +weighted graphs. By default igraph will select the algorithm automatically: if the graph has an edge attribute called \code{weight} or the \code{weights} argument is not \code{NULL} then Prim's algorithm is chosen, otherwise the unweighted algorithm is used.} diff --git a/man/radius.Rd b/man/radius.Rd index 16cb54ccbe5..0f353e271fb 100644 --- a/man/radius.Rd +++ b/man/radius.Rd @@ -61,5 +61,5 @@ Other paths: \code{\link{graph_center}()} } \concept{paths} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_radius_dijkstra}{\code{radius_dijkstra()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Structural.html#igraph_radius}{\code{radius()}}.} diff --git a/man/sample_chung_lu.Rd b/man/sample_chung_lu.Rd index 28a0dfdbd5b..f0d00d6cc2f 100644 --- a/man/sample_chung_lu.Rd +++ b/man/sample_chung_lu.Rd @@ -202,5 +202,5 @@ Random graph models (games) \code{\link{sample_tree}()} } \concept{games} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_chung_lu_game}{\code{chung_lu_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_chung_lu_game}{\code{chung_lu_game()}}.} diff --git a/man/sample_correlated_gnp.Rd b/man/sample_correlated_gnp.Rd index 215c5f1c4c3..565a0b2293e 100644 --- a/man/sample_correlated_gnp.Rd +++ b/man/sample_correlated_gnp.Rd @@ -84,5 +84,5 @@ Random graph models (games) \code{\link{sample_tree}()} } \concept{games} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_correlated_game}{\code{correlated_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_correlated_game}{\code{correlated_game()}}.} diff --git a/man/sample_correlated_gnp_pair.Rd b/man/sample_correlated_gnp_pair.Rd index 8244f3a5bcc..9e397212ef7 100644 --- a/man/sample_correlated_gnp_pair.Rd +++ b/man/sample_correlated_gnp_pair.Rd @@ -78,5 +78,5 @@ Random graph models (games) } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_correlated_pair_game}{\code{correlated_pair_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_correlated_pair_game}{\code{correlated_pair_game()}}.} diff --git a/man/sample_dot_product.Rd b/man/sample_dot_product.Rd index 44e6f018a5a..c9baf59e001 100644 --- a/man/sample_dot_product.Rd +++ b/man/sample_dot_product.Rd @@ -89,5 +89,5 @@ Gabor Csardi \email{csardi.gabor@gmail.com} } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_dot_product_game}{\code{dot_product_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_dot_product_game}{\code{dot_product_game()}}.} diff --git a/man/sample_fitness.Rd b/man/sample_fitness.Rd index 1502423df95..28d1ec28925 100644 --- a/man/sample_fitness.Rd +++ b/man/sample_fitness.Rd @@ -111,5 +111,5 @@ Tamas Nepusz \email{ntamas@gmail.com} } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_static_fitness_game}{\code{static_fitness_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_static_fitness_game}{\code{static_fitness_game()}}.} diff --git a/man/sample_fitness_pl.Rd b/man/sample_fitness_pl.Rd index 166c910685a..003c9ae2411 100644 --- a/man/sample_fitness_pl.Rd +++ b/man/sample_fitness_pl.Rd @@ -120,5 +120,5 @@ Tamas Nepusz \email{ntamas@gmail.com} } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_static_power_law_game}{\code{static_power_law_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_static_power_law_game}{\code{static_power_law_game()}}.} diff --git a/man/sample_forestfire.Rd b/man/sample_forestfire.Rd index 76eff55ac99..9ada534faf1 100644 --- a/man/sample_forestfire.Rd +++ b/man/sample_forestfire.Rd @@ -109,5 +109,5 @@ Gabor Csardi \email{csardi.gabor@gmail.com} } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_forest_fire_game}{\code{forest_fire_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_forest_fire_game}{\code{forest_fire_game()}}.} diff --git a/man/sample_growing.Rd b/man/sample_growing.Rd index 6423905fb78..7ba98da51ad 100644 --- a/man/sample_growing.Rd +++ b/man/sample_growing.Rd @@ -74,5 +74,5 @@ Gabor Csardi \email{csardi.gabor@gmail.com} } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_growing_random_game}{\code{growing_random_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_growing_random_game}{\code{growing_random_game()}}.} diff --git a/man/sample_hierarchical_sbm.Rd b/man/sample_hierarchical_sbm.Rd index 9f7e79f906e..f62dc6e2f59 100644 --- a/man/sample_hierarchical_sbm.Rd +++ b/man/sample_hierarchical_sbm.Rd @@ -91,5 +91,5 @@ Gabor Csardi \email{csardi.gabor@gmail.com} } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_hsbm_game}{\code{hsbm_game()}}, \href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_hsbm_list_game}{\code{hsbm_list_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_hsbm_game}{\code{hsbm_game()}}, \href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_hsbm_list_game}{\code{hsbm_list_game()}}.} diff --git a/man/sample_islands.Rd b/man/sample_islands.Rd index 20c0536f2fe..324d88cb57a 100644 --- a/man/sample_islands.Rd +++ b/man/sample_islands.Rd @@ -68,5 +68,5 @@ Samuel Thiriot } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_simple_interconnected_islands_game}{\code{simple_interconnected_islands_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_simple_interconnected_islands_game}{\code{simple_interconnected_islands_game()}}.} diff --git a/man/sample_k_regular.Rd b/man/sample_k_regular.Rd index 102511c17da..9074a8e79cf 100644 --- a/man/sample_k_regular.Rd +++ b/man/sample_k_regular.Rd @@ -80,5 +80,5 @@ Tamas Nepusz \email{ntamas@gmail.com} } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_k_regular_game}{\code{k_regular_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_k_regular_game}{\code{k_regular_game()}}.} diff --git a/man/sample_sbm.Rd b/man/sample_sbm.Rd index e11e2c4315a..1fe65860ee8 100644 --- a/man/sample_sbm.Rd +++ b/man/sample_sbm.Rd @@ -85,5 +85,5 @@ Gabor Csardi \email{csardi.gabor@gmail.com} } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_sbm_game}{\code{sbm_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_sbm_game}{\code{sbm_game()}}.} diff --git a/man/sample_spanning_tree.Rd b/man/sample_spanning_tree.Rd index 69efb56e52b..1100e6a41af 100644 --- a/man/sample_spanning_tree.Rd +++ b/man/sample_spanning_tree.Rd @@ -4,14 +4,14 @@ \alias{sample_spanning_tree} \title{Samples from the spanning trees of a graph randomly and uniformly} \usage{ -sample_spanning_tree(graph, vid = 0) +sample_spanning_tree(graph, vid = NULL) } \arguments{ \item{graph}{The input graph to sample from. Edge directions are ignored if the graph is directed.} \item{vid}{When the graph is disconnected, this argument specifies how to -handle the situation. When the argument is zero (the default), the sampling +handle the situation. When the argument is \code{NULL} (the default), the sampling will be performed component-wise, and the result will be a spanning forest. When the argument contains a vertex ID, only the component containing the given vertex will be processed, and the result will be a spanning tree of the diff --git a/man/sample_tree.Rd b/man/sample_tree.Rd index f2e025926a5..1857319212f 100644 --- a/man/sample_tree.Rd +++ b/man/sample_tree.Rd @@ -66,5 +66,5 @@ Random graph models (games) } \concept{games} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Generators.html#igraph_tree_game}{\code{tree_game()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Games.html#igraph_tree_game}{\code{tree_game()}}.} diff --git a/man/similarity.Rd b/man/similarity.Rd index 5f124a707bc..ac9820c3f42 100644 --- a/man/similarity.Rd +++ b/man/similarity.Rd @@ -6,16 +6,18 @@ \usage{ similarity( graph, - vids = V(graph), + vids = deprecated(), mode = c("all", "out", "in", "total"), loops = FALSE, - method = c("jaccard", "dice", "invlogweighted") + method = c("jaccard", "dice", "invlogweighted"), + vids_from = V(graph), + vids_to = vids_from ) } \arguments{ \item{graph}{The input graph.} -\item{vids}{The vertex ids for which the similarity is calculated.} +\item{vids}{lifecycle::badge("deprecated")} \item{mode}{The type of neighboring vertices to use for the calculation, possible values: \sQuote{\code{out}}, \sQuote{\verb{in}}, @@ -25,6 +27,12 @@ possible values: \sQuote{\code{out}}, \sQuote{\verb{in}}, sets.} \item{method}{The method to use.} + +\item{vids_from}{The vertex IDs of the first set of vertices of the pairs +for which the calculation will be done.} + +\item{vids_to}{The vertex IDs of the second set of vertices of the pairs +for which the calculation will be done.} } \value{ A \code{length(vids)} by \code{length(vids)} numeric matrix diff --git a/man/simplify.Rd b/man/simplify.Rd index 93a2ced2ceb..5e4fddd8677 100644 --- a/man/simplify.Rd +++ b/man/simplify.Rd @@ -29,6 +29,12 @@ removed.} \code{remove.multiple=TRUE}. In this case many edges might be mapped to a single one in the new graph, and their attributes are combined. Please see \code{\link[=attribute.combination]{attribute.combination()}} for details on this.} + +\item{directed}{Boolean.Whether to consider the directions of edges. +The default, \code{TRUE} means that edge directions will be considered. +\code{FALSE} means that edge directions will be ignored and a directed graph +with at least one mutual edge pair will be considered non-simple. +Ignored for undirected graphs.} } \value{ a new graph object with the edges deleted. @@ -65,6 +71,11 @@ is_simple(g) is_simple(simplify(g, remove.loops = FALSE)) is_simple(simplify(g, remove.multiple = FALSE)) is_simple(simplify(g)) + +# directed argument +g <- graph_from_literal(1 +-+ 2 -+ 3) +is_simple(g) +is_simple(g, directed = FALSE) } \seealso{ \code{\link[=which_loop]{which_loop()}}, \code{\link[=which_multiple]{which_multiple()}} and diff --git a/man/sir.Rd b/man/sir.Rd index 9d765427c62..d413677b05a 100644 --- a/man/sir.Rd +++ b/man/sir.Rd @@ -126,5 +126,5 @@ Gabor Csardi \email{csardi.gabor@gmail.com}. Eric Kolaczyk } \concept{processes} \keyword{graphs} -\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Spatial-Games.html#igraph_sir}{\code{sir()}}.} +\section{Related documentation in the C library}{\href{https://igraph.org/c/html/latest/igraph-Processes.html#igraph_sir}{\code{sir()}}.} diff --git a/patch/0001-fix-include-quotes.patch b/patch/0001-fix-include-quotes.patch deleted file mode 100644 index e178d2a3964..00000000000 --- a/patch/0001-fix-include-quotes.patch +++ /dev/null @@ -1,25 +0,0 @@ -From c6ff0ba179c304572cf0bc285201aebb963f89ae Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Kirill=20M=C3=BCller?= -Date: Wed, 8 Jan 2025 05:21:39 +0100 -Subject: [PATCH] fix include quotes - ---- - src/vendor/cigraph/vendor/plfit/lbfgs.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/vendor/cigraph/vendor/plfit/lbfgs.c b/src/vendor/cigraph/vendor/plfit/lbfgs.c -index 6472a9aa26..c1b7fac28f 100644 ---- a/src/vendor/cigraph/vendor/plfit/lbfgs.c -+++ b/src/vendor/cigraph/vendor/plfit/lbfgs.c -@@ -70,7 +70,7 @@ licence. - #include - #include - --#include -+#include "lbfgs.h" - - #ifdef _MSC_VER - #define inline __inline --- -2.47.1 - diff --git a/patch/0002-upstream-deps.patch b/patch/0002-upstream-deps.patch deleted file mode 100644 index 34436e531fd..00000000000 --- a/patch/0002-upstream-deps.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 77f21dc92bc6717d8668140211c36620388014f0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Kirill=20M=C3=BCller?= -Date: Mon, 28 Jul 2025 21:25:09 +0200 -Subject: [PATCH] upstream-deps - ---- - src/vendor/cigraph/interfaces/functions.yaml | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/vendor/cigraph/interfaces/functions.yaml b/src/vendor/cigraph/interfaces/functions.yaml -index 633fa25425..f447f9afff 100644 ---- a/src/vendor/cigraph/interfaces/functions.yaml -+++ b/src/vendor/cigraph/interfaces/functions.yaml -@@ -1321,9 +1321,11 @@ igraph_count_reachable: - - igraph_bond_percolation: - PARAMS: GRAPH graph, OUT VECTOR_INT giant_size, OUT VECTOR_INT vetex_count, OPTIONAL EDGE_INDICES edge_order -+ DEPS: edge_order ON graph - - igraph_site_percolation: - PARAMS: GRAPH graph, OUT VECTOR_INT giant_size, OUT VECTOR_INT edge_count, OPTIONAL VERTEX_INDICES vertex_order -+ DEPS: vertex_order ON graph - - igraph_edgelist_percolation: - PARAMS: VERTEX_INDEX_PAIRS edges, OUT VECTOR_INT giant_size, OUT VECTOR_INT vertex_count --- -2.49.0 - diff --git a/patch/0003-Temporary-fix.patch b/patch/0003-Temporary-fix.patch deleted file mode 100644 index 106fa39f8a7..00000000000 --- a/patch/0003-Temporary-fix.patch +++ /dev/null @@ -1,25 +0,0 @@ -From ffced517fdd10884cf5c99cabc9b2f5587926f23 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Kirill=20M=C3=BCller?= -Date: Thu, 7 Aug 2025 17:10:17 +0200 -Subject: [PATCH] Temporary fix - ---- - src/vendor/cigraph/src/operators/permute.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/vendor/cigraph/src/operators/permute.c b/src/vendor/cigraph/src/operators/permute.c -index 60cbb08b12..f84ba6bc66 100644 ---- a/src/vendor/cigraph/src/operators/permute.c -+++ b/src/vendor/cigraph/src/operators/permute.c -@@ -24,7 +24,7 @@ - - #include "igraph_constructors.h" - #include "igraph_interface.h" --#include "igraph_isomorphism.h" -+#include "igraph_topology.h" - - #include "graph/attributes.h" - --- -2.49.0 - diff --git a/patch/0004-Tweak-function-definitions.patch b/patch/0004-Tweak-function-definitions.patch new file mode 100644 index 00000000000..1867fe30e0a --- /dev/null +++ b/patch/0004-Tweak-function-definitions.patch @@ -0,0 +1,154 @@ +From c8c9b9194093aa700f38a3e55cb76412eb54b851 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Kirill=20M=C3=BCller?= +Date: Sun, 17 Aug 2025 15:31:16 +0200 +Subject: [PATCH] Tweak function definitions + +--- + src/vendor/cigraph/interfaces/functions.yaml | 28 +++++++++++--------- + src/vendor/cigraph/interfaces/types.yaml | 7 ++++- + 2 files changed, 22 insertions(+), 13 deletions(-) + +diff --git a/src/vendor/cigraph/interfaces/functions.yaml b/src/vendor/cigraph/interfaces/functions.yaml +index c8b9ca948e..cee8b524c3 100644 +--- a/src/vendor/cigraph/interfaces/functions.yaml ++++ b/src/vendor/cigraph/interfaces/functions.yaml +@@ -230,8 +230,9 @@ igraph_adjlist: + + igraph_full_bipartite: + PARAMS: |- +- OUT GRAPH graph, OPTIONAL OUT BIPARTITE_TYPES types, INTEGER n1, ++ OUT GRAPH graph, OPTIONAL OUT ALL_BIPARTITE_TYPES types, INTEGER n1, + INTEGER n2, BOOLEAN directed=False, NEIMODE mode=ALL ++ DEPS: types ON graph + + igraph_full_multipartite: + PARAMS: |- +@@ -523,14 +524,14 @@ igraph_get_shortest_paths: + VERTEX from, VERTEX_SELECTOR to=ALL, NEIMODE mode=OUT, + OPTIONAL OUT VECTOR_INT parents, + OPTIONAL OUT VECTOR_INT inbound_edges +- DEPS: weights ON graph, edges ON graph, from ON graph, to ON graph ++ DEPS: weights ON graph, vertices ON graph, edges ON graph, from ON graph, to ON graph + + igraph_get_all_shortest_paths: + PARAMS: |- + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OPTIONAL OUT VERTEX_INDICES_LIST vertices, OPTIONAL OUT EDGE_INDICES_LIST edges, + OPTIONAL OUT VECTOR_INT nrgeo, VERTEX from, VERTEX_SELECTOR to, NEIMODE mode=OUT +- DEPS: weights ON graph, edges ON graph, from ON graph, to ON graph ++ DEPS: weights ON graph, vertices ON graph, edges ON graph, from ON graph, to ON graph + + igraph_distances_dijkstra: + PARAMS: |- +@@ -694,7 +695,7 @@ igraph_edge_betweenness_subset: + BOOLEAN directed=True, VERTEX_SELECTOR sources=ALL, VERTEX_SELECTOR targets=ALL, + OPTIONAL EDGE_WEIGHTS weights + DEPS: |- +- eids ON graph, weights ON graph, res ON graph, sources ON graph, targets ON graph ++ res ON graph eids, eids ON graph, sources ON graph, targets ON graph, weights ON graph + + igraph_harmonic_centrality: + PARAMS: |- +@@ -905,6 +906,7 @@ igraph_hub_and_authority_scores: + GRAPH graph, OUT ALL_VERTEX_QTY hub_vector, OUT ALL_VERTEX_QTY authority_vector, + OUT REAL value, OPTIONAL EDGE_WEIGHTS weights, + INOUT ARPACK_OPTIONS options=ARPACK_DEFAULTS ++ DEPS: weights ON graph, hub_vector ON graph, authority_vector ON graph + + igraph_unfold_tree: + PARAMS: |- +@@ -1187,6 +1189,7 @@ igraph_create_bipartite: + PARAMS: |- + OUT GRAPH graph, IN BIPARTITE_TYPES types, + VECTOR_INT edges, BOOLEAN directed=False ++ DEPS: types ON graph, edges ON graph + + igraph_biadjacency: + PARAMS: |- +@@ -1197,7 +1200,7 @@ igraph_biadjacency: + igraph_weighted_biadjacency: + PARAMS: |- + OUT GRAPH graph, +- OUT BIPARTITE_TYPES types, OUT EDGE_WEIGHTS weights, ++ OUT ALL_BIPARTITE_TYPES types, OUT EDGE_WEIGHTS weights, + MATRIX biadjmatrix, + BOOLEAN directed=False, NEIMODE mode=ALL + DEPS: |- +@@ -1221,17 +1224,17 @@ igraph_bipartite_game_gnp: + + igraph_bipartite_game_gnm: + PARAMS: |- +- OUT GRAPH graph, OPTIONAL OUT BIPARTITE_TYPES types, ++ OUT GRAPH graph, OPTIONAL OUT ALL_BIPARTITE_TYPES types, + INTEGER n1, INTEGER n2, INTEGER m, BOOLEAN directed=False, + NEIMODE mode=ALL, BOOLEAN multiple=False ++ DEPS: types ON graph + + igraph_bipartite_iea_game: + PARAMS: |- +- OUT GRAPH graph, OPTIONAL OUT BIPARTITE_TYPES types, ++ OUT GRAPH graph, OPTIONAL OUT ALL_BIPARTITE_TYPES types, + INTEGER n1, INTEGER n2, INTEGER m, + BOOLEAN directed=False, NEIMODE mode=ALL +- DEPS: |- +- types ON graph ++ DEPS: types ON graph + + ####################################### + # Spectral properties +@@ -2472,7 +2475,7 @@ igraph_maximum_bipartite_matching: + OPTIONAL OUT REAL matching_weight, + OUT INDEX_VECTOR matching, + OPTIONAL EDGE_WEIGHTS weights, REAL eps=.Machine$double.eps +- DEPS: types ON graph, weights ON graph ++ DEPS: types ON graph matching, weights ON graph + + ####################################### + # Embedding +@@ -2609,7 +2612,7 @@ igraph_eulerian_cycle: + + igraph_fundamental_cycles: + PARAMS: |- +- GRAPH graph, OUT EDGE_INDICES_LIST basis, OPTIONAL VERTEX start, ++ GRAPH graph, OUT EDGE_INDICES_LIST basis, OPTIONAL VERTEX start=-1, + INTEGER bfs_cutoff=-1, OPTIONAL EDGE_WEIGHTS weights + DEPS: weights ON graph, basis ON graph, start ON graph + +@@ -2649,7 +2652,7 @@ igraph_minimum_spanning_tree: + DEPS: res ON graph, weights ON graph + + igraph_random_spanning_tree: +- PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL VERTEX vid ++ PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL VERTEX vid=-1 + DEPS: res ON graph, vid ON graph + + igraph_tree_game: +@@ -2720,6 +2723,7 @@ igraph_vertex_path_from_edge_path: + PARAMS: |- + GRAPH graph, OPTIONAL VERTEX start, EDGE_INDICES edge_path, + OUT VERTEX_INDICES vertex_path, NEIMODE mode=OUT ++ DEPS: start ON graph, edge_path ON graph, vertex_path ON graph + + ####################################### + # Meta info +diff --git a/src/vendor/cigraph/interfaces/types.yaml b/src/vendor/cigraph/interfaces/types.yaml +index 3382fd4d14..3d4819fe2d 100644 +--- a/src/vendor/cigraph/interfaces/types.yaml ++++ b/src/vendor/cigraph/interfaces/types.yaml +@@ -169,7 +169,12 @@ VERTEX_SELECTOR: + + BIPARTITE_TYPES: + # A vector containing Booleans that define the two partitions of a +- # bipartite graph ++ # bipartite graph, for a set of vertices ++ CTYPE: igraph_vector_bool_t ++ FLAGS: BY_REF ++ ++ALL_BIPARTITE_TYPES: ++ # Same as BIPARTITE_TYPES, for all vertices of a graph + CTYPE: igraph_vector_bool_t + FLAGS: BY_REF + +-- +2.49.0 + diff --git a/patch/0004-chore-Fix-remaining-Stimulus-types.patch b/patch/0004-chore-Fix-remaining-Stimulus-types.patch deleted file mode 100644 index 2295e6b671b..00000000000 --- a/patch/0004-chore-Fix-remaining-Stimulus-types.patch +++ /dev/null @@ -1,63 +0,0 @@ -From e1b3a867c2b8a7cb4499a5ff2a581127293a04e9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Kirill=20M=C3=BCller?= -Date: Sun, 17 Aug 2025 10:38:47 +0200 -Subject: [PATCH] chore: Fix remaining Stimulus types - ---- - src/vendor/cigraph/interfaces/functions.yaml | 7 ++++--- - src/vendor/cigraph/interfaces/types.yaml | 7 ++++++- - 2 files changed, 10 insertions(+), 4 deletions(-) - -diff --git a/src/vendor/cigraph/interfaces/functions.yaml b/src/vendor/cigraph/interfaces/functions.yaml -index f447f9afff..d621d01fef 100644 ---- a/src/vendor/cigraph/interfaces/functions.yaml -+++ b/src/vendor/cigraph/interfaces/functions.yaml -@@ -203,8 +203,9 @@ igraph_adjlist: - - igraph_full_bipartite: - PARAMS: |- -- OUT GRAPH graph, OPTIONAL OUT BIPARTITE_TYPES types, INTEGER n1, -+ OUT GRAPH graph, OPTIONAL OUT ALL_BIPARTITE_TYPES types, INTEGER n1, - INTEGER n2, BOOLEAN directed=False, NEIMODE mode=ALL -+ DEPS: types ON graph - - igraph_full_multipartite: - PARAMS: |- -@@ -521,14 +522,14 @@ igraph_get_shortest_paths: - VERTEX from, VERTEX_SELECTOR to=ALL, NEIMODE mode=OUT, - OPTIONAL OUT VECTOR_INT parents, - OPTIONAL OUT VECTOR_INT inbound_edges -- DEPS: edges ON graph, from ON graph, to ON graph -+ DEPS: vertices ON graph, edges ON graph, from ON graph, to ON graph - - igraph_get_all_shortest_paths: - PARAMS: |- - GRAPH graph, OPTIONAL OUT VERTEXSET_LIST vertices, - OPTIONAL OUT EDGESET_LIST edges, OPTIONAL OUT VECTOR_INT nrgeo, - VERTEX from, VERTEX_SELECTOR to, NEIMODE mode=OUT -- DEPS: edges ON graph, from ON graph, to ON graph -+ DEPS: vertices ON graph, edges ON graph, from ON graph, to ON graph - - igraph_distances_dijkstra: - PARAMS: |- -diff --git a/src/vendor/cigraph/interfaces/types.yaml b/src/vendor/cigraph/interfaces/types.yaml -index bdb9dd08a8..0a95c14ff1 100644 ---- a/src/vendor/cigraph/interfaces/types.yaml -+++ b/src/vendor/cigraph/interfaces/types.yaml -@@ -173,7 +173,12 @@ VERTEX_SELECTOR: - - BIPARTITE_TYPES: - # A vector containing Booleans that define the two partitions of a -- # bipartite graph -+ # bipartite graph, for a set of vertices -+ CTYPE: igraph_vector_bool_t -+ FLAGS: BY_REF -+ -+ALL_BIPARTITE_TYPES: -+ # Same as BIPARTITE_TYPES, for all vertices of a graph - CTYPE: igraph_vector_bool_t - FLAGS: BY_REF - --- -2.49.0 - diff --git a/patch/0005-Accept-out-parameter.patch b/patch/0005-Accept-out-parameter.patch deleted file mode 100644 index bbcc5027899..00000000000 --- a/patch/0005-Accept-out-parameter.patch +++ /dev/null @@ -1,29 +0,0 @@ -From dea8c80ae39c7dff6bd3e5060ef6d6088352f200 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Kirill=20M=C3=BCller?= -Date: Sun, 17 Aug 2025 14:50:44 +0200 -Subject: [PATCH] Accept out parameter - ---- - tools/stimulus/types-RC.yaml | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/tools/stimulus/types-RC.yaml b/tools/stimulus/types-RC.yaml -index e0091a0a78..7255680cf4 100644 ---- a/tools/stimulus/types-RC.yaml -+++ b/tools/stimulus/types-RC.yaml -@@ -427,6 +427,12 @@ ALL_VERTEX_QTY: - igraph_vector_destroy(&%C%); - IGRAPH_FINALLY_CLEAN(1); - -+NEIMODE: -+ CALL: -+ IN: '%C%' -+ INOUT: '&%C%' -+ OUT: 'NULL' -+ - VERTEX_SELECTOR: - CALL: - IN: '%C%' --- -2.49.0 - diff --git a/patch/0007-deps.patch b/patch/0007-deps.patch new file mode 100644 index 00000000000..e94f643a207 --- /dev/null +++ b/patch/0007-deps.patch @@ -0,0 +1,24 @@ +From eb04b1de45d13baf0d7b78d09fe568a69745ecc3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Kirill=20M=C3=BCller?= +Date: Sun, 19 Oct 2025 16:22:43 +0200 +Subject: [PATCH] deps + +--- + src/vendor/cigraph/interfaces/functions.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/vendor/cigraph/interfaces/functions.yaml b/src/vendor/cigraph/interfaces/functions.yaml +index 5ee970b5d8..560bf6157d 100644 +--- a/src/vendor/cigraph/interfaces/functions.yaml ++++ b/src/vendor/cigraph/interfaces/functions.yaml +@@ -63,6 +63,7 @@ igraph_neighbors: + PARAMS: |- + GRAPH graph, OUT VERTEX_INDICES neis, VERTEX vid, NEIMODE mode=ALL, + LOOPS loops=TWICE, BOOLEAN multiple=True ++ DEPS: neis ON graph, vid ON graph + FLAGS: no_rng + + igraph_is_directed: +-- +2.50.1 + diff --git a/patch/0008-Tweak-function-definitions.patch b/patch/0008-Tweak-function-definitions.patch new file mode 100644 index 00000000000..389a658b908 --- /dev/null +++ b/patch/0008-Tweak-function-definitions.patch @@ -0,0 +1,34 @@ +From 7545c34b50bf4e0d6b0c45a1f9af92e709a11034 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Kirill=20M=C3=BCller?= +Date: Sun, 26 Oct 2025 01:35:37 +0200 +Subject: [PATCH] Tweak function definitions + +--- + src/vendor/cigraph/interfaces/functions.yaml | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/vendor/cigraph/interfaces/functions.yaml b/src/vendor/cigraph/interfaces/functions.yaml +index 17d0ba25fe..a1ba2d947a 100644 +--- a/src/vendor/cigraph/interfaces/functions.yaml ++++ b/src/vendor/cigraph/interfaces/functions.yaml +@@ -2669,7 +2669,7 @@ igraph_fundamental_cycles: + PARAMS: |- + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OUT EDGE_INDICES_LIST basis, +- OPTIONAL VERTEX start, ++ OPTIONAL VERTEX start=-1, + REAL bfs_cutoff=UNLIMITED + DEPS: weights ON graph, basis ON graph, start ON graph + +@@ -2710,7 +2710,7 @@ igraph_minimum_spanning_tree: + DEPS: res ON graph, weights ON graph + + igraph_random_spanning_tree: +- PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL VERTEX vid ++ PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL VERTEX vid=-1 + DEPS: res ON graph, vid ON graph + + igraph_tree_game: +-- +2.50.1 + diff --git a/src/Makevars.in b/src/Makevars.in index 35405db624b..8d340b8c3b0 100644 --- a/src/Makevars.in +++ b/src/Makevars.in @@ -22,10 +22,11 @@ PKG_CFLAGS=$(C_VISIBILITY) PKG_CXXFLAGS=$(CXX_VISIBILITY) PKG_FFLAGS=$(F_VISIBILITY) -PKG_CPPFLAGS=-DUSING_R -I. -Ivendor -Ivendor/cigraph/src -Ivendor/cigraph/include -Ivendor/cigraph/vendor -Ivendor/io/parsers @cflags@ \ - -DNDEBUG -DIGRAPH_THREAD_LOCAL= \ +PKG_CPPFLAGS=-DUSING_R -I. -Ivendor -Ivendor/cigraph/src -Ivendor/cigraph/include -Ivendor/cigraph/vendor -Ivendor/io/parsers -Ivendor/cigraph/vendor/infomap/src @cflags@ \ + -DNDEBUG -DNTIMER -DNPRINT -DIGRAPH_THREAD_LOCAL= \ -DPRPACK_IGRAPH_SUPPORT \ -DHAVE_GFORTRAN=1 \ + -DHAVE_INFOMAP=1 \ -D_GNU_SOURCE=1 PKG_LIBS = @libs@ $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) diff --git a/src/Makevars.ucrt b/src/Makevars.ucrt index b91c03877db..86e8050f8bc 100644 --- a/src/Makevars.ucrt +++ b/src/Makevars.ucrt @@ -27,10 +27,11 @@ else PKG_LIBS = $(shell pkg-config --libs libxml-2.0 glpk) endif -PKG_CPPFLAGS += -DUSING_R -I. -Ivendor -Ivendor/cigraph/src -Ivendor/cigraph/include -Ivendor/cigraph/vendor -Ivendor/io/parsers -Ivendor/mini-gmp \ - -DNDEBUG -DIGRAPH_THREAD_LOCAL= \ +PKG_CPPFLAGS += -DUSING_R -I. -Ivendor -Ivendor/cigraph/src -Ivendor/cigraph/include -Ivendor/cigraph/vendor -Ivendor/io/parsers -Ivendor/mini-gmp -Ivendor/cigraph/vendor/infomap/src \ + -DNDEBUG -DNTIMER -DNPRINT -DIGRAPH_THREAD_LOCAL= \ -DPRPACK_IGRAPH_SUPPORT \ -DHAVE_GFORTRAN=1 \ + -DHAVE_INFOMAP=1 \ -D_GNU_SOURCE=1 \ -DHAVE_LIBXML diff --git a/src/Makevars.win b/src/Makevars.win index f0ed80c2fdf..4959aedc057 100644 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -19,10 +19,11 @@ LIB_XML ?= $(MINGW_PREFIX) GLPK_HOME ?= $(MINGW_PREFIX) LIB_GMP ?= $(MINGW_PREFIX) -PKG_CPPFLAGS=-DUSING_R -I. -Ivendor -Ivendor/cigraph/src -Ivendor/cigraph/include -Ivendor/cigraph/vendor -Ivendor/io/parsers -Ivendor/mini-gmp \ - -DNDEBUG -DIGRAPH_THREAD_LOCAL= \ +PKG_CPPFLAGS=-DUSING_R -I. -Ivendor -Ivendor/cigraph/src -Ivendor/cigraph/include -Ivendor/cigraph/vendor -Ivendor/io/parsers -Ivendor/mini-gmp -Ivendor/cigraph/vendor/infomap/src \ + -DNDEBUG -DNTIMER -DNPRINT -DIGRAPH_THREAD_LOCAL= \ -DPRPACK_IGRAPH_SUPPORT \ -DHAVE_GFORTRAN=1 \ + -DHAVE_INFOMAP=1 \ -D_GNU_SOURCE=1 \ -DHAVE_LIBXML diff --git a/src/cpp11.cpp b/src/cpp11.cpp index b8774dc926b..59c9d8b7d3b 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -34,32 +34,36 @@ extern SEXP R_igraph_all_st_cuts(SEXP, SEXP, SEXP); extern SEXP R_igraph_all_st_mincuts(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_are_adjacent(SEXP, SEXP, SEXP); extern SEXP R_igraph_articulation_points(SEXP); -extern SEXP R_igraph_assortativity(SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_assortativity(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_assortativity_degree(SEXP, SEXP); -extern SEXP R_igraph_assortativity_nominal(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_assortativity_nominal(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_asymmetric_preference_game(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_atlas(SEXP); -extern SEXP R_igraph_automorphism_group(SEXP, SEXP, SEXP); +extern SEXP R_igraph_automorphism_group(SEXP, SEXP); +extern SEXP R_igraph_automorphism_group_bliss(SEXP, SEXP, SEXP); extern SEXP R_igraph_average_local_efficiency(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_average_path_length_dijkstra(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_average_path_length(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_avg_nearest_neighbor_degree(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_barabasi_aging_game(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_barabasi_game(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_betweenness_cutoff(SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_betweenness_subset(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_beta_weighted_gabriel_graph(SEXP, SEXP); +extern SEXP R_igraph_betweenness_cutoff(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_betweenness_subset(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_bfs(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_bfs_simple(SEXP, SEXP, SEXP); extern SEXP R_igraph_biadjacency(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_bibcoupling(SEXP, SEXP); extern SEXP R_igraph_biconnected_components(SEXP); -extern SEXP R_igraph_bipartite_game_gnm(SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_bipartite_game_gnp(SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_bipartite_game_gnm(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_bipartite_game_gnp(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_bipartite_iea_game(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_bipartite_projection(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_bipartite_projection_size(SEXP, SEXP); extern SEXP R_igraph_bond_percolation(SEXP, SEXP); extern SEXP R_igraph_bridges(SEXP); extern SEXP R_igraph_callaway_traits_game(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_canonical_permutation(SEXP, SEXP, SEXP); +extern SEXP R_igraph_canonical_permutation(SEXP, SEXP); +extern SEXP R_igraph_canonical_permutation_bliss(SEXP, SEXP, SEXP); extern SEXP R_igraph_centralization(SEXP, SEXP, SEXP); extern SEXP R_igraph_centralization_betweenness(SEXP, SEXP, SEXP); extern SEXP R_igraph_centralization_betweenness_tmax(SEXP, SEXP, SEXP); @@ -67,15 +71,16 @@ extern SEXP R_igraph_centralization_closeness(SEXP, SEXP, SEXP); extern SEXP R_igraph_centralization_closeness_tmax(SEXP, SEXP, SEXP); extern SEXP R_igraph_centralization_degree(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_centralization_degree_tmax(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_centralization_eigenvector_centrality(SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_centralization_eigenvector_centrality_tmax(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_centralization_eigenvector_centrality(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_centralization_eigenvector_centrality_tmax(SEXP, SEXP, SEXP); extern SEXP R_igraph_chung_lu_game(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_circle_beta_skeleton(SEXP, SEXP); extern SEXP R_igraph_circulant(SEXP, SEXP, SEXP); extern SEXP R_igraph_cited_type_game(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_citing_cited_type_game(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_clique_number(SEXP); extern SEXP R_igraph_clique_size_hist(SEXP, SEXP, SEXP); -extern SEXP R_igraph_cliques(SEXP, SEXP, SEXP); +extern SEXP R_igraph_cliques(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_closeness(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_closeness_cutoff(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_cocitation(SEXP, SEXP); @@ -84,12 +89,13 @@ extern SEXP R_igraph_cohesive_blocks(SEXP); extern SEXP R_igraph_community_edge_betweenness(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_community_fastgreedy(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_community_fluid_communities(SEXP, SEXP); -extern SEXP R_igraph_community_infomap(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_community_label_propagation(SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_community_infomap(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_community_label_propagation(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_community_leading_eigenvector(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_community_leiden(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_community_leiden(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_community_leiden_simple(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_community_multilevel(SEXP, SEXP, SEXP); -extern SEXP R_igraph_community_optimal_modularity(SEXP, SEXP); +extern SEXP R_igraph_community_optimal_modularity(SEXP, SEXP, SEXP); extern SEXP R_igraph_compare_communities(SEXP, SEXP, SEXP); extern SEXP R_igraph_complementer(SEXP, SEXP); extern SEXP R_igraph_compose(SEXP, SEXP); @@ -103,7 +109,8 @@ extern SEXP R_igraph_coreness(SEXP, SEXP); extern SEXP R_igraph_correlated_game(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_correlated_pair_game(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_count_adjacent_triangles(SEXP, SEXP); -extern SEXP R_igraph_count_automorphisms(SEXP, SEXP, SEXP); +extern SEXP R_igraph_count_automorphisms(SEXP, SEXP); +extern SEXP R_igraph_count_automorphisms_bliss(SEXP, SEXP, SEXP); extern SEXP R_igraph_count_isomorphisms_vf2(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_count_loops(SEXP); extern SEXP R_igraph_count_multiple(SEXP, SEXP); @@ -118,11 +125,11 @@ extern SEXP R_igraph_decompose(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_degree(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_degree_correlation_vector(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_degree_sequence_game(SEXP, SEXP, SEXP); +extern SEXP R_igraph_delaunay_graph(SEXP); extern SEXP R_igraph_delete_edges(SEXP, SEXP); extern SEXP R_igraph_delete_vertices(SEXP, SEXP); -extern SEXP R_igraph_delete_vertices_idx(SEXP, SEXP); -extern SEXP R_igraph_density(SEXP, SEXP); -extern SEXP R_igraph_deterministic_optimal_imitation(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_delete_vertices_map(SEXP, SEXP); +extern SEXP R_igraph_density(SEXP, SEXP, SEXP); extern SEXP R_igraph_dfs(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_diameter(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_difference(SEXP, SEXP); @@ -133,20 +140,20 @@ extern SEXP R_igraph_dominator_tree(SEXP, SEXP, SEXP); extern SEXP R_igraph_dot_product_game(SEXP, SEXP); extern SEXP R_igraph_dyad_census(SEXP); extern SEXP R_igraph_ecc(SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_eccentricity_dijkstra(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_eccentricity(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_ecount(SEXP); -extern SEXP R_igraph_edge_betweenness(SEXP, SEXP, SEXP); -extern SEXP R_igraph_edge_betweenness_cutoff(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_edge_betweenness_subset(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_edge_betweenness(SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_edge_betweenness_cutoff(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_edge_betweenness_subset(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_edge_connectivity(SEXP, SEXP); extern SEXP R_igraph_edge_disjoint_paths(SEXP, SEXP, SEXP); extern SEXP R_igraph_edgelist_percolation(SEXP); -extern SEXP R_igraph_edges(SEXP, SEXP); +extern SEXP R_igraph_edges(SEXP, SEXP, SEXP); extern SEXP R_igraph_eigen_adjacency(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_eigenvector_centrality(SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_eigenvector_centrality(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_empty(SEXP, SEXP); -extern SEXP R_igraph_erdos_renyi_game_gnm(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_erdos_renyi_game_gnp(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_erdos_renyi_game_gnm(SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_erdos_renyi_game_gnp(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_es_adj(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_es_pairs(SEXP, SEXP, SEXP); extern SEXP R_igraph_es_path(SEXP, SEXP, SEXP); @@ -169,14 +176,15 @@ extern SEXP R_igraph_full_bipartite(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_full_citation(SEXP, SEXP); extern SEXP R_igraph_full_multipartite(SEXP, SEXP, SEXP); extern SEXP R_igraph_fundamental_cycles(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_gabriel_graph(SEXP); extern SEXP R_igraph_generalized_petersen(SEXP, SEXP); extern SEXP R_igraph_get_adjacency(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_get_adjacency_sparse(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_get_all_eids_between(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_get_all_shortest_paths(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_get_all_shortest_paths(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_get_all_shortest_paths_dijkstra(SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_get_all_simple_paths(SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_get_biadjacency(SEXP, SEXP); +extern SEXP R_igraph_get_all_simple_paths(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_get_biadjacency(SEXP, SEXP, SEXP); extern SEXP R_igraph_get_diameter(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_get_edgelist(SEXP, SEXP); extern SEXP R_igraph_get_eids(SEXP, SEXP, SEXP, SEXP); @@ -185,7 +193,7 @@ extern SEXP R_igraph_get_isomorphisms_vf2_callback(SEXP, SEXP, SEXP, SEXP, SEXP, extern SEXP R_igraph_get_k_shortest_paths(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_get_laplacian(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_get_laplacian_sparse(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_get_shortest_path(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_get_shortest_path(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_get_shortest_path_bellman_ford(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_get_shortest_path_dijkstra(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_get_shortest_paths(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); @@ -197,7 +205,7 @@ extern SEXP R_igraph_get_widest_paths(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_girth(SEXP); extern SEXP R_igraph_global_efficiency(SEXP, SEXP, SEXP); extern SEXP R_igraph_gomory_hu_tree(SEXP, SEXP); -extern SEXP R_igraph_graph_center_dijkstra(SEXP, SEXP, SEXP); +extern SEXP R_igraph_graph_center(SEXP, SEXP, SEXP); extern SEXP R_igraph_graph_count(SEXP, SEXP); extern SEXP R_igraph_graph_power(SEXP, SEXP, SEXP); extern SEXP R_igraph_graphlets(SEXP, SEXP, SEXP); @@ -220,9 +228,10 @@ extern SEXP R_igraph_hrg_sample_many(SEXP, SEXP); extern SEXP R_igraph_hrg_size(SEXP); extern SEXP R_igraph_hsbm_game(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_hsbm_list_game(SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_hub_and_authority_scores(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_hub_and_authority_scores(SEXP, SEXP, SEXP); extern SEXP R_igraph_hypercube(SEXP, SEXP); -extern SEXP R_igraph_incident(SEXP, SEXP, SEXP); +extern SEXP R_igraph_iea_game(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_incident(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_independence_number(SEXP); extern SEXP R_igraph_independent_vertex_sets(SEXP, SEXP, SEXP); extern SEXP R_igraph_induced_subgraph(SEXP, SEXP, SEXP); @@ -252,7 +261,7 @@ extern SEXP R_igraph_is_multiple(SEXP, SEXP); extern SEXP R_igraph_is_mutual(SEXP, SEXP, SEXP); extern SEXP R_igraph_is_perfect(SEXP); extern SEXP R_igraph_is_separator(SEXP, SEXP); -extern SEXP R_igraph_is_simple(SEXP); +extern SEXP R_igraph_is_simple(SEXP, SEXP); extern SEXP R_igraph_is_tree(SEXP, SEXP); extern SEXP R_igraph_is_vertex_coloring(SEXP, SEXP); extern SEXP R_igraph_isoclass(SEXP); @@ -299,7 +308,7 @@ extern SEXP R_igraph_layout_sugiyama(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_layout_umap(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_layout_umap_3d(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_layout_umap_compute_weights(SEXP, SEXP, SEXP); -extern SEXP R_igraph_lcf_vector(SEXP, SEXP, SEXP); +extern SEXP R_igraph_lcf(SEXP, SEXP, SEXP); extern SEXP R_igraph_linegraph(SEXP); extern SEXP R_igraph_list_triangles(SEXP); extern SEXP R_igraph_local_efficiency(SEXP, SEXP, SEXP, SEXP, SEXP); @@ -311,13 +320,14 @@ extern SEXP R_igraph_local_scan_k_ecount(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_local_scan_k_ecount_them(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_local_scan_neighborhood_ecount(SEXP, SEXP, SEXP); extern SEXP R_igraph_local_scan_subset_ecount(SEXP, SEXP, SEXP); +extern SEXP R_igraph_lune_beta_skeleton(SEXP, SEXP); extern SEXP R_igraph_maxdegree(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_maxflow(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_maximal_cliques(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_maximal_cliques_count(SEXP, SEXP, SEXP); extern SEXP R_igraph_maximal_cliques_file(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_maximal_cliques_hist(SEXP, SEXP, SEXP); -extern SEXP R_igraph_maximal_independent_vertex_sets(SEXP); +extern SEXP R_igraph_maximal_independent_vertex_sets(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_maximum_bipartite_matching(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_maximum_cardinality_search(SEXP); extern SEXP R_igraph_mean_degree(SEXP, SEXP); @@ -325,21 +335,20 @@ extern SEXP R_igraph_mincut(SEXP, SEXP); extern SEXP R_igraph_mincut_value(SEXP, SEXP); extern SEXP R_igraph_minimum_cycle_basis(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_minimum_size_separators(SEXP); -extern SEXP R_igraph_minimum_spanning_tree_prim(SEXP, SEXP); -extern SEXP R_igraph_minimum_spanning_tree_unweighted(SEXP); +extern SEXP R_igraph_minimum_spanning_tree(SEXP, SEXP, SEXP); extern SEXP R_igraph_modularity(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_modularity_matrix(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_moran_process(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_motifs_randesu(SEXP, SEXP, SEXP); extern SEXP R_igraph_motifs_randesu_estimate(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_motifs_randesu_no(SEXP, SEXP, SEXP); extern SEXP R_igraph_mybracket3_set(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_mycielski_graph(SEXP); extern SEXP R_igraph_mycielskian(SEXP, SEXP); +extern SEXP R_igraph_nearest_neighbor_graph(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_neighborhood(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_neighborhood_graphs(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_neighborhood_size(SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_neighbors(SEXP, SEXP, SEXP); +extern SEXP R_igraph_neighbors(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_path_graph(SEXP, SEXP, SEXP); extern SEXP R_igraph_path_length_hist(SEXP, SEXP); extern SEXP R_igraph_permute_vertices(SEXP, SEXP); @@ -349,9 +358,8 @@ extern SEXP R_igraph_power_law_fit(SEXP, SEXP, SEXP); extern SEXP R_igraph_power_law_fit_new(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_preference_game(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_product(SEXP, SEXP, SEXP); -extern SEXP R_igraph_pseudo_diameter(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_pseudo_diameter_dijkstra(SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_radius_dijkstra(SEXP, SEXP, SEXP); +extern SEXP R_igraph_pseudo_diameter(SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_radius(SEXP, SEXP, SEXP); extern SEXP R_igraph_random_sample(SEXP, SEXP, SEXP); extern SEXP R_igraph_random_spanning_tree(SEXP, SEXP); extern SEXP R_igraph_random_walk(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); @@ -368,31 +376,31 @@ extern SEXP R_igraph_realize_degree_sequence(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_recent_degree_aging_game(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_reciprocity(SEXP, SEXP, SEXP); extern SEXP R_igraph_regular_tree(SEXP, SEXP, SEXP); +extern SEXP R_igraph_relative_neighborhood_graph(SEXP); extern SEXP R_igraph_residual_graph(SEXP, SEXP, SEXP); extern SEXP R_igraph_reverse_edges(SEXP, SEXP); extern SEXP R_igraph_reverse_residual_graph(SEXP, SEXP, SEXP); extern SEXP R_igraph_rewire(SEXP, SEXP, SEXP); extern SEXP R_igraph_rewire_directed_edges(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_rewire_edges(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_rewire_edges(SEXP, SEXP, SEXP); extern SEXP R_igraph_rich_club_sequence(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_ring(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_rooted_product(SEXP, SEXP, SEXP); extern SEXP R_igraph_roots_for_tree_layout(SEXP, SEXP, SEXP); -extern SEXP R_igraph_roulette_wheel_imitation(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_running_mean(SEXP, SEXP); extern SEXP R_igraph_sample_dirichlet(SEXP, SEXP); extern SEXP R_igraph_sample_sphere_surface(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_sample_sphere_volume(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_sbm_game(SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_sbm_game(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_shortest_paths(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_similarity_dice(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_similarity_dice(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_similarity_dice_es(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_similarity_dice_pairs(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_similarity_inverse_log_weighted(SEXP, SEXP, SEXP); -extern SEXP R_igraph_similarity_jaccard(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_similarity_jaccard(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_similarity_jaccard_es(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_similarity_jaccard_pairs(SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_simple_cycles(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_simple_cycles(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_simple_interconnected_islands_game(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_simplify(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_simplify_and_colorize(SEXP); @@ -400,6 +408,7 @@ extern SEXP R_igraph_sir(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_site_percolation(SEXP, SEXP); extern SEXP R_igraph_solve_lsap(SEXP, SEXP); extern SEXP R_igraph_spanner(SEXP, SEXP, SEXP); +extern SEXP R_igraph_spatial_edge_lengths(SEXP, SEXP, SEXP); extern SEXP R_igraph_spinglass_community(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_spinglass_my_community(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_split_join_distance(SEXP, SEXP); @@ -409,9 +418,8 @@ extern SEXP R_igraph_st_mincut(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_st_mincut_value(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_st_vertex_connectivity(SEXP, SEXP, SEXP); extern SEXP R_igraph_star(SEXP, SEXP, SEXP); -extern SEXP R_igraph_static_fitness_game(SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_static_power_law_game(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_stochastic_imitation(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_static_fitness_game(SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_static_power_law_game(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_strength(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_subcomponent(SEXP, SEXP, SEXP); extern SEXP R_igraph_subgraph_from_edges(SEXP, SEXP, SEXP); @@ -424,7 +432,6 @@ extern SEXP R_igraph_to_prufer(SEXP); extern SEXP R_igraph_to_undirected(SEXP, SEXP, SEXP); extern SEXP R_igraph_topological_sorting(SEXP, SEXP); extern SEXP R_igraph_transitive_closure(SEXP); -extern SEXP R_igraph_transitive_closure_dag(SEXP); extern SEXP R_igraph_transitivity_avglocal_undirected(SEXP, SEXP); extern SEXP R_igraph_transitivity_barrat(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_transitivity_local_undirected(SEXP, SEXP, SEXP); @@ -442,15 +449,15 @@ extern SEXP R_igraph_version(void); extern SEXP R_igraph_vertex_coloring_greedy(SEXP, SEXP); extern SEXP R_igraph_vertex_connectivity(SEXP, SEXP); extern SEXP R_igraph_vertex_disjoint_paths(SEXP, SEXP, SEXP); -extern SEXP R_igraph_vertex_path_from_edge_path(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_voronoi(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_vs_adj(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_vs_nei(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_walktrap_community(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_watts_strogatz_game(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_weighted_adjacency(SEXP, SEXP, SEXP); +extern SEXP R_igraph_weighted_biadjacency(SEXP, SEXP, SEXP); extern SEXP R_igraph_weighted_clique_number(SEXP, SEXP); -extern SEXP R_igraph_weighted_cliques(SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_weighted_cliques(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_wheel(SEXP, SEXP, SEXP); extern SEXP R_igraph_widest_path_widths_dijkstra(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_widest_path_widths_floyd_warshall(SEXP, SEXP, SEXP, SEXP, SEXP); @@ -494,7 +501,6 @@ extern SEXP Rx_igraph_edges(SEXP, SEXP); extern SEXP Rx_igraph_famous(SEXP); extern SEXP Rx_igraph_get_adjedgelist(SEXP, SEXP, SEXP); extern SEXP Rx_igraph_get_adjlist(SEXP, SEXP, SEXP, SEXP); -extern SEXP Rx_igraph_get_all_simple_paths_pp(SEXP); extern SEXP Rx_igraph_get_attr_mode(SEXP, SEXP); extern SEXP Rx_igraph_get_edge(SEXP, SEXP); extern SEXP Rx_igraph_get_edgelist(SEXP, SEXP); @@ -505,7 +511,6 @@ extern SEXP Rx_igraph_graphlets_candidate_basis(SEXP, SEXP); extern SEXP Rx_igraph_graphlets_project(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP Rx_igraph_i_levc_arp(SEXP, SEXP, SEXP); extern SEXP Rx_igraph_identical_graphs(SEXP, SEXP, SEXP); -extern SEXP Rx_igraph_incident(SEXP, SEXP, SEXP); extern SEXP Rx_igraph_incident_edges(SEXP, SEXP, SEXP); extern SEXP Rx_igraph_independence_number(SEXP); extern SEXP Rx_igraph_intersection(SEXP, SEXP); @@ -516,8 +521,6 @@ extern SEXP Rx_igraph_maximal_cliques_count(SEXP, SEXP, SEXP, SEXP); extern SEXP Rx_igraph_maximal_independent_vertex_sets(SEXP); extern SEXP Rx_igraph_mincut(SEXP, SEXP); extern SEXP Rx_igraph_mincut_value(SEXP, SEXP); -extern SEXP Rx_igraph_minimum_spanning_tree_prim(SEXP, SEXP); -extern SEXP Rx_igraph_minimum_spanning_tree_unweighted(SEXP); extern SEXP Rx_igraph_mybracket2(SEXP, SEXP, SEXP); extern SEXP Rx_igraph_mybracket2_copy(SEXP, SEXP, SEXP); extern SEXP Rx_igraph_mybracket2_names(SEXP, SEXP, SEXP); @@ -560,32 +563,36 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_all_st_mincuts", (DL_FUNC) &R_igraph_all_st_mincuts, 4}, {"R_igraph_are_adjacent", (DL_FUNC) &R_igraph_are_adjacent, 3}, {"R_igraph_articulation_points", (DL_FUNC) &R_igraph_articulation_points, 1}, - {"R_igraph_assortativity", (DL_FUNC) &R_igraph_assortativity, 5}, + {"R_igraph_assortativity", (DL_FUNC) &R_igraph_assortativity, 6}, {"R_igraph_assortativity_degree", (DL_FUNC) &R_igraph_assortativity_degree, 2}, - {"R_igraph_assortativity_nominal", (DL_FUNC) &R_igraph_assortativity_nominal, 4}, + {"R_igraph_assortativity_nominal", (DL_FUNC) &R_igraph_assortativity_nominal, 5}, {"R_igraph_asymmetric_preference_game", (DL_FUNC) &R_igraph_asymmetric_preference_game, 6}, {"R_igraph_atlas", (DL_FUNC) &R_igraph_atlas, 1}, - {"R_igraph_automorphism_group", (DL_FUNC) &R_igraph_automorphism_group, 3}, + {"R_igraph_automorphism_group", (DL_FUNC) &R_igraph_automorphism_group, 2}, + {"R_igraph_automorphism_group_bliss", (DL_FUNC) &R_igraph_automorphism_group_bliss, 3}, {"R_igraph_average_local_efficiency", (DL_FUNC) &R_igraph_average_local_efficiency, 4}, - {"R_igraph_average_path_length_dijkstra", (DL_FUNC) &R_igraph_average_path_length_dijkstra, 4}, + {"R_igraph_average_path_length", (DL_FUNC) &R_igraph_average_path_length, 4}, {"R_igraph_avg_nearest_neighbor_degree", (DL_FUNC) &R_igraph_avg_nearest_neighbor_degree, 5}, {"R_igraph_barabasi_aging_game", (DL_FUNC) &R_igraph_barabasi_aging_game, 12}, {"R_igraph_barabasi_game", (DL_FUNC) &R_igraph_barabasi_game, 9}, - {"R_igraph_betweenness_cutoff", (DL_FUNC) &R_igraph_betweenness_cutoff, 5}, - {"R_igraph_betweenness_subset", (DL_FUNC) &R_igraph_betweenness_subset, 6}, + {"R_igraph_beta_weighted_gabriel_graph", (DL_FUNC) &R_igraph_beta_weighted_gabriel_graph, 2}, + {"R_igraph_betweenness_cutoff", (DL_FUNC) &R_igraph_betweenness_cutoff, 6}, + {"R_igraph_betweenness_subset", (DL_FUNC) &R_igraph_betweenness_subset, 7}, {"R_igraph_bfs", (DL_FUNC) &R_igraph_bfs, 15}, {"R_igraph_bfs_simple", (DL_FUNC) &R_igraph_bfs_simple, 3}, {"R_igraph_biadjacency", (DL_FUNC) &R_igraph_biadjacency, 4}, {"R_igraph_bibcoupling", (DL_FUNC) &R_igraph_bibcoupling, 2}, {"R_igraph_biconnected_components", (DL_FUNC) &R_igraph_biconnected_components, 1}, - {"R_igraph_bipartite_game_gnm", (DL_FUNC) &R_igraph_bipartite_game_gnm, 5}, - {"R_igraph_bipartite_game_gnp", (DL_FUNC) &R_igraph_bipartite_game_gnp, 5}, + {"R_igraph_bipartite_game_gnm", (DL_FUNC) &R_igraph_bipartite_game_gnm, 7}, + {"R_igraph_bipartite_game_gnp", (DL_FUNC) &R_igraph_bipartite_game_gnp, 7}, + {"R_igraph_bipartite_iea_game", (DL_FUNC) &R_igraph_bipartite_iea_game, 5}, {"R_igraph_bipartite_projection", (DL_FUNC) &R_igraph_bipartite_projection, 4}, {"R_igraph_bipartite_projection_size", (DL_FUNC) &R_igraph_bipartite_projection_size, 2}, {"R_igraph_bond_percolation", (DL_FUNC) &R_igraph_bond_percolation, 2}, {"R_igraph_bridges", (DL_FUNC) &R_igraph_bridges, 1}, {"R_igraph_callaway_traits_game", (DL_FUNC) &R_igraph_callaway_traits_game, 6}, - {"R_igraph_canonical_permutation", (DL_FUNC) &R_igraph_canonical_permutation, 3}, + {"R_igraph_canonical_permutation", (DL_FUNC) &R_igraph_canonical_permutation, 2}, + {"R_igraph_canonical_permutation_bliss", (DL_FUNC) &R_igraph_canonical_permutation_bliss, 3}, {"R_igraph_centralization", (DL_FUNC) &R_igraph_centralization, 3}, {"R_igraph_centralization_betweenness", (DL_FUNC) &R_igraph_centralization_betweenness, 3}, {"R_igraph_centralization_betweenness_tmax", (DL_FUNC) &R_igraph_centralization_betweenness_tmax, 3}, @@ -593,15 +600,16 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_centralization_closeness_tmax", (DL_FUNC) &R_igraph_centralization_closeness_tmax, 3}, {"R_igraph_centralization_degree", (DL_FUNC) &R_igraph_centralization_degree, 4}, {"R_igraph_centralization_degree_tmax", (DL_FUNC) &R_igraph_centralization_degree_tmax, 4}, - {"R_igraph_centralization_eigenvector_centrality", (DL_FUNC) &R_igraph_centralization_eigenvector_centrality, 5}, - {"R_igraph_centralization_eigenvector_centrality_tmax", (DL_FUNC) &R_igraph_centralization_eigenvector_centrality_tmax, 4}, + {"R_igraph_centralization_eigenvector_centrality", (DL_FUNC) &R_igraph_centralization_eigenvector_centrality, 4}, + {"R_igraph_centralization_eigenvector_centrality_tmax", (DL_FUNC) &R_igraph_centralization_eigenvector_centrality_tmax, 3}, {"R_igraph_chung_lu_game", (DL_FUNC) &R_igraph_chung_lu_game, 4}, + {"R_igraph_circle_beta_skeleton", (DL_FUNC) &R_igraph_circle_beta_skeleton, 2}, {"R_igraph_circulant", (DL_FUNC) &R_igraph_circulant, 3}, {"R_igraph_cited_type_game", (DL_FUNC) &R_igraph_cited_type_game, 5}, {"R_igraph_citing_cited_type_game", (DL_FUNC) &R_igraph_citing_cited_type_game, 5}, {"R_igraph_clique_number", (DL_FUNC) &R_igraph_clique_number, 1}, {"R_igraph_clique_size_hist", (DL_FUNC) &R_igraph_clique_size_hist, 3}, - {"R_igraph_cliques", (DL_FUNC) &R_igraph_cliques, 3}, + {"R_igraph_cliques", (DL_FUNC) &R_igraph_cliques, 4}, {"R_igraph_closeness", (DL_FUNC) &R_igraph_closeness, 5}, {"R_igraph_closeness_cutoff", (DL_FUNC) &R_igraph_closeness_cutoff, 6}, {"R_igraph_cocitation", (DL_FUNC) &R_igraph_cocitation, 2}, @@ -610,12 +618,13 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_community_edge_betweenness", (DL_FUNC) &R_igraph_community_edge_betweenness, 8}, {"R_igraph_community_fastgreedy", (DL_FUNC) &R_igraph_community_fastgreedy, 5}, {"R_igraph_community_fluid_communities", (DL_FUNC) &R_igraph_community_fluid_communities, 2}, - {"R_igraph_community_infomap", (DL_FUNC) &R_igraph_community_infomap, 4}, - {"R_igraph_community_label_propagation", (DL_FUNC) &R_igraph_community_label_propagation, 5}, + {"R_igraph_community_infomap", (DL_FUNC) &R_igraph_community_infomap, 6}, + {"R_igraph_community_label_propagation", (DL_FUNC) &R_igraph_community_label_propagation, 6}, {"R_igraph_community_leading_eigenvector", (DL_FUNC) &R_igraph_community_leading_eigenvector, 9}, - {"R_igraph_community_leiden", (DL_FUNC) &R_igraph_community_leiden, 8}, + {"R_igraph_community_leiden", (DL_FUNC) &R_igraph_community_leiden, 9}, + {"R_igraph_community_leiden_simple", (DL_FUNC) &R_igraph_community_leiden_simple, 8}, {"R_igraph_community_multilevel", (DL_FUNC) &R_igraph_community_multilevel, 3}, - {"R_igraph_community_optimal_modularity", (DL_FUNC) &R_igraph_community_optimal_modularity, 2}, + {"R_igraph_community_optimal_modularity", (DL_FUNC) &R_igraph_community_optimal_modularity, 3}, {"R_igraph_compare_communities", (DL_FUNC) &R_igraph_compare_communities, 3}, {"R_igraph_complementer", (DL_FUNC) &R_igraph_complementer, 2}, {"R_igraph_compose", (DL_FUNC) &R_igraph_compose, 2}, @@ -629,7 +638,8 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_correlated_game", (DL_FUNC) &R_igraph_correlated_game, 4}, {"R_igraph_correlated_pair_game", (DL_FUNC) &R_igraph_correlated_pair_game, 5}, {"R_igraph_count_adjacent_triangles", (DL_FUNC) &R_igraph_count_adjacent_triangles, 2}, - {"R_igraph_count_automorphisms", (DL_FUNC) &R_igraph_count_automorphisms, 3}, + {"R_igraph_count_automorphisms", (DL_FUNC) &R_igraph_count_automorphisms, 2}, + {"R_igraph_count_automorphisms_bliss", (DL_FUNC) &R_igraph_count_automorphisms_bliss, 3}, {"R_igraph_count_isomorphisms_vf2", (DL_FUNC) &R_igraph_count_isomorphisms_vf2, 6}, {"R_igraph_count_loops", (DL_FUNC) &R_igraph_count_loops, 1}, {"R_igraph_count_multiple", (DL_FUNC) &R_igraph_count_multiple, 2}, @@ -644,11 +654,11 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_degree", (DL_FUNC) &R_igraph_degree, 4}, {"R_igraph_degree_correlation_vector", (DL_FUNC) &R_igraph_degree_correlation_vector, 5}, {"R_igraph_degree_sequence_game", (DL_FUNC) &R_igraph_degree_sequence_game, 3}, + {"R_igraph_delaunay_graph", (DL_FUNC) &R_igraph_delaunay_graph, 1}, {"R_igraph_delete_edges", (DL_FUNC) &R_igraph_delete_edges, 2}, {"R_igraph_delete_vertices", (DL_FUNC) &R_igraph_delete_vertices, 2}, - {"R_igraph_delete_vertices_idx", (DL_FUNC) &R_igraph_delete_vertices_idx, 2}, - {"R_igraph_density", (DL_FUNC) &R_igraph_density, 2}, - {"R_igraph_deterministic_optimal_imitation", (DL_FUNC) &R_igraph_deterministic_optimal_imitation, 6}, + {"R_igraph_delete_vertices_map", (DL_FUNC) &R_igraph_delete_vertices_map, 2}, + {"R_igraph_density", (DL_FUNC) &R_igraph_density, 3}, {"R_igraph_dfs", (DL_FUNC) &R_igraph_dfs, 12}, {"R_igraph_diameter", (DL_FUNC) &R_igraph_diameter, 4}, {"R_igraph_difference", (DL_FUNC) &R_igraph_difference, 2}, @@ -659,20 +669,20 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_dot_product_game", (DL_FUNC) &R_igraph_dot_product_game, 2}, {"R_igraph_dyad_census", (DL_FUNC) &R_igraph_dyad_census, 1}, {"R_igraph_ecc", (DL_FUNC) &R_igraph_ecc, 5}, - {"R_igraph_eccentricity_dijkstra", (DL_FUNC) &R_igraph_eccentricity_dijkstra, 4}, + {"R_igraph_eccentricity", (DL_FUNC) &R_igraph_eccentricity, 4}, {"R_igraph_ecount", (DL_FUNC) &R_igraph_ecount, 1}, - {"R_igraph_edge_betweenness", (DL_FUNC) &R_igraph_edge_betweenness, 3}, - {"R_igraph_edge_betweenness_cutoff", (DL_FUNC) &R_igraph_edge_betweenness_cutoff, 4}, - {"R_igraph_edge_betweenness_subset", (DL_FUNC) &R_igraph_edge_betweenness_subset, 6}, + {"R_igraph_edge_betweenness", (DL_FUNC) &R_igraph_edge_betweenness, 5}, + {"R_igraph_edge_betweenness_cutoff", (DL_FUNC) &R_igraph_edge_betweenness_cutoff, 6}, + {"R_igraph_edge_betweenness_subset", (DL_FUNC) &R_igraph_edge_betweenness_subset, 7}, {"R_igraph_edge_connectivity", (DL_FUNC) &R_igraph_edge_connectivity, 2}, {"R_igraph_edge_disjoint_paths", (DL_FUNC) &R_igraph_edge_disjoint_paths, 3}, {"R_igraph_edgelist_percolation", (DL_FUNC) &R_igraph_edgelist_percolation, 1}, - {"R_igraph_edges", (DL_FUNC) &R_igraph_edges, 2}, + {"R_igraph_edges", (DL_FUNC) &R_igraph_edges, 3}, {"R_igraph_eigen_adjacency", (DL_FUNC) &R_igraph_eigen_adjacency, 4}, - {"R_igraph_eigenvector_centrality", (DL_FUNC) &R_igraph_eigenvector_centrality, 5}, + {"R_igraph_eigenvector_centrality", (DL_FUNC) &R_igraph_eigenvector_centrality, 4}, {"R_igraph_empty", (DL_FUNC) &R_igraph_empty, 2}, - {"R_igraph_erdos_renyi_game_gnm", (DL_FUNC) &R_igraph_erdos_renyi_game_gnm, 4}, - {"R_igraph_erdos_renyi_game_gnp", (DL_FUNC) &R_igraph_erdos_renyi_game_gnp, 4}, + {"R_igraph_erdos_renyi_game_gnm", (DL_FUNC) &R_igraph_erdos_renyi_game_gnm, 5}, + {"R_igraph_erdos_renyi_game_gnp", (DL_FUNC) &R_igraph_erdos_renyi_game_gnp, 5}, {"R_igraph_es_adj", (DL_FUNC) &R_igraph_es_adj, 4}, {"R_igraph_es_pairs", (DL_FUNC) &R_igraph_es_pairs, 3}, {"R_igraph_es_path", (DL_FUNC) &R_igraph_es_path, 3}, @@ -695,14 +705,15 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_full_citation", (DL_FUNC) &R_igraph_full_citation, 2}, {"R_igraph_full_multipartite", (DL_FUNC) &R_igraph_full_multipartite, 3}, {"R_igraph_fundamental_cycles", (DL_FUNC) &R_igraph_fundamental_cycles, 4}, + {"R_igraph_gabriel_graph", (DL_FUNC) &R_igraph_gabriel_graph, 1}, {"R_igraph_generalized_petersen", (DL_FUNC) &R_igraph_generalized_petersen, 2}, {"R_igraph_get_adjacency", (DL_FUNC) &R_igraph_get_adjacency, 4}, {"R_igraph_get_adjacency_sparse", (DL_FUNC) &R_igraph_get_adjacency_sparse, 4}, {"R_igraph_get_all_eids_between", (DL_FUNC) &R_igraph_get_all_eids_between, 4}, - {"R_igraph_get_all_shortest_paths", (DL_FUNC) &R_igraph_get_all_shortest_paths, 4}, + {"R_igraph_get_all_shortest_paths", (DL_FUNC) &R_igraph_get_all_shortest_paths, 5}, {"R_igraph_get_all_shortest_paths_dijkstra", (DL_FUNC) &R_igraph_get_all_shortest_paths_dijkstra, 5}, - {"R_igraph_get_all_simple_paths", (DL_FUNC) &R_igraph_get_all_simple_paths, 5}, - {"R_igraph_get_biadjacency", (DL_FUNC) &R_igraph_get_biadjacency, 2}, + {"R_igraph_get_all_simple_paths", (DL_FUNC) &R_igraph_get_all_simple_paths, 7}, + {"R_igraph_get_biadjacency", (DL_FUNC) &R_igraph_get_biadjacency, 3}, {"R_igraph_get_diameter", (DL_FUNC) &R_igraph_get_diameter, 4}, {"R_igraph_get_edgelist", (DL_FUNC) &R_igraph_get_edgelist, 2}, {"R_igraph_get_eids", (DL_FUNC) &R_igraph_get_eids, 4}, @@ -711,7 +722,7 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_get_k_shortest_paths", (DL_FUNC) &R_igraph_get_k_shortest_paths, 6}, {"R_igraph_get_laplacian", (DL_FUNC) &R_igraph_get_laplacian, 4}, {"R_igraph_get_laplacian_sparse", (DL_FUNC) &R_igraph_get_laplacian_sparse, 4}, - {"R_igraph_get_shortest_path", (DL_FUNC) &R_igraph_get_shortest_path, 4}, + {"R_igraph_get_shortest_path", (DL_FUNC) &R_igraph_get_shortest_path, 5}, {"R_igraph_get_shortest_path_bellman_ford", (DL_FUNC) &R_igraph_get_shortest_path_bellman_ford, 5}, {"R_igraph_get_shortest_path_dijkstra", (DL_FUNC) &R_igraph_get_shortest_path_dijkstra, 5}, {"R_igraph_get_shortest_paths", (DL_FUNC) &R_igraph_get_shortest_paths, 10}, @@ -723,7 +734,7 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_girth", (DL_FUNC) &R_igraph_girth, 1}, {"R_igraph_global_efficiency", (DL_FUNC) &R_igraph_global_efficiency, 3}, {"R_igraph_gomory_hu_tree", (DL_FUNC) &R_igraph_gomory_hu_tree, 2}, - {"R_igraph_graph_center_dijkstra", (DL_FUNC) &R_igraph_graph_center_dijkstra, 3}, + {"R_igraph_graph_center", (DL_FUNC) &R_igraph_graph_center, 3}, {"R_igraph_graph_count", (DL_FUNC) &R_igraph_graph_count, 2}, {"R_igraph_graph_power", (DL_FUNC) &R_igraph_graph_power, 3}, {"R_igraph_graphlets", (DL_FUNC) &R_igraph_graphlets, 3}, @@ -746,9 +757,10 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_hrg_size", (DL_FUNC) &R_igraph_hrg_size, 1}, {"R_igraph_hsbm_game", (DL_FUNC) &R_igraph_hsbm_game, 5}, {"R_igraph_hsbm_list_game", (DL_FUNC) &R_igraph_hsbm_list_game, 5}, - {"R_igraph_hub_and_authority_scores", (DL_FUNC) &R_igraph_hub_and_authority_scores, 4}, + {"R_igraph_hub_and_authority_scores", (DL_FUNC) &R_igraph_hub_and_authority_scores, 3}, {"R_igraph_hypercube", (DL_FUNC) &R_igraph_hypercube, 2}, - {"R_igraph_incident", (DL_FUNC) &R_igraph_incident, 3}, + {"R_igraph_iea_game", (DL_FUNC) &R_igraph_iea_game, 4}, + {"R_igraph_incident", (DL_FUNC) &R_igraph_incident, 4}, {"R_igraph_independence_number", (DL_FUNC) &R_igraph_independence_number, 1}, {"R_igraph_independent_vertex_sets", (DL_FUNC) &R_igraph_independent_vertex_sets, 3}, {"R_igraph_induced_subgraph", (DL_FUNC) &R_igraph_induced_subgraph, 3}, @@ -778,7 +790,7 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_is_mutual", (DL_FUNC) &R_igraph_is_mutual, 3}, {"R_igraph_is_perfect", (DL_FUNC) &R_igraph_is_perfect, 1}, {"R_igraph_is_separator", (DL_FUNC) &R_igraph_is_separator, 2}, - {"R_igraph_is_simple", (DL_FUNC) &R_igraph_is_simple, 1}, + {"R_igraph_is_simple", (DL_FUNC) &R_igraph_is_simple, 2}, {"R_igraph_is_tree", (DL_FUNC) &R_igraph_is_tree, 2}, {"R_igraph_is_vertex_coloring", (DL_FUNC) &R_igraph_is_vertex_coloring, 2}, {"R_igraph_isoclass", (DL_FUNC) &R_igraph_isoclass, 1}, @@ -825,7 +837,7 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_layout_umap", (DL_FUNC) &R_igraph_layout_umap, 7}, {"R_igraph_layout_umap_3d", (DL_FUNC) &R_igraph_layout_umap_3d, 7}, {"R_igraph_layout_umap_compute_weights", (DL_FUNC) &R_igraph_layout_umap_compute_weights, 3}, - {"R_igraph_lcf_vector", (DL_FUNC) &R_igraph_lcf_vector, 3}, + {"R_igraph_lcf", (DL_FUNC) &R_igraph_lcf, 3}, {"R_igraph_linegraph", (DL_FUNC) &R_igraph_linegraph, 1}, {"R_igraph_list_triangles", (DL_FUNC) &R_igraph_list_triangles, 1}, {"R_igraph_local_efficiency", (DL_FUNC) &R_igraph_local_efficiency, 5}, @@ -837,13 +849,14 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_local_scan_k_ecount_them", (DL_FUNC) &R_igraph_local_scan_k_ecount_them, 5}, {"R_igraph_local_scan_neighborhood_ecount", (DL_FUNC) &R_igraph_local_scan_neighborhood_ecount, 3}, {"R_igraph_local_scan_subset_ecount", (DL_FUNC) &R_igraph_local_scan_subset_ecount, 3}, + {"R_igraph_lune_beta_skeleton", (DL_FUNC) &R_igraph_lune_beta_skeleton, 2}, {"R_igraph_maxdegree", (DL_FUNC) &R_igraph_maxdegree, 4}, {"R_igraph_maxflow", (DL_FUNC) &R_igraph_maxflow, 4}, {"R_igraph_maximal_cliques", (DL_FUNC) &R_igraph_maximal_cliques, 4}, {"R_igraph_maximal_cliques_count", (DL_FUNC) &R_igraph_maximal_cliques_count, 3}, {"R_igraph_maximal_cliques_file", (DL_FUNC) &R_igraph_maximal_cliques_file, 5}, {"R_igraph_maximal_cliques_hist", (DL_FUNC) &R_igraph_maximal_cliques_hist, 3}, - {"R_igraph_maximal_independent_vertex_sets", (DL_FUNC) &R_igraph_maximal_independent_vertex_sets, 1}, + {"R_igraph_maximal_independent_vertex_sets", (DL_FUNC) &R_igraph_maximal_independent_vertex_sets, 4}, {"R_igraph_maximum_bipartite_matching", (DL_FUNC) &R_igraph_maximum_bipartite_matching, 4}, {"R_igraph_maximum_cardinality_search", (DL_FUNC) &R_igraph_maximum_cardinality_search, 1}, {"R_igraph_mean_degree", (DL_FUNC) &R_igraph_mean_degree, 2}, @@ -851,21 +864,20 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_mincut_value", (DL_FUNC) &R_igraph_mincut_value, 2}, {"R_igraph_minimum_cycle_basis", (DL_FUNC) &R_igraph_minimum_cycle_basis, 5}, {"R_igraph_minimum_size_separators", (DL_FUNC) &R_igraph_minimum_size_separators, 1}, - {"R_igraph_minimum_spanning_tree_prim", (DL_FUNC) &R_igraph_minimum_spanning_tree_prim, 2}, - {"R_igraph_minimum_spanning_tree_unweighted", (DL_FUNC) &R_igraph_minimum_spanning_tree_unweighted, 1}, + {"R_igraph_minimum_spanning_tree", (DL_FUNC) &R_igraph_minimum_spanning_tree, 3}, {"R_igraph_modularity", (DL_FUNC) &R_igraph_modularity, 5}, {"R_igraph_modularity_matrix", (DL_FUNC) &R_igraph_modularity_matrix, 4}, - {"R_igraph_moran_process", (DL_FUNC) &R_igraph_moran_process, 5}, {"R_igraph_motifs_randesu", (DL_FUNC) &R_igraph_motifs_randesu, 3}, {"R_igraph_motifs_randesu_estimate", (DL_FUNC) &R_igraph_motifs_randesu_estimate, 5}, {"R_igraph_motifs_randesu_no", (DL_FUNC) &R_igraph_motifs_randesu_no, 3}, {"R_igraph_mybracket3_set", (DL_FUNC) &R_igraph_mybracket3_set, 5}, {"R_igraph_mycielski_graph", (DL_FUNC) &R_igraph_mycielski_graph, 1}, {"R_igraph_mycielskian", (DL_FUNC) &R_igraph_mycielskian, 2}, + {"R_igraph_nearest_neighbor_graph", (DL_FUNC) &R_igraph_nearest_neighbor_graph, 5}, {"R_igraph_neighborhood", (DL_FUNC) &R_igraph_neighborhood, 5}, {"R_igraph_neighborhood_graphs", (DL_FUNC) &R_igraph_neighborhood_graphs, 5}, {"R_igraph_neighborhood_size", (DL_FUNC) &R_igraph_neighborhood_size, 5}, - {"R_igraph_neighbors", (DL_FUNC) &R_igraph_neighbors, 3}, + {"R_igraph_neighbors", (DL_FUNC) &R_igraph_neighbors, 5}, {"R_igraph_path_graph", (DL_FUNC) &R_igraph_path_graph, 3}, {"R_igraph_path_length_hist", (DL_FUNC) &R_igraph_path_length_hist, 2}, {"R_igraph_permute_vertices", (DL_FUNC) &R_igraph_permute_vertices, 2}, @@ -875,9 +887,8 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_power_law_fit_new", (DL_FUNC) &R_igraph_power_law_fit_new, 5}, {"R_igraph_preference_game", (DL_FUNC) &R_igraph_preference_game, 7}, {"R_igraph_product", (DL_FUNC) &R_igraph_product, 3}, - {"R_igraph_pseudo_diameter", (DL_FUNC) &R_igraph_pseudo_diameter, 4}, - {"R_igraph_pseudo_diameter_dijkstra", (DL_FUNC) &R_igraph_pseudo_diameter_dijkstra, 5}, - {"R_igraph_radius_dijkstra", (DL_FUNC) &R_igraph_radius_dijkstra, 3}, + {"R_igraph_pseudo_diameter", (DL_FUNC) &R_igraph_pseudo_diameter, 5}, + {"R_igraph_radius", (DL_FUNC) &R_igraph_radius, 3}, {"R_igraph_random_sample", (DL_FUNC) &R_igraph_random_sample, 3}, {"R_igraph_random_spanning_tree", (DL_FUNC) &R_igraph_random_spanning_tree, 2}, {"R_igraph_random_walk", (DL_FUNC) &R_igraph_random_walk, 6}, @@ -894,31 +905,31 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_recent_degree_aging_game", (DL_FUNC) &R_igraph_recent_degree_aging_game, 10}, {"R_igraph_reciprocity", (DL_FUNC) &R_igraph_reciprocity, 3}, {"R_igraph_regular_tree", (DL_FUNC) &R_igraph_regular_tree, 3}, + {"R_igraph_relative_neighborhood_graph", (DL_FUNC) &R_igraph_relative_neighborhood_graph, 1}, {"R_igraph_residual_graph", (DL_FUNC) &R_igraph_residual_graph, 3}, {"R_igraph_reverse_edges", (DL_FUNC) &R_igraph_reverse_edges, 2}, {"R_igraph_reverse_residual_graph", (DL_FUNC) &R_igraph_reverse_residual_graph, 3}, {"R_igraph_rewire", (DL_FUNC) &R_igraph_rewire, 3}, {"R_igraph_rewire_directed_edges", (DL_FUNC) &R_igraph_rewire_directed_edges, 4}, - {"R_igraph_rewire_edges", (DL_FUNC) &R_igraph_rewire_edges, 4}, + {"R_igraph_rewire_edges", (DL_FUNC) &R_igraph_rewire_edges, 3}, {"R_igraph_rich_club_sequence", (DL_FUNC) &R_igraph_rich_club_sequence, 6}, {"R_igraph_ring", (DL_FUNC) &R_igraph_ring, 4}, {"R_igraph_rooted_product", (DL_FUNC) &R_igraph_rooted_product, 3}, {"R_igraph_roots_for_tree_layout", (DL_FUNC) &R_igraph_roots_for_tree_layout, 3}, - {"R_igraph_roulette_wheel_imitation", (DL_FUNC) &R_igraph_roulette_wheel_imitation, 6}, {"R_igraph_running_mean", (DL_FUNC) &R_igraph_running_mean, 2}, {"R_igraph_sample_dirichlet", (DL_FUNC) &R_igraph_sample_dirichlet, 2}, {"R_igraph_sample_sphere_surface", (DL_FUNC) &R_igraph_sample_sphere_surface, 4}, {"R_igraph_sample_sphere_volume", (DL_FUNC) &R_igraph_sample_sphere_volume, 4}, - {"R_igraph_sbm_game", (DL_FUNC) &R_igraph_sbm_game, 5}, + {"R_igraph_sbm_game", (DL_FUNC) &R_igraph_sbm_game, 4}, {"R_igraph_shortest_paths", (DL_FUNC) &R_igraph_shortest_paths, 6}, - {"R_igraph_similarity_dice", (DL_FUNC) &R_igraph_similarity_dice, 4}, + {"R_igraph_similarity_dice", (DL_FUNC) &R_igraph_similarity_dice, 5}, {"R_igraph_similarity_dice_es", (DL_FUNC) &R_igraph_similarity_dice_es, 4}, {"R_igraph_similarity_dice_pairs", (DL_FUNC) &R_igraph_similarity_dice_pairs, 4}, {"R_igraph_similarity_inverse_log_weighted", (DL_FUNC) &R_igraph_similarity_inverse_log_weighted, 3}, - {"R_igraph_similarity_jaccard", (DL_FUNC) &R_igraph_similarity_jaccard, 4}, + {"R_igraph_similarity_jaccard", (DL_FUNC) &R_igraph_similarity_jaccard, 5}, {"R_igraph_similarity_jaccard_es", (DL_FUNC) &R_igraph_similarity_jaccard_es, 4}, {"R_igraph_similarity_jaccard_pairs", (DL_FUNC) &R_igraph_similarity_jaccard_pairs, 4}, - {"R_igraph_simple_cycles", (DL_FUNC) &R_igraph_simple_cycles, 4}, + {"R_igraph_simple_cycles", (DL_FUNC) &R_igraph_simple_cycles, 5}, {"R_igraph_simple_interconnected_islands_game", (DL_FUNC) &R_igraph_simple_interconnected_islands_game, 4}, {"R_igraph_simplify", (DL_FUNC) &R_igraph_simplify, 4}, {"R_igraph_simplify_and_colorize", (DL_FUNC) &R_igraph_simplify_and_colorize, 1}, @@ -926,6 +937,7 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_site_percolation", (DL_FUNC) &R_igraph_site_percolation, 2}, {"R_igraph_solve_lsap", (DL_FUNC) &R_igraph_solve_lsap, 2}, {"R_igraph_spanner", (DL_FUNC) &R_igraph_spanner, 3}, + {"R_igraph_spatial_edge_lengths", (DL_FUNC) &R_igraph_spatial_edge_lengths, 3}, {"R_igraph_spinglass_community", (DL_FUNC) &R_igraph_spinglass_community, 11}, {"R_igraph_spinglass_my_community", (DL_FUNC) &R_igraph_spinglass_my_community, 6}, {"R_igraph_split_join_distance", (DL_FUNC) &R_igraph_split_join_distance, 2}, @@ -935,9 +947,8 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_st_mincut_value", (DL_FUNC) &R_igraph_st_mincut_value, 4}, {"R_igraph_st_vertex_connectivity", (DL_FUNC) &R_igraph_st_vertex_connectivity, 3}, {"R_igraph_star", (DL_FUNC) &R_igraph_star, 3}, - {"R_igraph_static_fitness_game", (DL_FUNC) &R_igraph_static_fitness_game, 5}, - {"R_igraph_static_power_law_game", (DL_FUNC) &R_igraph_static_power_law_game, 7}, - {"R_igraph_stochastic_imitation", (DL_FUNC) &R_igraph_stochastic_imitation, 6}, + {"R_igraph_static_fitness_game", (DL_FUNC) &R_igraph_static_fitness_game, 4}, + {"R_igraph_static_power_law_game", (DL_FUNC) &R_igraph_static_power_law_game, 6}, {"R_igraph_strength", (DL_FUNC) &R_igraph_strength, 5}, {"R_igraph_subcomponent", (DL_FUNC) &R_igraph_subcomponent, 3}, {"R_igraph_subgraph_from_edges", (DL_FUNC) &R_igraph_subgraph_from_edges, 3}, @@ -950,7 +961,6 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_to_undirected", (DL_FUNC) &R_igraph_to_undirected, 3}, {"R_igraph_topological_sorting", (DL_FUNC) &R_igraph_topological_sorting, 2}, {"R_igraph_transitive_closure", (DL_FUNC) &R_igraph_transitive_closure, 1}, - {"R_igraph_transitive_closure_dag", (DL_FUNC) &R_igraph_transitive_closure_dag, 1}, {"R_igraph_transitivity_avglocal_undirected", (DL_FUNC) &R_igraph_transitivity_avglocal_undirected, 2}, {"R_igraph_transitivity_barrat", (DL_FUNC) &R_igraph_transitivity_barrat, 4}, {"R_igraph_transitivity_local_undirected", (DL_FUNC) &R_igraph_transitivity_local_undirected, 3}, @@ -968,15 +978,15 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_vertex_coloring_greedy", (DL_FUNC) &R_igraph_vertex_coloring_greedy, 2}, {"R_igraph_vertex_connectivity", (DL_FUNC) &R_igraph_vertex_connectivity, 2}, {"R_igraph_vertex_disjoint_paths", (DL_FUNC) &R_igraph_vertex_disjoint_paths, 3}, - {"R_igraph_vertex_path_from_edge_path", (DL_FUNC) &R_igraph_vertex_path_from_edge_path, 4}, {"R_igraph_voronoi", (DL_FUNC) &R_igraph_voronoi, 5}, {"R_igraph_vs_adj", (DL_FUNC) &R_igraph_vs_adj, 4}, {"R_igraph_vs_nei", (DL_FUNC) &R_igraph_vs_nei, 4}, {"R_igraph_walktrap_community", (DL_FUNC) &R_igraph_walktrap_community, 6}, {"R_igraph_watts_strogatz_game", (DL_FUNC) &R_igraph_watts_strogatz_game, 6}, {"R_igraph_weighted_adjacency", (DL_FUNC) &R_igraph_weighted_adjacency, 3}, + {"R_igraph_weighted_biadjacency", (DL_FUNC) &R_igraph_weighted_biadjacency, 3}, {"R_igraph_weighted_clique_number", (DL_FUNC) &R_igraph_weighted_clique_number, 2}, - {"R_igraph_weighted_cliques", (DL_FUNC) &R_igraph_weighted_cliques, 5}, + {"R_igraph_weighted_cliques", (DL_FUNC) &R_igraph_weighted_cliques, 6}, {"R_igraph_wheel", (DL_FUNC) &R_igraph_wheel, 3}, {"R_igraph_widest_path_widths_dijkstra", (DL_FUNC) &R_igraph_widest_path_widths_dijkstra, 5}, {"R_igraph_widest_path_widths_floyd_warshall", (DL_FUNC) &R_igraph_widest_path_widths_floyd_warshall, 5}, @@ -1020,7 +1030,6 @@ static const R_CallMethodDef CallEntries[] = { {"Rx_igraph_famous", (DL_FUNC) &Rx_igraph_famous, 1}, {"Rx_igraph_get_adjedgelist", (DL_FUNC) &Rx_igraph_get_adjedgelist, 3}, {"Rx_igraph_get_adjlist", (DL_FUNC) &Rx_igraph_get_adjlist, 4}, - {"Rx_igraph_get_all_simple_paths_pp", (DL_FUNC) &Rx_igraph_get_all_simple_paths_pp, 1}, {"Rx_igraph_get_attr_mode", (DL_FUNC) &Rx_igraph_get_attr_mode, 2}, {"Rx_igraph_get_edge", (DL_FUNC) &Rx_igraph_get_edge, 2}, {"Rx_igraph_get_edgelist", (DL_FUNC) &Rx_igraph_get_edgelist, 2}, @@ -1031,7 +1040,6 @@ static const R_CallMethodDef CallEntries[] = { {"Rx_igraph_graphlets_project", (DL_FUNC) &Rx_igraph_graphlets_project, 5}, {"Rx_igraph_i_levc_arp", (DL_FUNC) &Rx_igraph_i_levc_arp, 3}, {"Rx_igraph_identical_graphs", (DL_FUNC) &Rx_igraph_identical_graphs, 3}, - {"Rx_igraph_incident", (DL_FUNC) &Rx_igraph_incident, 3}, {"Rx_igraph_incident_edges", (DL_FUNC) &Rx_igraph_incident_edges, 3}, {"Rx_igraph_independence_number", (DL_FUNC) &Rx_igraph_independence_number, 1}, {"Rx_igraph_intersection", (DL_FUNC) &Rx_igraph_intersection, 2}, @@ -1042,8 +1050,6 @@ static const R_CallMethodDef CallEntries[] = { {"Rx_igraph_maximal_independent_vertex_sets", (DL_FUNC) &Rx_igraph_maximal_independent_vertex_sets, 1}, {"Rx_igraph_mincut", (DL_FUNC) &Rx_igraph_mincut, 2}, {"Rx_igraph_mincut_value", (DL_FUNC) &Rx_igraph_mincut_value, 2}, - {"Rx_igraph_minimum_spanning_tree_prim", (DL_FUNC) &Rx_igraph_minimum_spanning_tree_prim, 2}, - {"Rx_igraph_minimum_spanning_tree_unweighted", (DL_FUNC) &Rx_igraph_minimum_spanning_tree_unweighted, 1}, {"Rx_igraph_mybracket2", (DL_FUNC) &Rx_igraph_mybracket2, 3}, {"Rx_igraph_mybracket2_copy", (DL_FUNC) &Rx_igraph_mybracket2_copy, 3}, {"Rx_igraph_mybracket2_names", (DL_FUNC) &Rx_igraph_mybracket2_names, 3}, diff --git a/src/rinterface.c b/src/rinterface.c index a2218afcc69..c5aadec5b83 100644 --- a/src/rinterface.c +++ b/src/rinterface.c @@ -201,9 +201,9 @@ SEXP R_igraph_delete_vertices(SEXP graph, SEXP vertices) { } /*-------------------------------------------/ -/ igraph_delete_vertices_idx / +/ igraph_delete_vertices_map / /-------------------------------------------*/ -SEXP R_igraph_delete_vertices_idx(SEXP graph, SEXP vertices) { +SEXP R_igraph_delete_vertices_map(SEXP graph, SEXP vertices) { /* Declarations */ igraph_t c_graph; igraph_vs_t c_vertices; @@ -223,7 +223,7 @@ SEXP R_igraph_delete_vertices_idx(SEXP graph, SEXP vertices) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_invidx, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_invidx); /* Call igraph */ - IGRAPH_R_CHECK(igraph_delete_vertices_idx(&c_graph, c_vertices, &c_idx, &c_invidx)); + IGRAPH_R_CHECK(igraph_delete_vertices_map(&c_graph, c_vertices, &c_idx, &c_invidx)); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -299,12 +299,14 @@ SEXP R_igraph_ecount(SEXP graph) { /*-------------------------------------------/ / igraph_neighbors / /-------------------------------------------*/ -SEXP R_igraph_neighbors(SEXP graph, SEXP vid, SEXP mode) { +SEXP R_igraph_neighbors(SEXP graph, SEXP vid, SEXP mode, SEXP loops, SEXP multiple) { /* Declarations */ igraph_t c_graph; igraph_vector_int_t c_neis; igraph_integer_t c_vid; igraph_neimode_t c_mode; + igraph_loops_t c_loops; + igraph_bool_t c_multiple; SEXP neis; SEXP r_result; @@ -314,8 +316,11 @@ SEXP R_igraph_neighbors(SEXP graph, SEXP vid, SEXP mode) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_neis); c_vid = (igraph_integer_t) REAL(vid)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); + c_loops = (igraph_loops_t) Rf_asInteger(loops); + IGRAPH_R_CHECK_BOOL(multiple); + c_multiple = LOGICAL(multiple)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_neighbors(&c_graph, &c_neis, c_vid, c_mode)); + IGRAPH_R_CHECK(igraph_neighbors(&c_graph, &c_neis, c_vid, c_mode, c_loops, c_multiple)); /* Convert output */ PROTECT(neis=R_igraph_vector_int_to_SEXPp1(&c_neis)); @@ -358,7 +363,7 @@ SEXP R_igraph_degree(SEXP graph, SEXP vids, SEXP mode, SEXP loops) { igraph_vector_int_t c_res; igraph_vs_t c_vids; igraph_neimode_t c_mode; - igraph_bool_t c_loops; + igraph_loops_t c_loops; SEXP res; SEXP r_result; @@ -369,8 +374,7 @@ SEXP R_igraph_degree(SEXP graph, SEXP vids, SEXP mode, SEXP loops) { igraph_vector_int_t c_vids_data; R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); c_mode = (igraph_neimode_t) Rf_asInteger(mode); - IGRAPH_R_CHECK_BOOL(loops); - c_loops = LOGICAL(loops)[0]; + c_loops = (igraph_loops_t) Rf_asInteger(loops); /* Call igraph */ IGRAPH_R_CHECK(igraph_degree(&c_graph, &c_res, c_vids, c_mode, c_loops)); @@ -389,11 +393,12 @@ SEXP R_igraph_degree(SEXP graph, SEXP vids, SEXP mode, SEXP loops) { /*-------------------------------------------/ / igraph_edges / /-------------------------------------------*/ -SEXP R_igraph_edges(SEXP graph, SEXP eids) { +SEXP R_igraph_edges(SEXP graph, SEXP eids, SEXP bycol) { /* Declarations */ igraph_t c_graph; igraph_es_t c_eids; igraph_vector_int_t c_edges; + igraph_bool_t c_bycol; SEXP edges; SEXP r_result; @@ -403,8 +408,10 @@ SEXP R_igraph_edges(SEXP graph, SEXP eids) { IGRAPH_R_CHECK(R_SEXP_to_igraph_es(eids, &c_graph, &c_eids, &c_eids_data)); IGRAPH_R_CHECK(igraph_vector_int_init(&c_edges, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edges); + IGRAPH_R_CHECK_BOOL(bycol); + c_bycol = LOGICAL(bycol)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_edges(&c_graph, c_eids, &c_edges)); + IGRAPH_R_CHECK(igraph_edges(&c_graph, c_eids, &c_edges, c_bycol)); /* Convert output */ igraph_vector_int_destroy(&c_eids_data); @@ -455,12 +462,13 @@ SEXP R_igraph_get_all_eids_between(SEXP graph, SEXP from, SEXP to, SEXP directed /*-------------------------------------------/ / igraph_incident / /-------------------------------------------*/ -SEXP R_igraph_incident(SEXP graph, SEXP vid, SEXP mode) { +SEXP R_igraph_incident(SEXP graph, SEXP vid, SEXP mode, SEXP loops) { /* Declarations */ igraph_t c_graph; igraph_vector_int_t c_eids; igraph_integer_t c_vid; igraph_neimode_t c_mode; + igraph_loops_t c_loops; SEXP eids; SEXP r_result; @@ -470,8 +478,9 @@ SEXP R_igraph_incident(SEXP graph, SEXP vid, SEXP mode) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_eids); c_vid = (igraph_integer_t) REAL(vid)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); + c_loops = (igraph_loops_t) Rf_asInteger(loops); /* Call igraph */ - IGRAPH_R_CHECK(igraph_incident(&c_graph, &c_eids, c_vid, c_mode)); + IGRAPH_R_CHECK(igraph_incident(&c_graph, &c_eids, c_vid, c_mode, c_loops)); /* Convert output */ PROTECT(eids=R_igraph_vector_int_to_SEXPp1(&c_eids)); @@ -500,7 +509,9 @@ SEXP R_igraph_adjacency(SEXP adjmatrix, SEXP mode, SEXP loops) { c_mode = (igraph_adjacency_t) Rf_asInteger(mode); c_loops = (igraph_loops_t) Rf_asInteger(loops); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_adjacency(&c_graph, &c_adjmatrix, c_mode, c_loops)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -535,7 +546,9 @@ SEXP R_igraph_weighted_adjacency(SEXP adjmatrix, SEXP mode, SEXP loops) { weights=R_GlobalEnv; /* hack to have a non-NULL value */ c_loops = (igraph_loops_t) Rf_asInteger(loops); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_weighted_adjacency(&c_graph, &c_adjmatrix, c_mode, &c_weights, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -577,7 +590,9 @@ SEXP R_igraph_wheel(SEXP n, SEXP mode, SEXP center) { IGRAPH_R_CHECK_INT(center); c_center = (igraph_integer_t) REAL(center)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_wheel(&c_graph, c_n, c_mode, c_center)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -607,7 +622,9 @@ SEXP R_igraph_hypercube(SEXP n, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hypercube(&c_graph, c_n, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -647,7 +664,9 @@ SEXP R_igraph_square_lattice(SEXP dimvector, SEXP nei, SEXP directed, SEXP mutua R_SEXP_to_vector_bool(periodic, &c_periodic); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_square_lattice(&c_graph, &c_dimvector, c_nei, c_directed, c_mutual, (Rf_isNull(periodic) ? 0 : &c_periodic))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_square_lattice(&c_graph, &c_dimvector, c_nei, c_directed, c_mutual, (Rf_isNull(periodic) ? NULL : &c_periodic))); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -682,7 +701,9 @@ SEXP R_igraph_triangular_lattice(SEXP dimvector, SEXP directed, SEXP mutual) { IGRAPH_R_CHECK_BOOL(mutual); c_mutual = LOGICAL(mutual)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_triangular_lattice(&c_graph, &c_dimvector, c_directed, c_mutual)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -717,7 +738,9 @@ SEXP R_igraph_path_graph(SEXP n, SEXP directed, SEXP mutual) { IGRAPH_R_CHECK_BOOL(mutual); c_mutual = LOGICAL(mutual)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_path_graph(&c_graph, c_n, c_directed, c_mutual)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -750,7 +773,9 @@ SEXP R_igraph_cycle_graph(SEXP n, SEXP directed, SEXP mutual) { IGRAPH_R_CHECK_BOOL(mutual); c_mutual = LOGICAL(mutual)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_cycle_graph(&c_graph, c_n, c_directed, c_mutual)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -779,7 +804,9 @@ SEXP R_igraph_symmetric_tree(SEXP branches, SEXP type) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_branches); c_type = (igraph_tree_mode_t) Rf_asInteger(type); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_symmetric_tree(&c_graph, &c_branches, c_type)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -813,7 +840,9 @@ SEXP R_igraph_regular_tree(SEXP h, SEXP k, SEXP type) { c_k = (igraph_integer_t) REAL(k)[0]; c_type = (igraph_tree_mode_t) Rf_asInteger(type); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_regular_tree(&c_graph, c_h, c_k, c_type)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -843,7 +872,9 @@ SEXP R_igraph_full_citation(SEXP n, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_full_citation(&c_graph, c_n, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -870,7 +901,9 @@ SEXP R_igraph_atlas(SEXP number) { IGRAPH_R_CHECK_INT(number); c_number = (igraph_integer_t) REAL(number)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_atlas(&c_graph, c_number)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -903,7 +936,9 @@ SEXP R_igraph_extended_chordal_ring(SEXP nodes, SEXP W, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_extended_chordal_ring(&c_graph, c_nodes, &c_W, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -937,7 +972,9 @@ SEXP R_igraph_graph_power(SEXP graph, SEXP order, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_graph_power(&c_graph, &c_res, c_order, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -963,7 +1000,9 @@ SEXP R_igraph_linegraph(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_linegraph(&c_graph, &c_linegraph)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_linegraph); @@ -1063,9 +1102,9 @@ SEXP R_igraph_famous(SEXP name) { } /*-------------------------------------------/ -/ igraph_lcf_vector / +/ igraph_lcf / /-------------------------------------------*/ -SEXP R_igraph_lcf_vector(SEXP n, SEXP shifts, SEXP repeats) { +SEXP R_igraph_lcf(SEXP n, SEXP shifts, SEXP repeats) { /* Declarations */ igraph_t c_graph; igraph_integer_t c_n; @@ -1082,7 +1121,9 @@ SEXP R_igraph_lcf_vector(SEXP n, SEXP shifts, SEXP repeats) { IGRAPH_R_CHECK_INT(repeats); c_repeats = (igraph_integer_t) REAL(repeats)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_lcf_vector(&c_graph, c_n, &c_shifts, c_repeats)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_lcf(&c_graph, c_n, &c_shifts, c_repeats)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1111,7 +1152,9 @@ SEXP R_igraph_mycielski_graph(SEXP k) { IGRAPH_R_CHECK_INT(k); c_k = (igraph_integer_t) REAL(k)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_mycielski_graph(&c_graph, c_k)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1142,7 +1185,9 @@ SEXP R_igraph_adjlist(SEXP adjlist, SEXP mode, SEXP duplicate) { IGRAPH_R_CHECK_BOOL(duplicate); c_duplicate = LOGICAL(duplicate)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_adjlist(&c_graph, &c_adjlist, c_mode, c_duplicate)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1182,7 +1227,9 @@ SEXP R_igraph_full_bipartite(SEXP n1, SEXP n2, SEXP directed, SEXP mode) { c_directed = LOGICAL(directed)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_full_bipartite(&c_graph, &c_types, c_n1, c_n2, c_directed, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -1228,7 +1275,9 @@ SEXP R_igraph_full_multipartite(SEXP n, SEXP directed, SEXP mode) { c_directed = LOGICAL(directed)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_full_multipartite(&c_graph, &c_types, &c_n, c_directed, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -1279,7 +1328,9 @@ SEXP R_igraph_realize_degree_sequence(SEXP out_deg, SEXP in_deg, SEXP allowed_ed c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); c_method = (igraph_realize_degseq_t) Rf_asInteger(method); /* Call igraph */ - IGRAPH_R_CHECK(igraph_realize_degree_sequence(&c_graph, &c_out_deg, (Rf_isNull(in_deg) ? 0 : &c_in_deg), c_allowed_edge_types, c_method)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_realize_degree_sequence(&c_graph, &c_out_deg, (Rf_isNull(in_deg) ? NULL : &c_in_deg), c_allowed_edge_types, c_method)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1317,7 +1368,9 @@ SEXP R_igraph_realize_bipartite_degree_sequence(SEXP degrees1, SEXP degrees2, SE c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); c_method = (igraph_realize_degseq_t) Rf_asInteger(method); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_realize_bipartite_degree_sequence(&c_graph, &c_degrees1, &c_degrees2, c_allowed_edge_types, c_method)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1354,7 +1407,9 @@ SEXP R_igraph_circulant(SEXP n, SEXP shifts, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_circulant(&c_graph, c_n, &c_shifts, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1386,7 +1441,9 @@ SEXP R_igraph_generalized_petersen(SEXP n, SEXP k) { IGRAPH_R_CHECK_INT(k); c_k = (igraph_integer_t) REAL(k)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_generalized_petersen(&c_graph, c_n, c_k)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1420,7 +1477,9 @@ SEXP R_igraph_turan(SEXP n, SEXP r) { IGRAPH_R_CHECK_INT(r); c_r = (igraph_integer_t) REAL(r)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_turan(&c_graph, &c_types, c_n, c_r)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -1446,13 +1505,14 @@ SEXP R_igraph_turan(SEXP n, SEXP r) { /*-------------------------------------------/ / igraph_erdos_renyi_game_gnp / /-------------------------------------------*/ -SEXP R_igraph_erdos_renyi_game_gnp(SEXP n, SEXP p, SEXP directed, SEXP loops) { +SEXP R_igraph_erdos_renyi_game_gnp(SEXP n, SEXP p, SEXP directed, SEXP allowed_edge_types, SEXP edge_labeled) { /* Declarations */ igraph_t c_graph; igraph_integer_t c_n; igraph_real_t c_p; igraph_bool_t c_directed; - igraph_bool_t c_loops; + igraph_edge_type_sw_t c_allowed_edge_types; + igraph_bool_t c_edge_labeled; SEXP graph; SEXP r_result; @@ -1463,10 +1523,13 @@ SEXP R_igraph_erdos_renyi_game_gnp(SEXP n, SEXP p, SEXP directed, SEXP loops) { c_p = REAL(p)[0]; IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; - IGRAPH_R_CHECK_BOOL(loops); - c_loops = LOGICAL(loops)[0]; + c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); + IGRAPH_R_CHECK_BOOL(edge_labeled); + c_edge_labeled = LOGICAL(edge_labeled)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_erdos_renyi_game_gnp(&c_graph, c_n, c_p, c_directed, c_loops)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_erdos_renyi_game_gnp(&c_graph, c_n, c_p, c_directed, c_allowed_edge_types, c_edge_labeled)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1482,7 +1545,47 @@ SEXP R_igraph_erdos_renyi_game_gnp(SEXP n, SEXP p, SEXP directed, SEXP loops) { /*-------------------------------------------/ / igraph_erdos_renyi_game_gnm / /-------------------------------------------*/ -SEXP R_igraph_erdos_renyi_game_gnm(SEXP n, SEXP m, SEXP directed, SEXP loops) { +SEXP R_igraph_erdos_renyi_game_gnm(SEXP n, SEXP m, SEXP directed, SEXP allowed_edge_types, SEXP edge_labeled) { + /* Declarations */ + igraph_t c_graph; + igraph_integer_t c_n; + igraph_integer_t c_m; + igraph_bool_t c_directed; + igraph_edge_type_sw_t c_allowed_edge_types; + igraph_bool_t c_edge_labeled; + SEXP graph; + + SEXP r_result; + /* Convert input */ + IGRAPH_R_CHECK_INT(n); + c_n = (igraph_integer_t) REAL(n)[0]; + IGRAPH_R_CHECK_INT(m); + c_m = (igraph_integer_t) REAL(m)[0]; + IGRAPH_R_CHECK_BOOL(directed); + c_directed = LOGICAL(directed)[0]; + c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); + IGRAPH_R_CHECK_BOOL(edge_labeled); + c_edge_labeled = LOGICAL(edge_labeled)[0]; + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_erdos_renyi_game_gnm(&c_graph, c_n, c_m, c_directed, c_allowed_edge_types, c_edge_labeled)); + PutRNGstate(); + + /* Convert output */ + IGRAPH_FINALLY(igraph_destroy, &c_graph); + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); + IGRAPH_FINALLY_CLEAN(1); + r_result = graph; + + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_iea_game / +/-------------------------------------------*/ +SEXP R_igraph_iea_game(SEXP n, SEXP m, SEXP directed, SEXP loops) { /* Declarations */ igraph_t c_graph; igraph_integer_t c_n; @@ -1502,7 +1605,9 @@ SEXP R_igraph_erdos_renyi_game_gnm(SEXP n, SEXP m, SEXP directed, SEXP loops) { IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_erdos_renyi_game_gnm(&c_graph, c_n, c_m, c_directed, c_loops)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_iea_game(&c_graph, c_n, c_m, c_directed, c_loops)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1538,7 +1643,9 @@ SEXP R_igraph_growing_random_game(SEXP n, SEXP m, SEXP directed, SEXP citation) IGRAPH_R_CHECK_BOOL(citation); c_citation = LOGICAL(citation)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_growing_random_game(&c_graph, c_n, c_m, c_directed, c_citation)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1585,7 +1692,9 @@ SEXP R_igraph_preference_game(SEXP nodes, SEXP types, SEXP type_dist, SEXP fixed IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_preference_game(&c_graph, c_nodes, c_types, &c_type_dist, c_fixed_sizes, &c_pref_matrix, &c_node_type_vec, c_directed, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -1643,7 +1752,9 @@ SEXP R_igraph_asymmetric_preference_game(SEXP nodes, SEXP out_types, SEXP in_typ IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_asymmetric_preference_game(&c_graph, c_nodes, c_out_types, c_in_types, &c_type_dist_matrix, &c_pref_matrix, &c_node_type_out_vec, &c_node_type_in_vec, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -1674,12 +1785,11 @@ SEXP R_igraph_asymmetric_preference_game(SEXP nodes, SEXP out_types, SEXP in_typ /*-------------------------------------------/ / igraph_rewire_edges / /-------------------------------------------*/ -SEXP R_igraph_rewire_edges(SEXP graph, SEXP prob, SEXP loops, SEXP multiple) { +SEXP R_igraph_rewire_edges(SEXP graph, SEXP prob, SEXP allowed_edge_types) { /* Declarations */ igraph_t c_graph; igraph_real_t c_prob; - igraph_bool_t c_loops; - igraph_bool_t c_multiple; + igraph_edge_type_sw_t c_allowed_edge_types; SEXP r_result; /* Convert input */ @@ -1687,12 +1797,11 @@ SEXP R_igraph_rewire_edges(SEXP graph, SEXP prob, SEXP loops, SEXP multiple) { IGRAPH_FINALLY(igraph_destroy, &c_graph); IGRAPH_R_CHECK_REAL(prob); c_prob = REAL(prob)[0]; - IGRAPH_R_CHECK_BOOL(loops); - c_loops = LOGICAL(loops)[0]; - IGRAPH_R_CHECK_BOOL(multiple); - c_multiple = LOGICAL(multiple)[0]; + c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); /* Call igraph */ - IGRAPH_R_CHECK(igraph_rewire_edges(&c_graph, c_prob, c_loops, c_multiple)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_rewire_edges(&c_graph, c_prob, c_allowed_edge_types)); + PutRNGstate(); /* Convert output */ PROTECT(graph=R_igraph_to_SEXP(&c_graph)); @@ -1724,7 +1833,9 @@ SEXP R_igraph_rewire_directed_edges(SEXP graph, SEXP prob, SEXP loops, SEXP mode c_loops = LOGICAL(loops)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_rewire_directed_edges(&c_graph, c_prob, c_loops, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(graph=R_igraph_to_SEXP(&c_graph)); @@ -1762,7 +1873,9 @@ SEXP R_igraph_forest_fire_game(SEXP nodes, SEXP fw_prob, SEXP bw_factor, SEXP am IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_forest_fire_game(&c_graph, c_nodes, c_fw_prob, c_bw_factor, c_ambs, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1798,7 +1911,9 @@ SEXP R_igraph_simple_interconnected_islands_game(SEXP islands_n, SEXP islands_si IGRAPH_R_CHECK_INT(n_inter); c_n_inter = (igraph_integer_t) REAL(n_inter)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_simple_interconnected_islands_game(&c_graph, c_islands_n, c_islands_size, c_islands_pin, c_n_inter)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1833,7 +1948,9 @@ SEXP R_igraph_chung_lu_game(SEXP out_weights, SEXP in_weights, SEXP loops, SEXP c_loops = LOGICAL(loops)[0]; c_variant = (igraph_chung_lu_t) Rf_asInteger(variant); /* Call igraph */ - IGRAPH_R_CHECK(igraph_chung_lu_game(&c_graph, &c_out_weights, (Rf_isNull(in_weights) ? 0 : &c_in_weights), c_loops, c_variant)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_chung_lu_game(&c_graph, &c_out_weights, (Rf_isNull(in_weights) ? NULL : &c_in_weights), c_loops, c_variant)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1849,14 +1966,13 @@ SEXP R_igraph_chung_lu_game(SEXP out_weights, SEXP in_weights, SEXP loops, SEXP /*-------------------------------------------/ / igraph_static_fitness_game / /-------------------------------------------*/ -SEXP R_igraph_static_fitness_game(SEXP no_of_edges, SEXP fitness_out, SEXP fitness_in, SEXP loops, SEXP multiple) { +SEXP R_igraph_static_fitness_game(SEXP no_of_edges, SEXP fitness_out, SEXP fitness_in, SEXP allowed_edge_types) { /* Declarations */ igraph_t c_graph; igraph_integer_t c_no_of_edges; igraph_vector_t c_fitness_out; igraph_vector_t c_fitness_in; - igraph_bool_t c_loops; - igraph_bool_t c_multiple; + igraph_edge_type_sw_t c_allowed_edge_types; SEXP graph; SEXP r_result; @@ -1867,12 +1983,11 @@ SEXP R_igraph_static_fitness_game(SEXP no_of_edges, SEXP fitness_out, SEXP fitne if (!Rf_isNull(fitness_in)) { R_SEXP_to_vector(fitness_in, &c_fitness_in); } - IGRAPH_R_CHECK_BOOL(loops); - c_loops = LOGICAL(loops)[0]; - IGRAPH_R_CHECK_BOOL(multiple); - c_multiple = LOGICAL(multiple)[0]; + c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); /* Call igraph */ - IGRAPH_R_CHECK(igraph_static_fitness_game(&c_graph, c_no_of_edges, &c_fitness_out, (Rf_isNull(fitness_in) ? 0 : &c_fitness_in), c_loops, c_multiple)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_static_fitness_game(&c_graph, c_no_of_edges, &c_fitness_out, (Rf_isNull(fitness_in) ? NULL : &c_fitness_in), c_allowed_edge_types)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1888,15 +2003,14 @@ SEXP R_igraph_static_fitness_game(SEXP no_of_edges, SEXP fitness_out, SEXP fitne /*-------------------------------------------/ / igraph_static_power_law_game / /-------------------------------------------*/ -SEXP R_igraph_static_power_law_game(SEXP no_of_nodes, SEXP no_of_edges, SEXP exponent_out, SEXP exponent_in, SEXP loops, SEXP multiple, SEXP finite_size_correction) { +SEXP R_igraph_static_power_law_game(SEXP no_of_nodes, SEXP no_of_edges, SEXP exponent_out, SEXP exponent_in, SEXP allowed_edge_types, SEXP finite_size_correction) { /* Declarations */ igraph_t c_graph; igraph_integer_t c_no_of_nodes; igraph_integer_t c_no_of_edges; igraph_real_t c_exponent_out; igraph_real_t c_exponent_in; - igraph_bool_t c_loops; - igraph_bool_t c_multiple; + igraph_edge_type_sw_t c_allowed_edge_types; igraph_bool_t c_finite_size_correction; SEXP graph; @@ -1910,14 +2024,13 @@ SEXP R_igraph_static_power_law_game(SEXP no_of_nodes, SEXP no_of_edges, SEXP exp c_exponent_out = REAL(exponent_out)[0]; IGRAPH_R_CHECK_REAL(exponent_in); c_exponent_in = REAL(exponent_in)[0]; - IGRAPH_R_CHECK_BOOL(loops); - c_loops = LOGICAL(loops)[0]; - IGRAPH_R_CHECK_BOOL(multiple); - c_multiple = LOGICAL(multiple)[0]; + c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); IGRAPH_R_CHECK_BOOL(finite_size_correction); c_finite_size_correction = LOGICAL(finite_size_correction)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_static_power_law_game(&c_graph, c_no_of_nodes, c_no_of_edges, c_exponent_out, c_exponent_in, c_loops, c_multiple, c_finite_size_correction)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_static_power_law_game(&c_graph, c_no_of_nodes, c_no_of_edges, c_exponent_out, c_exponent_in, c_allowed_edge_types, c_finite_size_correction)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1953,7 +2066,9 @@ SEXP R_igraph_k_regular_game(SEXP no_of_nodes, SEXP k, SEXP directed, SEXP multi IGRAPH_R_CHECK_BOOL(multiple); c_multiple = LOGICAL(multiple)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_k_regular_game(&c_graph, c_no_of_nodes, c_k, c_directed, c_multiple)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -1969,29 +2084,27 @@ SEXP R_igraph_k_regular_game(SEXP no_of_nodes, SEXP k, SEXP directed, SEXP multi /*-------------------------------------------/ / igraph_sbm_game / /-------------------------------------------*/ -SEXP R_igraph_sbm_game(SEXP n, SEXP pref_matrix, SEXP block_sizes, SEXP directed, SEXP loops) { +SEXP R_igraph_sbm_game(SEXP pref_matrix, SEXP block_sizes, SEXP directed, SEXP allowed_edge_types) { /* Declarations */ igraph_t c_graph; - igraph_integer_t c_n; igraph_matrix_t c_pref_matrix; igraph_vector_int_t c_block_sizes; igraph_bool_t c_directed; - igraph_bool_t c_loops; + igraph_edge_type_sw_t c_allowed_edge_types; SEXP graph; SEXP r_result; /* Convert input */ - IGRAPH_R_CHECK_INT(n); - c_n = (igraph_integer_t) REAL(n)[0]; R_SEXP_to_matrix(pref_matrix, &c_pref_matrix); IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(block_sizes, &c_block_sizes)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_block_sizes); IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; - IGRAPH_R_CHECK_BOOL(loops); - c_loops = LOGICAL(loops)[0]; + c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); /* Call igraph */ - IGRAPH_R_CHECK(igraph_sbm_game(&c_graph, c_n, &c_pref_matrix, &c_block_sizes, c_directed, c_loops)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_sbm_game(&c_graph, &c_pref_matrix, &c_block_sizes, c_directed, c_allowed_edge_types)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -2030,7 +2143,9 @@ SEXP R_igraph_hsbm_game(SEXP n, SEXP m, SEXP rho, SEXP C, SEXP p) { IGRAPH_R_CHECK_REAL(p); c_p = REAL(p)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hsbm_game(&c_graph, c_n, c_m, &c_rho, &c_C, c_p)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -2067,7 +2182,9 @@ SEXP R_igraph_hsbm_list_game(SEXP n, SEXP mlist, SEXP rholist, SEXP Clist, SEXP IGRAPH_R_CHECK_REAL(p); c_p = REAL(p)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hsbm_list_game(&c_graph, c_n, &c_mlist, &c_rholist, &c_Clist, c_p)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -2087,8 +2204,8 @@ SEXP R_igraph_hsbm_list_game(SEXP n, SEXP mlist, SEXP rholist, SEXP Clist, SEXP /-------------------------------------------*/ SEXP R_igraph_correlated_game(SEXP old_graph, SEXP corr, SEXP p, SEXP permutation) { /* Declarations */ - igraph_t c_old_graph; igraph_t c_new_graph; + igraph_t c_old_graph; igraph_real_t c_corr; igraph_real_t c_p; igraph_vector_int_t c_permutation; @@ -2109,7 +2226,9 @@ SEXP R_igraph_correlated_game(SEXP old_graph, SEXP corr, SEXP p, SEXP permutatio IGRAPH_FINALLY(igraph_vector_int_destroy, &c_permutation); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_correlated_game(&c_old_graph, &c_new_graph, c_corr, c_p, (Rf_isNull(permutation) ? 0 : &c_permutation))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_correlated_game(&c_new_graph, &c_old_graph, c_corr, c_p, (Rf_isNull(permutation) ? NULL : &c_permutation))); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_new_graph); @@ -2157,7 +2276,9 @@ SEXP R_igraph_correlated_pair_game(SEXP n, SEXP corr, SEXP p, SEXP directed, SEX IGRAPH_FINALLY(igraph_vector_int_destroy, &c_permutation); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_correlated_pair_game(&c_graph1, &c_graph2, c_n, c_corr, c_p, c_directed, (Rf_isNull(permutation) ? 0 : &c_permutation))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_correlated_pair_game(&c_graph1, &c_graph2, c_n, c_corr, c_p, c_directed, (Rf_isNull(permutation) ? NULL : &c_permutation))); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -2199,7 +2320,9 @@ SEXP R_igraph_dot_product_game(SEXP vecs, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_dot_product_game(&c_graph, &c_vecs, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -2213,103 +2336,29 @@ SEXP R_igraph_dot_product_game(SEXP vecs, SEXP directed) { } /*-------------------------------------------/ -/ igraph_sample_sphere_surface / -/-------------------------------------------*/ -SEXP R_igraph_sample_sphere_surface(SEXP dim, SEXP n, SEXP radius, SEXP positive) { - /* Declarations */ - igraph_integer_t c_dim; - igraph_integer_t c_n; - igraph_real_t c_radius; - igraph_bool_t c_positive; - igraph_matrix_t c_res; - SEXP res; - - SEXP r_result; - /* Convert input */ - IGRAPH_R_CHECK_INT(dim); - c_dim = (igraph_integer_t) REAL(dim)[0]; - IGRAPH_R_CHECK_INT(n); - c_n = (igraph_integer_t) REAL(n)[0]; - IGRAPH_R_CHECK_REAL(radius); - c_radius = REAL(radius)[0]; - IGRAPH_R_CHECK_BOOL(positive); - c_positive = LOGICAL(positive)[0]; - IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); - IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); - /* Call igraph */ - IGRAPH_R_CHECK(igraph_sample_sphere_surface(c_dim, c_n, c_radius, c_positive, &c_res)); - - /* Convert output */ - PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); - igraph_matrix_destroy(&c_res); - IGRAPH_FINALLY_CLEAN(1); - r_result = res; - - UNPROTECT(1); - return(r_result); -} - -/*-------------------------------------------/ -/ igraph_sample_sphere_volume / -/-------------------------------------------*/ -SEXP R_igraph_sample_sphere_volume(SEXP dim, SEXP n, SEXP radius, SEXP positive) { - /* Declarations */ - igraph_integer_t c_dim; - igraph_integer_t c_n; - igraph_real_t c_radius; - igraph_bool_t c_positive; - igraph_matrix_t c_res; - SEXP res; - - SEXP r_result; - /* Convert input */ - IGRAPH_R_CHECK_INT(dim); - c_dim = (igraph_integer_t) REAL(dim)[0]; - IGRAPH_R_CHECK_INT(n); - c_n = (igraph_integer_t) REAL(n)[0]; - IGRAPH_R_CHECK_REAL(radius); - c_radius = REAL(radius)[0]; - IGRAPH_R_CHECK_BOOL(positive); - c_positive = LOGICAL(positive)[0]; - IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); - IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); - /* Call igraph */ - IGRAPH_R_CHECK(igraph_sample_sphere_volume(c_dim, c_n, c_radius, c_positive, &c_res)); - - /* Convert output */ - PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); - igraph_matrix_destroy(&c_res); - IGRAPH_FINALLY_CLEAN(1); - r_result = res; - - UNPROTECT(1); - return(r_result); -} - -/*-------------------------------------------/ -/ igraph_sample_dirichlet / +/ igraph_are_adjacent / /-------------------------------------------*/ -SEXP R_igraph_sample_dirichlet(SEXP n, SEXP alpha) { +SEXP R_igraph_are_adjacent(SEXP graph, SEXP v1, SEXP v2) { /* Declarations */ - igraph_integer_t c_n; - igraph_vector_t c_alpha; - igraph_matrix_t c_res; + igraph_t c_graph; + igraph_integer_t c_v1; + igraph_integer_t c_v2; + igraph_bool_t c_res; SEXP res; SEXP r_result; /* Convert input */ - IGRAPH_R_CHECK_INT(n); - c_n = (igraph_integer_t) REAL(n)[0]; - R_SEXP_to_vector(alpha, &c_alpha); - IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); - IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); + R_SEXP_to_igraph(graph, &c_graph); + c_v1 = (igraph_integer_t) REAL(v1)[0]; + c_v2 = (igraph_integer_t) REAL(v2)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_sample_dirichlet(c_n, &c_alpha, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_are_adjacent(&c_graph, c_v1, c_v2, &c_res)); + PutRNGstate(); /* Convert output */ - PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); - igraph_matrix_destroy(&c_res); - IGRAPH_FINALLY_CLEAN(1); + PROTECT(res=NEW_LOGICAL(1)); + LOGICAL(res)[0]=c_res; r_result = res; UNPROTECT(1); @@ -2317,28 +2366,73 @@ SEXP R_igraph_sample_dirichlet(SEXP n, SEXP alpha) { } /*-------------------------------------------/ -/ igraph_are_adjacent / +/ igraph_diameter / /-------------------------------------------*/ -SEXP R_igraph_are_adjacent(SEXP graph, SEXP v1, SEXP v2) { +SEXP R_igraph_diameter(SEXP graph, SEXP weights, SEXP directed, SEXP unconnected) { /* Declarations */ igraph_t c_graph; - igraph_integer_t c_v1; - igraph_integer_t c_v2; - igraph_bool_t c_res; + igraph_vector_t c_weights; + igraph_real_t c_res; + igraph_integer_t c_from; + igraph_integer_t c_to; + igraph_vector_int_t c_vertex_path; + igraph_vector_int_t c_edge_path; + igraph_bool_t c_directed; + igraph_bool_t c_unconnected; SEXP res; + SEXP from; + SEXP to; + SEXP vertex_path; + SEXP edge_path; - SEXP r_result; + SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - c_v1 = (igraph_integer_t) REAL(v1)[0]; - c_v2 = (igraph_integer_t) REAL(v2)[0]; + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } + c_from=0; + c_to=0; + IGRAPH_R_CHECK(igraph_vector_int_init(&c_vertex_path, 0)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vertex_path); + IGRAPH_R_CHECK(igraph_vector_int_init(&c_edge_path, 0)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edge_path); + IGRAPH_R_CHECK_BOOL(directed); + c_directed = LOGICAL(directed)[0]; + IGRAPH_R_CHECK_BOOL(unconnected); + c_unconnected = LOGICAL(unconnected)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_are_adjacent(&c_graph, c_v1, c_v2, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_diameter(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, &c_from, &c_to, &c_vertex_path, &c_edge_path, c_directed, c_unconnected)); + PutRNGstate(); /* Convert output */ - PROTECT(res=NEW_LOGICAL(1)); - LOGICAL(res)[0]=c_res; - r_result = res; + PROTECT(r_result=NEW_LIST(5)); + PROTECT(r_names=NEW_CHARACTER(5)); + PROTECT(res=NEW_NUMERIC(1)); + REAL(res)[0]=c_res; + PROTECT(from=NEW_NUMERIC(1)); + REAL(from)[0]=(double) c_from; + PROTECT(to=NEW_NUMERIC(1)); + REAL(to)[0]=(double) c_to; + PROTECT(vertex_path=R_igraph_vector_int_to_SEXP(&c_vertex_path)); + igraph_vector_int_destroy(&c_vertex_path); + IGRAPH_FINALLY_CLEAN(1); + PROTECT(edge_path=R_igraph_vector_int_to_SEXP(&c_edge_path)); + igraph_vector_int_destroy(&c_edge_path); + IGRAPH_FINALLY_CLEAN(1); + SET_VECTOR_ELT(r_result, 0, res); + SET_VECTOR_ELT(r_result, 1, from); + SET_VECTOR_ELT(r_result, 2, to); + SET_VECTOR_ELT(r_result, 3, vertex_path); + SET_VECTOR_ELT(r_result, 4, edge_path); + SET_STRING_ELT(r_names, 0, Rf_mkChar("res")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("from")); + SET_STRING_ELT(r_names, 2, Rf_mkChar("to")); + SET_STRING_ELT(r_names, 3, Rf_mkChar("vertex_path")); + SET_STRING_ELT(r_names, 4, Rf_mkChar("edge_path")); + SET_NAMES(r_result, r_names); + UNPROTECT(6); UNPROTECT(1); return(r_result); @@ -2377,7 +2471,9 @@ SEXP R_igraph_closeness(SEXP graph, SEXP vids, SEXP mode, SEXP weights, SEXP nor IGRAPH_R_CHECK_BOOL(normalized); c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_closeness(&c_graph, &c_res, &c_reachable_count, &c_all_reachable, c_vids, c_mode, (Rf_isNull(weights) ? 0 : &c_weights), c_normalized)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_closeness(&c_graph, &c_res, &c_reachable_count, &c_all_reachable, c_vids, c_mode, (Rf_isNull(weights) ? NULL : &c_weights), c_normalized)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -2441,7 +2537,9 @@ SEXP R_igraph_closeness_cutoff(SEXP graph, SEXP vids, SEXP mode, SEXP weights, S IGRAPH_R_CHECK_REAL(cutoff); c_cutoff = REAL(cutoff)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_closeness_cutoff(&c_graph, &c_res, &c_reachable_count, &c_all_reachable, c_vids, c_mode, (Rf_isNull(weights) ? 0 : &c_weights), c_normalized, c_cutoff)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_closeness_cutoff(&c_graph, &c_res, &c_reachable_count, &c_all_reachable, c_vids, c_mode, (Rf_isNull(weights) ? NULL : &c_weights), c_normalized, c_cutoff)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -2472,9 +2570,10 @@ SEXP R_igraph_closeness_cutoff(SEXP graph, SEXP vids, SEXP mode, SEXP weights, S /*-------------------------------------------/ / igraph_get_shortest_path / /-------------------------------------------*/ -SEXP R_igraph_get_shortest_path(SEXP graph, SEXP from, SEXP to, SEXP mode) { +SEXP R_igraph_get_shortest_path(SEXP graph, SEXP weights, SEXP from, SEXP to, SEXP mode) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_int_t c_vertices; igraph_vector_int_t c_edges; igraph_integer_t c_from; @@ -2486,6 +2585,9 @@ SEXP R_igraph_get_shortest_path(SEXP graph, SEXP from, SEXP to, SEXP mode) { SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK(igraph_vector_int_init(&c_vertices, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vertices); IGRAPH_R_CHECK(igraph_vector_int_init(&c_edges, 0)); @@ -2494,7 +2596,9 @@ SEXP R_igraph_get_shortest_path(SEXP graph, SEXP from, SEXP to, SEXP mode) { c_to = (igraph_integer_t) REAL(to)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_shortest_path(&c_graph, &c_vertices, &c_edges, c_from, c_to, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_shortest_path(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_vertices, &c_edges, c_from, c_to, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -2545,7 +2649,9 @@ SEXP R_igraph_get_shortest_path_bellman_ford(SEXP graph, SEXP from, SEXP to, SEX } c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_shortest_path_bellman_ford(&c_graph, &c_vertices, &c_edges, c_from, c_to, (Rf_isNull(weights) ? 0 : &c_weights), c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_shortest_path_bellman_ford(&c_graph, &c_vertices, &c_edges, c_from, c_to, (Rf_isNull(weights) ? NULL : &c_weights), c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -2596,7 +2702,9 @@ SEXP R_igraph_get_shortest_path_dijkstra(SEXP graph, SEXP from, SEXP to, SEXP we } c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_shortest_path_dijkstra(&c_graph, &c_vertices, &c_edges, c_from, c_to, (Rf_isNull(weights) ? 0 : &c_weights), c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_shortest_path_dijkstra(&c_graph, &c_vertices, &c_edges, c_from, c_to, (Rf_isNull(weights) ? NULL : &c_weights), c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -2621,9 +2729,10 @@ SEXP R_igraph_get_shortest_path_dijkstra(SEXP graph, SEXP from, SEXP to, SEXP we /*-------------------------------------------/ / igraph_get_all_shortest_paths / /-------------------------------------------*/ -SEXP R_igraph_get_all_shortest_paths(SEXP graph, SEXP from, SEXP to, SEXP mode) { +SEXP R_igraph_get_all_shortest_paths(SEXP graph, SEXP weights, SEXP from, SEXP to, SEXP mode) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_int_list_t c_vertices; igraph_vector_int_list_t c_edges; igraph_vector_int_t c_nrgeo; @@ -2637,10 +2746,17 @@ SEXP R_igraph_get_all_shortest_paths(SEXP graph, SEXP from, SEXP to, SEXP mode) SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_vertices, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_vertices); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_edges, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_edges); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } + if (0 != igraph_vector_int_list_init(&c_vertices, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_vertices); + if (0 != igraph_vector_int_list_init(&c_edges, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_edges); IGRAPH_R_CHECK(igraph_vector_int_init(&c_nrgeo, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_nrgeo); c_from = (igraph_integer_t) REAL(from)[0]; @@ -2648,7 +2764,9 @@ SEXP R_igraph_get_all_shortest_paths(SEXP graph, SEXP from, SEXP to, SEXP mode) R_SEXP_to_igraph_vs(to, &c_graph, &c_to, &c_to_data); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_all_shortest_paths(&c_graph, &c_vertices, &c_edges, &c_nrgeo, c_from, c_to, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_all_shortest_paths(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_vertices, &c_edges, &c_nrgeo, c_from, c_to, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -2697,10 +2815,14 @@ SEXP R_igraph_get_all_shortest_paths_dijkstra(SEXP graph, SEXP from, SEXP to, SE SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_vertices, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_vertices); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_edges, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_edges); + if (0 != igraph_vector_int_list_init(&c_vertices, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_vertices); + if (0 != igraph_vector_int_list_init(&c_edges, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_edges); IGRAPH_R_CHECK(igraph_vector_int_init(&c_nrgeo, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_nrgeo); c_from = (igraph_integer_t) REAL(from)[0]; @@ -2711,7 +2833,9 @@ SEXP R_igraph_get_all_shortest_paths_dijkstra(SEXP graph, SEXP from, SEXP to, SE } c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_all_shortest_paths_dijkstra(&c_graph, &c_vertices, &c_edges, &c_nrgeo, c_from, c_to, (Rf_isNull(weights) ? 0 : &c_weights), c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_all_shortest_paths_dijkstra(&c_graph, &c_vertices, &c_edges, &c_nrgeo, c_from, c_to, (Rf_isNull(weights) ? NULL : &c_weights), c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -2770,7 +2894,9 @@ SEXP R_igraph_voronoi(SEXP graph, SEXP generators, SEXP weights, SEXP mode, SEXP c_mode = (igraph_neimode_t) Rf_asInteger(mode); c_tiebreaker = (igraph_voronoi_tiebreaker_t) Rf_asInteger(tiebreaker); /* Call igraph */ - IGRAPH_R_CHECK(igraph_voronoi(&c_graph, &c_membership, &c_distances, &c_generators, (Rf_isNull(weights) ? 0 : &c_weights), c_mode, c_tiebreaker)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_voronoi(&c_graph, &c_membership, &c_distances, &c_generators, (Rf_isNull(weights) ? NULL : &c_weights), c_mode, c_tiebreaker)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -2797,33 +2923,43 @@ SEXP R_igraph_voronoi(SEXP graph, SEXP generators, SEXP weights, SEXP mode, SEXP /*-------------------------------------------/ / igraph_get_all_simple_paths / /-------------------------------------------*/ -SEXP R_igraph_get_all_simple_paths(SEXP graph, SEXP from, SEXP to, SEXP cutoff, SEXP mode) { +SEXP R_igraph_get_all_simple_paths(SEXP graph, SEXP from, SEXP to, SEXP mode, SEXP minlen, SEXP maxlen, SEXP max_results) { /* Declarations */ igraph_t c_graph; - igraph_vector_int_t c_res; + igraph_vector_int_list_t c_res; igraph_integer_t c_from; igraph_vs_t c_to; - igraph_integer_t c_cutoff; igraph_neimode_t c_mode; + igraph_integer_t c_minlen; + igraph_integer_t c_maxlen; + igraph_integer_t c_max_results; SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_init(&c_res, 0)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_res); + if (0 != igraph_vector_int_list_init(&c_res, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_res); c_from = (igraph_integer_t) REAL(from)[0]; igraph_vector_int_t c_to_data; R_SEXP_to_igraph_vs(to, &c_graph, &c_to, &c_to_data); - IGRAPH_R_CHECK_INT(cutoff); - c_cutoff = (igraph_integer_t) REAL(cutoff)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); + IGRAPH_R_CHECK_INT(minlen); + c_minlen = (igraph_integer_t) REAL(minlen)[0]; + IGRAPH_R_CHECK_INT(maxlen); + c_maxlen = (igraph_integer_t) REAL(maxlen)[0]; + IGRAPH_R_CHECK_INT(max_results); + c_max_results = (igraph_integer_t) REAL(max_results)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_all_simple_paths(&c_graph, &c_res, c_from, c_to, c_cutoff, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_all_simple_paths(&c_graph, &c_res, c_from, c_to, c_mode, c_minlen, c_maxlen, c_max_results)); + PutRNGstate(); /* Convert output */ - PROTECT(res=R_igraph_vector_int_to_SEXPp1(&c_res)); - igraph_vector_int_destroy(&c_res); + PROTECT(res=R_igraph_vector_int_list_to_SEXPp1(&c_res)); + igraph_vector_int_list_destroy(&c_res); IGRAPH_FINALLY_CLEAN(1); igraph_vector_int_destroy(&c_to_data); igraph_vs_destroy(&c_to); @@ -2855,17 +2991,23 @@ SEXP R_igraph_get_k_shortest_paths(SEXP graph, SEXP weights, SEXP k, SEXP from, if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_vertex_paths, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_vertex_paths); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_edge_paths, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_edge_paths); + if (0 != igraph_vector_int_list_init(&c_vertex_paths, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_vertex_paths); + if (0 != igraph_vector_int_list_init(&c_edge_paths, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_edge_paths); IGRAPH_R_CHECK_INT(k); c_k = (igraph_integer_t) REAL(k)[0]; c_from = (igraph_integer_t) REAL(from)[0]; c_to = (igraph_integer_t) REAL(to)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_k_shortest_paths(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_vertex_paths, &c_edge_paths, c_k, c_from, c_to, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_k_shortest_paths(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_vertex_paths, &c_edge_paths, c_k, c_from, c_to, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -2914,7 +3056,9 @@ SEXP R_igraph_get_widest_path(SEXP graph, SEXP from, SEXP to, SEXP weights, SEXP R_SEXP_to_vector(weights, &c_weights); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_get_widest_path(&c_graph, &c_vertices, &c_edges, c_from, c_to, &c_weights, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -2958,10 +3102,14 @@ SEXP R_igraph_get_widest_paths(SEXP graph, SEXP from, SEXP to, SEXP weights, SEX SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_vertices, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_vertices); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_edges, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_edges); + if (0 != igraph_vector_int_list_init(&c_vertices, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_vertices); + if (0 != igraph_vector_int_list_init(&c_edges, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_edges); c_from = (igraph_integer_t) REAL(from)[0]; igraph_vector_int_t c_to_data; R_SEXP_to_igraph_vs(to, &c_graph, &c_to, &c_to_data); @@ -2972,7 +3120,9 @@ SEXP R_igraph_get_widest_paths(SEXP graph, SEXP from, SEXP to, SEXP weights, SEX IGRAPH_R_CHECK(igraph_vector_int_init(&c_inbound_edges, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_inbound_edges); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_get_widest_paths(&c_graph, &c_vertices, &c_edges, c_from, c_to, &c_weights, c_mode, &c_parents, &c_inbound_edges)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(4)); @@ -3031,7 +3181,9 @@ SEXP R_igraph_widest_path_widths_dijkstra(SEXP graph, SEXP from, SEXP to, SEXP w R_SEXP_to_vector(weights, &c_weights); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_widest_path_widths_dijkstra(&c_graph, &c_res, c_from, c_to, &c_weights, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -3072,7 +3224,9 @@ SEXP R_igraph_widest_path_widths_floyd_warshall(SEXP graph, SEXP from, SEXP to, R_SEXP_to_vector(weights, &c_weights); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_widest_path_widths_floyd_warshall(&c_graph, &c_res, c_from, c_to, &c_weights, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -3110,7 +3264,9 @@ SEXP R_igraph_spanner(SEXP graph, SEXP stretch, SEXP weights) { R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_spanner(&c_graph, &c_spanner, c_stretch, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_spanner(&c_graph, &c_spanner, c_stretch, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ PROTECT(spanner=R_igraph_vector_int_to_SEXPp1(&c_spanner)); @@ -3125,32 +3281,37 @@ SEXP R_igraph_spanner(SEXP graph, SEXP stretch, SEXP weights) { /*-------------------------------------------/ / igraph_betweenness_cutoff / /-------------------------------------------*/ -SEXP R_igraph_betweenness_cutoff(SEXP graph, SEXP vids, SEXP directed, SEXP weights, SEXP cutoff) { +SEXP R_igraph_betweenness_cutoff(SEXP graph, SEXP weights, SEXP vids, SEXP directed, SEXP normalized, SEXP cutoff) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_t c_res; igraph_vs_t c_vids; igraph_bool_t c_directed; - igraph_vector_t c_weights; + igraph_bool_t c_normalized; igraph_real_t c_cutoff; SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK(igraph_vector_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_res); igraph_vector_int_t c_vids_data; R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } + IGRAPH_R_CHECK_BOOL(normalized); + c_normalized = LOGICAL(normalized)[0]; IGRAPH_R_CHECK_REAL(cutoff); c_cutoff = REAL(cutoff)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_betweenness_cutoff(&c_graph, &c_res, c_vids, c_directed, (Rf_isNull(weights) ? 0 : &c_weights), c_cutoff)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_betweenness_cutoff(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_vids, c_directed, c_normalized, c_cutoff)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -3167,35 +3328,40 @@ SEXP R_igraph_betweenness_cutoff(SEXP graph, SEXP vids, SEXP directed, SEXP weig /*-------------------------------------------/ / igraph_betweenness_subset / /-------------------------------------------*/ -SEXP R_igraph_betweenness_subset(SEXP graph, SEXP vids, SEXP directed, SEXP sources, SEXP targets, SEXP weights) { +SEXP R_igraph_betweenness_subset(SEXP graph, SEXP weights, SEXP vids, SEXP sources, SEXP targets, SEXP directed, SEXP normalized) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_t c_res; igraph_vs_t c_vids; - igraph_bool_t c_directed; igraph_vs_t c_sources; igraph_vs_t c_targets; - igraph_vector_t c_weights; + igraph_bool_t c_directed; + igraph_bool_t c_normalized; SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK(igraph_vector_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_res); igraph_vector_int_t c_vids_data; R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); - IGRAPH_R_CHECK_BOOL(directed); - c_directed = LOGICAL(directed)[0]; igraph_vector_int_t c_sources_data; R_SEXP_to_igraph_vs(sources, &c_graph, &c_sources, &c_sources_data); igraph_vector_int_t c_targets_data; R_SEXP_to_igraph_vs(targets, &c_graph, &c_targets, &c_targets_data); - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } + IGRAPH_R_CHECK_BOOL(directed); + c_directed = LOGICAL(directed)[0]; + IGRAPH_R_CHECK_BOOL(normalized); + c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_betweenness_subset(&c_graph, &c_res, c_vids, c_directed, c_sources, c_targets, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_betweenness_subset(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_vids, c_sources, c_targets, c_directed, c_normalized)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -3216,31 +3382,41 @@ SEXP R_igraph_betweenness_subset(SEXP graph, SEXP vids, SEXP directed, SEXP sour /*-------------------------------------------/ / igraph_edge_betweenness / /-------------------------------------------*/ -SEXP R_igraph_edge_betweenness(SEXP graph, SEXP directed, SEXP weights) { +SEXP R_igraph_edge_betweenness(SEXP graph, SEXP weights, SEXP eids, SEXP directed, SEXP normalized) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_t c_res; + igraph_es_t c_eids; igraph_bool_t c_directed; - igraph_vector_t c_weights; + igraph_bool_t c_normalized; SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK(igraph_vector_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_res); + igraph_vector_int_t c_eids_data; + IGRAPH_R_CHECK(R_SEXP_to_igraph_es(eids, &c_graph, &c_eids, &c_eids_data)); IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } + IGRAPH_R_CHECK_BOOL(normalized); + c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_edge_betweenness(&c_graph, &c_res, c_directed, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_edge_betweenness(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_eids, c_directed, c_normalized)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); igraph_vector_destroy(&c_res); IGRAPH_FINALLY_CLEAN(1); + igraph_vector_int_destroy(&c_eids_data); + igraph_es_destroy(&c_eids); r_result = res; UNPROTECT(1); @@ -3250,34 +3426,44 @@ SEXP R_igraph_edge_betweenness(SEXP graph, SEXP directed, SEXP weights) { /*-------------------------------------------/ / igraph_edge_betweenness_cutoff / /-------------------------------------------*/ -SEXP R_igraph_edge_betweenness_cutoff(SEXP graph, SEXP directed, SEXP weights, SEXP cutoff) { +SEXP R_igraph_edge_betweenness_cutoff(SEXP graph, SEXP weights, SEXP eids, SEXP directed, SEXP normalized, SEXP cutoff) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_t c_res; + igraph_es_t c_eids; igraph_bool_t c_directed; - igraph_vector_t c_weights; + igraph_bool_t c_normalized; igraph_real_t c_cutoff; SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK(igraph_vector_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_res); + igraph_vector_int_t c_eids_data; + IGRAPH_R_CHECK(R_SEXP_to_igraph_es(eids, &c_graph, &c_eids, &c_eids_data)); IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } + IGRAPH_R_CHECK_BOOL(normalized); + c_normalized = LOGICAL(normalized)[0]; IGRAPH_R_CHECK_REAL(cutoff); c_cutoff = REAL(cutoff)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_edge_betweenness_cutoff(&c_graph, &c_res, c_directed, (Rf_isNull(weights) ? 0 : &c_weights), c_cutoff)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_edge_betweenness_cutoff(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_eids, c_directed, c_normalized, c_cutoff)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); igraph_vector_destroy(&c_res); IGRAPH_FINALLY_CLEAN(1); + igraph_vector_int_destroy(&c_eids_data); + igraph_es_destroy(&c_eids); r_result = res; UNPROTECT(1); @@ -3287,46 +3473,51 @@ SEXP R_igraph_edge_betweenness_cutoff(SEXP graph, SEXP directed, SEXP weights, S /*-------------------------------------------/ / igraph_edge_betweenness_subset / /-------------------------------------------*/ -SEXP R_igraph_edge_betweenness_subset(SEXP graph, SEXP eids, SEXP directed, SEXP sources, SEXP targets, SEXP weights) { +SEXP R_igraph_edge_betweenness_subset(SEXP graph, SEXP weights, SEXP sources, SEXP targets, SEXP eids, SEXP directed, SEXP normalized) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_t c_res; - igraph_es_t c_eids; - igraph_bool_t c_directed; igraph_vs_t c_sources; igraph_vs_t c_targets; - igraph_vector_t c_weights; + igraph_es_t c_eids; + igraph_bool_t c_directed; + igraph_bool_t c_normalized; SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK(igraph_vector_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_res); - igraph_vector_int_t c_eids_data; - IGRAPH_R_CHECK(R_SEXP_to_igraph_es(eids, &c_graph, &c_eids, &c_eids_data)); - IGRAPH_R_CHECK_BOOL(directed); - c_directed = LOGICAL(directed)[0]; igraph_vector_int_t c_sources_data; R_SEXP_to_igraph_vs(sources, &c_graph, &c_sources, &c_sources_data); igraph_vector_int_t c_targets_data; R_SEXP_to_igraph_vs(targets, &c_graph, &c_targets, &c_targets_data); - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } + igraph_vector_int_t c_eids_data; + IGRAPH_R_CHECK(R_SEXP_to_igraph_es(eids, &c_graph, &c_eids, &c_eids_data)); + IGRAPH_R_CHECK_BOOL(directed); + c_directed = LOGICAL(directed)[0]; + IGRAPH_R_CHECK_BOOL(normalized); + c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_edge_betweenness_subset(&c_graph, &c_res, c_eids, c_directed, c_sources, c_targets, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_edge_betweenness_subset(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_sources, c_targets, c_eids, c_directed, c_normalized)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); igraph_vector_destroy(&c_res); IGRAPH_FINALLY_CLEAN(1); - igraph_vector_int_destroy(&c_eids_data); - igraph_es_destroy(&c_eids); igraph_vector_int_destroy(&c_sources_data); igraph_vs_destroy(&c_sources); igraph_vector_int_destroy(&c_targets_data); igraph_vs_destroy(&c_targets); + igraph_vector_int_destroy(&c_eids_data); + igraph_es_destroy(&c_eids); r_result = res; UNPROTECT(1); @@ -3363,7 +3554,9 @@ SEXP R_igraph_harmonic_centrality_cutoff(SEXP graph, SEXP vids, SEXP mode, SEXP IGRAPH_R_CHECK_REAL(cutoff); c_cutoff = REAL(cutoff)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_harmonic_centrality_cutoff(&c_graph, &c_res, c_vids, c_mode, (Rf_isNull(weights) ? 0 : &c_weights), c_normalized, c_cutoff)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_harmonic_centrality_cutoff(&c_graph, &c_res, c_vids, c_mode, (Rf_isNull(weights) ? NULL : &c_weights), c_normalized, c_cutoff)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -3380,17 +3573,17 @@ SEXP R_igraph_harmonic_centrality_cutoff(SEXP graph, SEXP vids, SEXP mode, SEXP /*-------------------------------------------/ / igraph_personalized_pagerank / /-------------------------------------------*/ -SEXP R_igraph_personalized_pagerank(SEXP graph, SEXP algo, SEXP vids, SEXP directed, SEXP damping, SEXP personalized, SEXP weights, SEXP options) { +SEXP R_igraph_personalized_pagerank(SEXP graph, SEXP weights, SEXP reset, SEXP damping, SEXP directed, SEXP vids, SEXP algo, SEXP options) { /* Declarations */ igraph_t c_graph; - igraph_pagerank_algo_t c_algo; + igraph_vector_t c_weights; igraph_vector_t c_vector; igraph_real_t c_value; - igraph_vs_t c_vids; - igraph_bool_t c_directed; + igraph_vector_t c_reset; igraph_real_t c_damping; - igraph_vector_t c_personalized; - igraph_vector_t c_weights; + igraph_bool_t c_directed; + igraph_vs_t c_vids; + igraph_pagerank_algo_t c_algo; igraph_arpack_options_t c_options1; void* c_options; SEXP vector; @@ -3399,21 +3592,21 @@ SEXP R_igraph_personalized_pagerank(SEXP graph, SEXP algo, SEXP vids, SEXP direc SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - c_algo = (igraph_pagerank_algo_t) Rf_asInteger(algo); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK(igraph_vector_init(&c_vector, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_vector); - igraph_vector_int_t c_vids_data; - R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); - IGRAPH_R_CHECK_BOOL(directed); - c_directed = LOGICAL(directed)[0]; + if (!Rf_isNull(reset)) { + R_SEXP_to_vector(reset, &c_reset); + } IGRAPH_R_CHECK_REAL(damping); c_damping = REAL(damping)[0]; - if (!Rf_isNull(personalized)) { - R_SEXP_to_vector(personalized, &c_personalized); - } - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } + IGRAPH_R_CHECK_BOOL(directed); + c_directed = LOGICAL(directed)[0]; + igraph_vector_int_t c_vids_data; + R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); + c_algo = (igraph_pagerank_algo_t) Rf_asInteger(algo); if (!Rf_isNull(options)) { if (c_algo == IGRAPH_PAGERANK_ALGO_ARPACK) { R_SEXP_to_igraph_arpack_options(options, &c_options1); @@ -3423,7 +3616,9 @@ SEXP R_igraph_personalized_pagerank(SEXP graph, SEXP algo, SEXP vids, SEXP direc } } /* Call igraph */ - IGRAPH_R_CHECK(igraph_personalized_pagerank(&c_graph, c_algo, &c_vector, &c_value, c_vids, c_directed, c_damping, (Rf_isNull(personalized) ? 0 : &c_personalized), (Rf_isNull(weights) ? 0 : &c_weights), c_options)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_personalized_pagerank(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_vector, &c_value, (Rf_isNull(reset) ? NULL : &c_reset), c_damping, c_directed, c_vids, c_algo, c_options)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -3456,17 +3651,17 @@ SEXP R_igraph_personalized_pagerank(SEXP graph, SEXP algo, SEXP vids, SEXP direc /*-------------------------------------------/ / igraph_personalized_pagerank_vs / /-------------------------------------------*/ -SEXP R_igraph_personalized_pagerank_vs(SEXP graph, SEXP algo, SEXP vids, SEXP directed, SEXP damping, SEXP reset_vids, SEXP weights, SEXP options) { +SEXP R_igraph_personalized_pagerank_vs(SEXP graph, SEXP weights, SEXP reset_vids, SEXP damping, SEXP directed, SEXP vids, SEXP algo, SEXP options) { /* Declarations */ igraph_t c_graph; - igraph_pagerank_algo_t c_algo; + igraph_vector_t c_weights; igraph_vector_t c_vector; igraph_real_t c_value; - igraph_vs_t c_vids; - igraph_bool_t c_directed; - igraph_real_t c_damping; igraph_vs_t c_reset_vids; - igraph_vector_t c_weights; + igraph_real_t c_damping; + igraph_bool_t c_directed; + igraph_vs_t c_vids; + igraph_pagerank_algo_t c_algo; igraph_arpack_options_t c_options1; void* c_options; SEXP vector; @@ -3475,20 +3670,20 @@ SEXP R_igraph_personalized_pagerank_vs(SEXP graph, SEXP algo, SEXP vids, SEXP di SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - c_algo = (igraph_pagerank_algo_t) Rf_asInteger(algo); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK(igraph_vector_init(&c_vector, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_vector); - igraph_vector_int_t c_vids_data; - R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); - IGRAPH_R_CHECK_BOOL(directed); - c_directed = LOGICAL(directed)[0]; - IGRAPH_R_CHECK_REAL(damping); - c_damping = REAL(damping)[0]; igraph_vector_int_t c_reset_vids_data; R_SEXP_to_igraph_vs(reset_vids, &c_graph, &c_reset_vids, &c_reset_vids_data); - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } + IGRAPH_R_CHECK_REAL(damping); + c_damping = REAL(damping)[0]; + IGRAPH_R_CHECK_BOOL(directed); + c_directed = LOGICAL(directed)[0]; + igraph_vector_int_t c_vids_data; + R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); + c_algo = (igraph_pagerank_algo_t) Rf_asInteger(algo); if (!Rf_isNull(options)) { if (c_algo == IGRAPH_PAGERANK_ALGO_ARPACK) { R_SEXP_to_igraph_arpack_options(options, &c_options1); @@ -3498,7 +3693,9 @@ SEXP R_igraph_personalized_pagerank_vs(SEXP graph, SEXP algo, SEXP vids, SEXP di } } /* Call igraph */ - IGRAPH_R_CHECK(igraph_personalized_pagerank_vs(&c_graph, c_algo, &c_vector, &c_value, c_vids, c_directed, c_damping, c_reset_vids, (Rf_isNull(weights) ? 0 : &c_weights), c_options)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_personalized_pagerank_vs(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_vector, &c_value, c_reset_vids, c_damping, c_directed, c_vids, c_algo, c_options)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -3508,10 +3705,10 @@ SEXP R_igraph_personalized_pagerank_vs(SEXP graph, SEXP algo, SEXP vids, SEXP di IGRAPH_FINALLY_CLEAN(1); PROTECT(value=NEW_NUMERIC(1)); REAL(value)[0]=c_value; - igraph_vector_int_destroy(&c_vids_data); - igraph_vs_destroy(&c_vids); igraph_vector_int_destroy(&c_reset_vids_data); igraph_vs_destroy(&c_reset_vids); + igraph_vector_int_destroy(&c_vids_data); + igraph_vs_destroy(&c_vids); if (c_algo == IGRAPH_PAGERANK_ALGO_ARPACK) { PROTECT(options = Rx_igraph_arpack_options_to_SEXP(&c_options1)); } else { @@ -3533,27 +3730,38 @@ SEXP R_igraph_personalized_pagerank_vs(SEXP graph, SEXP algo, SEXP vids, SEXP di /*-------------------------------------------/ / igraph_rewire / /-------------------------------------------*/ -SEXP R_igraph_rewire(SEXP rewire, SEXP n, SEXP mode) { +SEXP R_igraph_rewire(SEXP rewire, SEXP n, SEXP allowed_edge_types) { /* Declarations */ igraph_t c_rewire; igraph_integer_t c_n; - igraph_rewiring_t c_mode; + igraph_edge_type_sw_t c_allowed_edge_types; + igraph_rewiring_stats_t c_stats; + SEXP stats; - SEXP r_result; + SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph_copy(rewire, &c_rewire); IGRAPH_FINALLY(igraph_destroy, &c_rewire); IGRAPH_R_CHECK_INT(n); c_n = (igraph_integer_t) REAL(n)[0]; - c_mode = (igraph_rewiring_t) Rf_asInteger(mode); + c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); /* Call igraph */ - IGRAPH_R_CHECK(igraph_rewire(&c_rewire, c_n, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_rewire(&c_rewire, c_n, c_allowed_edge_types, &c_stats)); + PutRNGstate(); /* Convert output */ + PROTECT(r_result=NEW_LIST(2)); + PROTECT(r_names=NEW_CHARACTER(2)); PROTECT(rewire=R_igraph_to_SEXP(&c_rewire)); IGRAPH_I_DESTROY(&c_rewire); IGRAPH_FINALLY_CLEAN(1); - r_result = rewire; + SET_VECTOR_ELT(r_result, 0, rewire); + SET_VECTOR_ELT(r_result, 1, stats); + SET_STRING_ELT(r_names, 0, Rf_mkChar("rewire")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("stats")); + SET_NAMES(r_result, r_names); + UNPROTECT(3); UNPROTECT(1); return(r_result); @@ -3577,7 +3785,9 @@ SEXP R_igraph_induced_subgraph(SEXP graph, SEXP vids, SEXP impl) { R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); c_impl = (igraph_subgraph_implementation_t) Rf_asInteger(impl); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_induced_subgraph(&c_graph, &c_res, c_vids, c_impl)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -3611,7 +3821,9 @@ SEXP R_igraph_subgraph_from_edges(SEXP graph, SEXP eids, SEXP delete_vertices) { IGRAPH_R_CHECK_BOOL(delete_vertices); c_delete_vertices = LOGICAL(delete_vertices)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_subgraph_from_edges(&c_graph, &c_res, c_eids, c_delete_vertices)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -3641,7 +3853,9 @@ SEXP R_igraph_reverse_edges(SEXP graph, SEXP eids) { igraph_vector_int_t c_eids_data; IGRAPH_R_CHECK(R_SEXP_to_igraph_es(eids, &c_graph, &c_eids, &c_eids_data)); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_reverse_edges(&c_graph, c_eids)); + PutRNGstate(); /* Convert output */ PROTECT(graph=R_igraph_to_SEXP(&c_graph)); @@ -3656,14 +3870,14 @@ SEXP R_igraph_reverse_edges(SEXP graph, SEXP eids) { } /*-------------------------------------------/ -/ igraph_average_path_length_dijkstra / +/ igraph_average_path_length / /-------------------------------------------*/ -SEXP R_igraph_average_path_length_dijkstra(SEXP graph, SEXP weights, SEXP directed, SEXP unconn) { +SEXP R_igraph_average_path_length(SEXP graph, SEXP weights, SEXP directed, SEXP unconn) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_real_t c_res; igraph_real_t c_unconn_pairs; - igraph_vector_t c_weights; igraph_bool_t c_directed; igraph_bool_t c_unconn; SEXP res; @@ -3680,7 +3894,9 @@ SEXP R_igraph_average_path_length_dijkstra(SEXP graph, SEXP weights, SEXP direct IGRAPH_R_CHECK_BOOL(unconn); c_unconn = LOGICAL(unconn)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_average_path_length_dijkstra(&c_graph, &c_res, &c_unconn_pairs, (Rf_isNull(weights) ? 0 : &c_weights), c_directed, c_unconn)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_average_path_length(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, &c_unconn_pairs, c_directed, c_unconn)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -3692,7 +3908,7 @@ SEXP R_igraph_average_path_length_dijkstra(SEXP graph, SEXP weights, SEXP direct SET_VECTOR_ELT(r_result, 0, res); SET_VECTOR_ELT(r_result, 1, unconn_pairs); SET_STRING_ELT(r_names, 0, Rf_mkChar("res")); - SET_STRING_ELT(r_names, 1, Rf_mkChar("unconnected")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("unconn_pairs")); SET_NAMES(r_result, r_names); UNPROTECT(3); @@ -3720,7 +3936,9 @@ SEXP R_igraph_path_length_hist(SEXP graph, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_path_length_hist(&c_graph, &c_res, &c_unconnected, c_directed)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -3762,7 +3980,9 @@ SEXP R_igraph_simplify(SEXP graph, SEXP remove_multiple, SEXP remove_loops, SEXP R_SEXP_to_attr_comb(edge_attr_comb, &c_edge_attr_comb); IGRAPH_FINALLY(igraph_attribute_combination_destroy, &c_edge_attr_comb); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_simplify(&c_graph, c_remove_multiple, c_remove_loops, &c_edge_attr_comb)); + PutRNGstate(); /* Convert output */ PROTECT(graph=R_igraph_to_SEXP(&c_graph)); @@ -3791,7 +4011,9 @@ SEXP R_igraph_transitivity_undirected(SEXP graph, SEXP mode) { R_SEXP_to_igraph(graph, &c_graph); c_mode = (igraph_transitivity_mode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_transitivity_undirected(&c_graph, &c_res, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -3822,7 +4044,9 @@ SEXP R_igraph_transitivity_local_undirected(SEXP graph, SEXP vids, SEXP mode) { R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); c_mode = (igraph_transitivity_mode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_transitivity_local_undirected(&c_graph, &c_res, c_vids, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -3851,7 +4075,9 @@ SEXP R_igraph_transitivity_avglocal_undirected(SEXP graph, SEXP mode) { R_SEXP_to_igraph(graph, &c_graph); c_mode = (igraph_transitivity_mode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_transitivity_avglocal_undirected(&c_graph, &c_res, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -3886,7 +4112,9 @@ SEXP R_igraph_transitivity_barrat(SEXP graph, SEXP vids, SEXP weights, SEXP mode } c_mode = (igraph_transitivity_mode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_transitivity_barrat(&c_graph, &c_res, c_vids, (Rf_isNull(weights) ? 0 : &c_weights), c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_transitivity_barrat(&c_graph, &c_res, c_vids, (Rf_isNull(weights) ? NULL : &c_weights), c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -3927,7 +4155,9 @@ SEXP R_igraph_ecc(SEXP graph, SEXP eids, SEXP k, SEXP offset, SEXP normalize) { IGRAPH_R_CHECK_BOOL(normalize); c_normalize = LOGICAL(normalize)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_ecc(&c_graph, &c_res, c_eids, c_k, c_offset, c_normalize)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -3959,7 +4189,9 @@ SEXP R_igraph_reciprocity(SEXP graph, SEXP ignore_loops, SEXP mode) { c_ignore_loops = LOGICAL(ignore_loops)[0]; c_mode = (igraph_reciprocity_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_reciprocity(&c_graph, &c_res, c_ignore_loops, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -3992,7 +4224,9 @@ SEXP R_igraph_constraint(SEXP graph, SEXP vids, SEXP weights) { R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_constraint(&c_graph, &c_res, c_vids, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_constraint(&c_graph, &c_res, c_vids, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -4015,7 +4249,7 @@ SEXP R_igraph_maxdegree(SEXP graph, SEXP vids, SEXP mode, SEXP loops) { igraph_integer_t c_res; igraph_vs_t c_vids; igraph_neimode_t c_mode; - igraph_bool_t c_loops; + igraph_loops_t c_loops; SEXP res; SEXP r_result; @@ -4025,10 +4259,11 @@ SEXP R_igraph_maxdegree(SEXP graph, SEXP vids, SEXP mode, SEXP loops) { igraph_vector_int_t c_vids_data; R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); c_mode = (igraph_neimode_t) Rf_asInteger(mode); - IGRAPH_R_CHECK_BOOL(loops); - c_loops = LOGICAL(loops)[0]; + c_loops = (igraph_loops_t) Rf_asInteger(loops); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_maxdegree(&c_graph, &c_res, c_vids, c_mode, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -4044,9 +4279,10 @@ SEXP R_igraph_maxdegree(SEXP graph, SEXP vids, SEXP mode, SEXP loops) { /*-------------------------------------------/ / igraph_density / /-------------------------------------------*/ -SEXP R_igraph_density(SEXP graph, SEXP loops) { +SEXP R_igraph_density(SEXP graph, SEXP weights, SEXP loops) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_real_t c_res; igraph_bool_t c_loops; SEXP res; @@ -4054,10 +4290,15 @@ SEXP R_igraph_density(SEXP graph, SEXP loops) { SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_density(&c_graph, &c_res, c_loops)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_density(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -4084,7 +4325,9 @@ SEXP R_igraph_mean_degree(SEXP graph, SEXP loops) { IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_mean_degree(&c_graph, &c_res, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -4112,7 +4355,9 @@ SEXP R_igraph_topological_sorting(SEXP graph, SEXP mode) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_res); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_topological_sorting(&c_graph, &c_res, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_to_SEXP(&c_res)); @@ -4145,7 +4390,9 @@ SEXP R_igraph_feedback_arc_set(SEXP graph, SEXP weights, SEXP algo) { } c_algo = (igraph_fas_algorithm_t) Rf_asInteger(algo); /* Call igraph */ - IGRAPH_R_CHECK(igraph_feedback_arc_set(&c_graph, &c_result, (Rf_isNull(weights) ? 0 : &c_weights), c_algo)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_feedback_arc_set(&c_graph, &c_result, (Rf_isNull(weights) ? NULL : &c_weights), c_algo)); + PutRNGstate(); /* Convert output */ PROTECT(result=R_igraph_vector_int_to_SEXPp1(&c_result)); @@ -4178,7 +4425,9 @@ SEXP R_igraph_feedback_vertex_set(SEXP graph, SEXP weights, SEXP algo) { } c_algo = (igraph_fvs_algorithm_t) Rf_asInteger(algo); /* Call igraph */ - IGRAPH_R_CHECK(igraph_feedback_vertex_set(&c_graph, &c_result, (Rf_isNull(weights) ? 0 : &c_weights), c_algo)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_feedback_vertex_set(&c_graph, &c_result, (Rf_isNull(weights) ? NULL : &c_weights), c_algo)); + PutRNGstate(); /* Convert output */ PROTECT(result=R_igraph_vector_int_to_SEXPp1(&c_result)); @@ -4208,7 +4457,9 @@ SEXP R_igraph_is_loop(SEXP graph, SEXP es) { igraph_vector_int_t c_es_data; IGRAPH_R_CHECK(R_SEXP_to_igraph_es(es, &c_graph, &c_es, &c_es_data)); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_loop(&c_graph, &c_res, c_es)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_bool_to_SEXP(&c_res)); @@ -4235,7 +4486,9 @@ SEXP R_igraph_is_dag(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_dag(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_LOGICAL(1)); @@ -4259,7 +4512,9 @@ SEXP R_igraph_is_acyclic(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_acyclic(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_LOGICAL(1)); @@ -4273,17 +4528,22 @@ SEXP R_igraph_is_acyclic(SEXP graph) { /*-------------------------------------------/ / igraph_is_simple / /-------------------------------------------*/ -SEXP R_igraph_is_simple(SEXP graph) { +SEXP R_igraph_is_simple(SEXP graph, SEXP directed) { /* Declarations */ igraph_t c_graph; igraph_bool_t c_res; + igraph_bool_t c_directed; SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + IGRAPH_R_CHECK_BOOL(directed); + c_directed = LOGICAL(directed)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_is_simple(&c_graph, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_is_simple(&c_graph, &c_res, c_directed)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_LOGICAL(1)); @@ -4312,7 +4572,9 @@ SEXP R_igraph_is_multiple(SEXP graph, SEXP es) { igraph_vector_int_t c_es_data; IGRAPH_R_CHECK(R_SEXP_to_igraph_es(es, &c_graph, &c_es, &c_es_data)); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_multiple(&c_graph, &c_res, c_es)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_bool_to_SEXP(&c_res)); @@ -4339,7 +4601,9 @@ SEXP R_igraph_has_loop(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_has_loop(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_LOGICAL(1)); @@ -4363,7 +4627,9 @@ SEXP R_igraph_has_multiple(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_has_multiple(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_LOGICAL(1)); @@ -4388,7 +4654,9 @@ SEXP R_igraph_count_loops(SEXP graph) { R_SEXP_to_igraph(graph, &c_graph); c_loop_count=0; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_count_loops(&c_graph, &c_loop_count)); + PutRNGstate(); /* Convert output */ PROTECT(loop_count=NEW_NUMERIC(1)); @@ -4417,7 +4685,9 @@ SEXP R_igraph_count_multiple(SEXP graph, SEXP es) { igraph_vector_int_t c_es_data; IGRAPH_R_CHECK(R_SEXP_to_igraph_es(es, &c_graph, &c_es, &c_es_data)); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_count_multiple(&c_graph, &c_res, c_es)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_to_SEXP(&c_res)); @@ -4438,30 +4708,32 @@ SEXP R_igraph_girth(SEXP graph) { /* Declarations */ igraph_t c_graph; igraph_real_t c_girth; - igraph_vector_int_t c_circle; + igraph_vector_int_t c_cycle; SEXP girth; - SEXP circle; + SEXP cycle; SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_init(&c_circle, 0)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_circle); + IGRAPH_R_CHECK(igraph_vector_int_init(&c_cycle, 0)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_cycle); /* Call igraph */ - IGRAPH_R_CHECK(igraph_girth(&c_graph, &c_girth, &c_circle)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_girth(&c_graph, &c_girth, &c_cycle)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); PROTECT(r_names=NEW_CHARACTER(2)); PROTECT(girth=NEW_NUMERIC(1)); REAL(girth)[0]=c_girth; - PROTECT(circle=R_igraph_vector_int_to_SEXPp1(&c_circle)); - igraph_vector_int_destroy(&c_circle); + PROTECT(cycle=R_igraph_vector_int_to_SEXPp1(&c_cycle)); + igraph_vector_int_destroy(&c_cycle); IGRAPH_FINALLY_CLEAN(1); SET_VECTOR_ELT(r_result, 0, girth); - SET_VECTOR_ELT(r_result, 1, circle); + SET_VECTOR_ELT(r_result, 1, cycle); SET_STRING_ELT(r_names, 0, Rf_mkChar("girth")); - SET_STRING_ELT(r_names, 1, Rf_mkChar("circle")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("cycle")); SET_NAMES(r_result, r_names); UNPROTECT(3); @@ -4482,7 +4754,9 @@ SEXP R_igraph_is_perfect(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_perfect(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_LOGICAL(1)); @@ -4496,13 +4770,12 @@ SEXP R_igraph_is_perfect(SEXP graph) { /*-------------------------------------------/ / igraph_eigenvector_centrality / /-------------------------------------------*/ -SEXP R_igraph_eigenvector_centrality(SEXP graph, SEXP directed, SEXP scale, SEXP weights, SEXP options) { +SEXP R_igraph_eigenvector_centrality(SEXP graph, SEXP mode, SEXP weights, SEXP options) { /* Declarations */ igraph_t c_graph; igraph_vector_t c_vector; igraph_real_t c_value; - igraph_bool_t c_directed; - igraph_bool_t c_scale; + igraph_neimode_t c_mode; igraph_vector_t c_weights; igraph_arpack_options_t c_options; SEXP vector; @@ -4513,16 +4786,15 @@ SEXP R_igraph_eigenvector_centrality(SEXP graph, SEXP directed, SEXP scale, SEXP R_SEXP_to_igraph(graph, &c_graph); IGRAPH_R_CHECK(igraph_vector_init(&c_vector, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_vector); - IGRAPH_R_CHECK_BOOL(directed); - c_directed = LOGICAL(directed)[0]; - IGRAPH_R_CHECK_BOOL(scale); - c_scale = LOGICAL(scale)[0]; + c_mode = (igraph_neimode_t) Rf_asInteger(mode); if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } R_SEXP_to_igraph_arpack_options(options, &c_options); /* Call igraph */ - IGRAPH_R_CHECK(igraph_eigenvector_centrality(&c_graph, &c_vector, &c_value, c_directed, c_scale, (Rf_isNull(weights) ? 0 : &c_weights), &c_options)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_eigenvector_centrality(&c_graph, &c_vector, &c_value, c_mode, (Rf_isNull(weights) ? NULL : &c_weights), &c_options)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -4549,53 +4821,52 @@ SEXP R_igraph_eigenvector_centrality(SEXP graph, SEXP directed, SEXP scale, SEXP /*-------------------------------------------/ / igraph_hub_and_authority_scores / /-------------------------------------------*/ -SEXP R_igraph_hub_and_authority_scores(SEXP graph, SEXP scale, SEXP weights, SEXP options) { +SEXP R_igraph_hub_and_authority_scores(SEXP graph, SEXP weights, SEXP options) { /* Declarations */ igraph_t c_graph; - igraph_vector_t c_hub; - igraph_vector_t c_authority; + igraph_vector_t c_hub_vector; + igraph_vector_t c_authority_vector; igraph_real_t c_value; - igraph_bool_t c_scale; igraph_vector_t c_weights; igraph_arpack_options_t c_options; - SEXP hub; - SEXP authority; + SEXP hub_vector; + SEXP authority_vector; SEXP value; SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_init(&c_hub, 0)); - IGRAPH_FINALLY(igraph_vector_destroy, &c_hub); - IGRAPH_R_CHECK(igraph_vector_init(&c_authority, 0)); - IGRAPH_FINALLY(igraph_vector_destroy, &c_authority); - IGRAPH_R_CHECK_BOOL(scale); - c_scale = LOGICAL(scale)[0]; + IGRAPH_R_CHECK(igraph_vector_init(&c_hub_vector, 0)); + IGRAPH_FINALLY(igraph_vector_destroy, &c_hub_vector); + IGRAPH_R_CHECK(igraph_vector_init(&c_authority_vector, 0)); + IGRAPH_FINALLY(igraph_vector_destroy, &c_authority_vector); if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } R_SEXP_to_igraph_arpack_options(options, &c_options); /* Call igraph */ - IGRAPH_R_CHECK(igraph_hub_and_authority_scores(&c_graph, &c_hub, &c_authority, &c_value, c_scale, (Rf_isNull(weights) ? 0 : &c_weights), &c_options)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_hub_and_authority_scores(&c_graph, &c_hub_vector, &c_authority_vector, &c_value, (Rf_isNull(weights) ? NULL : &c_weights), &c_options)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(4)); PROTECT(r_names=NEW_CHARACTER(4)); - PROTECT(hub=R_igraph_vector_to_SEXP(&c_hub)); - igraph_vector_destroy(&c_hub); + PROTECT(hub_vector=R_igraph_vector_to_SEXP(&c_hub_vector)); + igraph_vector_destroy(&c_hub_vector); IGRAPH_FINALLY_CLEAN(1); - PROTECT(authority=R_igraph_vector_to_SEXP(&c_authority)); - igraph_vector_destroy(&c_authority); + PROTECT(authority_vector=R_igraph_vector_to_SEXP(&c_authority_vector)); + igraph_vector_destroy(&c_authority_vector); IGRAPH_FINALLY_CLEAN(1); PROTECT(value=NEW_NUMERIC(1)); REAL(value)[0]=c_value; PROTECT(options=Rx_igraph_arpack_options_to_SEXP(&c_options)); - SET_VECTOR_ELT(r_result, 0, hub); - SET_VECTOR_ELT(r_result, 1, authority); + SET_VECTOR_ELT(r_result, 0, hub_vector); + SET_VECTOR_ELT(r_result, 1, authority_vector); SET_VECTOR_ELT(r_result, 2, value); SET_VECTOR_ELT(r_result, 3, options); - SET_STRING_ELT(r_names, 0, Rf_mkChar("hub")); - SET_STRING_ELT(r_names, 1, Rf_mkChar("authority")); + SET_STRING_ELT(r_names, 0, Rf_mkChar("hub_vector")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("authority_vector")); SET_STRING_ELT(r_names, 2, Rf_mkChar("value")); SET_STRING_ELT(r_names, 3, Rf_mkChar("options")); SET_NAMES(r_result, r_names); @@ -4627,7 +4898,9 @@ SEXP R_igraph_unfold_tree(SEXP graph, SEXP mode, SEXP roots) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_vertex_index, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vertex_index); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_unfold_tree(&c_graph, &c_tree, c_mode, &c_roots, &c_vertex_index)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -4673,7 +4946,9 @@ SEXP R_igraph_is_mutual(SEXP graph, SEXP es, SEXP loops) { IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_mutual(&c_graph, &c_res, c_es, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_bool_to_SEXP(&c_res)); @@ -4703,7 +4978,9 @@ SEXP R_igraph_has_mutual(SEXP graph, SEXP loops) { IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_has_mutual(&c_graph, &c_res, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_LOGICAL(1)); @@ -4733,7 +5010,9 @@ SEXP R_igraph_maximum_cardinality_search(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_alpham1, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_alpham1); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_maximum_cardinality_search(&c_graph, &c_alpha, &c_alpham1)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -4785,7 +5064,9 @@ SEXP R_igraph_avg_nearest_neighbor_degree(SEXP graph, SEXP vids, SEXP mode, SEXP R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_avg_nearest_neighbor_degree(&c_graph, c_vids, c_mode, c_neighbor_degree_mode, &c_knn, &c_knnk, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_avg_nearest_neighbor_degree(&c_graph, c_vids, c_mode, c_neighbor_degree_mode, &c_knn, &c_knnk, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -4835,7 +5116,9 @@ SEXP R_igraph_degree_correlation_vector(SEXP graph, SEXP weights, SEXP from_mode IGRAPH_R_CHECK_BOOL(directed_neighbors); c_directed_neighbors = LOGICAL(directed_neighbors)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_degree_correlation_vector(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_knnk, c_from_mode, c_to_mode, c_directed_neighbors)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_degree_correlation_vector(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_knnk, c_from_mode, c_to_mode, c_directed_neighbors)); + PutRNGstate(); /* Convert output */ PROTECT(knnk=R_igraph_vector_to_SEXP(&c_knnk)); @@ -4878,7 +5161,9 @@ SEXP R_igraph_rich_club_sequence(SEXP graph, SEXP weights, SEXP vertex_order, SE IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_rich_club_sequence(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_res, &c_vertex_order, c_normalized, c_loops, c_directed)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_rich_club_sequence(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, &c_vertex_order, c_normalized, c_loops, c_directed)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -4901,7 +5186,7 @@ SEXP R_igraph_strength(SEXP graph, SEXP vids, SEXP mode, SEXP loops, SEXP weight igraph_vector_t c_res; igraph_vs_t c_vids; igraph_neimode_t c_mode; - igraph_bool_t c_loops; + igraph_loops_t c_loops; igraph_vector_t c_weights; SEXP res; @@ -4913,13 +5198,14 @@ SEXP R_igraph_strength(SEXP graph, SEXP vids, SEXP mode, SEXP loops, SEXP weight igraph_vector_int_t c_vids_data; R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); c_mode = (igraph_neimode_t) Rf_asInteger(mode); - IGRAPH_R_CHECK_BOOL(loops); - c_loops = LOGICAL(loops)[0]; + c_loops = (igraph_loops_t) Rf_asInteger(loops); if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_strength(&c_graph, &c_res, c_vids, c_mode, c_loops, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_strength(&c_graph, &c_res, c_vids, c_mode, c_loops, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -4950,7 +5236,9 @@ SEXP R_igraph_centralization(SEXP scores, SEXP theoretical_max, SEXP normalized) IGRAPH_R_CHECK_BOOL(normalized); c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ + GetRNGstate(); c_result=igraph_centralization(&c_scores, c_theoretical_max, c_normalized); + PutRNGstate(); /* Convert output */ @@ -4969,7 +5257,7 @@ SEXP R_igraph_centralization_degree(SEXP graph, SEXP mode, SEXP loops, SEXP norm igraph_t c_graph; igraph_vector_t c_res; igraph_neimode_t c_mode; - igraph_bool_t c_loops; + igraph_loops_t c_loops; igraph_real_t c_centralization; igraph_real_t c_theoretical_max; igraph_bool_t c_normalized; @@ -4983,12 +5271,13 @@ SEXP R_igraph_centralization_degree(SEXP graph, SEXP mode, SEXP loops, SEXP norm IGRAPH_R_CHECK(igraph_vector_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_res); c_mode = (igraph_neimode_t) Rf_asInteger(mode); - IGRAPH_R_CHECK_BOOL(loops); - c_loops = LOGICAL(loops)[0]; + c_loops = (igraph_loops_t) Rf_asInteger(loops); IGRAPH_R_CHECK_BOOL(normalized); c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_centralization_degree(&c_graph, &c_res, c_mode, c_loops, &c_centralization, &c_theoretical_max, c_normalized)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -5021,7 +5310,7 @@ SEXP R_igraph_centralization_degree_tmax(SEXP graph, SEXP nodes, SEXP mode, SEXP igraph_t c_graph; igraph_integer_t c_nodes; igraph_neimode_t c_mode; - igraph_bool_t c_loops; + igraph_loops_t c_loops; igraph_real_t c_res; SEXP res; @@ -5033,10 +5322,11 @@ SEXP R_igraph_centralization_degree_tmax(SEXP graph, SEXP nodes, SEXP mode, SEXP IGRAPH_R_CHECK_INT(nodes); c_nodes = (igraph_integer_t) REAL(nodes)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); - IGRAPH_R_CHECK_BOOL(loops); - c_loops = LOGICAL(loops)[0]; + c_loops = (igraph_loops_t) Rf_asInteger(loops); /* Call igraph */ - IGRAPH_R_CHECK(igraph_centralization_degree_tmax((Rf_isNull(graph) ? 0 : &c_graph), c_nodes, c_mode, c_loops, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_centralization_degree_tmax((Rf_isNull(graph) ? NULL : &c_graph), c_nodes, c_mode, c_loops, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -5072,7 +5362,9 @@ SEXP R_igraph_centralization_betweenness(SEXP graph, SEXP directed, SEXP normali IGRAPH_R_CHECK_BOOL(normalized); c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_centralization_betweenness(&c_graph, &c_res, c_directed, &c_centralization, &c_theoretical_max, c_normalized)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -5118,7 +5410,9 @@ SEXP R_igraph_centralization_betweenness_tmax(SEXP graph, SEXP nodes, SEXP direc IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_centralization_betweenness_tmax((Rf_isNull(graph) ? 0 : &c_graph), c_nodes, c_directed, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_centralization_betweenness_tmax((Rf_isNull(graph) ? NULL : &c_graph), c_nodes, c_directed, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -5153,7 +5447,9 @@ SEXP R_igraph_centralization_closeness(SEXP graph, SEXP mode, SEXP normalized) { IGRAPH_R_CHECK_BOOL(normalized); c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_centralization_closeness(&c_graph, &c_res, c_mode, &c_centralization, &c_theoretical_max, c_normalized)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -5198,7 +5494,9 @@ SEXP R_igraph_centralization_closeness_tmax(SEXP graph, SEXP nodes, SEXP mode) { c_nodes = (igraph_integer_t) REAL(nodes)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_centralization_closeness_tmax((Rf_isNull(graph) ? 0 : &c_graph), c_nodes, c_mode, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_centralization_closeness_tmax((Rf_isNull(graph) ? NULL : &c_graph), c_nodes, c_mode, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -5212,13 +5510,12 @@ SEXP R_igraph_centralization_closeness_tmax(SEXP graph, SEXP nodes, SEXP mode) { /*-------------------------------------------/ / igraph_centralization_eigenvector_centrality / /-------------------------------------------*/ -SEXP R_igraph_centralization_eigenvector_centrality(SEXP graph, SEXP directed, SEXP scale, SEXP options, SEXP normalized) { +SEXP R_igraph_centralization_eigenvector_centrality(SEXP graph, SEXP mode, SEXP options, SEXP normalized) { /* Declarations */ igraph_t c_graph; igraph_vector_t c_vector; igraph_real_t c_value; - igraph_bool_t c_directed; - igraph_bool_t c_scale; + igraph_neimode_t c_mode; igraph_arpack_options_t c_options; igraph_real_t c_centralization; igraph_real_t c_theoretical_max; @@ -5233,15 +5530,14 @@ SEXP R_igraph_centralization_eigenvector_centrality(SEXP graph, SEXP directed, S R_SEXP_to_igraph(graph, &c_graph); IGRAPH_R_CHECK(igraph_vector_init(&c_vector, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_vector); - IGRAPH_R_CHECK_BOOL(directed); - c_directed = LOGICAL(directed)[0]; - IGRAPH_R_CHECK_BOOL(scale); - c_scale = LOGICAL(scale)[0]; + c_mode = (igraph_neimode_t) Rf_asInteger(mode); R_SEXP_to_igraph_arpack_options(options, &c_options); IGRAPH_R_CHECK_BOOL(normalized); c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_centralization_eigenvector_centrality(&c_graph, &c_vector, &c_value, c_directed, c_scale, &c_options, &c_centralization, &c_theoretical_max, c_normalized)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_centralization_eigenvector_centrality(&c_graph, &c_vector, &c_value, c_mode, &c_options, &c_centralization, &c_theoretical_max, c_normalized)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(5)); @@ -5276,12 +5572,11 @@ SEXP R_igraph_centralization_eigenvector_centrality(SEXP graph, SEXP directed, S /*-------------------------------------------/ / igraph_centralization_eigenvector_centrality_tmax / /-------------------------------------------*/ -SEXP R_igraph_centralization_eigenvector_centrality_tmax(SEXP graph, SEXP nodes, SEXP directed, SEXP scale) { +SEXP R_igraph_centralization_eigenvector_centrality_tmax(SEXP graph, SEXP nodes, SEXP mode) { /* Declarations */ igraph_t c_graph; igraph_integer_t c_nodes; - igraph_bool_t c_directed; - igraph_bool_t c_scale; + igraph_neimode_t c_mode; igraph_real_t c_res; SEXP res; @@ -5292,12 +5587,11 @@ SEXP R_igraph_centralization_eigenvector_centrality_tmax(SEXP graph, SEXP nodes, } IGRAPH_R_CHECK_INT(nodes); c_nodes = (igraph_integer_t) REAL(nodes)[0]; - IGRAPH_R_CHECK_BOOL(directed); - c_directed = LOGICAL(directed)[0]; - IGRAPH_R_CHECK_BOOL(scale); - c_scale = LOGICAL(scale)[0]; + c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_centralization_eigenvector_centrality_tmax((Rf_isNull(graph) ? 0 : &c_graph), c_nodes, c_directed, c_scale, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_centralization_eigenvector_centrality_tmax((Rf_isNull(graph) ? NULL : &c_graph), c_nodes, c_mode, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -5311,9 +5605,10 @@ SEXP R_igraph_centralization_eigenvector_centrality_tmax(SEXP graph, SEXP nodes, /*-------------------------------------------/ / igraph_assortativity_nominal / /-------------------------------------------*/ -SEXP R_igraph_assortativity_nominal(SEXP graph, SEXP types, SEXP directed, SEXP normalized) { +SEXP R_igraph_assortativity_nominal(SEXP graph, SEXP weights, SEXP types, SEXP directed, SEXP normalized) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_int_t c_types; igraph_real_t c_res; igraph_bool_t c_directed; @@ -5323,6 +5618,9 @@ SEXP R_igraph_assortativity_nominal(SEXP graph, SEXP types, SEXP directed, SEXP SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } R_SEXP_to_vector_int_copy(types, &c_types); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_types); IGRAPH_R_CHECK_BOOL(directed); @@ -5330,7 +5628,9 @@ SEXP R_igraph_assortativity_nominal(SEXP graph, SEXP types, SEXP directed, SEXP IGRAPH_R_CHECK_BOOL(normalized); c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_assortativity_nominal(&c_graph, &c_types, &c_res, c_directed, c_normalized)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_assortativity_nominal(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_types, &c_res, c_directed, c_normalized)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_types); @@ -5346,9 +5646,10 @@ SEXP R_igraph_assortativity_nominal(SEXP graph, SEXP types, SEXP directed, SEXP /*-------------------------------------------/ / igraph_assortativity / /-------------------------------------------*/ -SEXP R_igraph_assortativity(SEXP graph, SEXP values, SEXP values_in, SEXP directed, SEXP normalized) { +SEXP R_igraph_assortativity(SEXP graph, SEXP weights, SEXP values, SEXP values_in, SEXP directed, SEXP normalized) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_t c_values; igraph_vector_t c_values_in; igraph_real_t c_res; @@ -5359,6 +5660,9 @@ SEXP R_igraph_assortativity(SEXP graph, SEXP values, SEXP values_in, SEXP direct SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } R_SEXP_to_vector(values, &c_values); if (!Rf_isNull(values_in)) { R_SEXP_to_vector(values_in, &c_values_in); @@ -5368,7 +5672,9 @@ SEXP R_igraph_assortativity(SEXP graph, SEXP values, SEXP values_in, SEXP direct IGRAPH_R_CHECK_BOOL(normalized); c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_assortativity(&c_graph, &c_values, (Rf_isNull(values_in) ? 0 : &c_values_in), &c_res, c_directed, c_normalized)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_assortativity(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_values, (Rf_isNull(values_in) ? NULL : &c_values_in), &c_res, c_directed, c_normalized)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -5395,7 +5701,9 @@ SEXP R_igraph_assortativity_degree(SEXP graph, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_assortativity_degree(&c_graph, &c_res, c_directed)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -5431,7 +5739,9 @@ SEXP R_igraph_joint_degree_matrix(SEXP graph, SEXP weights, SEXP max_out_degree, IGRAPH_R_CHECK_INT(max_in_degree); c_max_in_degree = (igraph_integer_t) REAL(max_in_degree)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_joint_degree_matrix(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_jdm, c_max_out_degree, c_max_in_degree)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_joint_degree_matrix(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_jdm, c_max_out_degree, c_max_in_degree)); + PutRNGstate(); /* Convert output */ PROTECT(jdm=R_igraph_matrix_to_SEXP(&c_jdm)); @@ -5478,7 +5788,9 @@ SEXP R_igraph_joint_degree_distribution(SEXP graph, SEXP weights, SEXP from_mode IGRAPH_R_CHECK_INT(max_to_degree); c_max_to_degree = (igraph_integer_t) REAL(max_to_degree)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_joint_degree_distribution(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_p, c_from_mode, c_to_mode, c_directed_neighbors, c_normalized, c_max_from_degree, c_max_to_degree)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_joint_degree_distribution(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_p, c_from_mode, c_to_mode, c_directed_neighbors, c_normalized, c_max_from_degree, c_max_to_degree)); + PutRNGstate(); /* Convert output */ PROTECT(p=R_igraph_matrix_to_SEXP(&c_p)); @@ -5526,7 +5838,9 @@ SEXP R_igraph_joint_type_distribution(SEXP graph, SEXP weights, SEXP from_types, IGRAPH_R_CHECK_BOOL(normalized); c_normalized = LOGICAL(normalized)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_joint_type_distribution(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_p, &c_from_types, (Rf_isNull(to_types) ? 0 : &c_to_types), c_directed, c_normalized)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_joint_type_distribution(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_p, &c_from_types, (Rf_isNull(to_types) ? NULL : &c_to_types), c_directed, c_normalized)); + PutRNGstate(); /* Convert output */ PROTECT(p=R_igraph_matrix_to_SEXP(&c_p)); @@ -5560,7 +5874,9 @@ SEXP R_igraph_contract_vertices(SEXP graph, SEXP mapping, SEXP vertex_attr_comb) R_SEXP_to_attr_comb(vertex_attr_comb, &c_vertex_attr_comb); IGRAPH_FINALLY(igraph_attribute_combination_destroy, &c_vertex_attr_comb); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_contract_vertices(&c_graph, &c_mapping, &c_vertex_attr_comb)); + PutRNGstate(); /* Convert output */ PROTECT(graph=R_igraph_to_SEXP(&c_graph)); @@ -5577,9 +5893,9 @@ SEXP R_igraph_contract_vertices(SEXP graph, SEXP mapping, SEXP vertex_attr_comb) } /*-------------------------------------------/ -/ igraph_eccentricity_dijkstra / +/ igraph_eccentricity / /-------------------------------------------*/ -SEXP R_igraph_eccentricity_dijkstra(SEXP graph, SEXP weights, SEXP vids, SEXP mode) { +SEXP R_igraph_eccentricity(SEXP graph, SEXP weights, SEXP vids, SEXP mode) { /* Declarations */ igraph_t c_graph; igraph_vector_t c_weights; @@ -5600,7 +5916,9 @@ SEXP R_igraph_eccentricity_dijkstra(SEXP graph, SEXP weights, SEXP vids, SEXP mo R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_eccentricity_dijkstra(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_res, c_vids, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_eccentricity(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_vids, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -5615,9 +5933,9 @@ SEXP R_igraph_eccentricity_dijkstra(SEXP graph, SEXP weights, SEXP vids, SEXP mo } /*-------------------------------------------/ -/ igraph_graph_center_dijkstra / +/ igraph_graph_center / /-------------------------------------------*/ -SEXP R_igraph_graph_center_dijkstra(SEXP graph, SEXP weights, SEXP mode) { +SEXP R_igraph_graph_center(SEXP graph, SEXP weights, SEXP mode) { /* Declarations */ igraph_t c_graph; igraph_vector_t c_weights; @@ -5635,7 +5953,9 @@ SEXP R_igraph_graph_center_dijkstra(SEXP graph, SEXP weights, SEXP mode) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_res); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_graph_center_dijkstra(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_res, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_graph_center(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_to_SEXPp1(&c_res)); @@ -5648,9 +5968,9 @@ SEXP R_igraph_graph_center_dijkstra(SEXP graph, SEXP weights, SEXP mode) { } /*-------------------------------------------/ -/ igraph_radius_dijkstra / +/ igraph_radius / /-------------------------------------------*/ -SEXP R_igraph_radius_dijkstra(SEXP graph, SEXP weights, SEXP mode) { +SEXP R_igraph_radius(SEXP graph, SEXP weights, SEXP mode) { /* Declarations */ igraph_t c_graph; igraph_vector_t c_weights; @@ -5666,7 +5986,9 @@ SEXP R_igraph_radius_dijkstra(SEXP graph, SEXP weights, SEXP mode) { } c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_radius_dijkstra(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_radius, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_radius(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_radius, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(radius=NEW_NUMERIC(1)); @@ -5680,9 +6002,10 @@ SEXP R_igraph_radius_dijkstra(SEXP graph, SEXP weights, SEXP mode) { /*-------------------------------------------/ / igraph_pseudo_diameter / /-------------------------------------------*/ -SEXP R_igraph_pseudo_diameter(SEXP graph, SEXP start_vid, SEXP directed, SEXP unconnected) { +SEXP R_igraph_pseudo_diameter(SEXP graph, SEXP weights, SEXP start_vid, SEXP directed, SEXP unconnected) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_real_t c_diameter; igraph_integer_t c_start_vid; igraph_integer_t c_from; @@ -5696,6 +6019,9 @@ SEXP R_igraph_pseudo_diameter(SEXP graph, SEXP start_vid, SEXP directed, SEXP un SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } c_start_vid = (igraph_integer_t) REAL(start_vid)[0]; c_from=0; c_to=0; @@ -5704,7 +6030,9 @@ SEXP R_igraph_pseudo_diameter(SEXP graph, SEXP start_vid, SEXP directed, SEXP un IGRAPH_R_CHECK_BOOL(unconnected); c_unconnected = LOGICAL(unconnected)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_pseudo_diameter(&c_graph, &c_diameter, c_start_vid, &c_from, &c_to, c_directed, c_unconnected)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_pseudo_diameter(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_diameter, c_start_vid, &c_from, &c_to, c_directed, c_unconnected)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -5729,83 +6057,30 @@ SEXP R_igraph_pseudo_diameter(SEXP graph, SEXP start_vid, SEXP directed, SEXP un } /*-------------------------------------------/ -/ igraph_pseudo_diameter_dijkstra / +/ igraph_diversity / /-------------------------------------------*/ -SEXP R_igraph_pseudo_diameter_dijkstra(SEXP graph, SEXP weights, SEXP start_vid, SEXP directed, SEXP unconnected) { +SEXP R_igraph_diversity(SEXP graph, SEXP weights, SEXP vids) { /* Declarations */ igraph_t c_graph; igraph_vector_t c_weights; - igraph_real_t c_diameter; - igraph_integer_t c_start_vid; - igraph_integer_t c_from; - igraph_integer_t c_to; - igraph_bool_t c_directed; - igraph_bool_t c_unconnected; - SEXP diameter; - SEXP from; - SEXP to; + igraph_vector_t c_res; + igraph_vs_t c_vids; + SEXP res; - SEXP r_result, r_names; + SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } - c_start_vid = (igraph_integer_t) REAL(start_vid)[0]; - c_from=0; - c_to=0; - IGRAPH_R_CHECK_BOOL(directed); - c_directed = LOGICAL(directed)[0]; - IGRAPH_R_CHECK_BOOL(unconnected); - c_unconnected = LOGICAL(unconnected)[0]; + IGRAPH_R_CHECK(igraph_vector_init(&c_res, 0)); + IGRAPH_FINALLY(igraph_vector_destroy, &c_res); + igraph_vector_int_t c_vids_data; + R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); /* Call igraph */ - IGRAPH_R_CHECK(igraph_pseudo_diameter_dijkstra(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_diameter, c_start_vid, &c_from, &c_to, c_directed, c_unconnected)); - - /* Convert output */ - PROTECT(r_result=NEW_LIST(3)); - PROTECT(r_names=NEW_CHARACTER(3)); - PROTECT(diameter=NEW_NUMERIC(1)); - REAL(diameter)[0]=c_diameter; - PROTECT(from=NEW_NUMERIC(1)); - REAL(from)[0]=(double) c_from; - PROTECT(to=NEW_NUMERIC(1)); - REAL(to)[0]=(double) c_to; - SET_VECTOR_ELT(r_result, 0, diameter); - SET_VECTOR_ELT(r_result, 1, from); - SET_VECTOR_ELT(r_result, 2, to); - SET_STRING_ELT(r_names, 0, Rf_mkChar("diameter")); - SET_STRING_ELT(r_names, 1, Rf_mkChar("from")); - SET_STRING_ELT(r_names, 2, Rf_mkChar("to")); - SET_NAMES(r_result, r_names); - UNPROTECT(4); - - UNPROTECT(1); - return(r_result); -} - -/*-------------------------------------------/ -/ igraph_diversity / -/-------------------------------------------*/ -SEXP R_igraph_diversity(SEXP graph, SEXP weights, SEXP vids) { - /* Declarations */ - igraph_t c_graph; - igraph_vector_t c_weights; - igraph_vector_t c_res; - igraph_vs_t c_vids; - SEXP res; - - SEXP r_result; - /* Convert input */ - R_SEXP_to_igraph(graph, &c_graph); - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } - IGRAPH_R_CHECK(igraph_vector_init(&c_res, 0)); - IGRAPH_FINALLY(igraph_vector_destroy, &c_res); - igraph_vector_int_t c_vids_data; - R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); - /* Call igraph */ - IGRAPH_R_CHECK(igraph_diversity(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_res, c_vids)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_diversity(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_vids)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -5851,7 +6126,9 @@ SEXP R_igraph_random_walk(SEXP graph, SEXP weights, SEXP start, SEXP mode, SEXP c_steps = (igraph_integer_t) REAL(steps)[0]; c_stuck = (igraph_random_walk_stuck_t) Rf_asInteger(stuck); /* Call igraph */ - IGRAPH_R_CHECK(igraph_random_walk(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_vertices, &c_edges, c_start, c_mode, c_steps, c_stuck)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_random_walk(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_vertices, &c_edges, c_start, c_mode, c_steps, c_stuck)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -5879,8 +6156,8 @@ SEXP R_igraph_random_walk(SEXP graph, SEXP weights, SEXP start, SEXP mode, SEXP SEXP R_igraph_global_efficiency(SEXP graph, SEXP weights, SEXP directed) { /* Declarations */ igraph_t c_graph; - igraph_real_t c_res; igraph_vector_t c_weights; + igraph_real_t c_res; igraph_bool_t c_directed; SEXP res; @@ -5893,7 +6170,9 @@ SEXP R_igraph_global_efficiency(SEXP graph, SEXP weights, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_global_efficiency(&c_graph, &c_res, (Rf_isNull(weights) ? 0 : &c_weights), c_directed)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_global_efficiency(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_directed)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -5907,12 +6186,12 @@ SEXP R_igraph_global_efficiency(SEXP graph, SEXP weights, SEXP directed) { /*-------------------------------------------/ / igraph_local_efficiency / /-------------------------------------------*/ -SEXP R_igraph_local_efficiency(SEXP graph, SEXP vids, SEXP weights, SEXP directed, SEXP mode) { +SEXP R_igraph_local_efficiency(SEXP graph, SEXP weights, SEXP vids, SEXP directed, SEXP mode) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_t c_res; igraph_vs_t c_vids; - igraph_vector_t c_weights; igraph_bool_t c_directed; igraph_neimode_t c_mode; SEXP res; @@ -5920,18 +6199,20 @@ SEXP R_igraph_local_efficiency(SEXP graph, SEXP vids, SEXP weights, SEXP directe SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK(igraph_vector_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_res); igraph_vector_int_t c_vids_data; R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_local_efficiency(&c_graph, &c_res, c_vids, (Rf_isNull(weights) ? 0 : &c_weights), c_directed, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_local_efficiency(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_vids, c_directed, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -5951,8 +6232,8 @@ SEXP R_igraph_local_efficiency(SEXP graph, SEXP vids, SEXP weights, SEXP directe SEXP R_igraph_average_local_efficiency(SEXP graph, SEXP weights, SEXP directed, SEXP mode) { /* Declarations */ igraph_t c_graph; - igraph_real_t c_res; igraph_vector_t c_weights; + igraph_real_t c_res; igraph_bool_t c_directed; igraph_neimode_t c_mode; SEXP res; @@ -5967,7 +6248,9 @@ SEXP R_igraph_average_local_efficiency(SEXP graph, SEXP weights, SEXP directed, c_directed = LOGICAL(directed)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_average_local_efficiency(&c_graph, &c_res, (Rf_isNull(weights) ? 0 : &c_weights), c_directed, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_average_local_efficiency(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, c_directed, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -5978,32 +6261,6 @@ SEXP R_igraph_average_local_efficiency(SEXP graph, SEXP weights, SEXP directed, return(r_result); } -/*-------------------------------------------/ -/ igraph_transitive_closure_dag / -/-------------------------------------------*/ -SEXP R_igraph_transitive_closure_dag(SEXP graph) { - /* Declarations */ - igraph_t c_graph; - igraph_t c_closure; - SEXP closure; - - SEXP r_result; - /* Convert input */ - R_SEXP_to_igraph(graph, &c_graph); - /* Call igraph */ - IGRAPH_R_CHECK(igraph_transitive_closure_dag(&c_graph, &c_closure)); - - /* Convert output */ - IGRAPH_FINALLY(igraph_destroy, &c_closure); - PROTECT(closure=R_igraph_to_SEXP(&c_closure)); - IGRAPH_I_DESTROY(&c_closure); - IGRAPH_FINALLY_CLEAN(1); - r_result = closure; - - UNPROTECT(1); - return(r_result); -} - /*-------------------------------------------/ / igraph_transitive_closure / /-------------------------------------------*/ @@ -6017,7 +6274,9 @@ SEXP R_igraph_transitive_closure(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_transitive_closure(&c_graph, &c_closure)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_closure); @@ -6045,7 +6304,9 @@ SEXP R_igraph_trussness(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_trussness, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_trussness); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_trussness(&c_graph, &c_trussness)); + PutRNGstate(); /* Convert output */ PROTECT(trussness=R_igraph_vector_int_to_SEXP(&c_trussness)); @@ -6081,7 +6342,9 @@ SEXP R_igraph_is_graphical(SEXP out_deg, SEXP in_deg, SEXP allowed_edge_types) { } c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); /* Call igraph */ - IGRAPH_R_CHECK(igraph_is_graphical(&c_out_deg, (Rf_isNull(in_deg) ? 0 : &c_in_deg), c_allowed_edge_types, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_is_graphical(&c_out_deg, (Rf_isNull(in_deg) ? NULL : &c_in_deg), c_allowed_edge_types, &c_res)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_out_deg); @@ -6123,7 +6386,9 @@ SEXP R_igraph_bfs_simple(SEXP graph, SEXP root, SEXP mode) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_parents, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_parents); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_bfs_simple(&c_graph, c_root, c_mode, &c_order, &c_layers, &c_parents)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -6175,7 +6440,9 @@ SEXP R_igraph_bipartite_projection_size(SEXP graph, SEXP types) { c_vcount2=0; c_ecount2=0; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_bipartite_projection_size(&c_graph, &c_types, &c_vcount1, &c_ecount1, &c_vcount2, &c_ecount2)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(4)); @@ -6222,7 +6489,9 @@ SEXP R_igraph_create_bipartite(SEXP types, SEXP edges, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_create_bipartite(&c_graph, &c_types, &c_edges, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -6240,11 +6509,11 @@ SEXP R_igraph_create_bipartite(SEXP types, SEXP edges, SEXP directed) { /*-------------------------------------------/ / igraph_biadjacency / /-------------------------------------------*/ -SEXP R_igraph_biadjacency(SEXP incidence, SEXP directed, SEXP mode, SEXP multiple) { +SEXP R_igraph_biadjacency(SEXP biadjmatrix, SEXP directed, SEXP mode, SEXP multiple) { /* Declarations */ igraph_t c_graph; igraph_vector_bool_t c_types; - igraph_matrix_t c_incidence; + igraph_matrix_t c_biadjmatrix; igraph_bool_t c_directed; igraph_neimode_t c_mode; igraph_bool_t c_multiple; @@ -6255,14 +6524,16 @@ SEXP R_igraph_biadjacency(SEXP incidence, SEXP directed, SEXP mode, SEXP multipl /* Convert input */ IGRAPH_R_CHECK(igraph_vector_bool_init(&c_types, 0)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types); - R_SEXP_to_matrix(incidence, &c_incidence); + R_SEXP_to_matrix(biadjmatrix, &c_biadjmatrix); IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); IGRAPH_R_CHECK_BOOL(multiple); c_multiple = LOGICAL(multiple)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_biadjacency(&c_graph, &c_types, &c_incidence, c_directed, c_mode, c_multiple)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_biadjacency(&c_graph, &c_types, &c_biadjmatrix, c_directed, c_mode, c_multiple)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -6285,13 +6556,71 @@ SEXP R_igraph_biadjacency(SEXP incidence, SEXP directed, SEXP mode, SEXP multipl return(r_result); } +/*-------------------------------------------/ +/ igraph_weighted_biadjacency / +/-------------------------------------------*/ +SEXP R_igraph_weighted_biadjacency(SEXP biadjmatrix, SEXP directed, SEXP mode) { + /* Declarations */ + igraph_t c_graph; + igraph_vector_bool_t c_types; + igraph_vector_t c_weights; + igraph_matrix_t c_biadjmatrix; + igraph_bool_t c_directed; + igraph_neimode_t c_mode; + SEXP graph; + SEXP types; + SEXP weights; + + SEXP r_result, r_names; + /* Convert input */ + IGRAPH_R_CHECK(igraph_vector_bool_init(&c_types, 0)); + IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types); + IGRAPH_R_CHECK(igraph_vector_init(&c_weights, 0)); + IGRAPH_FINALLY(igraph_vector_destroy, &c_weights); + weights=R_GlobalEnv; /* hack to have a non-NULL value */ + R_SEXP_to_matrix(biadjmatrix, &c_biadjmatrix); + IGRAPH_R_CHECK_BOOL(directed); + c_directed = LOGICAL(directed)[0]; + c_mode = (igraph_neimode_t) Rf_asInteger(mode); + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_weighted_biadjacency(&c_graph, &c_types, &c_weights, &c_biadjmatrix, c_directed, c_mode)); + PutRNGstate(); + + /* Convert output */ + PROTECT(r_result=NEW_LIST(3)); + PROTECT(r_names=NEW_CHARACTER(3)); + IGRAPH_FINALLY(igraph_destroy, &c_graph); + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); + IGRAPH_FINALLY_CLEAN(1); + PROTECT(types=R_igraph_vector_bool_to_SEXP(&c_types)); + igraph_vector_bool_destroy(&c_types); + IGRAPH_FINALLY_CLEAN(1); + PROTECT(weights=R_igraph_0orvector_to_SEXP(&c_weights)); + igraph_vector_destroy(&c_weights); + IGRAPH_FINALLY_CLEAN(1); + SET_VECTOR_ELT(r_result, 0, graph); + SET_VECTOR_ELT(r_result, 1, types); + SET_VECTOR_ELT(r_result, 2, weights); + SET_STRING_ELT(r_names, 0, Rf_mkChar("graph")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("types")); + SET_STRING_ELT(r_names, 2, Rf_mkChar("weights")); + SET_NAMES(r_result, r_names); + UNPROTECT(4); + + UNPROTECT(1); + return(r_result); +} + /*-------------------------------------------/ / igraph_get_biadjacency / /-------------------------------------------*/ -SEXP R_igraph_get_biadjacency(SEXP graph, SEXP types) { +SEXP R_igraph_get_biadjacency(SEXP graph, SEXP types, SEXP weights) { /* Declarations */ igraph_t c_graph; igraph_vector_bool_t c_types; + igraph_vector_t c_weights; igraph_matrix_t c_res; igraph_vector_int_t c_row_ids; igraph_vector_int_t c_col_ids; @@ -6303,6 +6632,9 @@ SEXP R_igraph_get_biadjacency(SEXP graph, SEXP types) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); R_SEXP_to_vector_bool(types, &c_types); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); IGRAPH_R_CHECK(igraph_vector_int_init(&c_row_ids, 0)); @@ -6310,7 +6642,9 @@ SEXP R_igraph_get_biadjacency(SEXP graph, SEXP types) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_col_ids, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_col_ids); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_biadjacency(&c_graph, &c_types, &c_res, &c_row_ids, &c_col_ids)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_biadjacency(&c_graph, &c_types, (Rf_isNull(weights) ? NULL : &c_weights), &c_res, &c_row_ids, &c_col_ids)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -6354,7 +6688,9 @@ SEXP R_igraph_is_bipartite(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_bool_init(&c_type, 0)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_type); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_bipartite(&c_graph, &c_res, &c_type)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -6378,7 +6714,7 @@ SEXP R_igraph_is_bipartite(SEXP graph) { /*-------------------------------------------/ / igraph_bipartite_game_gnp / /-------------------------------------------*/ -SEXP R_igraph_bipartite_game_gnp(SEXP n1, SEXP n2, SEXP p, SEXP directed, SEXP mode) { +SEXP R_igraph_bipartite_game_gnp(SEXP n1, SEXP n2, SEXP p, SEXP directed, SEXP mode, SEXP allowed_edge_types, SEXP edge_labeled) { /* Declarations */ igraph_t c_graph; igraph_vector_bool_t c_types; @@ -6387,6 +6723,8 @@ SEXP R_igraph_bipartite_game_gnp(SEXP n1, SEXP n2, SEXP p, SEXP directed, SEXP m igraph_real_t c_p; igraph_bool_t c_directed; igraph_neimode_t c_mode; + igraph_edge_type_sw_t c_allowed_edge_types; + igraph_bool_t c_edge_labeled; SEXP graph; SEXP types; @@ -6403,8 +6741,13 @@ SEXP R_igraph_bipartite_game_gnp(SEXP n1, SEXP n2, SEXP p, SEXP directed, SEXP m IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); + c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); + IGRAPH_R_CHECK_BOOL(edge_labeled); + c_edge_labeled = LOGICAL(edge_labeled)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_bipartite_game_gnp(&c_graph, &c_types, c_n1, c_n2, c_p, c_directed, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_bipartite_game_gnp(&c_graph, &c_types, c_n1, c_n2, c_p, c_directed, c_mode, c_allowed_edge_types, c_edge_labeled)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -6430,7 +6773,66 @@ SEXP R_igraph_bipartite_game_gnp(SEXP n1, SEXP n2, SEXP p, SEXP directed, SEXP m /*-------------------------------------------/ / igraph_bipartite_game_gnm / /-------------------------------------------*/ -SEXP R_igraph_bipartite_game_gnm(SEXP n1, SEXP n2, SEXP m, SEXP directed, SEXP mode) { +SEXP R_igraph_bipartite_game_gnm(SEXP n1, SEXP n2, SEXP m, SEXP directed, SEXP mode, SEXP allowed_edge_types, SEXP edge_labeled) { + /* Declarations */ + igraph_t c_graph; + igraph_vector_bool_t c_types; + igraph_integer_t c_n1; + igraph_integer_t c_n2; + igraph_integer_t c_m; + igraph_bool_t c_directed; + igraph_neimode_t c_mode; + igraph_edge_type_sw_t c_allowed_edge_types; + igraph_bool_t c_edge_labeled; + SEXP graph; + SEXP types; + + SEXP r_result, r_names; + /* Convert input */ + IGRAPH_R_CHECK(igraph_vector_bool_init(&c_types, 0)); + IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types); + IGRAPH_R_CHECK_INT(n1); + c_n1 = (igraph_integer_t) REAL(n1)[0]; + IGRAPH_R_CHECK_INT(n2); + c_n2 = (igraph_integer_t) REAL(n2)[0]; + IGRAPH_R_CHECK_INT(m); + c_m = (igraph_integer_t) REAL(m)[0]; + IGRAPH_R_CHECK_BOOL(directed); + c_directed = LOGICAL(directed)[0]; + c_mode = (igraph_neimode_t) Rf_asInteger(mode); + c_allowed_edge_types = (igraph_edge_type_sw_t) Rf_asInteger(allowed_edge_types); + IGRAPH_R_CHECK_BOOL(edge_labeled); + c_edge_labeled = LOGICAL(edge_labeled)[0]; + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_bipartite_game_gnm(&c_graph, &c_types, c_n1, c_n2, c_m, c_directed, c_mode, c_allowed_edge_types, c_edge_labeled)); + PutRNGstate(); + + /* Convert output */ + PROTECT(r_result=NEW_LIST(2)); + PROTECT(r_names=NEW_CHARACTER(2)); + IGRAPH_FINALLY(igraph_destroy, &c_graph); + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); + IGRAPH_FINALLY_CLEAN(1); + PROTECT(types=R_igraph_vector_bool_to_SEXP(&c_types)); + igraph_vector_bool_destroy(&c_types); + IGRAPH_FINALLY_CLEAN(1); + SET_VECTOR_ELT(r_result, 0, graph); + SET_VECTOR_ELT(r_result, 1, types); + SET_STRING_ELT(r_names, 0, Rf_mkChar("graph")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("types")); + SET_NAMES(r_result, r_names); + UNPROTECT(3); + + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_bipartite_iea_game / +/-------------------------------------------*/ +SEXP R_igraph_bipartite_iea_game(SEXP n1, SEXP n2, SEXP m, SEXP directed, SEXP mode) { /* Declarations */ igraph_t c_graph; igraph_vector_bool_t c_types; @@ -6456,7 +6858,9 @@ SEXP R_igraph_bipartite_game_gnm(SEXP n1, SEXP n2, SEXP m, SEXP directed, SEXP m c_directed = LOGICAL(directed)[0]; c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_bipartite_game_gnm(&c_graph, &c_types, c_n1, c_n2, c_m, c_directed, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_bipartite_iea_game(&c_graph, &c_types, c_n1, c_n2, c_m, c_directed, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -6502,7 +6906,9 @@ SEXP R_igraph_get_laplacian(SEXP graph, SEXP mode, SEXP normalization, SEXP weig R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_laplacian(&c_graph, &c_res, c_mode, c_normalization, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_laplacian(&c_graph, &c_res, c_mode, c_normalization, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -6537,7 +6943,9 @@ SEXP R_igraph_get_laplacian_sparse(SEXP graph, SEXP mode, SEXP normalization, SE R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_laplacian_sparse(&c_graph, &c_sparseres, c_mode, c_normalization, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_laplacian_sparse(&c_graph, &c_sparseres, c_mode, c_normalization, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ PROTECT(sparseres=R_igraph_sparsemat_to_SEXP(&c_sparseres)); @@ -6573,7 +6981,9 @@ SEXP R_igraph_connected_components(SEXP graph, SEXP mode) { c_no=0; c_mode = (igraph_connectedness_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_connected_components(&c_graph, &c_membership, &c_csize, &c_no, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -6614,7 +7024,9 @@ SEXP R_igraph_is_connected(SEXP graph, SEXP mode) { R_SEXP_to_igraph(graph, &c_graph); c_mode = (igraph_connectedness_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_connected(&c_graph, &c_res, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_LOGICAL(1)); @@ -6640,7 +7052,9 @@ SEXP R_igraph_articulation_points(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_articulation_points(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_to_SEXPp1(&c_res)); @@ -6673,16 +7087,24 @@ SEXP R_igraph_biconnected_components(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); c_no=0; - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_tree_edges, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_tree_edges); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_component_edges, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_component_edges); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_components, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_components); + if (0 != igraph_vector_int_list_init(&c_tree_edges, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_tree_edges); + if (0 != igraph_vector_int_list_init(&c_component_edges, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_component_edges); + if (0 != igraph_vector_int_list_init(&c_components, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_components); IGRAPH_R_CHECK(igraph_vector_int_init(&c_articulation_points, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_articulation_points); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_biconnected_components(&c_graph, &c_no, &c_tree_edges, &c_component_edges, &c_components, &c_articulation_points)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(5)); @@ -6733,7 +7155,9 @@ SEXP R_igraph_bridges(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_bridges(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_to_SEXPp1(&c_res)); @@ -6758,7 +7182,9 @@ SEXP R_igraph_is_biconnected(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_biconnected(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_LOGICAL(1)); @@ -6786,7 +7212,9 @@ SEXP R_igraph_count_reachable(SEXP graph, SEXP mode) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_counts); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_count_reachable(&c_graph, &c_counts, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(counts=R_igraph_vector_int_to_SEXP(&c_counts)); @@ -6825,7 +7253,9 @@ SEXP R_igraph_bond_percolation(SEXP graph, SEXP edge_order) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edge_order); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_bond_percolation(&c_graph, &c_giant_size, &c_vetex_count, (Rf_isNull(edge_order) ? 0 : &c_edge_order))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_bond_percolation(&c_graph, &c_giant_size, &c_vetex_count, (Rf_isNull(edge_order) ? NULL : &c_edge_order))); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -6876,7 +7306,9 @@ SEXP R_igraph_site_percolation(SEXP graph, SEXP vertex_order) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vertex_order); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_site_percolation(&c_graph, &c_giant_size, &c_edge_count, (Rf_isNull(vertex_order) ? 0 : &c_vertex_order))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_site_percolation(&c_graph, &c_giant_size, &c_edge_count, (Rf_isNull(vertex_order) ? NULL : &c_vertex_order))); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -6920,7 +7352,9 @@ SEXP R_igraph_edgelist_percolation(SEXP edges) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_vertex_count, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vertex_count); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_edgelist_percolation(&c_edges, &c_giant_size, &c_vertex_count)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -6963,7 +7397,9 @@ SEXP R_igraph_is_clique(SEXP graph, SEXP candidate, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_clique(&c_graph, c_candidate, c_directed, &c_res)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_candidate_data); @@ -6979,25 +7415,32 @@ SEXP R_igraph_is_clique(SEXP graph, SEXP candidate, SEXP directed) { /*-------------------------------------------/ / igraph_cliques / /-------------------------------------------*/ -SEXP R_igraph_cliques(SEXP graph, SEXP min_size, SEXP max_size) { +SEXP R_igraph_cliques(SEXP graph, SEXP min_size, SEXP max_size, SEXP max_results) { /* Declarations */ igraph_t c_graph; igraph_vector_int_list_t c_res; igraph_integer_t c_min_size; igraph_integer_t c_max_size; + igraph_integer_t c_max_results; SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_res, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_res); + if (0 != igraph_vector_int_list_init(&c_res, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_res); IGRAPH_R_CHECK_INT(min_size); c_min_size = (igraph_integer_t) REAL(min_size)[0]; IGRAPH_R_CHECK_INT(max_size); c_max_size = (igraph_integer_t) REAL(max_size)[0]; + IGRAPH_R_CHECK_INT(max_results); + c_max_results = (igraph_integer_t) REAL(max_results)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_cliques(&c_graph, &c_res, c_min_size, c_max_size)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_cliques(&c_graph, &c_res, c_min_size, c_max_size, c_max_results)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_list_to_SEXPp1(&c_res)); @@ -7030,7 +7473,9 @@ SEXP R_igraph_clique_size_hist(SEXP graph, SEXP min_size, SEXP max_size) { IGRAPH_R_CHECK_INT(max_size); c_max_size = (igraph_integer_t) REAL(max_size)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_clique_size_hist(&c_graph, &c_hist, c_min_size, c_max_size)); + PutRNGstate(); /* Convert output */ PROTECT(hist=R_igraph_vector_to_SEXP(&c_hist)); @@ -7054,10 +7499,14 @@ SEXP R_igraph_largest_cliques(SEXP graph) { SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_res, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_res); + if (0 != igraph_vector_int_list_init(&c_res, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_largest_cliques(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_list_to_SEXPp1(&c_res)); @@ -7089,7 +7538,9 @@ SEXP R_igraph_maximal_cliques_count(SEXP graph, SEXP min_size, SEXP max_size) { IGRAPH_R_CHECK_INT(max_size); c_max_size = (igraph_integer_t) REAL(max_size)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_maximal_cliques_count(&c_graph, &c_no, c_min_size, c_max_size)); + PutRNGstate(); /* Convert output */ PROTECT(no=NEW_NUMERIC(1)); @@ -7121,7 +7572,9 @@ SEXP R_igraph_maximal_cliques_hist(SEXP graph, SEXP min_size, SEXP max_size) { IGRAPH_R_CHECK_INT(max_size); c_max_size = (igraph_integer_t) REAL(max_size)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_maximal_cliques_hist(&c_graph, &c_hist, c_min_size, c_max_size)); + PutRNGstate(); /* Convert output */ PROTECT(hist=R_igraph_vector_to_SEXP(&c_hist)); @@ -7147,7 +7600,9 @@ SEXP R_igraph_clique_number(SEXP graph) { R_SEXP_to_igraph(graph, &c_graph); c_no=0; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_clique_number(&c_graph, &c_no)); + PutRNGstate(); /* Convert output */ PROTECT(no=NEW_NUMERIC(1)); @@ -7161,14 +7616,15 @@ SEXP R_igraph_clique_number(SEXP graph) { /*-------------------------------------------/ / igraph_weighted_cliques / /-------------------------------------------*/ -SEXP R_igraph_weighted_cliques(SEXP graph, SEXP vertex_weights, SEXP min_weight, SEXP max_weight, SEXP maximal) { +SEXP R_igraph_weighted_cliques(SEXP graph, SEXP vertex_weights, SEXP maximal, SEXP min_weight, SEXP max_weight, SEXP max_results) { /* Declarations */ igraph_t c_graph; igraph_vector_t c_vertex_weights; igraph_vector_int_list_t c_res; + igraph_bool_t c_maximal; igraph_real_t c_min_weight; igraph_real_t c_max_weight; - igraph_bool_t c_maximal; + igraph_integer_t c_max_results; SEXP res; SEXP r_result; @@ -7177,16 +7633,22 @@ SEXP R_igraph_weighted_cliques(SEXP graph, SEXP vertex_weights, SEXP min_weight, if (!Rf_isNull(vertex_weights)) { R_SEXP_to_vector(vertex_weights, &c_vertex_weights); } - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_res, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_res); + if (0 != igraph_vector_int_list_init(&c_res, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_res); + IGRAPH_R_CHECK_BOOL(maximal); + c_maximal = LOGICAL(maximal)[0]; IGRAPH_R_CHECK_REAL(min_weight); c_min_weight = REAL(min_weight)[0]; IGRAPH_R_CHECK_REAL(max_weight); c_max_weight = REAL(max_weight)[0]; - IGRAPH_R_CHECK_BOOL(maximal); - c_maximal = LOGICAL(maximal)[0]; + IGRAPH_R_CHECK_INT(max_results); + c_max_results = (igraph_integer_t) REAL(max_results)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_weighted_cliques(&c_graph, (Rf_isNull(vertex_weights) ? 0 : &c_vertex_weights), &c_res, c_min_weight, c_max_weight, c_maximal)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_weighted_cliques(&c_graph, (Rf_isNull(vertex_weights) ? NULL : &c_vertex_weights), &c_res, c_maximal, c_min_weight, c_max_weight, c_max_results)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_list_to_SEXPp1(&c_res)); @@ -7214,10 +7676,14 @@ SEXP R_igraph_largest_weighted_cliques(SEXP graph, SEXP vertex_weights) { if (!Rf_isNull(vertex_weights)) { R_SEXP_to_vector(vertex_weights, &c_vertex_weights); } - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_res, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_res); + if (0 != igraph_vector_int_list_init(&c_res, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_res); /* Call igraph */ - IGRAPH_R_CHECK(igraph_largest_weighted_cliques(&c_graph, (Rf_isNull(vertex_weights) ? 0 : &c_vertex_weights), &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_largest_weighted_cliques(&c_graph, (Rf_isNull(vertex_weights) ? NULL : &c_vertex_weights), &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_list_to_SEXPp1(&c_res)); @@ -7246,7 +7712,9 @@ SEXP R_igraph_weighted_clique_number(SEXP graph, SEXP vertex_weights) { R_SEXP_to_vector(vertex_weights, &c_vertex_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_weighted_clique_number(&c_graph, (Rf_isNull(vertex_weights) ? 0 : &c_vertex_weights), &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_weighted_clique_number(&c_graph, (Rf_isNull(vertex_weights) ? NULL : &c_vertex_weights), &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -7273,7 +7741,9 @@ SEXP R_igraph_is_independent_vertex_set(SEXP graph, SEXP candidate) { igraph_vector_int_t c_candidate_data; R_SEXP_to_igraph_vs(candidate, &c_graph, &c_candidate, &c_candidate_data); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_independent_vertex_set(&c_graph, c_candidate, &c_res)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_candidate_data); @@ -7298,10 +7768,14 @@ SEXP R_igraph_largest_independent_vertex_sets(SEXP graph) { SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_res, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_res); + if (0 != igraph_vector_int_list_init(&c_res, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_largest_independent_vertex_sets(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_list_to_SEXPp1(&c_res)); @@ -7316,19 +7790,32 @@ SEXP R_igraph_largest_independent_vertex_sets(SEXP graph) { /*-------------------------------------------/ / igraph_maximal_independent_vertex_sets / /-------------------------------------------*/ -SEXP R_igraph_maximal_independent_vertex_sets(SEXP graph) { +SEXP R_igraph_maximal_independent_vertex_sets(SEXP graph, SEXP min_size, SEXP max_size, SEXP max_results) { /* Declarations */ igraph_t c_graph; igraph_vector_int_list_t c_res; + igraph_integer_t c_min_size; + igraph_integer_t c_max_size; + igraph_integer_t c_max_results; SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_res, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_res); + if (0 != igraph_vector_int_list_init(&c_res, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_res); + IGRAPH_R_CHECK_INT(min_size); + c_min_size = (igraph_integer_t) REAL(min_size)[0]; + IGRAPH_R_CHECK_INT(max_size); + c_max_size = (igraph_integer_t) REAL(max_size)[0]; + IGRAPH_R_CHECK_INT(max_results); + c_max_results = (igraph_integer_t) REAL(max_results)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_maximal_independent_vertex_sets(&c_graph, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_maximal_independent_vertex_sets(&c_graph, &c_res, c_min_size, c_max_size, c_max_results)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_list_to_SEXPp1(&c_res)); @@ -7354,7 +7841,9 @@ SEXP R_igraph_independence_number(SEXP graph) { R_SEXP_to_igraph(graph, &c_graph); c_no=0; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_independence_number(&c_graph, &c_no)); + PutRNGstate(); /* Convert output */ PROTECT(no=NEW_NUMERIC(1)); @@ -7380,7 +7869,9 @@ SEXP R_igraph_layout_random(SEXP graph) { IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_random(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7410,7 +7901,9 @@ SEXP R_igraph_layout_circle(SEXP graph, SEXP order) { igraph_vector_int_t c_order_data; R_SEXP_to_igraph_vs(order, &c_graph, &c_order, &c_order_data); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_circle(&c_graph, &c_res, c_order)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7449,7 +7942,9 @@ SEXP R_igraph_layout_star(SEXP graph, SEXP center, SEXP order) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_order); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_layout_star(&c_graph, &c_res, c_center, (Rf_isNull(order) ? 0 : &c_order))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_layout_star(&c_graph, &c_res, c_center, (Rf_isNull(order) ? NULL : &c_order))); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7481,7 +7976,9 @@ SEXP R_igraph_layout_grid(SEXP graph, SEXP width) { IGRAPH_R_CHECK_INT(width); c_width = (igraph_integer_t) REAL(width)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_grid(&c_graph, &c_res, c_width)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7514,7 +8011,9 @@ SEXP R_igraph_layout_grid_3d(SEXP graph, SEXP width, SEXP height) { IGRAPH_R_CHECK_INT(height); c_height = (igraph_integer_t) REAL(height)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_grid_3d(&c_graph, &c_res, c_width, c_height)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7545,7 +8044,9 @@ SEXP R_igraph_roots_for_tree_layout(SEXP graph, SEXP mode, SEXP heuristic) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_roots); c_heuristic = (igraph_root_choice_t) Rf_asInteger(heuristic); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_roots_for_tree_layout(&c_graph, c_mode, &c_roots, c_heuristic)); + PutRNGstate(); /* Convert output */ PROTECT(roots=R_igraph_vector_int_to_SEXPp1(&c_roots)); @@ -7572,7 +8073,9 @@ SEXP R_igraph_layout_random_3d(SEXP graph) { IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_random_3d(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7599,7 +8102,9 @@ SEXP R_igraph_layout_sphere(SEXP graph) { IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_sphere(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7634,7 +8139,9 @@ SEXP R_igraph_layout_drl(SEXP graph, SEXP res, SEXP use_seed, SEXP options, SEXP R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_layout_drl(&c_graph, &c_res, c_use_seed, &c_options, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_layout_drl(&c_graph, &c_res, c_use_seed, &c_options, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7669,7 +8176,9 @@ SEXP R_igraph_layout_drl_3d(SEXP graph, SEXP res, SEXP use_seed, SEXP options, S R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_layout_drl_3d(&c_graph, &c_res, c_use_seed, &c_options, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_layout_drl_3d(&c_graph, &c_res, c_use_seed, &c_options, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7688,24 +8197,22 @@ SEXP R_igraph_layout_sugiyama(SEXP graph, SEXP layers, SEXP hgap, SEXP vgap, SEX /* Declarations */ igraph_t c_graph; igraph_matrix_t c_res; - igraph_t c_extd_graph; - igraph_vector_int_t c_extd_to_orig_eids; + igraph_matrix_list_t c_routing; igraph_vector_int_t c_layers; igraph_real_t c_hgap; igraph_real_t c_vgap; igraph_integer_t c_maxiter; igraph_vector_t c_weights; SEXP res; - SEXP extd_graph; - SEXP extd_to_orig_eids; + SEXP routing; SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); - IGRAPH_R_CHECK(igraph_vector_int_init(&c_extd_to_orig_eids, 0)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_extd_to_orig_eids); + IGRAPH_R_CHECK(igraph_matrix_list_init(&c_routing, 0)); + IGRAPH_FINALLY(igraph_matrix_list_destroy, &c_routing); if (!Rf_isNull(layers)) { R_SEXP_to_vector_int_copy(layers, &c_layers); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_layers); @@ -7723,31 +8230,27 @@ SEXP R_igraph_layout_sugiyama(SEXP graph, SEXP layers, SEXP hgap, SEXP vgap, SEX R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_layout_sugiyama(&c_graph, &c_res, &c_extd_graph, &c_extd_to_orig_eids, (Rf_isNull(layers) ? 0 : &c_layers), c_hgap, c_vgap, c_maxiter, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_layout_sugiyama(&c_graph, &c_res, &c_routing, (Rf_isNull(layers) ? NULL : &c_layers), c_hgap, c_vgap, c_maxiter, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ - PROTECT(r_result=NEW_LIST(3)); - PROTECT(r_names=NEW_CHARACTER(3)); + PROTECT(r_result=NEW_LIST(2)); + PROTECT(r_names=NEW_CHARACTER(2)); PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); igraph_matrix_destroy(&c_res); IGRAPH_FINALLY_CLEAN(1); - IGRAPH_FINALLY(igraph_destroy, &c_extd_graph); - PROTECT(extd_graph=R_igraph_to_SEXP(&c_extd_graph)); - IGRAPH_I_DESTROY(&c_extd_graph); - IGRAPH_FINALLY_CLEAN(1); - PROTECT(extd_to_orig_eids=R_igraph_vector_int_to_SEXPp1(&c_extd_to_orig_eids)); - igraph_vector_int_destroy(&c_extd_to_orig_eids); + PROTECT(routing=R_igraph_matrixlist_to_SEXP(&c_routing)); + igraph_matrix_list_destroy(&c_routing); IGRAPH_FINALLY_CLEAN(1); igraph_vector_int_destroy(&c_layers); IGRAPH_FINALLY_CLEAN(1); SET_VECTOR_ELT(r_result, 0, res); - SET_VECTOR_ELT(r_result, 1, extd_graph); - SET_VECTOR_ELT(r_result, 2, extd_to_orig_eids); + SET_VECTOR_ELT(r_result, 1, routing); SET_STRING_ELT(r_names, 0, Rf_mkChar("res")); - SET_STRING_ELT(r_names, 1, Rf_mkChar("extd_graph")); - SET_STRING_ELT(r_names, 2, Rf_mkChar("extd_to_orig_eids")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("routing")); SET_NAMES(r_result, r_names); - UNPROTECT(4); + UNPROTECT(3); UNPROTECT(1); return(r_result); @@ -7775,7 +8278,9 @@ SEXP R_igraph_layout_mds(SEXP graph, SEXP dist, SEXP dim) { IGRAPH_R_CHECK_INT(dim); c_dim = (igraph_integer_t) REAL(dim)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_layout_mds(&c_graph, &c_res, (Rf_isNull(dist) ? 0 : &c_dist), c_dim)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_layout_mds(&c_graph, &c_res, (Rf_isNull(dist) ? NULL : &c_dist), c_dim)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7813,7 +8318,9 @@ SEXP R_igraph_layout_bipartite(SEXP graph, SEXP types, SEXP hgap, SEXP vgap, SEX IGRAPH_R_CHECK_INT(maxiter); c_maxiter = (igraph_integer_t) REAL(maxiter)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_bipartite(&c_graph, &c_types, &c_res, c_hgap, c_vgap, c_maxiter)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7854,7 +8361,9 @@ SEXP R_igraph_layout_gem(SEXP graph, SEXP res, SEXP use_seed, SEXP maxiter, SEXP IGRAPH_R_CHECK_REAL(temp_init); c_temp_init = REAL(temp_init)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_gem(&c_graph, &c_res, c_use_seed, c_maxiter, c_temp_max, c_temp_min, c_temp_init)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7907,7 +8416,9 @@ SEXP R_igraph_layout_davidson_harel(SEXP graph, SEXP res, SEXP use_seed, SEXP ma IGRAPH_R_CHECK_REAL(weight_node_edge_dist); c_weight_node_edge_dist = REAL(weight_node_edge_dist)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_davidson_harel(&c_graph, &c_res, c_use_seed, c_maxiter, c_fineiter, c_cool_fact, c_weight_node_dist, c_weight_border, c_weight_edge_lengths, c_weight_edge_crossings, c_weight_node_edge_dist)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7949,7 +8460,9 @@ SEXP R_igraph_layout_umap(SEXP graph, SEXP res, SEXP use_seed, SEXP distances, S IGRAPH_R_CHECK_BOOL(distances_are_weights); c_distances_are_weights = LOGICAL(distances_are_weights)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_layout_umap(&c_graph, &c_res, c_use_seed, (Rf_isNull(distances) ? 0 : &c_distances), c_min_dist, c_epochs, c_distances_are_weights)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_layout_umap(&c_graph, &c_res, c_use_seed, (Rf_isNull(distances) ? NULL : &c_distances), c_min_dist, c_epochs, c_distances_are_weights)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -7991,7 +8504,9 @@ SEXP R_igraph_layout_umap_3d(SEXP graph, SEXP res, SEXP use_seed, SEXP distances IGRAPH_R_CHECK_BOOL(distances_are_weights); c_distances_are_weights = LOGICAL(distances_are_weights)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_layout_umap_3d(&c_graph, &c_res, c_use_seed, (Rf_isNull(distances) ? 0 : &c_distances), c_min_dist, c_epochs, c_distances_are_weights)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_layout_umap_3d(&c_graph, &c_res, c_use_seed, (Rf_isNull(distances) ? NULL : &c_distances), c_min_dist, c_epochs, c_distances_are_weights)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -8019,7 +8534,9 @@ SEXP R_igraph_layout_umap_compute_weights(SEXP graph, SEXP distances, SEXP weigh IGRAPH_R_CHECK(R_SEXP_to_vector_copy(weights, &c_weights)); IGRAPH_FINALLY(igraph_vector_destroy, &c_weights); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_umap_compute_weights(&c_graph, &c_distances, &c_weights)); + PutRNGstate(); /* Convert output */ PROTECT(weights=R_igraph_vector_to_SEXP(&c_weights)); @@ -8045,7 +8562,9 @@ SEXP R_igraph_layout_align(SEXP graph, SEXP layout) { IGRAPH_R_CHECK(R_SEXP_to_igraph_matrix_copy(layout, &c_layout)); IGRAPH_FINALLY(igraph_matrix_destroy, &c_layout); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_layout_align(&c_graph, &c_layout)); + PutRNGstate(); /* Convert output */ PROTECT(layout=R_igraph_matrix_to_SEXP(&c_layout)); @@ -8075,7 +8594,9 @@ SEXP R_igraph_cocitation(SEXP graph, SEXP vids) { igraph_vector_int_t c_vids_data; R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_cocitation(&c_graph, &c_res, c_vids)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -8107,7 +8628,9 @@ SEXP R_igraph_bibcoupling(SEXP graph, SEXP vids) { igraph_vector_int_t c_vids_data; R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_bibcoupling(&c_graph, &c_res, c_vids)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -8124,11 +8647,12 @@ SEXP R_igraph_bibcoupling(SEXP graph, SEXP vids) { /*-------------------------------------------/ / igraph_similarity_dice / /-------------------------------------------*/ -SEXP R_igraph_similarity_dice(SEXP graph, SEXP vids, SEXP mode, SEXP loops) { +SEXP R_igraph_similarity_dice(SEXP graph, SEXP from, SEXP to, SEXP mode, SEXP loops) { /* Declarations */ igraph_t c_graph; igraph_matrix_t c_res; - igraph_vs_t c_vids; + igraph_vs_t c_from; + igraph_vs_t c_to; igraph_neimode_t c_mode; igraph_bool_t c_loops; SEXP res; @@ -8138,20 +8662,26 @@ SEXP R_igraph_similarity_dice(SEXP graph, SEXP vids, SEXP mode, SEXP loops) { R_SEXP_to_igraph(graph, &c_graph); IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); - igraph_vector_int_t c_vids_data; - R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); + igraph_vector_int_t c_from_data; + R_SEXP_to_igraph_vs(from, &c_graph, &c_from, &c_from_data); + igraph_vector_int_t c_to_data; + R_SEXP_to_igraph_vs(to, &c_graph, &c_to, &c_to_data); c_mode = (igraph_neimode_t) Rf_asInteger(mode); IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_similarity_dice(&c_graph, &c_res, c_vids, c_mode, c_loops)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_similarity_dice(&c_graph, &c_res, c_from, c_to, c_mode, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); igraph_matrix_destroy(&c_res); IGRAPH_FINALLY_CLEAN(1); - igraph_vector_int_destroy(&c_vids_data); - igraph_vs_destroy(&c_vids); + igraph_vector_int_destroy(&c_from_data); + igraph_vs_destroy(&c_from); + igraph_vector_int_destroy(&c_to_data); + igraph_vs_destroy(&c_to); r_result = res; UNPROTECT(1); @@ -8181,7 +8711,9 @@ SEXP R_igraph_similarity_dice_es(SEXP graph, SEXP es, SEXP mode, SEXP loops) { IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_similarity_dice_es(&c_graph, &c_res, c_es, c_mode, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -8218,7 +8750,9 @@ SEXP R_igraph_similarity_dice_pairs(SEXP graph, SEXP pairs, SEXP mode, SEXP loop IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_similarity_dice_pairs(&c_graph, &c_res, &c_pairs, c_mode, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -8252,7 +8786,9 @@ SEXP R_igraph_similarity_inverse_log_weighted(SEXP graph, SEXP vids, SEXP mode) R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_similarity_inverse_log_weighted(&c_graph, &c_res, c_vids, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -8269,11 +8805,12 @@ SEXP R_igraph_similarity_inverse_log_weighted(SEXP graph, SEXP vids, SEXP mode) /*-------------------------------------------/ / igraph_similarity_jaccard / /-------------------------------------------*/ -SEXP R_igraph_similarity_jaccard(SEXP graph, SEXP vids, SEXP mode, SEXP loops) { +SEXP R_igraph_similarity_jaccard(SEXP graph, SEXP from, SEXP to, SEXP mode, SEXP loops) { /* Declarations */ igraph_t c_graph; igraph_matrix_t c_res; - igraph_vs_t c_vids; + igraph_vs_t c_from; + igraph_vs_t c_to; igraph_neimode_t c_mode; igraph_bool_t c_loops; SEXP res; @@ -8283,20 +8820,26 @@ SEXP R_igraph_similarity_jaccard(SEXP graph, SEXP vids, SEXP mode, SEXP loops) { R_SEXP_to_igraph(graph, &c_graph); IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); - igraph_vector_int_t c_vids_data; - R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); + igraph_vector_int_t c_from_data; + R_SEXP_to_igraph_vs(from, &c_graph, &c_from, &c_from_data); + igraph_vector_int_t c_to_data; + R_SEXP_to_igraph_vs(to, &c_graph, &c_to, &c_to_data); c_mode = (igraph_neimode_t) Rf_asInteger(mode); IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_similarity_jaccard(&c_graph, &c_res, c_vids, c_mode, c_loops)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_similarity_jaccard(&c_graph, &c_res, c_from, c_to, c_mode, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); igraph_matrix_destroy(&c_res); IGRAPH_FINALLY_CLEAN(1); - igraph_vector_int_destroy(&c_vids_data); - igraph_vs_destroy(&c_vids); + igraph_vector_int_destroy(&c_from_data); + igraph_vs_destroy(&c_from); + igraph_vector_int_destroy(&c_to_data); + igraph_vs_destroy(&c_to); r_result = res; UNPROTECT(1); @@ -8326,7 +8869,9 @@ SEXP R_igraph_similarity_jaccard_es(SEXP graph, SEXP es, SEXP mode, SEXP loops) IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_similarity_jaccard_es(&c_graph, &c_res, c_es, c_mode, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -8363,7 +8908,9 @@ SEXP R_igraph_similarity_jaccard_pairs(SEXP graph, SEXP pairs, SEXP mode, SEXP l IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_similarity_jaccard_pairs(&c_graph, &c_res, &c_pairs, c_mode, c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -8396,7 +8943,9 @@ SEXP R_igraph_compare_communities(SEXP comm1, SEXP comm2, SEXP method) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_comm2); c_method = (igraph_community_comparison_t) Rf_asInteger(method); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_compare_communities(&c_comm1, &c_comm2, &c_res, c_method)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_comm1); @@ -8437,7 +8986,9 @@ SEXP R_igraph_modularity(SEXP graph, SEXP membership, SEXP weights, SEXP resolut IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_modularity(&c_graph, &c_membership, (Rf_isNull(weights) ? 0 : &c_weights), c_resolution, c_directed, &c_modularity)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_modularity(&c_graph, &c_membership, (Rf_isNull(weights) ? NULL : &c_weights), c_resolution, c_directed, &c_modularity)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_membership); @@ -8475,7 +9026,9 @@ SEXP R_igraph_modularity_matrix(SEXP graph, SEXP weights, SEXP resolution, SEXP IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_modularity_matrix(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), c_resolution, &c_modmat, c_directed)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_modularity_matrix(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), c_resolution, &c_modmat, c_directed)); + PutRNGstate(); /* Convert output */ PROTECT(modmat=R_igraph_matrix_to_SEXP(&c_modmat)); @@ -8505,7 +9058,9 @@ SEXP R_igraph_community_fluid_communities(SEXP graph, SEXP no_of_communities) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_membership, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_membership); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_community_fluid_communities(&c_graph, c_no_of_communities, &c_membership)); + PutRNGstate(); /* Convert output */ PROTECT(membership=R_igraph_vector_int_to_SEXP(&c_membership)); @@ -8520,7 +9075,7 @@ SEXP R_igraph_community_fluid_communities(SEXP graph, SEXP no_of_communities) { /*-------------------------------------------/ / igraph_community_label_propagation / /-------------------------------------------*/ -SEXP R_igraph_community_label_propagation(SEXP graph, SEXP mode, SEXP weights, SEXP initial, SEXP fixed) { +SEXP R_igraph_community_label_propagation(SEXP graph, SEXP mode, SEXP weights, SEXP initial, SEXP fixed, SEXP lpa_variant) { /* Declarations */ igraph_t c_graph; igraph_vector_int_t c_membership; @@ -8528,6 +9083,7 @@ SEXP R_igraph_community_label_propagation(SEXP graph, SEXP mode, SEXP weights, S igraph_vector_t c_weights; igraph_vector_int_t c_initial; igraph_vector_bool_t c_fixed; + igraph_lpa_variant_t c_lpa_variant; SEXP membership; SEXP r_result; @@ -8549,8 +9105,11 @@ SEXP R_igraph_community_label_propagation(SEXP graph, SEXP mode, SEXP weights, S if (!Rf_isNull(fixed)) { R_SEXP_to_vector_bool(fixed, &c_fixed); } + c_lpa_variant = (igraph_lpa_variant_t) Rf_asInteger(lpa_variant); /* Call igraph */ - IGRAPH_R_CHECK(igraph_community_label_propagation(&c_graph, &c_membership, c_mode, (Rf_isNull(weights) ? 0 : &c_weights), (Rf_isNull(initial) ? 0 : &c_initial), (Rf_isNull(fixed) ? 0 : &c_fixed))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_community_label_propagation(&c_graph, &c_membership, c_mode, (Rf_isNull(weights) ? NULL : &c_weights), (Rf_isNull(initial) ? NULL : &c_initial), (Rf_isNull(fixed) ? NULL : &c_fixed), c_lpa_variant)); + PutRNGstate(); /* Convert output */ PROTECT(membership=R_igraph_vector_int_to_SEXP(&c_membership)); @@ -8594,7 +9153,9 @@ SEXP R_igraph_community_multilevel(SEXP graph, SEXP weights, SEXP resolution) { IGRAPH_R_CHECK(igraph_vector_init(&c_modularity, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_modularity); /* Call igraph */ - IGRAPH_R_CHECK(igraph_community_multilevel(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), c_resolution, &c_membership, &c_memberships, &c_modularity)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_community_multilevel(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), c_resolution, &c_membership, &c_memberships, &c_modularity)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -8624,25 +9185,30 @@ SEXP R_igraph_community_multilevel(SEXP graph, SEXP weights, SEXP resolution) { /*-------------------------------------------/ / igraph_community_optimal_modularity / /-------------------------------------------*/ -SEXP R_igraph_community_optimal_modularity(SEXP graph, SEXP weights) { +SEXP R_igraph_community_optimal_modularity(SEXP graph, SEXP weights, SEXP resolution) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; + igraph_real_t c_resolution; igraph_real_t c_modularity; igraph_vector_int_t c_membership; - igraph_vector_t c_weights; SEXP modularity; SEXP membership; SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_init(&c_membership, 0)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_membership); if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } + IGRAPH_R_CHECK_REAL(resolution); + c_resolution = REAL(resolution)[0]; + IGRAPH_R_CHECK(igraph_vector_int_init(&c_membership, 0)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_membership); /* Call igraph */ - IGRAPH_R_CHECK(igraph_community_optimal_modularity(&c_graph, &c_modularity, &c_membership, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_community_optimal_modularity(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), c_resolution, &c_modularity, &c_membership)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -8666,11 +9232,12 @@ SEXP R_igraph_community_optimal_modularity(SEXP graph, SEXP weights) { /*-------------------------------------------/ / igraph_community_leiden / /-------------------------------------------*/ -SEXP R_igraph_community_leiden(SEXP graph, SEXP weights, SEXP vertex_weights, SEXP resolution, SEXP beta, SEXP start, SEXP n_iterations, SEXP membership) { +SEXP R_igraph_community_leiden(SEXP graph, SEXP weights, SEXP vertex_out_weights, SEXP vertex_in_weights, SEXP resolution, SEXP beta, SEXP start, SEXP n_iterations, SEXP membership) { /* Declarations */ igraph_t c_graph; igraph_vector_t c_weights; - igraph_vector_t c_vertex_weights; + igraph_vector_t c_vertex_out_weights; + igraph_vector_t c_vertex_in_weights; igraph_real_t c_resolution; igraph_real_t c_beta; igraph_bool_t c_start; @@ -8687,8 +9254,11 @@ SEXP R_igraph_community_leiden(SEXP graph, SEXP weights, SEXP vertex_weights, SE if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } - if (!Rf_isNull(vertex_weights)) { - R_SEXP_to_vector(vertex_weights, &c_vertex_weights); + if (!Rf_isNull(vertex_out_weights)) { + R_SEXP_to_vector(vertex_out_weights, &c_vertex_out_weights); + } + if (!Rf_isNull(vertex_in_weights)) { + R_SEXP_to_vector(vertex_in_weights, &c_vertex_in_weights); } IGRAPH_R_CHECK_REAL(resolution); c_resolution = REAL(resolution)[0]; @@ -8707,7 +9277,9 @@ SEXP R_igraph_community_leiden(SEXP graph, SEXP weights, SEXP vertex_weights, SE } c_nb_clusters=0; /* Call igraph */ - IGRAPH_R_CHECK(igraph_community_leiden(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), (Rf_isNull(vertex_weights) ? 0 : &c_vertex_weights), c_resolution, c_beta, c_start, c_n_iterations, &c_membership, &c_nb_clusters, &c_quality)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_community_leiden(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), (Rf_isNull(vertex_out_weights) ? NULL : &c_vertex_out_weights), (Rf_isNull(vertex_in_weights) ? NULL : &c_vertex_in_weights), c_resolution, c_beta, c_start, c_n_iterations, &c_membership, &c_nb_clusters, &c_quality)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -8733,13 +9305,82 @@ SEXP R_igraph_community_leiden(SEXP graph, SEXP weights, SEXP vertex_weights, SE } /*-------------------------------------------/ -/ igraph_split_join_distance / +/ igraph_community_leiden_simple / /-------------------------------------------*/ -SEXP R_igraph_split_join_distance(SEXP comm1, SEXP comm2) { +SEXP R_igraph_community_leiden_simple(SEXP graph, SEXP weights, SEXP objective, SEXP resolution, SEXP beta, SEXP start, SEXP n_iterations, SEXP membership) { /* Declarations */ - igraph_vector_int_t c_comm1; - igraph_vector_int_t c_comm2; - igraph_integer_t c_distance12; + igraph_t c_graph; + igraph_vector_t c_weights; + igraph_leiden_objective_t c_objective; + igraph_real_t c_resolution; + igraph_real_t c_beta; + igraph_bool_t c_start; + igraph_integer_t c_n_iterations; + igraph_vector_int_t c_membership; + igraph_integer_t c_nb_clusters; + igraph_real_t c_quality; + SEXP nb_clusters; + SEXP quality; + + SEXP r_result, r_names; + /* Convert input */ + R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } + c_objective = (igraph_leiden_objective_t) Rf_asInteger(objective); + IGRAPH_R_CHECK_REAL(resolution); + c_resolution = REAL(resolution)[0]; + IGRAPH_R_CHECK_REAL(beta); + c_beta = REAL(beta)[0]; + IGRAPH_R_CHECK_BOOL(start); + c_start = LOGICAL(start)[0]; + IGRAPH_R_CHECK_INT(n_iterations); + c_n_iterations = (igraph_integer_t) REAL(n_iterations)[0]; + if (!Rf_isNull(membership)) { + IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(membership, &c_membership)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_membership); + } else { + IGRAPH_R_CHECK(igraph_vector_int_init(&c_membership, 0)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_membership); + } + c_nb_clusters=0; + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_community_leiden_simple(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), c_objective, c_resolution, c_beta, c_start, c_n_iterations, &c_membership, &c_nb_clusters, &c_quality)); + PutRNGstate(); + + /* Convert output */ + PROTECT(r_result=NEW_LIST(3)); + PROTECT(r_names=NEW_CHARACTER(3)); + PROTECT(membership=R_igraph_vector_int_to_SEXP(&c_membership)); + igraph_vector_int_destroy(&c_membership); + IGRAPH_FINALLY_CLEAN(1); + PROTECT(nb_clusters=NEW_NUMERIC(1)); + REAL(nb_clusters)[0]=(double) c_nb_clusters; + PROTECT(quality=NEW_NUMERIC(1)); + REAL(quality)[0]=c_quality; + SET_VECTOR_ELT(r_result, 0, membership); + SET_VECTOR_ELT(r_result, 1, nb_clusters); + SET_VECTOR_ELT(r_result, 2, quality); + SET_STRING_ELT(r_names, 0, Rf_mkChar("membership")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("nb_clusters")); + SET_STRING_ELT(r_names, 2, Rf_mkChar("quality")); + SET_NAMES(r_result, r_names); + UNPROTECT(4); + + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_split_join_distance / +/-------------------------------------------*/ +SEXP R_igraph_split_join_distance(SEXP comm1, SEXP comm2) { + /* Declarations */ + igraph_vector_int_t c_comm1; + igraph_vector_int_t c_comm2; + igraph_integer_t c_distance12; igraph_integer_t c_distance21; SEXP distance12; SEXP distance21; @@ -8753,7 +9394,9 @@ SEXP R_igraph_split_join_distance(SEXP comm1, SEXP comm2) { c_distance12=0; c_distance21=0; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_split_join_distance(&c_comm1, &c_comm2, &c_distance12, &c_distance21)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -8780,12 +9423,14 @@ SEXP R_igraph_split_join_distance(SEXP comm1, SEXP comm2) { /*-------------------------------------------/ / igraph_community_infomap / /-------------------------------------------*/ -SEXP R_igraph_community_infomap(SEXP graph, SEXP e_weights, SEXP v_weights, SEXP nb_trials) { +SEXP R_igraph_community_infomap(SEXP graph, SEXP edge_weights, SEXP vertex_weights, SEXP nb_trials, SEXP is_regularized, SEXP regularization_strength) { /* Declarations */ igraph_t c_graph; - igraph_vector_t c_e_weights; - igraph_vector_t c_v_weights; + igraph_vector_t c_edge_weights; + igraph_vector_t c_vertex_weights; igraph_integer_t c_nb_trials; + igraph_bool_t c_is_regularized; + igraph_real_t c_regularization_strength; igraph_vector_int_t c_membership; igraph_real_t c_codelength; SEXP membership; @@ -8794,18 +9439,24 @@ SEXP R_igraph_community_infomap(SEXP graph, SEXP e_weights, SEXP v_weights, SEXP SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - if (!Rf_isNull(e_weights)) { - R_SEXP_to_vector(e_weights, &c_e_weights); + if (!Rf_isNull(edge_weights)) { + R_SEXP_to_vector(edge_weights, &c_edge_weights); } - if (!Rf_isNull(v_weights)) { - R_SEXP_to_vector(v_weights, &c_v_weights); + if (!Rf_isNull(vertex_weights)) { + R_SEXP_to_vector(vertex_weights, &c_vertex_weights); } IGRAPH_R_CHECK_INT(nb_trials); c_nb_trials = (igraph_integer_t) REAL(nb_trials)[0]; + IGRAPH_R_CHECK_BOOL(is_regularized); + c_is_regularized = LOGICAL(is_regularized)[0]; + IGRAPH_R_CHECK_REAL(regularization_strength); + c_regularization_strength = REAL(regularization_strength)[0]; IGRAPH_R_CHECK(igraph_vector_int_init(&c_membership, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_membership); /* Call igraph */ - IGRAPH_R_CHECK(igraph_community_infomap(&c_graph, (Rf_isNull(e_weights) ? 0 : &c_e_weights), (Rf_isNull(v_weights) ? 0 : &c_v_weights), c_nb_trials, &c_membership, &c_codelength)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_community_infomap(&c_graph, (Rf_isNull(edge_weights) ? NULL : &c_edge_weights), (Rf_isNull(vertex_weights) ? NULL : &c_vertex_weights), c_nb_trials, c_is_regularized, c_regularization_strength, &c_membership, &c_codelength)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -8844,12 +9495,16 @@ SEXP R_igraph_graphlets_candidate_basis(SEXP graph, SEXP weights) { if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_cliques, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_cliques); + if (0 != igraph_vector_int_list_init(&c_cliques, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_cliques); IGRAPH_R_CHECK(igraph_vector_init(&c_thresholds, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_thresholds); /* Call igraph */ - IGRAPH_R_CHECK(igraph_graphlets_candidate_basis(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_cliques, &c_thresholds)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_graphlets_candidate_basis(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_cliques, &c_thresholds)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -8889,8 +9544,8 @@ SEXP R_igraph_graphlets_project(SEXP graph, SEXP weights, SEXP cliques, SEXP Muc if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } - IGRAPH_R_CHECK(R_igraph_SEXP_to_vector_int_list(cliques, &c_cliques)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_cliques); + R_igraph_SEXP_to_vector_int_list(cliques, &c_cliques); + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_cliques); IGRAPH_R_CHECK(R_SEXP_to_vector_copy(Muc, &c_Muc)); IGRAPH_FINALLY(igraph_vector_destroy, &c_Muc); IGRAPH_R_CHECK_BOOL(startMu); @@ -8898,7 +9553,9 @@ SEXP R_igraph_graphlets_project(SEXP graph, SEXP weights, SEXP cliques, SEXP Muc IGRAPH_R_CHECK_INT(niter); c_niter = (igraph_integer_t) REAL(niter)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_graphlets_project(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_cliques, &c_Muc, c_startMu, c_niter)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_graphlets_project(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_cliques, &c_Muc, c_startMu, c_niter)); + PutRNGstate(); /* Convert output */ igraph_vector_int_list_destroy(&c_cliques); @@ -8932,7 +9589,9 @@ SEXP R_igraph_hrg_fit(SEXP graph, SEXP hrg, SEXP start, SEXP steps) { IGRAPH_R_CHECK_INT(steps); c_steps = (igraph_integer_t) REAL(steps)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hrg_fit(&c_graph, &c_hrg, c_start, c_steps)); + PutRNGstate(); /* Convert output */ PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); @@ -8958,7 +9617,9 @@ SEXP R_igraph_hrg_sample(SEXP hrg) { IGRAPH_R_CHECK(R_SEXP_to_hrg_copy(hrg, &c_hrg)); IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hrg_sample(&c_hrg, &c_sample)); + PutRNGstate(); /* Convert output */ igraph_hrg_destroy(&c_hrg); @@ -8992,7 +9653,9 @@ SEXP R_igraph_hrg_sample_many(SEXP hrg, SEXP num_samples) { IGRAPH_R_CHECK_INT(num_samples); c_num_samples = (igraph_integer_t) REAL(num_samples)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hrg_sample_many(&c_hrg, &c_samples, c_num_samples)); + PutRNGstate(); /* Convert output */ igraph_hrg_destroy(&c_hrg); @@ -9020,7 +9683,9 @@ SEXP R_igraph_hrg_game(SEXP hrg) { IGRAPH_R_CHECK(R_SEXP_to_hrg_copy(hrg, &c_hrg)); IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hrg_game(&c_graph, &c_hrg)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -9063,7 +9728,9 @@ SEXP R_igraph_hrg_consensus(SEXP graph, SEXP hrg, SEXP start, SEXP num_samples) IGRAPH_R_CHECK_INT(num_samples); c_num_samples = (igraph_integer_t) REAL(num_samples)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hrg_consensus(&c_graph, &c_parents, &c_weights, &c_hrg, c_start, c_num_samples)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -9121,7 +9788,9 @@ SEXP R_igraph_hrg_predict(SEXP graph, SEXP hrg, SEXP start, SEXP num_samples, SE IGRAPH_R_CHECK_INT(num_bins); c_num_bins = (igraph_integer_t) REAL(num_bins)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hrg_predict(&c_graph, &c_edges, &c_prob, &c_hrg, c_start, c_num_samples, c_num_bins)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -9165,7 +9834,9 @@ SEXP R_igraph_hrg_create(SEXP graph, SEXP prob) { R_SEXP_to_igraph(graph, &c_graph); R_SEXP_to_vector(prob, &c_prob); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hrg_create(&c_hrg, &c_graph, &c_prob)); + PutRNGstate(); /* Convert output */ PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); @@ -9192,7 +9863,9 @@ SEXP R_igraph_hrg_resize(SEXP hrg, SEXP newsize) { IGRAPH_R_CHECK_INT(newsize); c_newsize = (igraph_integer_t) REAL(newsize)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_hrg_resize(&c_hrg, c_newsize)); + PutRNGstate(); /* Convert output */ PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); @@ -9216,7 +9889,9 @@ SEXP R_igraph_hrg_size(SEXP hrg) { IGRAPH_R_CHECK(R_SEXP_to_hrg_copy(hrg, &c_hrg)); IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg); /* Call igraph */ + GetRNGstate(); c_result=igraph_hrg_size(&c_hrg); + PutRNGstate(); /* Convert output */ igraph_hrg_destroy(&c_hrg); @@ -9246,7 +9921,9 @@ SEXP R_igraph_from_hrg_dendrogram(SEXP hrg) { IGRAPH_R_CHECK(igraph_vector_init(&c_prob, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_prob); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_from_hrg_dendrogram(&c_graph, &c_hrg, &c_prob)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -9294,7 +9971,9 @@ SEXP R_igraph_get_adjacency_sparse(SEXP graph, SEXP type, SEXP weights, SEXP loo } c_loops = (igraph_loops_t) Rf_asInteger(loops); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_adjacency_sparse(&c_graph, &c_sparsemat, c_type, (Rf_isNull(weights) ? 0 : &c_weights), c_loops)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_adjacency_sparse(&c_graph, &c_sparsemat, c_type, (Rf_isNull(weights) ? NULL : &c_weights), c_loops)); + PutRNGstate(); /* Convert output */ PROTECT(sparsemat=R_igraph_sparsemat_to_SEXP(&c_sparsemat)); @@ -9324,7 +10003,9 @@ SEXP R_igraph_get_edgelist(SEXP graph, SEXP bycol) { IGRAPH_R_CHECK_BOOL(bycol); c_bycol = LOGICAL(bycol)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_get_edgelist(&c_graph, &c_res, c_bycol)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_to_SEXP(&c_res)); @@ -9358,7 +10039,9 @@ SEXP R_igraph_get_stochastic(SEXP graph, SEXP column_wise, SEXP weights) { R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_stochastic(&c_graph, &c_res, c_column_wise, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_stochastic(&c_graph, &c_res, c_column_wise, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); @@ -9392,7 +10075,9 @@ SEXP R_igraph_get_stochastic_sparse(SEXP graph, SEXP column_wise, SEXP weights) R_SEXP_to_vector(weights, &c_weights); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_stochastic_sparse(&c_graph, &c_sparsemat, c_column_wise, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_stochastic_sparse(&c_graph, &c_sparsemat, c_column_wise, (Rf_isNull(weights) ? NULL : &c_weights))); + PutRNGstate(); /* Convert output */ PROTECT(sparsemat=R_igraph_sparsemat_to_SEXP(&c_sparsemat)); @@ -9418,7 +10103,9 @@ SEXP R_igraph_to_directed(SEXP graph, SEXP mode) { IGRAPH_FINALLY(igraph_destroy, &c_graph); c_mode = (igraph_to_directed_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_to_directed(&c_graph, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(graph=R_igraph_to_SEXP(&c_graph)); @@ -9447,7 +10134,9 @@ SEXP R_igraph_to_undirected(SEXP graph, SEXP mode, SEXP edge_attr_comb) { R_SEXP_to_attr_comb(edge_attr_comb, &c_edge_attr_comb); IGRAPH_FINALLY(igraph_attribute_combination_destroy, &c_edge_attr_comb); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_to_undirected(&c_graph, c_mode, &c_edge_attr_comb)); + PutRNGstate(); /* Convert output */ PROTECT(graph=R_igraph_to_SEXP(&c_graph)); @@ -9475,7 +10164,9 @@ SEXP R_igraph_read_graph_pajek(SEXP instream) { c_instream = R_igraph_fopen_read(instream); IGRAPH_FINALLY(fclose, c_instream); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_read_graph_pajek(&c_graph, c_instream)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -9505,7 +10196,9 @@ SEXP R_igraph_read_graph_graphml(SEXP instream, SEXP index) { IGRAPH_R_CHECK_INT(index); c_index = (igraph_integer_t) REAL(index)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_read_graph_graphml(&c_graph, c_instream, c_index)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -9535,7 +10228,9 @@ SEXP R_igraph_read_graph_graphdb(SEXP instream, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_read_graph_graphdb(&c_graph, c_instream, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -9562,7 +10257,9 @@ SEXP R_igraph_read_graph_gml(SEXP instream) { c_instream = R_igraph_fopen_read(instream); IGRAPH_FINALLY(fclose, c_instream); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_read_graph_gml(&c_graph, c_instream)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -9592,7 +10289,9 @@ SEXP R_igraph_read_graph_dl(SEXP instream, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_read_graph_dl(&c_graph, c_instream, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -9616,7 +10315,9 @@ SEXP R_igraph_write_graph_edgelist(SEXP graph, SEXP outstream) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_write_graph_edgelist(&c_graph, c_outstream)); + PutRNGstate(); /* Convert output */ @@ -9640,7 +10341,9 @@ SEXP R_igraph_write_graph_leda(SEXP graph, SEXP outstream, SEXP names, SEXP weig c_names = Rf_translateCharUTF8(STRING_ELT(names, 0)); c_weights = Rf_translateCharUTF8(STRING_ELT(weights, 0)); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_write_graph_leda(&c_graph, c_outstream, c_names, c_weights)); + PutRNGstate(); /* Convert output */ @@ -9663,7 +10366,9 @@ SEXP R_igraph_write_graph_graphml(SEXP graph, SEXP outstream, SEXP prefixattr) { IGRAPH_R_CHECK_BOOL(prefixattr); c_prefixattr = LOGICAL(prefixattr)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_write_graph_graphml(&c_graph, c_outstream, c_prefixattr)); + PutRNGstate(); /* Convert output */ @@ -9683,7 +10388,9 @@ SEXP R_igraph_write_graph_pajek(SEXP graph, SEXP outstream) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_write_graph_pajek(&c_graph, c_outstream)); + PutRNGstate(); /* Convert output */ @@ -9711,7 +10418,9 @@ SEXP R_igraph_write_graph_gml(SEXP graph, SEXP outstream, SEXP options, SEXP id, c_creator = Rf_translateCharUTF8(STRING_ELT(creator, 0)); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_write_graph_gml(&c_graph, c_outstream, c_options, &c_id, (Rf_isNull(creator) ? 0 : c_creator))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_write_graph_gml(&c_graph, c_outstream, c_options, &c_id, (Rf_isNull(creator) ? NULL : c_creator))); + PutRNGstate(); /* Convert output */ @@ -9731,7 +10440,9 @@ SEXP R_igraph_write_graph_dot(SEXP graph, SEXP outstream) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_write_graph_dot(&c_graph, c_outstream)); + PutRNGstate(); /* Convert output */ @@ -9762,7 +10473,9 @@ SEXP R_igraph_motifs_randesu(SEXP graph, SEXP size, SEXP cut_prob) { R_SEXP_to_vector(cut_prob, &c_cut_prob); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_motifs_randesu(&c_graph, &c_hist, c_size, (Rf_isNull(cut_prob) ? 0 : &c_cut_prob))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_motifs_randesu(&c_graph, &c_hist, c_size, (Rf_isNull(cut_prob) ? NULL : &c_cut_prob))); + PutRNGstate(); /* Convert output */ PROTECT(hist=R_igraph_vector_to_SEXP(&c_hist)); @@ -9780,7 +10493,7 @@ SEXP R_igraph_motifs_randesu(SEXP graph, SEXP size, SEXP cut_prob) { SEXP R_igraph_motifs_randesu_estimate(SEXP graph, SEXP size, SEXP cut_prob, SEXP sample_size, SEXP sample) { /* Declarations */ igraph_t c_graph; - igraph_integer_t c_est; + igraph_real_t c_est; igraph_integer_t c_size; igraph_vector_t c_cut_prob; igraph_integer_t c_sample_size; @@ -9790,7 +10503,6 @@ SEXP R_igraph_motifs_randesu_estimate(SEXP graph, SEXP size, SEXP cut_prob, SEXP SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - c_est=0; IGRAPH_R_CHECK_INT(size); c_size = (igraph_integer_t) REAL(size)[0]; if (!Rf_isNull(cut_prob)) { @@ -9806,11 +10518,13 @@ SEXP R_igraph_motifs_randesu_estimate(SEXP graph, SEXP size, SEXP cut_prob, SEXP IGRAPH_FINALLY(igraph_vector_int_destroy, &c_sample); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_motifs_randesu_estimate(&c_graph, &c_est, c_size, (Rf_isNull(cut_prob) ? 0 : &c_cut_prob), c_sample_size, (Rf_isNull(sample) ? 0 : &c_sample))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_motifs_randesu_estimate(&c_graph, &c_est, c_size, (Rf_isNull(cut_prob) ? NULL : &c_cut_prob), c_sample_size, (Rf_isNull(sample) ? NULL : &c_sample))); + PutRNGstate(); /* Convert output */ PROTECT(est=NEW_NUMERIC(1)); - REAL(est)[0]=(double) c_est; + REAL(est)[0]=c_est; igraph_vector_int_destroy(&c_sample); IGRAPH_FINALLY_CLEAN(1); r_result = est; @@ -9825,7 +10539,7 @@ SEXP R_igraph_motifs_randesu_estimate(SEXP graph, SEXP size, SEXP cut_prob, SEXP SEXP R_igraph_motifs_randesu_no(SEXP graph, SEXP size, SEXP cut_prob) { /* Declarations */ igraph_t c_graph; - igraph_integer_t c_no; + igraph_real_t c_no; igraph_integer_t c_size; igraph_vector_t c_cut_prob; SEXP no; @@ -9833,18 +10547,19 @@ SEXP R_igraph_motifs_randesu_no(SEXP graph, SEXP size, SEXP cut_prob) { SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - c_no=0; IGRAPH_R_CHECK_INT(size); c_size = (igraph_integer_t) REAL(size)[0]; if (!Rf_isNull(cut_prob)) { R_SEXP_to_vector(cut_prob, &c_cut_prob); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_motifs_randesu_no(&c_graph, &c_no, c_size, (Rf_isNull(cut_prob) ? 0 : &c_cut_prob))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_motifs_randesu_no(&c_graph, &c_no, c_size, (Rf_isNull(cut_prob) ? NULL : &c_cut_prob))); + PutRNGstate(); /* Convert output */ PROTECT(no=NEW_NUMERIC(1)); - REAL(no)[0]=(double) c_no; + REAL(no)[0]=c_no; r_result = no; UNPROTECT(1); @@ -9868,7 +10583,9 @@ SEXP R_igraph_dyad_census(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_dyad_census(&c_graph, &c_mut, &c_asym, &c_null)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -9907,7 +10624,9 @@ SEXP R_igraph_triad_census(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &c_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_triad_census(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -9937,7 +10656,9 @@ SEXP R_igraph_count_adjacent_triangles(SEXP graph, SEXP vids) { igraph_vector_int_t c_vids_data; R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_count_adjacent_triangles(&c_graph, &c_res, c_vids)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -9964,7 +10685,9 @@ SEXP R_igraph_count_triangles(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_count_triangles(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -9996,7 +10719,9 @@ SEXP R_igraph_local_scan_0(SEXP graph, SEXP weights, SEXP mode) { } c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_local_scan_0(&c_graph, &c_res, (Rf_isNull(weights) ? 0 : &c_weights), c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_local_scan_0(&c_graph, &c_res, (Rf_isNull(weights) ? NULL : &c_weights), c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -10031,7 +10756,9 @@ SEXP R_igraph_local_scan_0_them(SEXP us, SEXP them, SEXP weights_them, SEXP mode } c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_local_scan_0_them(&c_us, &c_them, &c_res, (Rf_isNull(weights_them) ? 0 : &c_weights_them), c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_local_scan_0_them(&c_us, &c_them, &c_res, (Rf_isNull(weights_them) ? NULL : &c_weights_them), c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -10064,7 +10791,9 @@ SEXP R_igraph_local_scan_1_ecount(SEXP graph, SEXP weights, SEXP mode) { } c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_local_scan_1_ecount(&c_graph, &c_res, (Rf_isNull(weights) ? 0 : &c_weights), c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_local_scan_1_ecount(&c_graph, &c_res, (Rf_isNull(weights) ? NULL : &c_weights), c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -10099,7 +10828,9 @@ SEXP R_igraph_local_scan_1_ecount_them(SEXP us, SEXP them, SEXP weights_them, SE } c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_local_scan_1_ecount_them(&c_us, &c_them, &c_res, (Rf_isNull(weights_them) ? 0 : &c_weights_them), c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_local_scan_1_ecount_them(&c_us, &c_them, &c_res, (Rf_isNull(weights_them) ? NULL : &c_weights_them), c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -10135,7 +10866,9 @@ SEXP R_igraph_local_scan_k_ecount(SEXP graph, SEXP k, SEXP weights, SEXP mode) { } c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_local_scan_k_ecount(&c_graph, c_k, &c_res, (Rf_isNull(weights) ? 0 : &c_weights), c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_local_scan_k_ecount(&c_graph, c_k, &c_res, (Rf_isNull(weights) ? NULL : &c_weights), c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -10173,7 +10906,9 @@ SEXP R_igraph_local_scan_k_ecount_them(SEXP us, SEXP them, SEXP k, SEXP weights_ } c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ - IGRAPH_R_CHECK(igraph_local_scan_k_ecount_them(&c_us, &c_them, c_k, &c_res, (Rf_isNull(weights_them) ? 0 : &c_weights_them), c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_local_scan_k_ecount_them(&c_us, &c_them, c_k, &c_res, (Rf_isNull(weights_them) ? NULL : &c_weights_them), c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -10204,10 +10939,12 @@ SEXP R_igraph_local_scan_neighborhood_ecount(SEXP graph, SEXP weights, SEXP neig if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } - IGRAPH_R_CHECK(R_igraph_SEXP_to_vector_int_list(neighborhoods, &c_neighborhoods)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_neighborhoods); + R_igraph_SEXP_to_vector_int_list(neighborhoods, &c_neighborhoods); + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_neighborhoods); /* Call igraph */ - IGRAPH_R_CHECK(igraph_local_scan_neighborhood_ecount(&c_graph, &c_res, (Rf_isNull(weights) ? 0 : &c_weights), &c_neighborhoods)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_local_scan_neighborhood_ecount(&c_graph, &c_res, (Rf_isNull(weights) ? NULL : &c_weights), &c_neighborhoods)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -10240,10 +10977,12 @@ SEXP R_igraph_local_scan_subset_ecount(SEXP graph, SEXP weights, SEXP subsets) { if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } - IGRAPH_R_CHECK(R_igraph_SEXP_to_vector_int_list(subsets, &c_subsets)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_subsets); + R_igraph_SEXP_to_vector_int_list(subsets, &c_subsets); + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_subsets); /* Call igraph */ - IGRAPH_R_CHECK(igraph_local_scan_subset_ecount(&c_graph, &c_res, (Rf_isNull(weights) ? 0 : &c_weights), &c_subsets)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_local_scan_subset_ecount(&c_graph, &c_res, (Rf_isNull(weights) ? NULL : &c_weights), &c_subsets)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -10272,7 +11011,9 @@ SEXP R_igraph_list_triangles(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_res, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_list_triangles(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_to_SEXPp1(&c_res)); @@ -10299,7 +11040,9 @@ SEXP R_igraph_disjoint_union(SEXP left, SEXP right) { R_SEXP_to_igraph(left, &c_left); R_SEXP_to_igraph(right, &c_right); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_disjoint_union(&c_res, &c_left, &c_right)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -10327,7 +11070,9 @@ SEXP R_igraph_join(SEXP left, SEXP right) { R_SEXP_to_igraph(left, &c_left); R_SEXP_to_igraph(right, &c_right); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_join(&c_res, &c_left, &c_right)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -10363,7 +11108,9 @@ SEXP R_igraph_union(SEXP left, SEXP right) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_edge_map_right, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edge_map_right); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_union(&c_res, &c_left, &c_right, &c_edge_map_left, &c_edge_map_right)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -10414,7 +11161,9 @@ SEXP R_igraph_intersection(SEXP left, SEXP right) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_edge_map_right, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edge_map_right); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_intersection(&c_res, &c_left, &c_right, &c_edge_map_left, &c_edge_map_right)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -10457,7 +11206,9 @@ SEXP R_igraph_difference(SEXP orig, SEXP sub) { R_SEXP_to_igraph(orig, &c_orig); R_SEXP_to_igraph(sub, &c_sub); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_difference(&c_res, &c_orig, &c_sub)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -10486,7 +11237,9 @@ SEXP R_igraph_complementer(SEXP graph, SEXP loops) { IGRAPH_R_CHECK_BOOL(loops); c_loops = LOGICAL(loops)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_complementer(&c_res, &c_graph, c_loops)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -10522,7 +11275,9 @@ SEXP R_igraph_compose(SEXP g1, SEXP g2) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_edge_map2, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edge_map2); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_compose(&c_res, &c_g1, &c_g2, &c_edge_map1, &c_edge_map2)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -10576,7 +11331,9 @@ SEXP R_igraph_induced_subgraph_map(SEXP graph, SEXP vids, SEXP impl) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_invmap, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_invmap); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_induced_subgraph_map(&c_graph, &c_res, c_vids, c_impl, &c_map, &c_invmap)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -10622,7 +11379,9 @@ SEXP R_igraph_mycielskian(SEXP graph, SEXP k) { IGRAPH_R_CHECK_INT(k); c_k = (igraph_integer_t) REAL(k)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_mycielskian(&c_graph, &c_res, c_k)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -10652,7 +11411,9 @@ SEXP R_igraph_product(SEXP g1, SEXP g2, SEXP type) { R_SEXP_to_igraph(g2, &c_g2); c_type = (igraph_product_t) Rf_asInteger(type); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_product(&c_res, &c_g1, &c_g2, c_type)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -10682,7 +11443,9 @@ SEXP R_igraph_rooted_product(SEXP g1, SEXP g2, SEXP root) { R_SEXP_to_igraph(g2, &c_g2); c_root = (igraph_integer_t) REAL(root)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_rooted_product(&c_res, &c_g1, &c_g2, c_root)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -10716,7 +11479,9 @@ SEXP R_igraph_gomory_hu_tree(SEXP graph, SEXP capacity) { R_SEXP_to_vector(capacity, &c_capacity); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_gomory_hu_tree(&c_graph, &c_tree, &c_flows, (Rf_isNull(capacity) ? 0 : &c_capacity))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_gomory_hu_tree(&c_graph, &c_tree, &c_flows, (Rf_isNull(capacity) ? NULL : &c_capacity))); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -10778,7 +11543,9 @@ SEXP R_igraph_maxflow(SEXP graph, SEXP source, SEXP target, SEXP capacity) { R_SEXP_to_vector(capacity, &c_capacity); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_maxflow(&c_graph, &c_value, &c_flow, &c_cut, &c_partition1, &c_partition2, c_source, c_target, (Rf_isNull(capacity) ? 0 : &c_capacity), &c_stats)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_maxflow(&c_graph, &c_value, &c_flow, &c_cut, &c_partition1, &c_partition2, c_source, c_target, (Rf_isNull(capacity) ? NULL : &c_capacity), &c_stats)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(6)); @@ -10846,7 +11613,9 @@ SEXP R_igraph_mincut(SEXP graph, SEXP capacity) { R_SEXP_to_vector(capacity, &c_capacity); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_mincut(&c_graph, &c_value, &c_partition1, &c_partition2, &c_cut, (Rf_isNull(capacity) ? 0 : &c_capacity))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_mincut(&c_graph, &c_value, &c_partition1, &c_partition2, &c_cut, (Rf_isNull(capacity) ? NULL : &c_capacity))); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(4)); @@ -10894,7 +11663,9 @@ SEXP R_igraph_mincut_value(SEXP graph, SEXP capacity) { R_SEXP_to_vector(capacity, &c_capacity); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_mincut_value(&c_graph, &c_res, (Rf_isNull(capacity) ? 0 : &c_capacity))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_mincut_value(&c_graph, &c_res, (Rf_isNull(capacity) ? NULL : &c_capacity))); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -10927,7 +11698,9 @@ SEXP R_igraph_residual_graph(SEXP graph, SEXP capacity, SEXP flow) { residual_capacity=R_GlobalEnv; /* hack to have a non-NULL value */ R_SEXP_to_vector(flow, &c_flow); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_residual_graph(&c_graph, &c_capacity, &c_residual, &c_residual_capacity, &c_flow)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -10967,7 +11740,9 @@ SEXP R_igraph_reverse_residual_graph(SEXP graph, SEXP capacity, SEXP flow) { R_SEXP_to_vector(capacity, &c_capacity); R_SEXP_to_vector(flow, &c_flow); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_reverse_residual_graph(&c_graph, &c_capacity, &c_residual, &c_flow)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_residual); @@ -11013,7 +11788,9 @@ SEXP R_igraph_st_mincut(SEXP graph, SEXP source, SEXP target, SEXP capacity) { R_SEXP_to_vector(capacity, &c_capacity); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_st_mincut(&c_graph, &c_value, &c_cut, &c_partition1, &c_partition2, c_source, c_target, (Rf_isNull(capacity) ? 0 : &c_capacity))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_st_mincut(&c_graph, &c_value, &c_cut, &c_partition1, &c_partition2, c_source, c_target, (Rf_isNull(capacity) ? NULL : &c_capacity))); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(4)); @@ -11061,7 +11838,9 @@ SEXP R_igraph_vertex_connectivity(SEXP graph, SEXP checks) { IGRAPH_R_CHECK_BOOL(checks); c_checks = LOGICAL(checks)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_vertex_connectivity(&c_graph, &c_res, c_checks)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -11089,7 +11868,9 @@ SEXP R_igraph_edge_connectivity(SEXP graph, SEXP checks) { IGRAPH_R_CHECK_BOOL(checks); c_checks = LOGICAL(checks)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_edge_connectivity(&c_graph, &c_res, c_checks)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -11117,7 +11898,9 @@ SEXP R_igraph_adhesion(SEXP graph, SEXP checks) { IGRAPH_R_CHECK_BOOL(checks); c_checks = LOGICAL(checks)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_adhesion(&c_graph, &c_res, c_checks)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -11145,7 +11928,9 @@ SEXP R_igraph_cohesion(SEXP graph, SEXP checks) { IGRAPH_R_CHECK_BOOL(checks); c_checks = LOGICAL(checks)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_cohesion(&c_graph, &c_res, c_checks)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_NUMERIC(1)); @@ -11181,7 +11966,9 @@ SEXP R_igraph_dominator_tree(SEXP graph, SEXP root, SEXP mode) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_leftout); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_dominator_tree(&c_graph, c_root, &c_dom, &c_domtree, &c_leftout, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -11225,14 +12012,20 @@ SEXP R_igraph_all_st_cuts(SEXP graph, SEXP source, SEXP target) { SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_cuts, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_cuts); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_partition1s, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_partition1s); + if (0 != igraph_vector_int_list_init(&c_cuts, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_cuts); + if (0 != igraph_vector_int_list_init(&c_partition1s, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_partition1s); c_source = (igraph_integer_t) REAL(source)[0]; c_target = (igraph_integer_t) REAL(target)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_all_st_cuts(&c_graph, &c_cuts, &c_partition1s, c_source, c_target)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -11273,17 +12066,23 @@ SEXP R_igraph_all_st_mincuts(SEXP graph, SEXP source, SEXP target, SEXP capacity SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_cuts, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_cuts); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_partition1s, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_partition1s); + if (0 != igraph_vector_int_list_init(&c_cuts, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_cuts); + if (0 != igraph_vector_int_list_init(&c_partition1s, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_partition1s); c_source = (igraph_integer_t) REAL(source)[0]; c_target = (igraph_integer_t) REAL(target)[0]; if (!Rf_isNull(capacity)) { R_SEXP_to_vector(capacity, &c_capacity); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_all_st_mincuts(&c_graph, &c_value, &c_cuts, &c_partition1s, c_source, c_target, (Rf_isNull(capacity) ? 0 : &c_capacity))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_all_st_mincuts(&c_graph, &c_value, &c_cuts, &c_partition1s, c_source, c_target, (Rf_isNull(capacity) ? NULL : &c_capacity))); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -11327,7 +12126,9 @@ SEXP R_igraph_even_tarjan_reduction(SEXP graph) { IGRAPH_FINALLY(igraph_vector_destroy, &c_capacity); capacity=R_GlobalEnv; /* hack to have a non-NULL value */ /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_even_tarjan_reduction(&c_graph, &c_graphbar, &c_capacity)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -11366,7 +12167,9 @@ SEXP R_igraph_is_separator(SEXP graph, SEXP candidate) { igraph_vector_int_t c_candidate_data; R_SEXP_to_igraph_vs(candidate, &c_graph, &c_candidate, &c_candidate_data); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_separator(&c_graph, c_candidate, &c_res)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_candidate_data); @@ -11395,7 +12198,9 @@ SEXP R_igraph_is_minimal_separator(SEXP graph, SEXP candidate) { igraph_vector_int_t c_candidate_data; R_SEXP_to_igraph_vs(candidate, &c_graph, &c_candidate, &c_candidate_data); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_minimal_separator(&c_graph, c_candidate, &c_res)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_candidate_data); @@ -11420,10 +12225,14 @@ SEXP R_igraph_all_minimal_st_separators(SEXP graph) { SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_separators, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_separators); + if (0 != igraph_vector_int_list_init(&c_separators, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_separators); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_all_minimal_st_separators(&c_graph, &c_separators)); + PutRNGstate(); /* Convert output */ PROTECT(separators=R_igraph_vector_int_list_to_SEXPp1(&c_separators)); @@ -11447,10 +12256,14 @@ SEXP R_igraph_minimum_size_separators(SEXP graph) { SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_separators, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_separators); + if (0 != igraph_vector_int_list_init(&c_separators, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_separators); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_minimum_size_separators(&c_graph, &c_separators)); + PutRNGstate(); /* Convert output */ PROTECT(separators=R_igraph_vector_int_list_to_SEXPp1(&c_separators)); @@ -11480,14 +12293,18 @@ SEXP R_igraph_cohesive_blocks(SEXP graph) { SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_blocks, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_blocks); + if (0 != igraph_vector_int_list_init(&c_blocks, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_blocks); IGRAPH_R_CHECK(igraph_vector_int_init(&c_cohesion, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_cohesion); IGRAPH_R_CHECK(igraph_vector_int_init(&c_parent, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_parent); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_cohesive_blocks(&c_graph, &c_blocks, &c_cohesion, &c_parent, &c_blockTree)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(4)); @@ -11537,7 +12354,9 @@ SEXP R_igraph_coreness(SEXP graph, SEXP mode) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_cores); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_coreness(&c_graph, &c_cores, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(cores=R_igraph_vector_int_to_SEXP(&c_cores)); @@ -11563,7 +12382,9 @@ SEXP R_igraph_isoclass(SEXP graph) { R_SEXP_to_igraph(graph, &c_graph); c_isoclass=0; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_isoclass(&c_graph, &c_isoclass)); + PutRNGstate(); /* Convert output */ PROTECT(isoclass=NEW_NUMERIC(1)); @@ -11589,7 +12410,9 @@ SEXP R_igraph_isomorphic(SEXP graph1, SEXP graph2) { R_SEXP_to_igraph(graph1, &c_graph1); R_SEXP_to_igraph(graph2, &c_graph2); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_isomorphic(&c_graph1, &c_graph2, &c_iso)); + PutRNGstate(); /* Convert output */ PROTECT(iso=NEW_LOGICAL(1)); @@ -11600,28 +12423,105 @@ SEXP R_igraph_isomorphic(SEXP graph1, SEXP graph2) { return(r_result); } +/*-------------------------------------------/ +/ igraph_automorphism_group / +/-------------------------------------------*/ +SEXP R_igraph_automorphism_group(SEXP graph, SEXP colors) { + /* Declarations */ + igraph_t c_graph; + igraph_vector_int_t c_colors; + igraph_vector_int_list_t c_generators; + SEXP generators; + + SEXP r_result; + /* Convert input */ + R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(colors)) { + IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(colors, &c_colors)); + } else { + IGRAPH_R_CHECK(igraph_vector_int_init(&c_colors, 0)); + } + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_colors); + if (0 != igraph_vector_int_list_init(&c_generators, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_generators); + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_automorphism_group(&c_graph, (Rf_isNull(colors) ? NULL : &c_colors), &c_generators)); + PutRNGstate(); + + /* Convert output */ + igraph_vector_int_destroy(&c_colors); + IGRAPH_FINALLY_CLEAN(1); + PROTECT(generators=R_igraph_vector_int_list_to_SEXPp1(&c_generators)); + igraph_vector_int_list_destroy(&c_generators); + IGRAPH_FINALLY_CLEAN(1); + r_result = generators; + + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_count_automorphisms / +/-------------------------------------------*/ +SEXP R_igraph_count_automorphisms(SEXP graph, SEXP colors) { + /* Declarations */ + igraph_t c_graph; + igraph_vector_int_t c_colors; + igraph_real_t c_result; + SEXP result; + + SEXP r_result; + /* Convert input */ + R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(colors)) { + IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(colors, &c_colors)); + } else { + IGRAPH_R_CHECK(igraph_vector_int_init(&c_colors, 0)); + } + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_colors); + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_count_automorphisms(&c_graph, (Rf_isNull(colors) ? NULL : &c_colors), &c_result)); + PutRNGstate(); + + /* Convert output */ + igraph_vector_int_destroy(&c_colors); + IGRAPH_FINALLY_CLEAN(1); + PROTECT(result=NEW_NUMERIC(1)); + REAL(result)[0]=c_result; + r_result = result; + + UNPROTECT(1); + return(r_result); +} + /*-------------------------------------------/ / igraph_isoclass_subgraph / /-------------------------------------------*/ SEXP R_igraph_isoclass_subgraph(SEXP graph, SEXP vids) { /* Declarations */ igraph_t c_graph; - igraph_vector_int_t c_vids; + igraph_vs_t c_vids; igraph_integer_t c_isoclass; SEXP isoclass; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(vids, &c_vids)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vids); + igraph_vector_int_t c_vids_data; + R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); c_isoclass=0; /* Call igraph */ - IGRAPH_R_CHECK(igraph_isoclass_subgraph(&c_graph, &c_vids, &c_isoclass)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_isoclass_subgraph(&c_graph, c_vids, &c_isoclass)); + PutRNGstate(); /* Convert output */ - igraph_vector_int_destroy(&c_vids); - IGRAPH_FINALLY_CLEAN(1); + igraph_vector_int_destroy(&c_vids_data); + igraph_vs_destroy(&c_vids); PROTECT(isoclass=NEW_NUMERIC(1)); REAL(isoclass)[0]=(double) c_isoclass; r_result = isoclass; @@ -11650,7 +12550,9 @@ SEXP R_igraph_isoclass_create(SEXP size, SEXP number, SEXP directed) { IGRAPH_R_CHECK_BOOL(directed); c_directed = LOGICAL(directed)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_isoclass_create(&c_graph, c_size, c_number, c_directed)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -11717,7 +12619,9 @@ SEXP R_igraph_isomorphic_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP IGRAPH_R_CHECK(igraph_vector_int_init(&c_map21, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_map21); /* Call igraph */ - IGRAPH_R_CHECK(igraph_isomorphic_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? 0 : &c_vertex_color1), (Rf_isNull(vertex_color2) ? 0 : &c_vertex_color2), (Rf_isNull(edge_color1) ? 0 : &c_edge_color1), (Rf_isNull(edge_color2) ? 0 : &c_edge_color2), &c_iso, &c_map12, &c_map21, 0, 0, 0)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_isomorphic_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? NULL : &c_vertex_color1), (Rf_isNull(vertex_color2) ? NULL : &c_vertex_color2), (Rf_isNull(edge_color1) ? NULL : &c_edge_color1), (Rf_isNull(edge_color2) ? NULL : &c_edge_color2), &c_iso, &c_map12, &c_map21, 0, 0, 0)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -11804,7 +12708,9 @@ SEXP R_igraph_get_isomorphisms_vf2_callback(SEXP graph1, SEXP graph2, SEXP verte IGRAPH_R_CHECK(igraph_vector_int_init(&c_map21, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_map21); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_isomorphisms_vf2_callback(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? 0 : &c_vertex_color1), (Rf_isNull(vertex_color2) ? 0 : &c_vertex_color2), (Rf_isNull(edge_color1) ? 0 : &c_edge_color1), (Rf_isNull(edge_color2) ? 0 : &c_edge_color2), &c_map12, &c_map21, 0, 0, 0, 0)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_isomorphisms_vf2_callback(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? NULL : &c_vertex_color1), (Rf_isNull(vertex_color2) ? NULL : &c_vertex_color2), (Rf_isNull(edge_color1) ? NULL : &c_edge_color1), (Rf_isNull(edge_color2) ? NULL : &c_edge_color2), &c_map12, &c_map21, 0, 0, 0, 0)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -11881,7 +12787,9 @@ SEXP R_igraph_count_isomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edge_color2); c_count=0; /* Call igraph */ - IGRAPH_R_CHECK(igraph_count_isomorphisms_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? 0 : &c_vertex_color1), (Rf_isNull(vertex_color2) ? 0 : &c_vertex_color2), (Rf_isNull(edge_color1) ? 0 : &c_edge_color1), (Rf_isNull(edge_color2) ? 0 : &c_edge_color2), &c_count, 0, 0, 0)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_count_isomorphisms_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? NULL : &c_vertex_color1), (Rf_isNull(vertex_color2) ? NULL : &c_vertex_color2), (Rf_isNull(edge_color1) ? NULL : &c_edge_color1), (Rf_isNull(edge_color2) ? NULL : &c_edge_color2), &c_count, 0, 0, 0)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_vertex_color1); @@ -11948,7 +12856,9 @@ SEXP R_igraph_get_isomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_maps, 0)); IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_maps); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_isomorphisms_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? 0 : &c_vertex_color1), (Rf_isNull(vertex_color2) ? 0 : &c_vertex_color2), (Rf_isNull(edge_color1) ? 0 : &c_edge_color1), (Rf_isNull(edge_color2) ? 0 : &c_edge_color2), &c_maps, 0, 0, 0)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_isomorphisms_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? NULL : &c_vertex_color1), (Rf_isNull(vertex_color2) ? NULL : &c_vertex_color2), (Rf_isNull(edge_color1) ? NULL : &c_edge_color1), (Rf_isNull(edge_color2) ? NULL : &c_edge_color2), &c_maps, 0, 0, 0)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_vertex_color1); @@ -11983,7 +12893,9 @@ SEXP R_igraph_subisomorphic(SEXP graph1, SEXP graph2) { R_SEXP_to_igraph(graph1, &c_graph1); R_SEXP_to_igraph(graph2, &c_graph2); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_subisomorphic(&c_graph1, &c_graph2, &c_iso)); + PutRNGstate(); /* Convert output */ PROTECT(iso=NEW_LOGICAL(1)); @@ -12048,7 +12960,9 @@ SEXP R_igraph_subisomorphic_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SE IGRAPH_R_CHECK(igraph_vector_int_init(&c_map21, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_map21); /* Call igraph */ - IGRAPH_R_CHECK(igraph_subisomorphic_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? 0 : &c_vertex_color1), (Rf_isNull(vertex_color2) ? 0 : &c_vertex_color2), (Rf_isNull(edge_color1) ? 0 : &c_edge_color1), (Rf_isNull(edge_color2) ? 0 : &c_edge_color2), &c_iso, &c_map12, &c_map21, 0, 0, 0)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_subisomorphic_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? NULL : &c_vertex_color1), (Rf_isNull(vertex_color2) ? NULL : &c_vertex_color2), (Rf_isNull(edge_color1) ? NULL : &c_edge_color1), (Rf_isNull(edge_color2) ? NULL : &c_edge_color2), &c_iso, &c_map12, &c_map21, 0, 0, 0)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -12129,7 +13043,9 @@ SEXP R_igraph_count_subisomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_co IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edge_color2); c_count=0; /* Call igraph */ - IGRAPH_R_CHECK(igraph_count_subisomorphisms_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? 0 : &c_vertex_color1), (Rf_isNull(vertex_color2) ? 0 : &c_vertex_color2), (Rf_isNull(edge_color1) ? 0 : &c_edge_color1), (Rf_isNull(edge_color2) ? 0 : &c_edge_color2), &c_count, 0, 0, 0)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_count_subisomorphisms_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? NULL : &c_vertex_color1), (Rf_isNull(vertex_color2) ? NULL : &c_vertex_color2), (Rf_isNull(edge_color1) ? NULL : &c_edge_color1), (Rf_isNull(edge_color2) ? NULL : &c_edge_color2), &c_count, 0, 0, 0)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_vertex_color1); @@ -12196,7 +13112,9 @@ SEXP R_igraph_get_subisomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_colo IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_maps, 0)); IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_maps); /* Call igraph */ - IGRAPH_R_CHECK(igraph_get_subisomorphisms_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? 0 : &c_vertex_color1), (Rf_isNull(vertex_color2) ? 0 : &c_vertex_color2), (Rf_isNull(edge_color1) ? 0 : &c_edge_color1), (Rf_isNull(edge_color2) ? 0 : &c_edge_color2), &c_maps, 0, 0, 0)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_get_subisomorphisms_vf2(&c_graph1, &c_graph2, (Rf_isNull(vertex_color1) ? NULL : &c_vertex_color1), (Rf_isNull(vertex_color2) ? NULL : &c_vertex_color2), (Rf_isNull(edge_color1) ? NULL : &c_edge_color1), (Rf_isNull(edge_color2) ? NULL : &c_edge_color2), &c_maps, 0, 0, 0)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_vertex_color1); @@ -12219,7 +13137,45 @@ SEXP R_igraph_get_subisomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_colo /*-------------------------------------------/ / igraph_canonical_permutation / /-------------------------------------------*/ -SEXP R_igraph_canonical_permutation(SEXP graph, SEXP colors, SEXP sh) { +SEXP R_igraph_canonical_permutation(SEXP graph, SEXP colors) { + /* Declarations */ + igraph_t c_graph; + igraph_vector_int_t c_colors; + igraph_vector_int_t c_labeling; + SEXP labeling; + + SEXP r_result; + /* Convert input */ + R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(colors)) { + IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(colors, &c_colors)); + } else { + IGRAPH_R_CHECK(igraph_vector_int_init(&c_colors, 0)); + } + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_colors); + IGRAPH_R_CHECK(igraph_vector_int_init(&c_labeling, 0)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_labeling); + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_canonical_permutation(&c_graph, (Rf_isNull(colors) ? NULL : &c_colors), &c_labeling)); + PutRNGstate(); + + /* Convert output */ + igraph_vector_int_destroy(&c_colors); + IGRAPH_FINALLY_CLEAN(1); + PROTECT(labeling=R_igraph_vector_int_to_SEXPp1(&c_labeling)); + igraph_vector_int_destroy(&c_labeling); + IGRAPH_FINALLY_CLEAN(1); + r_result = labeling; + + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_canonical_permutation_bliss / +/-------------------------------------------*/ +SEXP R_igraph_canonical_permutation_bliss(SEXP graph, SEXP colors, SEXP sh) { /* Declarations */ igraph_t c_graph; igraph_vector_int_t c_colors; @@ -12242,7 +13198,9 @@ SEXP R_igraph_canonical_permutation(SEXP graph, SEXP colors, SEXP sh) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_labeling); c_sh = (igraph_bliss_sh_t) Rf_asInteger(sh); /* Call igraph */ - IGRAPH_R_CHECK(igraph_canonical_permutation(&c_graph, (Rf_isNull(colors) ? 0 : &c_colors), &c_labeling, c_sh, &c_info)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_canonical_permutation_bliss(&c_graph, (Rf_isNull(colors) ? NULL : &c_colors), &c_labeling, c_sh, &c_info)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -12281,7 +13239,9 @@ SEXP R_igraph_permute_vertices(SEXP graph, SEXP permutation) { R_SEXP_to_vector_int_copy(permutation, &c_permutation); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_permutation); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_permute_vertices(&c_graph, &c_res, &c_permutation)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_res); @@ -12339,7 +13299,9 @@ SEXP R_igraph_isomorphic_bliss(SEXP graph1, SEXP graph2, SEXP colors1, SEXP colo IGRAPH_FINALLY(igraph_vector_int_destroy, &c_map21); c_sh = (igraph_bliss_sh_t) Rf_asInteger(sh); /* Call igraph */ - IGRAPH_R_CHECK(igraph_isomorphic_bliss(&c_graph1, &c_graph2, (Rf_isNull(colors1) ? 0 : &c_colors1), (Rf_isNull(colors2) ? 0 : &c_colors2), &c_iso, &c_map12, &c_map21, c_sh, &c_info1, &c_info2)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_isomorphic_bliss(&c_graph1, &c_graph2, (Rf_isNull(colors1) ? NULL : &c_colors1), (Rf_isNull(colors2) ? NULL : &c_colors2), &c_iso, &c_map12, &c_map21, c_sh, &c_info1, &c_info2)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(5)); @@ -12378,9 +13340,9 @@ SEXP R_igraph_isomorphic_bliss(SEXP graph1, SEXP graph2, SEXP colors1, SEXP colo } /*-------------------------------------------/ -/ igraph_count_automorphisms / +/ igraph_count_automorphisms_bliss / /-------------------------------------------*/ -SEXP R_igraph_count_automorphisms(SEXP graph, SEXP colors, SEXP sh) { +SEXP R_igraph_count_automorphisms_bliss(SEXP graph, SEXP colors, SEXP sh) { /* Declarations */ igraph_t c_graph; igraph_vector_int_t c_colors; @@ -12399,7 +13361,9 @@ SEXP R_igraph_count_automorphisms(SEXP graph, SEXP colors, SEXP sh) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_colors); c_sh = (igraph_bliss_sh_t) Rf_asInteger(sh); /* Call igraph */ - IGRAPH_R_CHECK(igraph_count_automorphisms(&c_graph, (Rf_isNull(colors) ? 0 : &c_colors), c_sh, &c_info)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_count_automorphisms_bliss(&c_graph, (Rf_isNull(colors) ? NULL : &c_colors), c_sh, &c_info)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_colors); @@ -12413,9 +13377,9 @@ SEXP R_igraph_count_automorphisms(SEXP graph, SEXP colors, SEXP sh) { } /*-------------------------------------------/ -/ igraph_automorphism_group / +/ igraph_automorphism_group_bliss / /-------------------------------------------*/ -SEXP R_igraph_automorphism_group(SEXP graph, SEXP colors, SEXP sh) { +SEXP R_igraph_automorphism_group_bliss(SEXP graph, SEXP colors, SEXP sh) { /* Declarations */ igraph_t c_graph; igraph_vector_int_t c_colors; @@ -12434,11 +13398,15 @@ SEXP R_igraph_automorphism_group(SEXP graph, SEXP colors, SEXP sh) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_colors, 0)); } IGRAPH_FINALLY(igraph_vector_int_destroy, &c_colors); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_generators, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_generators); + if (0 != igraph_vector_int_list_init(&c_generators, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_generators); c_sh = (igraph_bliss_sh_t) Rf_asInteger(sh); /* Call igraph */ - IGRAPH_R_CHECK(igraph_automorphism_group(&c_graph, (Rf_isNull(colors) ? 0 : &c_colors), &c_generators, c_sh, &c_info)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_automorphism_group_bliss(&c_graph, (Rf_isNull(colors) ? NULL : &c_colors), &c_generators, c_sh, &c_info)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -12482,7 +13450,9 @@ SEXP R_igraph_simplify_and_colorize(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_edge_color, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edge_color); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_simplify_and_colorize(&c_graph, &c_res, &c_vertex_color, &c_edge_color)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -12528,7 +13498,9 @@ SEXP R_igraph_graph_count(SEXP n, SEXP directed) { c_directed = LOGICAL(directed)[0]; c_count=0; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_graph_count(c_n, c_directed, &c_count)); + PutRNGstate(); /* Convert output */ PROTECT(count=NEW_NUMERIC(1)); @@ -12559,7 +13531,9 @@ SEXP R_igraph_is_matching(SEXP graph, SEXP types, SEXP matching) { R_SEXP_to_vector_int_copy(matching, &c_matching); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_matching); /* Call igraph */ - IGRAPH_R_CHECK(igraph_is_matching(&c_graph, (Rf_isNull(types) ? 0 : &c_types), &c_matching, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_is_matching(&c_graph, (Rf_isNull(types) ? NULL : &c_types), &c_matching, &c_res)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_matching); @@ -12592,7 +13566,9 @@ SEXP R_igraph_is_maximal_matching(SEXP graph, SEXP types, SEXP matching) { R_SEXP_to_vector_int_copy(matching, &c_matching); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_matching); /* Call igraph */ - IGRAPH_R_CHECK(igraph_is_maximal_matching(&c_graph, (Rf_isNull(types) ? 0 : &c_types), &c_matching, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_is_maximal_matching(&c_graph, (Rf_isNull(types) ? NULL : &c_types), &c_matching, &c_res)); + PutRNGstate(); /* Convert output */ igraph_vector_int_destroy(&c_matching); @@ -12634,7 +13610,9 @@ SEXP R_igraph_maximum_bipartite_matching(SEXP graph, SEXP types, SEXP weights, S IGRAPH_R_CHECK_REAL(eps); c_eps = REAL(eps)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_maximum_bipartite_matching(&c_graph, &c_types, &c_matching_size, &c_matching_weight, &c_matching, (Rf_isNull(weights) ? 0 : &c_weights), c_eps)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_maximum_bipartite_matching(&c_graph, &c_types, &c_matching_size, &c_matching_weight, &c_matching, (Rf_isNull(weights) ? NULL : &c_weights), c_eps)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(3)); @@ -12695,7 +13673,9 @@ SEXP R_igraph_eigen_adjacency(SEXP graph, SEXP algorithm, SEXP which, SEXP optio IGRAPH_FINALLY(igraph_matrix_complex_destroy, &c_cmplxvectors); cmplxvectors=R_GlobalEnv; /* hack to have a non-NULL value */ /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_eigen_adjacency(&c_graph, c_algorithm, &c_which, &c_options, 0, &c_values, &c_vectors, (Rf_isNull(cmplxvalues) ? NULL : &c_cmplxvalues), (Rf_isNull(cmplxvectors) ? NULL : &c_cmplxvectors))); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(5)); @@ -12749,7 +13729,9 @@ SEXP R_igraph_power_law_fit(SEXP data, SEXP xmin, SEXP force_continuous) { IGRAPH_R_CHECK_BOOL(force_continuous); c_force_continuous = LOGICAL(force_continuous)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_power_law_fit(&c_data, &c_res, c_xmin, c_force_continuous)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_plfit_result_to_SEXP(&c_res)); @@ -12783,7 +13765,9 @@ SEXP R_igraph_sir(SEXP graph, SEXP beta, SEXP gamma, SEXP no_sim) { IGRAPH_R_CHECK(igraph_vector_ptr_init(&c_res, 0)); IGRAPH_FINALLY(R_igraph_sirlist_destroy, &c_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_sir(&c_graph, c_beta, c_gamma, c_no_sim, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_sirlist_to_SEXP(&c_res)); @@ -12813,7 +13797,9 @@ SEXP R_igraph_running_mean(SEXP data, SEXP binwidth) { IGRAPH_R_CHECK_INT(binwidth); c_binwidth = (igraph_integer_t) REAL(binwidth)[0]; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_running_mean(&c_data, &c_res, c_binwidth)); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -12844,7 +13830,9 @@ SEXP R_igraph_convex_hull_2d(SEXP data) { IGRAPH_R_CHECK(igraph_matrix_init(&c_rescoords, 0, 0)); IGRAPH_FINALLY(igraph_matrix_destroy, &c_rescoords); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_convex_hull_2d(&c_data, &c_resverts, &c_rescoords)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -12880,7 +13868,9 @@ SEXP R_igraph_dim_select(SEXP sv) { R_SEXP_to_vector(sv, &c_sv); c_dim=0; /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_dim_select(&c_sv, &c_dim)); + PutRNGstate(); /* Convert output */ PROTECT(dim=NEW_NUMERIC(1)); @@ -12909,7 +13899,9 @@ SEXP R_igraph_solve_lsap(SEXP c, SEXP n) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_p, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_p); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_solve_lsap(&c_c, c_n, &c_p)); + PutRNGstate(); /* Convert output */ PROTECT(p=R_igraph_vector_int_to_SEXP(&c_p)); @@ -12942,7 +13934,9 @@ SEXP R_igraph_find_cycle(SEXP graph, SEXP mode) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edges); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_find_cycle(&c_graph, &c_vertices, &c_edges, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -12967,7 +13961,7 @@ SEXP R_igraph_find_cycle(SEXP graph, SEXP mode) { /*-------------------------------------------/ / igraph_simple_cycles / /-------------------------------------------*/ -SEXP R_igraph_simple_cycles(SEXP graph, SEXP mode, SEXP min_cycle_length, SEXP max_cycle_length) { +SEXP R_igraph_simple_cycles(SEXP graph, SEXP mode, SEXP min_cycle_length, SEXP max_cycle_length, SEXP max_results) { /* Declarations */ igraph_t c_graph; igraph_vector_int_list_t c_vertices; @@ -12975,23 +13969,32 @@ SEXP R_igraph_simple_cycles(SEXP graph, SEXP mode, SEXP min_cycle_length, SEXP m igraph_neimode_t c_mode; igraph_integer_t c_min_cycle_length; igraph_integer_t c_max_cycle_length; + igraph_integer_t c_max_results; SEXP vertices; SEXP edges; SEXP r_result, r_names; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_vertices, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_vertices); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_edges, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_edges); + if (0 != igraph_vector_int_list_init(&c_vertices, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_vertices); + if (0 != igraph_vector_int_list_init(&c_edges, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_edges); c_mode = (igraph_neimode_t) Rf_asInteger(mode); IGRAPH_R_CHECK_INT(min_cycle_length); c_min_cycle_length = (igraph_integer_t) REAL(min_cycle_length)[0]; IGRAPH_R_CHECK_INT(max_cycle_length); c_max_cycle_length = (igraph_integer_t) REAL(max_cycle_length)[0]; + IGRAPH_R_CHECK_INT(max_results); + c_max_results = (igraph_integer_t) REAL(max_results)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_simple_cycles(&c_graph, &c_vertices, &c_edges, c_mode, c_min_cycle_length, c_max_cycle_length)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_simple_cycles(&c_graph, &c_vertices, &c_edges, c_mode, c_min_cycle_length, c_max_cycle_length, c_max_results)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -13028,7 +14031,9 @@ SEXP R_igraph_is_eulerian(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_eulerian(&c_graph, &c_has_path, &c_has_cycle)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -13067,7 +14072,9 @@ SEXP R_igraph_eulerian_path(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_vertex_res, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vertex_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_eulerian_path(&c_graph, &c_edge_res, &c_vertex_res)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -13108,7 +14115,9 @@ SEXP R_igraph_eulerian_cycle(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_vertex_res, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vertex_res); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_eulerian_cycle(&c_graph, &c_edge_res, &c_vertex_res)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -13133,30 +14142,34 @@ SEXP R_igraph_eulerian_cycle(SEXP graph) { /*-------------------------------------------/ / igraph_fundamental_cycles / /-------------------------------------------*/ -SEXP R_igraph_fundamental_cycles(SEXP graph, SEXP start, SEXP bfs_cutoff, SEXP weights) { +SEXP R_igraph_fundamental_cycles(SEXP graph, SEXP weights, SEXP start, SEXP bfs_cutoff) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_int_list_t c_basis; igraph_integer_t c_start; - igraph_integer_t c_bfs_cutoff; - igraph_vector_t c_weights; + igraph_real_t c_bfs_cutoff; SEXP basis; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_basis, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_basis); - if (!Rf_isNull(start)) { - c_start = (igraph_integer_t) REAL(start)[0]; - } - IGRAPH_R_CHECK_INT(bfs_cutoff); - c_bfs_cutoff = (igraph_integer_t) REAL(bfs_cutoff)[0]; if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } + if (0 != igraph_vector_int_list_init(&c_basis, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_basis); + if (!Rf_isNull(start)) { + c_start = (igraph_integer_t) REAL(start)[0]; + } + IGRAPH_R_CHECK_REAL(bfs_cutoff); + c_bfs_cutoff = REAL(bfs_cutoff)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_fundamental_cycles(&c_graph, &c_basis, (Rf_isNull(start) ? 0 : c_start), c_bfs_cutoff, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_fundamental_cycles(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_basis, (Rf_isNull(start) ? -1 : c_start), c_bfs_cutoff)); + PutRNGstate(); /* Convert output */ PROTECT(basis=R_igraph_vector_int_list_to_SEXPp1(&c_basis)); @@ -13171,32 +14184,36 @@ SEXP R_igraph_fundamental_cycles(SEXP graph, SEXP start, SEXP bfs_cutoff, SEXP w /*-------------------------------------------/ / igraph_minimum_cycle_basis / /-------------------------------------------*/ -SEXP R_igraph_minimum_cycle_basis(SEXP graph, SEXP bfs_cutoff, SEXP complete, SEXP use_cycle_order, SEXP weights) { +SEXP R_igraph_minimum_cycle_basis(SEXP graph, SEXP weights, SEXP bfs_cutoff, SEXP complete, SEXP use_cycle_order) { /* Declarations */ igraph_t c_graph; + igraph_vector_t c_weights; igraph_vector_int_list_t c_basis; - igraph_integer_t c_bfs_cutoff; + igraph_real_t c_bfs_cutoff; igraph_bool_t c_complete; igraph_bool_t c_use_cycle_order; - igraph_vector_t c_weights; SEXP basis; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_list_init(&c_basis, 0)); - IGRAPH_FINALLY(igraph_vector_int_list_destroy, &c_basis); - IGRAPH_R_CHECK_INT(bfs_cutoff); - c_bfs_cutoff = (igraph_integer_t) REAL(bfs_cutoff)[0]; + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } + if (0 != igraph_vector_int_list_init(&c_basis, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &c_basis); + IGRAPH_R_CHECK_REAL(bfs_cutoff); + c_bfs_cutoff = REAL(bfs_cutoff)[0]; IGRAPH_R_CHECK_BOOL(complete); c_complete = LOGICAL(complete)[0]; IGRAPH_R_CHECK_BOOL(use_cycle_order); c_use_cycle_order = LOGICAL(use_cycle_order)[0]; - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } /* Call igraph */ - IGRAPH_R_CHECK(igraph_minimum_cycle_basis(&c_graph, &c_basis, c_bfs_cutoff, c_complete, c_use_cycle_order, (Rf_isNull(weights) ? 0 : &c_weights))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_minimum_cycle_basis(&c_graph, (Rf_isNull(weights) ? NULL : &c_weights), &c_basis, c_bfs_cutoff, c_complete, c_use_cycle_order)); + PutRNGstate(); /* Convert output */ PROTECT(basis=R_igraph_vector_int_list_to_SEXPp1(&c_basis)); @@ -13226,7 +14243,9 @@ SEXP R_igraph_is_tree(SEXP graph, SEXP mode) { c_root = -1; c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_tree(&c_graph, &c_res, &c_root, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -13265,7 +14284,9 @@ SEXP R_igraph_is_forest(SEXP graph, SEXP mode) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_roots); c_mode = (igraph_neimode_t) Rf_asInteger(mode); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_forest(&c_graph, &c_res, &c_roots, c_mode)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); @@ -13300,7 +14321,9 @@ SEXP R_igraph_from_prufer(SEXP prufer) { R_SEXP_to_vector_int_copy(prufer, &c_prufer); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_prufer); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_from_prufer(&c_graph, &c_prufer)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -13330,7 +14353,9 @@ SEXP R_igraph_to_prufer(SEXP graph) { IGRAPH_R_CHECK(igraph_vector_int_init(&c_prufer, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &c_prufer); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_to_prufer(&c_graph, &c_prufer)); + PutRNGstate(); /* Convert output */ PROTECT(prufer=R_igraph_vector_int_to_SEXPp1(&c_prufer)); @@ -13358,7 +14383,9 @@ SEXP R_igraph_tree_from_parent_vector(SEXP parents, SEXP type) { IGRAPH_FINALLY(igraph_vector_int_destroy, &c_parents); c_type = (igraph_tree_mode_t) Rf_asInteger(type); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_tree_from_parent_vector(&c_graph, &c_parents, c_type)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -13386,7 +14413,9 @@ SEXP R_igraph_is_complete(SEXP graph) { /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_is_complete(&c_graph, &c_res)); + PutRNGstate(); /* Convert output */ PROTECT(res=NEW_LOGICAL(1)); @@ -13398,54 +14427,35 @@ SEXP R_igraph_is_complete(SEXP graph) { } /*-------------------------------------------/ -/ igraph_minimum_spanning_tree_unweighted / -/-------------------------------------------*/ -SEXP R_igraph_minimum_spanning_tree_unweighted(SEXP graph) { - /* Declarations */ - igraph_t c_graph; - igraph_t c_mst; - SEXP mst; - - SEXP r_result; - /* Convert input */ - R_SEXP_to_igraph(graph, &c_graph); - /* Call igraph */ - IGRAPH_R_CHECK(igraph_minimum_spanning_tree_unweighted(&c_graph, &c_mst)); - - /* Convert output */ - IGRAPH_FINALLY(igraph_destroy, &c_mst); - PROTECT(mst=R_igraph_to_SEXP(&c_mst)); - IGRAPH_I_DESTROY(&c_mst); - IGRAPH_FINALLY_CLEAN(1); - r_result = mst; - - UNPROTECT(1); - return(r_result); -} - -/*-------------------------------------------/ -/ igraph_minimum_spanning_tree_prim / +/ igraph_minimum_spanning_tree / /-------------------------------------------*/ -SEXP R_igraph_minimum_spanning_tree_prim(SEXP graph, SEXP weights) { +SEXP R_igraph_minimum_spanning_tree(SEXP graph, SEXP weights, SEXP method) { /* Declarations */ igraph_t c_graph; - igraph_t c_mst; + igraph_vector_int_t c_res; igraph_vector_t c_weights; - SEXP mst; + igraph_mst_algorithm_t c_method; + SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - R_SEXP_to_vector(weights, &c_weights); + IGRAPH_R_CHECK(igraph_vector_int_init(&c_res, 0)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_res); + if (!Rf_isNull(weights)) { + R_SEXP_to_vector(weights, &c_weights); + } + c_method = (igraph_mst_algorithm_t) Rf_asInteger(method); /* Call igraph */ - IGRAPH_R_CHECK(igraph_minimum_spanning_tree_prim(&c_graph, &c_mst, &c_weights)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_minimum_spanning_tree(&c_graph, &c_res, (Rf_isNull(weights) ? NULL : &c_weights), c_method)); + PutRNGstate(); /* Convert output */ - IGRAPH_FINALLY(igraph_destroy, &c_mst); - PROTECT(mst=R_igraph_to_SEXP(&c_mst)); - IGRAPH_I_DESTROY(&c_mst); + PROTECT(res=R_igraph_vector_int_to_SEXPp1(&c_res)); + igraph_vector_int_destroy(&c_res); IGRAPH_FINALLY_CLEAN(1); - r_result = mst; + r_result = res; UNPROTECT(1); return(r_result); @@ -13470,7 +14480,9 @@ SEXP R_igraph_random_spanning_tree(SEXP graph, SEXP vid) { c_vid = (igraph_integer_t) REAL(vid)[0]; } /* Call igraph */ - IGRAPH_R_CHECK(igraph_random_spanning_tree(&c_graph, &c_res, (Rf_isNull(vid) ? 0 : c_vid))); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_random_spanning_tree(&c_graph, &c_res, (Rf_isNull(vid) ? -1 : c_vid))); + PutRNGstate(); /* Convert output */ PROTECT(res=R_igraph_vector_int_to_SEXPp1(&c_res)); @@ -13501,7 +14513,9 @@ SEXP R_igraph_tree_game(SEXP n, SEXP directed, SEXP method) { c_directed = LOGICAL(directed)[0]; c_method = (igraph_random_tree_t) Rf_asInteger(method); /* Call igraph */ + GetRNGstate(); IGRAPH_R_CHECK(igraph_tree_game(&c_graph, c_n, c_directed, c_method)); + PutRNGstate(); /* Convert output */ IGRAPH_FINALLY(igraph_destroy, &c_graph); @@ -13515,200 +14529,229 @@ SEXP R_igraph_tree_game(SEXP n, SEXP directed, SEXP method) { } /*-------------------------------------------/ -/ igraph_vertex_coloring_greedy / +/ igraph_nearest_neighbor_graph / /-------------------------------------------*/ -SEXP R_igraph_vertex_coloring_greedy(SEXP graph, SEXP heuristic) { +SEXP R_igraph_nearest_neighbor_graph(SEXP points, SEXP metric, SEXP neighbors, SEXP cutoff, SEXP directed) { /* Declarations */ igraph_t c_graph; - igraph_vector_int_t c_colors; - igraph_coloring_greedy_t c_heuristic; - SEXP colors; + igraph_matrix_t c_points; + igraph_metric_t c_metric; + igraph_integer_t c_neighbors; + igraph_real_t c_cutoff; + igraph_bool_t c_directed; + SEXP graph; SEXP r_result; /* Convert input */ - R_SEXP_to_igraph(graph, &c_graph); - IGRAPH_R_CHECK(igraph_vector_int_init(&c_colors, 0)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_colors); - c_heuristic = (igraph_coloring_greedy_t) Rf_asInteger(heuristic); + R_SEXP_to_matrix(points, &c_points); + c_metric = (igraph_metric_t) Rf_asInteger(metric); + IGRAPH_R_CHECK_INT(neighbors); + c_neighbors = (igraph_integer_t) REAL(neighbors)[0]; + IGRAPH_R_CHECK_REAL(cutoff); + c_cutoff = REAL(cutoff)[0]; + IGRAPH_R_CHECK_BOOL(directed); + c_directed = LOGICAL(directed)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_vertex_coloring_greedy(&c_graph, &c_colors, c_heuristic)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_nearest_neighbor_graph(&c_graph, &c_points, c_metric, c_neighbors, c_cutoff, c_directed)); + PutRNGstate(); /* Convert output */ - PROTECT(colors=R_igraph_vector_int_to_SEXP(&c_colors)); - igraph_vector_int_destroy(&c_colors); + IGRAPH_FINALLY(igraph_destroy, &c_graph); + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); IGRAPH_FINALLY_CLEAN(1); - r_result = colors; + r_result = graph; UNPROTECT(1); return(r_result); } /*-------------------------------------------/ -/ igraph_is_vertex_coloring / +/ igraph_delaunay_graph / /-------------------------------------------*/ -SEXP R_igraph_is_vertex_coloring(SEXP graph, SEXP types) { +SEXP R_igraph_delaunay_graph(SEXP points) { /* Declarations */ igraph_t c_graph; - igraph_vector_int_t c_types; - igraph_bool_t c_res; - SEXP res; + igraph_matrix_t c_points; + SEXP graph; SEXP r_result; /* Convert input */ - R_SEXP_to_igraph(graph, &c_graph); - if (!Rf_isNull(types)) { - IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(types, &c_types)); - } else { - IGRAPH_R_CHECK(igraph_vector_int_init(&c_types, 0)); - } - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_types); + R_SEXP_to_matrix(points, &c_points); /* Call igraph */ - IGRAPH_R_CHECK(igraph_is_vertex_coloring(&c_graph, &c_types, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_delaunay_graph(&c_graph, &c_points)); + PutRNGstate(); /* Convert output */ - igraph_vector_int_destroy(&c_types); + IGRAPH_FINALLY(igraph_destroy, &c_graph); + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); IGRAPH_FINALLY_CLEAN(1); - PROTECT(res=NEW_LOGICAL(1)); - LOGICAL(res)[0]=c_res; - r_result = res; + r_result = graph; UNPROTECT(1); return(r_result); } /*-------------------------------------------/ -/ igraph_is_bipartite_coloring / +/ igraph_gabriel_graph / /-------------------------------------------*/ -SEXP R_igraph_is_bipartite_coloring(SEXP graph, SEXP types) { +SEXP R_igraph_gabriel_graph(SEXP points) { /* Declarations */ igraph_t c_graph; - igraph_vector_bool_t c_types; - igraph_bool_t c_res; + igraph_matrix_t c_points; + SEXP graph; - SEXP res; - SEXP mode; + SEXP r_result; + /* Convert input */ + R_SEXP_to_matrix(points, &c_points); + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_gabriel_graph(&c_graph, &c_points)); + PutRNGstate(); - SEXP r_result, r_names; + /* Convert output */ + IGRAPH_FINALLY(igraph_destroy, &c_graph); + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); + IGRAPH_FINALLY_CLEAN(1); + r_result = graph; + + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_relative_neighborhood_graph / +/-------------------------------------------*/ +SEXP R_igraph_relative_neighborhood_graph(SEXP points) { + /* Declarations */ + igraph_t c_graph; + igraph_matrix_t c_points; + SEXP graph; + + SEXP r_result; /* Convert input */ - R_SEXP_to_igraph(graph, &c_graph); - R_SEXP_to_vector_bool(types, &c_types); + R_SEXP_to_matrix(points, &c_points); /* Call igraph */ - IGRAPH_R_CHECK(igraph_is_bipartite_coloring(&c_graph, &c_types, &c_res, 0)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_relative_neighborhood_graph(&c_graph, &c_points)); + PutRNGstate(); /* Convert output */ - PROTECT(res=NEW_LOGICAL(1)); - LOGICAL(res)[0]=c_res; - r_result = res; + IGRAPH_FINALLY(igraph_destroy, &c_graph); + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); + IGRAPH_FINALLY_CLEAN(1); + r_result = graph; UNPROTECT(1); return(r_result); } /*-------------------------------------------/ -/ igraph_is_edge_coloring / +/ igraph_lune_beta_skeleton / /-------------------------------------------*/ -SEXP R_igraph_is_edge_coloring(SEXP graph, SEXP types) { +SEXP R_igraph_lune_beta_skeleton(SEXP points, SEXP beta) { /* Declarations */ igraph_t c_graph; - igraph_vector_int_t c_types; - igraph_bool_t c_res; - SEXP res; + igraph_matrix_t c_points; + igraph_real_t c_beta; + SEXP graph; SEXP r_result; /* Convert input */ - R_SEXP_to_igraph(graph, &c_graph); - if (!Rf_isNull(types)) { - IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(types, &c_types)); - } else { - IGRAPH_R_CHECK(igraph_vector_int_init(&c_types, 0)); - } - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_types); + R_SEXP_to_matrix(points, &c_points); + IGRAPH_R_CHECK_REAL(beta); + c_beta = REAL(beta)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_is_edge_coloring(&c_graph, &c_types, &c_res)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_lune_beta_skeleton(&c_graph, &c_points, c_beta)); + PutRNGstate(); /* Convert output */ - igraph_vector_int_destroy(&c_types); + IGRAPH_FINALLY(igraph_destroy, &c_graph); + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); IGRAPH_FINALLY_CLEAN(1); - PROTECT(res=NEW_LOGICAL(1)); - LOGICAL(res)[0]=c_res; - r_result = res; + r_result = graph; UNPROTECT(1); return(r_result); } /*-------------------------------------------/ -/ igraph_deterministic_optimal_imitation / +/ igraph_circle_beta_skeleton / /-------------------------------------------*/ -SEXP R_igraph_deterministic_optimal_imitation(SEXP graph, SEXP vid, SEXP optimality, SEXP quantities, SEXP strategies, SEXP mode) { +SEXP R_igraph_circle_beta_skeleton(SEXP points, SEXP beta) { /* Declarations */ igraph_t c_graph; - igraph_integer_t c_vid; - igraph_optimal_t c_optimality; - igraph_vector_t c_quantities; - igraph_vector_int_t c_strategies; - igraph_neimode_t c_mode; + igraph_matrix_t c_points; + igraph_real_t c_beta; + SEXP graph; SEXP r_result; /* Convert input */ - R_SEXP_to_igraph(graph, &c_graph); - c_vid = (igraph_integer_t) REAL(vid)[0]; - c_optimality = (igraph_optimal_t) Rf_asInteger(optimality); - R_SEXP_to_vector(quantities, &c_quantities); - IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(strategies, &c_strategies)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_strategies); - c_mode = (igraph_neimode_t) Rf_asInteger(mode); + R_SEXP_to_matrix(points, &c_points); + IGRAPH_R_CHECK_REAL(beta); + c_beta = REAL(beta)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_deterministic_optimal_imitation(&c_graph, c_vid, c_optimality, &c_quantities, &c_strategies, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_circle_beta_skeleton(&c_graph, &c_points, c_beta)); + PutRNGstate(); /* Convert output */ - PROTECT(strategies=R_igraph_vector_int_to_SEXP(&c_strategies)); - igraph_vector_int_destroy(&c_strategies); + IGRAPH_FINALLY(igraph_destroy, &c_graph); + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); IGRAPH_FINALLY_CLEAN(1); - r_result = strategies; + r_result = graph; UNPROTECT(1); return(r_result); } /*-------------------------------------------/ -/ igraph_moran_process / +/ igraph_beta_weighted_gabriel_graph / /-------------------------------------------*/ -SEXP R_igraph_moran_process(SEXP graph, SEXP weights, SEXP quantities, SEXP strategies, SEXP mode) { +SEXP R_igraph_beta_weighted_gabriel_graph(SEXP points, SEXP max_beta) { /* Declarations */ igraph_t c_graph; igraph_vector_t c_weights; - igraph_vector_t c_quantities; - igraph_vector_int_t c_strategies; - igraph_neimode_t c_mode; + igraph_matrix_t c_points; + igraph_real_t c_max_beta; + SEXP graph; + SEXP weights; SEXP r_result, r_names; /* Convert input */ - R_SEXP_to_igraph(graph, &c_graph); - if (!Rf_isNull(weights)) { - R_SEXP_to_vector(weights, &c_weights); - } - IGRAPH_R_CHECK(R_SEXP_to_vector_copy(quantities, &c_quantities)); - IGRAPH_FINALLY(igraph_vector_destroy, &c_quantities); - IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(strategies, &c_strategies)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_strategies); - c_mode = (igraph_neimode_t) Rf_asInteger(mode); + IGRAPH_R_CHECK(igraph_vector_init(&c_weights, 0)); + IGRAPH_FINALLY(igraph_vector_destroy, &c_weights); + weights=R_GlobalEnv; /* hack to have a non-NULL value */ + R_SEXP_to_matrix(points, &c_points); + IGRAPH_R_CHECK_REAL(max_beta); + c_max_beta = REAL(max_beta)[0]; /* Call igraph */ - IGRAPH_R_CHECK(igraph_moran_process(&c_graph, (Rf_isNull(weights) ? 0 : &c_weights), &c_quantities, &c_strategies, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_beta_weighted_gabriel_graph(&c_graph, &c_weights, &c_points, c_max_beta)); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(2)); PROTECT(r_names=NEW_CHARACTER(2)); - PROTECT(quantities=R_igraph_vector_to_SEXP(&c_quantities)); - igraph_vector_destroy(&c_quantities); + IGRAPH_FINALLY(igraph_destroy, &c_graph); + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); IGRAPH_FINALLY_CLEAN(1); - PROTECT(strategies=R_igraph_vector_int_to_SEXP(&c_strategies)); - igraph_vector_int_destroy(&c_strategies); + PROTECT(weights=R_igraph_0orvector_to_SEXP(&c_weights)); + igraph_vector_destroy(&c_weights); IGRAPH_FINALLY_CLEAN(1); - SET_VECTOR_ELT(r_result, 0, quantities); - SET_VECTOR_ELT(r_result, 1, strategies); - SET_STRING_ELT(r_names, 0, Rf_mkChar("quantities")); - SET_STRING_ELT(r_names, 1, Rf_mkChar("strategies")); + SET_VECTOR_ELT(r_result, 0, graph); + SET_VECTOR_ELT(r_result, 1, weights); + SET_STRING_ELT(r_names, 0, Rf_mkChar("graph")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("weights")); SET_NAMES(r_result, r_names); UNPROTECT(3); @@ -13717,155 +14760,217 @@ SEXP R_igraph_moran_process(SEXP graph, SEXP weights, SEXP quantities, SEXP stra } /*-------------------------------------------/ -/ igraph_roulette_wheel_imitation / +/ igraph_spatial_edge_lengths / /-------------------------------------------*/ -SEXP R_igraph_roulette_wheel_imitation(SEXP graph, SEXP vid, SEXP is_local, SEXP quantities, SEXP strategies, SEXP mode) { +SEXP R_igraph_spatial_edge_lengths(SEXP graph, SEXP points, SEXP METRIC) { /* Declarations */ igraph_t c_graph; - igraph_integer_t c_vid; - igraph_bool_t c_is_local; - igraph_vector_t c_quantities; - igraph_vector_int_t c_strategies; - igraph_neimode_t c_mode; + igraph_vector_t c_lengths; + igraph_matrix_t c_points; + igraph_metric_t c_METRIC; + SEXP lengths; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - c_vid = (igraph_integer_t) REAL(vid)[0]; - IGRAPH_R_CHECK_BOOL(is_local); - c_is_local = LOGICAL(is_local)[0]; - R_SEXP_to_vector(quantities, &c_quantities); - IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(strategies, &c_strategies)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_strategies); - c_mode = (igraph_neimode_t) Rf_asInteger(mode); + IGRAPH_R_CHECK(igraph_vector_init(&c_lengths, 0)); + IGRAPH_FINALLY(igraph_vector_destroy, &c_lengths); + lengths=R_GlobalEnv; /* hack to have a non-NULL value */ + R_SEXP_to_matrix(points, &c_points); + c_METRIC = (igraph_metric_t) Rf_asInteger(METRIC); /* Call igraph */ - IGRAPH_R_CHECK(igraph_roulette_wheel_imitation(&c_graph, c_vid, c_is_local, &c_quantities, &c_strategies, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_spatial_edge_lengths(&c_graph, &c_lengths, &c_points, c_METRIC)); + PutRNGstate(); /* Convert output */ - PROTECT(strategies=R_igraph_vector_int_to_SEXP(&c_strategies)); - igraph_vector_int_destroy(&c_strategies); + PROTECT(lengths=R_igraph_0orvector_to_SEXP(&c_lengths)); + igraph_vector_destroy(&c_lengths); IGRAPH_FINALLY_CLEAN(1); - r_result = strategies; + r_result = lengths; UNPROTECT(1); return(r_result); } /*-------------------------------------------/ -/ igraph_stochastic_imitation / +/ igraph_vertex_coloring_greedy / /-------------------------------------------*/ -SEXP R_igraph_stochastic_imitation(SEXP graph, SEXP vid, SEXP algo, SEXP quantities, SEXP strategies, SEXP mode) { +SEXP R_igraph_vertex_coloring_greedy(SEXP graph, SEXP heuristic) { /* Declarations */ igraph_t c_graph; - igraph_integer_t c_vid; - igraph_imitate_algorithm_t c_algo; - igraph_vector_t c_quantities; - igraph_vector_int_t c_strategies; - igraph_neimode_t c_mode; + igraph_vector_int_t c_colors; + igraph_coloring_greedy_t c_heuristic; + SEXP colors; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - c_vid = (igraph_integer_t) REAL(vid)[0]; - c_algo = (igraph_imitate_algorithm_t) Rf_asInteger(algo); - R_SEXP_to_vector(quantities, &c_quantities); - IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(strategies, &c_strategies)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_strategies); - c_mode = (igraph_neimode_t) Rf_asInteger(mode); + IGRAPH_R_CHECK(igraph_vector_int_init(&c_colors, 0)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_colors); + c_heuristic = (igraph_coloring_greedy_t) Rf_asInteger(heuristic); /* Call igraph */ - IGRAPH_R_CHECK(igraph_stochastic_imitation(&c_graph, c_vid, c_algo, &c_quantities, &c_strategies, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_vertex_coloring_greedy(&c_graph, &c_colors, c_heuristic)); + PutRNGstate(); /* Convert output */ - PROTECT(strategies=R_igraph_vector_int_to_SEXP(&c_strategies)); - igraph_vector_int_destroy(&c_strategies); + PROTECT(colors=R_igraph_vector_int_to_SEXP(&c_colors)); + igraph_vector_int_destroy(&c_colors); IGRAPH_FINALLY_CLEAN(1); - r_result = strategies; + r_result = colors; UNPROTECT(1); return(r_result); } /*-------------------------------------------/ -/ igraph_expand_path_to_pairs / +/ igraph_is_vertex_coloring / /-------------------------------------------*/ -SEXP R_igraph_expand_path_to_pairs(SEXP path) { +SEXP R_igraph_is_vertex_coloring(SEXP graph, SEXP types) { /* Declarations */ - igraph_vector_int_t c_path; + igraph_t c_graph; + igraph_vector_int_t c_types; + igraph_bool_t c_res; + SEXP res; SEXP r_result; /* Convert input */ - R_SEXP_to_vector_int_copy(path, &c_path); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_path); + R_SEXP_to_igraph(graph, &c_graph); + if (!Rf_isNull(types)) { + IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(types, &c_types)); + } else { + IGRAPH_R_CHECK(igraph_vector_int_init(&c_types, 0)); + } + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_types); /* Call igraph */ - IGRAPH_R_CHECK(igraph_expand_path_to_pairs(&c_path)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_is_vertex_coloring(&c_graph, &c_types, &c_res)); + PutRNGstate(); /* Convert output */ - PROTECT(path=R_igraph_vector_int_to_SEXPp1(&c_path)); - igraph_vector_int_destroy(&c_path); + igraph_vector_int_destroy(&c_types); IGRAPH_FINALLY_CLEAN(1); - r_result = path; + PROTECT(res=NEW_LOGICAL(1)); + LOGICAL(res)[0]=c_res; + r_result = res; UNPROTECT(1); return(r_result); } /*-------------------------------------------/ -/ igraph_invalidate_cache / +/ igraph_is_bipartite_coloring / /-------------------------------------------*/ -SEXP R_igraph_invalidate_cache(SEXP graph) { +SEXP R_igraph_is_bipartite_coloring(SEXP graph, SEXP types) { /* Declarations */ igraph_t c_graph; + igraph_vector_bool_t c_types; + igraph_bool_t c_res; - SEXP r_result; + SEXP res; + SEXP mode; + + SEXP r_result, r_names; /* Convert input */ - R_SEXP_to_igraph_copy(graph, &c_graph); - IGRAPH_FINALLY(igraph_destroy, &c_graph); + R_SEXP_to_igraph(graph, &c_graph); + R_SEXP_to_vector_bool(types, &c_types); /* Call igraph */ - igraph_invalidate_cache(&c_graph); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_is_bipartite_coloring(&c_graph, &c_types, &c_res, 0)); + PutRNGstate(); /* Convert output */ - PROTECT(graph=R_igraph_to_SEXP(&c_graph)); - IGRAPH_I_DESTROY(&c_graph); - IGRAPH_FINALLY_CLEAN(1); - r_result = graph; + PROTECT(res=NEW_LOGICAL(1)); + LOGICAL(res)[0]=c_res; + r_result = res; UNPROTECT(1); return(r_result); } /*-------------------------------------------/ -/ igraph_vertex_path_from_edge_path / +/ igraph_is_edge_coloring / /-------------------------------------------*/ -SEXP R_igraph_vertex_path_from_edge_path(SEXP graph, SEXP start, SEXP edge_path, SEXP mode) { +SEXP R_igraph_is_edge_coloring(SEXP graph, SEXP types) { /* Declarations */ igraph_t c_graph; - igraph_integer_t c_start; - igraph_vector_int_t c_edge_path; - igraph_vector_int_t c_vertex_path; - igraph_neimode_t c_mode; - SEXP vertex_path; + igraph_vector_int_t c_types; + igraph_bool_t c_res; + SEXP res; SEXP r_result; /* Convert input */ R_SEXP_to_igraph(graph, &c_graph); - if (!Rf_isNull(start)) { - c_start = (igraph_integer_t) REAL(start)[0]; + if (!Rf_isNull(types)) { + IGRAPH_R_CHECK(R_SEXP_to_vector_int_copy(types, &c_types)); + } else { + IGRAPH_R_CHECK(igraph_vector_int_init(&c_types, 0)); } - R_SEXP_to_vector_int_copy(edge_path, &c_edge_path); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edge_path); - IGRAPH_R_CHECK(igraph_vector_int_init(&c_vertex_path, 0)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vertex_path); - c_mode = (igraph_neimode_t) Rf_asInteger(mode); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_types); /* Call igraph */ - IGRAPH_R_CHECK(igraph_vertex_path_from_edge_path(&c_graph, (Rf_isNull(start) ? 0 : c_start), &c_edge_path, &c_vertex_path, c_mode)); + GetRNGstate(); + IGRAPH_R_CHECK(igraph_is_edge_coloring(&c_graph, &c_types, &c_res)); + PutRNGstate(); /* Convert output */ - igraph_vector_int_destroy(&c_edge_path); + igraph_vector_int_destroy(&c_types); IGRAPH_FINALLY_CLEAN(1); - PROTECT(vertex_path=R_igraph_vector_int_to_SEXPp1(&c_vertex_path)); - igraph_vector_int_destroy(&c_vertex_path); + PROTECT(res=NEW_LOGICAL(1)); + LOGICAL(res)[0]=c_res; + r_result = res; + + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_expand_path_to_pairs / +/-------------------------------------------*/ +SEXP R_igraph_expand_path_to_pairs(SEXP path) { + /* Declarations */ + igraph_vector_int_t c_path; + + SEXP r_result; + /* Convert input */ + R_SEXP_to_vector_int_copy(path, &c_path); + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_path); + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_expand_path_to_pairs(&c_path)); + PutRNGstate(); + + /* Convert output */ + PROTECT(path=R_igraph_vector_int_to_SEXPp1(&c_path)); + igraph_vector_int_destroy(&c_path); + IGRAPH_FINALLY_CLEAN(1); + r_result = path; + + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_invalidate_cache / +/-------------------------------------------*/ +SEXP R_igraph_invalidate_cache(SEXP graph) { + /* Declarations */ + igraph_t c_graph; + + SEXP r_result; + /* Convert input */ + R_SEXP_to_igraph_copy(graph, &c_graph); + IGRAPH_FINALLY(igraph_destroy, &c_graph); + /* Call igraph */ + GetRNGstate(); + igraph_invalidate_cache(&c_graph); + PutRNGstate(); + + /* Convert output */ + PROTECT(graph=R_igraph_to_SEXP(&c_graph)); + IGRAPH_I_DESTROY(&c_graph); IGRAPH_FINALLY_CLEAN(1); - r_result = vertex_path; + r_result = graph; UNPROTECT(1); return(r_result); @@ -13889,7 +14994,9 @@ SEXP R_igraph_version(void) { /* Convert input */ /* Call igraph */ + GetRNGstate(); igraph_version(&c_version_string, &c_major, &c_minor, &c_subminor); + PutRNGstate(); /* Convert output */ PROTECT(r_result=NEW_LIST(4)); @@ -13915,3 +15022,113 @@ SEXP R_igraph_version(void) { UNPROTECT(1); return(r_result); } + +/*-------------------------------------------/ +/ igraph_sample_sphere_surface / +/-------------------------------------------*/ +SEXP R_igraph_sample_sphere_surface(SEXP dim, SEXP n, SEXP radius, SEXP positive) { + /* Declarations */ + igraph_integer_t c_dim; + igraph_integer_t c_n; + igraph_real_t c_radius; + igraph_bool_t c_positive; + igraph_matrix_t c_res; + SEXP res; + + SEXP r_result; + /* Convert input */ + IGRAPH_R_CHECK_INT(dim); + c_dim = (igraph_integer_t) REAL(dim)[0]; + IGRAPH_R_CHECK_INT(n); + c_n = (igraph_integer_t) REAL(n)[0]; + IGRAPH_R_CHECK_REAL(radius); + c_radius = REAL(radius)[0]; + IGRAPH_R_CHECK_BOOL(positive); + c_positive = LOGICAL(positive)[0]; + IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); + IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_sample_sphere_surface(c_dim, c_n, c_radius, c_positive, &c_res)); + PutRNGstate(); + + /* Convert output */ + PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); + igraph_matrix_destroy(&c_res); + IGRAPH_FINALLY_CLEAN(1); + r_result = res; + + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_sample_sphere_volume / +/-------------------------------------------*/ +SEXP R_igraph_sample_sphere_volume(SEXP dim, SEXP n, SEXP radius, SEXP positive) { + /* Declarations */ + igraph_integer_t c_dim; + igraph_integer_t c_n; + igraph_real_t c_radius; + igraph_bool_t c_positive; + igraph_matrix_t c_res; + SEXP res; + + SEXP r_result; + /* Convert input */ + IGRAPH_R_CHECK_INT(dim); + c_dim = (igraph_integer_t) REAL(dim)[0]; + IGRAPH_R_CHECK_INT(n); + c_n = (igraph_integer_t) REAL(n)[0]; + IGRAPH_R_CHECK_REAL(radius); + c_radius = REAL(radius)[0]; + IGRAPH_R_CHECK_BOOL(positive); + c_positive = LOGICAL(positive)[0]; + IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); + IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_sample_sphere_volume(c_dim, c_n, c_radius, c_positive, &c_res)); + PutRNGstate(); + + /* Convert output */ + PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); + igraph_matrix_destroy(&c_res); + IGRAPH_FINALLY_CLEAN(1); + r_result = res; + + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_sample_dirichlet / +/-------------------------------------------*/ +SEXP R_igraph_sample_dirichlet(SEXP n, SEXP alpha) { + /* Declarations */ + igraph_integer_t c_n; + igraph_vector_t c_alpha; + igraph_matrix_t c_res; + SEXP res; + + SEXP r_result; + /* Convert input */ + IGRAPH_R_CHECK_INT(n); + c_n = (igraph_integer_t) REAL(n)[0]; + R_SEXP_to_vector(alpha, &c_alpha); + IGRAPH_R_CHECK(igraph_matrix_init(&c_res, 0, 0)); + IGRAPH_FINALLY(igraph_matrix_destroy, &c_res); + /* Call igraph */ + GetRNGstate(); + IGRAPH_R_CHECK(igraph_sample_dirichlet(c_n, &c_alpha, &c_res)); + PutRNGstate(); + + /* Convert output */ + PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); + igraph_matrix_destroy(&c_res); + IGRAPH_FINALLY_CLEAN(1); + r_result = res; + + UNPROTECT(1); + return(r_result); +} diff --git a/src/rinterface.h b/src/rinterface.h index 4486ea3d91a..a04726ca4a9 100644 --- a/src/rinterface.h +++ b/src/rinterface.h @@ -37,7 +37,7 @@ #include "uuid/uuid.h" -#define IGRAPH_I_DESTROY IGRAPH_I_ATTRIBUTE_DESTROY +#define IGRAPH_I_DESTROY igraph_i_attribute_destroy SEXP Rx_igraph_add_env(SEXP graph); @@ -80,6 +80,7 @@ void R_igraph_sirlist_destroy(igraph_vector_ptr_t *sl); SEXP Rx_igraph_arpack_options_to_SEXP(const igraph_arpack_options_t *opt); SEXP R_igraph_bliss_info_to_SEXP(const igraph_bliss_info_t *info); +// FIXME: Remove inconsistent prefix igraph_error_t R_igraph_SEXP_to_strvector(SEXP rval, igraph_strvector_t *sv); igraph_error_t R_igraph_SEXP_to_strvector_copy(SEXP rval, igraph_strvector_t *sv); void R_SEXP_to_vector(SEXP sv, igraph_vector_t *v); @@ -150,3 +151,19 @@ FILE* R_igraph_fopen_read(SEXP instream); igraph_error_t R_get_int_scalar(SEXP sexp, R_xlen_t index, igraph_integer_t *res); igraph_error_t R_get_real_scalar(SEXP sexp, R_xlen_t index, igraph_real_t *res); igraph_error_t R_get_bool_scalar(SEXP sexp, R_xlen_t index, igraph_bool_t *res); + +igraph_error_t igraph_sample_sphere_surface(igraph_integer_t dim, + igraph_integer_t n, + igraph_real_t radius, + igraph_bool_t positive, + igraph_matrix_t *res); + +igraph_error_t igraph_sample_sphere_volume(igraph_integer_t dim, + igraph_integer_t n, + igraph_real_t radius, + igraph_bool_t positive, + igraph_matrix_t *res); + +igraph_error_t igraph_sample_dirichlet(igraph_integer_t n, + const igraph_vector_t *alpha, + igraph_matrix_t *res); diff --git a/src/rinterface_extra.c b/src/rinterface_extra.c index 053aa2f9a0a..e3b496a4d66 100644 --- a/src/rinterface_extra.c +++ b/src/rinterface_extra.c @@ -21,6 +21,8 @@ */ +#include "igraph_random.h" +#include "igraph_sampling.h" #include "rinterface.h" #include "rrandom.h" @@ -43,6 +45,11 @@ #include #endif + +#define RNG_BEGIN() GetRNGstate() +#define RNG_END() PutRNGstate() + + enum igraph_t_idx { igraph_t_idx_n = 0, igraph_t_idx_directed = 1, @@ -132,6 +139,11 @@ void igraph_vector_int_list_destroy_pv(void *pv_ptr) igraph_vector_int_list_destroy((igraph_vector_int_list_t*) pv_ptr); } +void igraph_es_destroy_pv(void* pv_ptr) +{ + igraph_es_destroy((igraph_es_t*) pv_ptr); +} + igraph_error_t R_get_int_scalar(SEXP sexp, R_xlen_t index, igraph_integer_t *res) { if (Rf_xlength(sexp) <= index) @@ -386,7 +398,7 @@ void R_igraph_attribute_clean_preserve_list(void) { } } -igraph_error_t R_igraph_attribute_init(igraph_t *graph, igraph_vector_ptr_t *attr) { +igraph_error_t R_igraph_attribute_init(igraph_t *graph, const igraph_attribute_record_list_t *attr) { SEXP result, names, gal; int px = 0; @@ -413,12 +425,12 @@ igraph_error_t R_igraph_attribute_init(igraph_t *graph, igraph_vector_ptr_t *att graph->attr=result; /* Add graph attributes */ - igraph_integer_t attrno= attr==NULL ? 0 : igraph_vector_ptr_size(attr); + igraph_integer_t attrno= attr==NULL ? 0 : igraph_attribute_record_list_size(attr); SET_VECTOR_ELT(result, 1, NEW_LIST(attrno)); gal=VECTOR_ELT(result, 1); PROTECT(names=NEW_CHARACTER(attrno)); px++; for (igraph_integer_t i=0; itype) { case IGRAPH_ATTRIBUTE_NUMERIC: - vec=(igraph_vector_t*) rec->value; + vec = rec->value.as_vector; if (igraph_vector_size(vec) > 0) { SET_VECTOR_ELT(gal, i, NEW_NUMERIC(1)); REAL(VECTOR_ELT(gal, i))[0]=VECTOR(*vec)[0]; } break; case IGRAPH_ATTRIBUTE_BOOLEAN: - log=(igraph_vector_bool_t*) rec->value; + log = rec->value.as_vector_bool; if (igraph_vector_bool_size(log) > 0) { SET_VECTOR_ELT(gal, i, NEW_LOGICAL(1)); LOGICAL(VECTOR_ELT(gal, i))[0]=VECTOR(*log)[0]; } break; case IGRAPH_ATTRIBUTE_STRING: - strvec=(igraph_strvector_t*) rec->value; + strvec = rec->value.as_strvector; if (igraph_strvector_size(strvec) > 0) { SET_VECTOR_ELT(gal, i, NEW_CHARACTER(1)); SET_STRING_ELT(VECTOR_ELT(gal,i), 0, Rf_mkChar(igraph_strvector_get(strvec, 0))); @@ -496,22 +508,22 @@ igraph_error_t R_igraph_attribute_copy(igraph_t *to, const igraph_t *from, return 0; } -SEXP R_igraph_attribute_add_vertices_append1(igraph_vector_ptr_t *nattr, +SEXP R_igraph_attribute_add_vertices_append1(const igraph_attribute_record_list_t *nattr, int j, int nv) { SEXP app = R_NilValue; - igraph_attribute_record_t *tmprec=VECTOR(*nattr)[j-1]; + igraph_attribute_record_t *tmprec=igraph_attribute_record_list_get_ptr(nattr, j-1); igraph_integer_t len = 0; switch (tmprec->type) { case IGRAPH_ATTRIBUTE_NUMERIC: - len = igraph_vector_size(tmprec->value); + len = igraph_vector_size(tmprec->value.as_vector); break; case IGRAPH_ATTRIBUTE_BOOLEAN: - len = igraph_vector_bool_size(tmprec->value); + len = igraph_vector_bool_size(tmprec->value.as_vector_bool); break; case IGRAPH_ATTRIBUTE_STRING: - len = igraph_strvector_size(tmprec->value); + len = igraph_strvector_size(tmprec->value.as_strvector); break; case IGRAPH_ATTRIBUTE_OBJECT: igraph_error("R objects not implemented yet", __FILE__, __LINE__, @@ -534,13 +546,13 @@ SEXP R_igraph_attribute_add_vertices_append1(igraph_vector_ptr_t *nattr, switch (tmprec->type) { case IGRAPH_ATTRIBUTE_NUMERIC: PROTECT(app=NEW_NUMERIC(nv)); - igraph_vector_copy_to(tmprec->value, REAL(app)); + igraph_vector_copy_to(tmprec->value.as_vector, REAL(app)); break; case IGRAPH_ATTRIBUTE_BOOLEAN: - PROTECT(app=R_igraph_vector_bool_to_SEXP(tmprec->value)); + PROTECT(app=R_igraph_vector_bool_to_SEXP(tmprec->value.as_vector_bool)); break; default: /* IGRAPH_ATTRIBUTE_STRING */ - PROTECT(app=R_igraph_strvector_to_SEXP(tmprec->value)); + PROTECT(app=R_igraph_strvector_to_SEXP(tmprec->value.as_strvector)); break; } @@ -549,7 +561,7 @@ SEXP R_igraph_attribute_add_vertices_append1(igraph_vector_ptr_t *nattr, } void R_igraph_attribute_add_vertices_append(SEXP val, igraph_integer_t nv, - igraph_vector_ptr_t *nattr) { + const igraph_attribute_record_list_t *nattr) { SEXP names; igraph_integer_t valno, nattrno; SEXP rep = R_NilValue; @@ -560,7 +572,7 @@ void R_igraph_attribute_add_vertices_append(SEXP val, igraph_integer_t nv, if (nattr==NULL) { nattrno=0; } else { - nattrno=igraph_vector_ptr_size(nattr); + nattrno=igraph_attribute_record_list_size(nattr); } for (igraph_integer_t i=0; iname); } if (l) { @@ -605,7 +617,7 @@ SEXP R_igraph_attribute_add_vertices_dup(SEXP attr) { } igraph_error_t R_igraph_attribute_add_vertices(igraph_t *graph, igraph_integer_t nv, - igraph_vector_ptr_t *nattr) { + const igraph_attribute_record_list_t *nattr) { SEXP attr=graph->attr; SEXP val, rep=0, names, newnames; igraph_vector_int_t news; @@ -621,7 +633,7 @@ igraph_error_t R_igraph_attribute_add_vertices(igraph_t *graph, igraph_integer_t if (nattr==NULL) { nattrno=0; } else { - nattrno=igraph_vector_ptr_size(nattr); + nattrno=igraph_attribute_record_list_size(nattr); } origlen=igraph_vcount(graph)-nv; @@ -630,7 +642,7 @@ igraph_error_t R_igraph_attribute_add_vertices(igraph_t *graph, igraph_integer_t if (igraph_vector_int_init(&news, 0)) Rf_error("Out of memory"); IGRAPH_FINALLY_PV(igraph_vector_int_destroy, &news); for (igraph_integer_t i=0; iname; igraph_bool_t l=0; for (igraph_integer_t j=0; !l && jname)); } @@ -836,22 +848,22 @@ SEXP R_igraph_attribute_add_edges_dup(SEXP attr) { return newattr; } -SEXP R_igraph_attribute_add_edges_append1(igraph_vector_ptr_t *nattr, igraph_integer_t j, +SEXP R_igraph_attribute_add_edges_append1(const igraph_attribute_record_list_t *nattr, igraph_integer_t j, igraph_integer_t ne) { SEXP app = R_NilValue; - igraph_attribute_record_t *tmprec=VECTOR(*nattr)[j-1]; + igraph_attribute_record_t *tmprec=igraph_attribute_record_list_get_ptr(nattr, j-1); igraph_integer_t len = 0; switch(tmprec->type) { case IGRAPH_ATTRIBUTE_NUMERIC: - len = igraph_vector_size(tmprec->value); + len = igraph_vector_size(tmprec->value.as_vector); break; case IGRAPH_ATTRIBUTE_BOOLEAN: - len = igraph_vector_bool_size(tmprec->value); + len = igraph_vector_bool_size(tmprec->value.as_vector_bool); break; case IGRAPH_ATTRIBUTE_STRING: - len = igraph_strvector_size(tmprec->value); + len = igraph_strvector_size(tmprec->value.as_strvector); break; case IGRAPH_ATTRIBUTE_OBJECT: igraph_error("R objects not implemented yet", __FILE__, __LINE__, @@ -874,13 +886,15 @@ SEXP R_igraph_attribute_add_edges_append1(igraph_vector_ptr_t *nattr, igraph_int switch (tmprec->type) { case IGRAPH_ATTRIBUTE_NUMERIC: PROTECT(app=NEW_NUMERIC(ne)); - igraph_vector_copy_to(tmprec->value, REAL(app)); + igraph_vector_copy_to(tmprec->value.as_vector, REAL(app)); break; case IGRAPH_ATTRIBUTE_BOOLEAN: - PROTECT(app=R_igraph_vector_bool_to_SEXP(tmprec->value)); + PROTECT(app=R_igraph_vector_bool_to_SEXP(tmprec->value.as_vector_bool)); break; - default: /* IGRAPH_ATTRIBUTE_STRING */ - PROTECT(app=R_igraph_strvector_to_SEXP(tmprec->value)); + case IGRAPH_ATTRIBUTE_STRING: + PROTECT(app=R_igraph_strvector_to_SEXP(tmprec->value.as_strvector)); + break; + default: break; } @@ -890,7 +904,7 @@ SEXP R_igraph_attribute_add_edges_append1(igraph_vector_ptr_t *nattr, igraph_int void R_igraph_attribute_add_edges_append(SEXP eal, const igraph_vector_int_t *edges, - igraph_vector_ptr_t *nattr) { + const igraph_attribute_record_list_t *nattr) { SEXP names; igraph_integer_t ealno; igraph_integer_t ne=igraph_vector_int_size(edges)/2, nattrno; @@ -902,7 +916,7 @@ void R_igraph_attribute_add_edges_append(SEXP eal, if (nattr==NULL) { nattrno=0; } else { - nattrno=igraph_vector_ptr_size(nattr); + nattrno=igraph_attribute_record_list_size(nattr); } for (igraph_integer_t i=0; iname); } if (l) { @@ -939,7 +953,7 @@ void R_igraph_attribute_add_edges_append(SEXP eal, } igraph_error_t R_igraph_attribute_add_edges(igraph_t *graph, const igraph_vector_int_t *edges, - igraph_vector_ptr_t *nattr) { + const igraph_attribute_record_list_t *nattr) { SEXP attr=graph->attr; SEXP eal, names, newnames; igraph_vector_int_t news; @@ -959,14 +973,14 @@ igraph_error_t R_igraph_attribute_add_edges(igraph_t *graph, const igraph_vector if (nattr==NULL) { nattrno=0; } else { - nattrno=igraph_vector_ptr_size(nattr); + nattrno=igraph_attribute_record_list_size(nattr); } origlen=igraph_ecount(graph)-ne; /* First add the new attributes, if any */ newattrs=0; for (igraph_integer_t i=0; iname; igraph_bool_t l=0; for (igraph_integer_t j=0; !l && jname)); } @@ -1914,7 +1928,7 @@ igraph_error_t R_igraph_attribute_combine_vertices(const igraph_t *graph, /* Create the TODO list first */ PROTECT(names=GET_NAMES(val)); px++; - TODO=igraph_Calloc(valno, igraph_integer_t); + TODO=IGRAPH_CALLOC(valno, igraph_integer_t); if (!TODO) { UNPROTECT(px); IGRAPH_ERROR("Cannot combine edge attributes", @@ -2088,7 +2102,7 @@ igraph_error_t R_igraph_attribute_combine_edges(const igraph_t *graph, IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, TODO); - funcs=igraph_Calloc(ealno, igraph_function_pointer_t); + funcs=IGRAPH_CALLOC(ealno, igraph_function_pointer_t); if (!funcs) { UNPROTECT(px); IGRAPH_ERROR("Cannot combine edge attributes", @@ -2361,7 +2375,7 @@ void checkInterruptFn(void *dummy) { R_CheckUserInterrupt(); } -igraph_error_t R_igraph_interrupt_handler(void *data) { +igraph_bool_t R_igraph_interrupt_handler(void) { /* We need to call R_CheckUserInterrupt() regularly to enable interruptions. * However, if an interruption is pending, R_CheckUserInterrupt() will * longjmp back to the top level so we cannot clean up ourselves by calling @@ -2377,9 +2391,9 @@ igraph_error_t R_igraph_interrupt_handler(void *data) { */ if (R_ToplevelExec(checkInterruptFn, NULL) == FALSE) { IGRAPH_FINALLY_FREE(); - return IGRAPH_INTERRUPTED; + return true; } - return IGRAPH_SUCCESS; + return false; } igraph_error_t R_igraph_progress_handler(const char *message, double percent, @@ -2403,17 +2417,15 @@ igraph_error_t R_igraph_progress_handler(const char *message, double percent, } igraph_error_t R_igraph_status_handler(const char *message, void *data) { - SEXP l1 = PROTECT(Rf_install("getNamespace")); - SEXP l2 = PROTECT(Rf_ScalarString(PROTECT(Rf_mkChar("igraph")))); - SEXP l3 = PROTECT(Rf_lang2(l1, l2)); - SEXP rho = PROTECT(Rf_eval(l3, R_BaseEnv)); - - SEXP l4 = PROTECT(Rf_install(".igraph.status")); + SEXP l1 = PROTECT(Rf_install(":::")); + SEXP l2 = PROTECT(Rf_install("igraph")); + SEXP l3 = PROTECT(Rf_install(".igraph.status")); + SEXP l4 = PROTECT(Rf_lang3(l1, l2, l3)); SEXP l5 = PROTECT(Rf_ScalarString(PROTECT(Rf_mkChar(message)))); SEXP l6 = PROTECT(Rf_lang2(l4, l5)); - PROTECT(Rf_eval(l6, rho)); + PROTECT(Rf_eval(l6, R_BaseEnv)); - UNPROTECT(10); + UNPROTECT(8); return 0; } @@ -2669,7 +2681,7 @@ SEXP R_igraph_matrix_to_SEXP(const igraph_matrix_t *m) { } PROTECT(result=NEW_NUMERIC(igraph_matrix_size(m))); - igraph_matrix_copy_to(m, REAL(result)); + igraph_matrix_copy_to(m, REAL(result), IGRAPH_COLUMN_MAJOR); PROTECT(dim=NEW_INTEGER(2)); INTEGER(dim)[0] = (int) nrow; INTEGER(dim)[1] = (int) ncol; @@ -2736,7 +2748,7 @@ SEXP R_igraph_matrix_complex_to_SEXP(const igraph_matrix_complex_t *m) { } PROTECT(result=NEW_COMPLEX(igraph_matrix_complex_size(m))); - igraph_matrix_complex_copy_to(m, (igraph_complex_t*) COMPLEX(result)); + igraph_matrix_complex_copy_to(m, (igraph_complex_t*) COMPLEX(result), IGRAPH_COLUMN_MAJOR); PROTECT(dim=NEW_INTEGER(2)); INTEGER(dim)[0] = (int) nrow; INTEGER(dim)[1] = (int) ncol; @@ -3266,7 +3278,7 @@ SEXP R_igraph_sparsemat_to_SEXP_cc(const igraph_sparsemat_t *sp) { igraph_vector_t x; R_SEXP_to_vector_int_copy(VECTOR_ELT(res, 2), &p); R_SEXP_to_vector_int_copy(VECTOR_ELT(res, 3), &i); - igraph_vector_view(&x, REAL(VECTOR_ELT(res, 4)), nz); + x = igraph_vector_view(REAL(VECTOR_ELT(res, 4)), nz); igraph_sparsemat_getelements_sorted(sp, &i, &p, &x); } @@ -3332,7 +3344,7 @@ void R_igraph_SEXP_to_vector_list(SEXP vectorlist, igraph_vector_list_t *list) { for (igraph_integer_t i=0; istor_begin=(char**) R_alloc((size_t) length, sizeof(char*)); + sv->stor_begin=(const char**) R_alloc((size_t) length, sizeof(char*)); sv->stor_end=sv->stor_begin+length; sv->end=sv->stor_end; for (igraph_integer_t i=0; i` header. While an igraph installation includes several sub-headers, these are for organizational purposes only, and their contents may change without notice. Only `#include ` is supported. + +#### Error codes + +- The `IGRAPH_EINVEVECTOR` error code was removed; `igraph_create()` and `igraph_add_edges()` that used to return this error code for invalid edge vectors will now return `IGRAPH_EINVAL` instead. +- The `IGRAPH_NONSQUARE` error code was removed; functions that used this error code now return `IGRAPH_EINVAL` instead when encountering a non-square matrix. +- The `IGRAPH_EGLP` error code and all other GLP-specific error codes (starting with `IGRAPH_GLP_`) were removed; functions that used this error code now return `IGRAPH_FAILURE` instead, providing more details in the message associated to the error code. +- The `IGRAPH_ELAPACK` error code was removed; functions that used this error code now return `IGRAPH_FAILURE` instead, providing more details in the message associated to the error code. +- The `IGRAPH_CPUTIME` error code was removed in favour of the interruption mechanism built into igraph. +- The unused `IGRAPH_EDIVZERO` and `IGRAPH_EATTRIBUTES` error codes were removed with no replacement. +- The deprecated error code `IGRAPH_ENEGLOOP` was removed. Use `IGRAPH_ENEGCYCLE` instead. The underlying numerical value is the same as it was for `IGRAPH_ENEGLOOP`. +- ARPACK-specific error codes (starting with `IGRAPH_ARPACK_...`) were replaced with a single `IGRAPH_EARPACK` error code. Details about the underlying ARPACK failure are provided in the error message. +- A new error code called `IGRAPH_EINVEID` was added for cases when an invalid edge ID was encountered in an edge ID vector. + +#### Core data structures + +- `igraph_strvector_push_back_len()` now takes a length parameter of `size_t` instead of `igraph_int_t`. +- `igraph_strvector_print()` no longer takes a file parameter. Use `igraph_strvector_fprint()` to print to a file. +- `igraph_vector_reverse()` no longer returns an error code. +- `igraph_vector_shuffle()` no longer returns an error code. +- `igraph_vector_swap()` and `igraph_matrix_swap()` no longer return an error code. +- `igraph_vector_list_swap()` and `igraph_graph_list_swap()` no longer return an error code. +- `igraph_vector_swap_elements()` no longer returns an error code. +- `igraph_vector_list_swap_elements()` and `igraph_graph_list_swap_elements()` no longer return an error code. +- `igraph_matrix_copy_to()` gained an `igraph_matrix_storage_t storage` parameter that specifies whether the data should be written in column-major or row-major format. +- `igraph_vector_view()`, `igraph_matrix_view()`, `igraph_matrix_view_from_vector()`, and `igraph_vector_ptr_view()` now return their result as a return value instead of an output parameter. This allows assigning the value to a `const` variable without triggering warnings with modern compilers. + +#### Attribute handling + +- `igraph_attribute_handler_t` members that formerly took an untyped `igraph_vector_ptr_t` argument are now taking a typed `igraph_attribute_record_list_t` argument instead. +- The deprecated `IGRAPH_ATTRIBUTE_DEFAULT` value of the `igraph_attribute_type_t` enum was removed. +- The `gettype` member of `igraph_attribute_table_t` was renamed to `get_type` for consistency with the naming scheme of other struct members. +- Attribute table members that retrieve graph, vertex or edge attributes must not clear the incoming result vector any more; results must be appended to the end of the provided result vector instead. +- The `value` member of `igraph_attribute_record_t` is now a union that can be used to formally treat the associated pointer as an `igraph_vector_t *`, `igraph_strvector_t *` or `igraph_vector_bool_t *`. + +#### Core graph manipulation + +- `igraph_delete_vertices_map()` (formerly called `igraph_delete_vertices_idx()`) and `igraph_induced_subgraph_map()` now use `-1` to represent unmapped vertices in the returned forward mapping vector and they do not offset vertex indices by 1 any more. Note that the inverse map always behaved this way, this change makes the two mappings consistent. +- `igraph_edges()` gained a new `igraph_bool_t bycol` argument that determines the order in which the edges are returned. `bycol = false` reproduces the existing behaviour, while `bycol = true` returns the edges suitable for a matrix stored in column-wise order. +- `igraph_neighbors()` and `igraph_vs_adj()` gained two extra arguments, `igraph_loops_t loops` and `igraph_bool_t multiple` to specify what to do with loop and multiple edges. This makes their interfaces consistent with `igraph_adjlist_init()`. Use `loops = IGRAPH_LOOPS_TWICE` and `multiple = true` to reproduce the previous behavior. +- `igraph_incident()` and `igraph_es_incident()` gained an extra `igraph_loops_t loops` argument to specify what to do with loop edges. This makes their interfaces consistent with `igraph_inclist_init()`. Use `loops = IGRAPH_LOOPS_TWICE` to reproduce the previous behavior. +- The `igraph_multiple_t` enum type was removed from the public API as it was essentially a Boolean. The symbolic constants `IGRAPH_MULTIPLE` (same as `true`) and `IGRAPH_NO_MULTIPLE` (same as `false`) were kept to improve readability of code written directly in C. + +#### Basic graph properties + +- `igraph_density()` now takes an optional `weights` parameter. +- `igraph_is_simple()` gained an extra `igraph_bool_t` argument that decides whether edge directions should be considered. Directed graphs with a mutual edge pair are treated as non-simple if this argument is set to `IGRAPH_UNDIRECTED` (which treats the graph as if it was undirected). +- The type of the `loops` argument of `igraph_adjlist_init_complementer()`, `igraph_centralization_degree()`, `igraph_centralization_degree_tmax()`, `igraph_degree()`, `igraph_maxdegree()`, `igraph_sort_vertex_ids_by_degree()` and `igraph_strength()` was changed to `igraph_loops_t` from `igraph_bool_t`, allowing finer-grained control about how loop edges are treated. Pass `IGRAPH_LOOPS_TWICE` and `IGRAPH_NO_LOOPS` to reproduce the previous behaviour of `true` and `false`. +- `igraph_get_biadjacency()` now takes a `weights` parameter, and can optionally create weighted biadjacency matrices. +- `igraph_adjacency()` now treats `IGRAPH_LOOPS_TWICE` as `IGRAPH_LOOPS_ONCE` when the mode is `IGRAPH_ADJ_DIRECTED`, `IGRAPH_ADJ_UPPER` or `IGRAPH_ADJ_LOWER`. For directed graphs, this is for the sake of consistency with the rest of the library where `IGRAPH_LOOPS_TWICE` is considered for undirected graphs only. For the "upper" and "lower" modes, double-counting the diagonal makes no sense because the double-counting artifact appears when you add the _transpose_ of an upper (or lower) diagonal matrix on top of the matrix itself. See Github issue #2501 for more context. + +#### Graph generators + +- `igraph_barabasi_game()`, `igraph_barabasi_aging_game()`, `igraph_recent_degree_game()` and `igraph_recent_degree_aging_game()` no longer interprets an empty `outseq` vector as a missing out-degree sequence. Pass `NULL` if you don't wish to specify an out-degree sequence. +- `igraph_degree_sequence_game()` no longer interprets an empty in-degree vector as a request for generating undirected graphs. To generate undirected graphs, pass `NULL` for in-degrees. +- `igraph_erdos_renyi_game_gnm()` uses a `igraph_edge_type_sw_t allowed_edge_types` parameter instead of `igraph_bool_t loops`, and can now uniformly sample not only simple graphs but also multigraphs. It also gained an `edge_labeled` Boolean parameter which controls whether to sample from the set of ordered edge lists (equivalent to `igraph_iea_game()` for multigraphs). +- `igraph_erdos_renyi_game_gnp()` uses a `igraph_edge_type_sw_t allowed_edge_types` parameter instead of `igraph_bool_t loops`, and can now sample multigraphs from a maximum entropy model with a prescribed _expected_ edge multiplicity. It also gained an `edge_labeled` Boolean parameter which controls whether to sample from the set of ordered edge lists. +- `igraph_bipartite_game_gnm()` gained an `igraph_edge_type_sw_t allowed_edge_types` parameter, and can now uniformly sample not only simple graphs but also multigraphs. It also gained an `edge_labeled` Boolean parameter which controls whether to sample from the set of ordered edge lists (equivalent to `igraph_bipartite_iea_game()` for multigraphs). +- `igraph_bipartite_game_gnp()` gained an `igraph_edge_type_sw_t allowed_edge_types` parameter, and can now sample multigraphs from a maximum entropy model with a prescribed _expected_ edge multiplicity. It also gained an `edge_labeled` Boolean parameter which controls whether to sample from the set of ordered edge lists. +- `igraph_lcf()` was renamed to `igraph_lcf_small()` and `igraph_lcf_vector()` was renamed to `igraph_lcf()`. Now `igraph_lcf()` takes shifts as a vector input, while `igraph_lcf_small()` accepts a shorthand notation where shifts are given as a variable number of function arguments. +- `igraph_sbm_game()` uses an `igraph_edge_type_sw_t allowed_edge_types` parameter instead of `igraph_bool_t loops` and now supports generating graphs with multi-edges. The parameter determining the total number of vertices (`n`) was removed as it was redundant. +- `igraph_rewire_edges()` uses an `igraph_edge_type_sw_t allowed_edge_types` parameter instead of `loops` and `multiple`. +- `igraph_rewire()` now takes an `igraph_edge_type_sw_t allowed_edge_types` parameter to specify whether to create self-loops. The `igraph_rewiring_t` enum type was removed. Instead of the old `IGRAPH_REWIRING_SIMPLE`, use `IGRAPH_SIMPLE_SW`. Instead of the old `IGRAPH_REWIRING_SIMPLE_LOOPS`, use `IGRAPH_LOOPS_SW`. +- `igraph_rewire()` now takes an optional `igraph_rewiring_stats_t *` output argument. You can pass the appropriate struct there to find out the number of successful swaps during the rewiring operation. +- `igraph_watts_strogatz_game()` uses an `igraph_edge_type_sw_t allowed_edge_types` parameter instead of `loops` and `multiple`. +- `igraph_static_fitness_game()` uses an `igraph_edge_type_sw_t allowed_edge_types` parameter instead of `loops` and `multiple`. +- `igraph_static_power_law_game()` uses an `igraph_edge_type_sw_t allowed_edge_types` parameter instead of `loops` and `multiple`. +- `igraph_correlated_game()` now takes the graph being constructed as the _first_ argument to remain consistent with other graph constructors. Earlier versions used to take the original graph as the first argument. +- The semantics of the `permutation` argument of `igraph_correlated_game()` and `igraph_correlated_pair_game()` has changed: the i-th element of the vector now contains the index of the _original_ vertex that will be mapped to the i-th vertex in the new graph. This is consistent with how `igraph_permute_vertices()` operates (which has also changed in igraph 1.0). + +#### Paths and cycles + +- `igraph_distances()`, `igraph_distances_cutoff()`, `igraph_get_shortest_path()`, `igraph_get_shortest_paths()` and `igraph_get_all_shortest_paths()` gained a `weights` argument. The functions now automatically select the appropriate implementation (unweighted, Dijkstra, Bellman-Ford or Johnson) algorithm based on whether weights are present and whether there are negative weights or not. You can still call the individual methods by their more specific names. +- `igraph_distances_johnson()` now takes an `igraph_neimode_t mode` parameter to determine in which direction paths should be followed. +- The weighted variants of `igraph_diameter()`, `igraph_pseudo_diameter()`, `igraph_radius()`, `igraph_graph_center()`, `igraph_eccentricity()` and `igraph_average_path_length()` were merged into the undirected ones by adding a new argument named `weights` in the second position. +- The `weights` parameter of `igraph_average_path_length()`, `igraph_global_efficiency()`, `igraph_local_efficiency()` and `igraph_average_local_efficiency()` were moved to the second position, after the `graph` itself, for consistency with other functions. +- `igraph_get_all_simple_paths()` returns its results in an integer vector list (`igraph_vector_int_list_t`) instead of a single integer vector. +- `igraph_get_all_simple_paths()` now has an additional parameter that allows restricting paths by minimum length as well, and its `mode` parameter was moved to before the path length limit parameters. +- `igraph_get_all_simple_paths()` gained a `max_results` parameter to limit the number of returned results. Pass `1` to return a single result, or `IGRAPH_UNLIMITED` to return all results. +- `igraph_simple_cycles()` gained a `max_results` parameter to limit the number of returned results. Pass `1` to return a single result, or `IGRAPH_UNLIMITED` to return all results. + +#### Community detection + +- `igraph_community_edge_betweenness()` now takes both a `weights` and a `lengths` parameter. Edge weights (interpreted as connection strengths) are used to divide betweenness scores before selecting them for removal as well as for the modularity computation. Edge lengths are used for defining shortest path lengths during the betweenness computation. This fixes issues #2229 and #1040. +- `igraph_community_infomap()` now supports regularization and gained the `is_regularized` and `regularization_strength` parameters. +- `igraph_community_label_propagation()` gained the `igraph_lpa_variant_t lpa_variant` parameter to allow specification of label propagation algorithm (LPA) variants. A new fast label propagation variant was added. Set `lpa_variant=DOMINANCE` to select the algorithm used up to igraph 0.10. +- `igraph_community_leiden()` now takes two `vertex_out_weights` and `vertex_in_weights` parameters in order to support directed graphs, instead of the previous single `node_weights` parameter. To obtain the old behavior for undirected graphs, pass the vertex weights as `vertex_out_weights` and set `vertex_in_weights` to `NULL`. +- The `history` parameter of `igraph_community_leading_eigenvector()` is now a pointer to an `igraph_vector_int_t` instead of an `igraph_vector_t`. +- `igraph_community_optimal_modularity()` now takes a `resolution` parameter and its `weight` parameter was moved to the second place. +- `igraph_community_spinglass_single()` now uses `igraph_real_t` for its `inner_links` and `outer_links` output parameters, as these return not simply edge counts, but the sum of the weights of some edges. + +#### Isomorphism functions and permutations + +- `igraph_count_automorphisms()` has been renamed to `igraph_count_automorphisms_bliss()` because it has a BLISS-specific interface. A new `igraph_count_automorphisms()` function was added with a simplified interface that does not depend on BLISS. +- `igraph_automorphism_group()` has been renamed to `igraph_automorphism_group_bliss()` because it has a BLISS-specific interface. A new `igraph_automorphism_group()` function was added with a simplified interface that does not depend on BLISS. +- `igraph_canonical_permutation()` has been renamed to `igraph_canonical_permutation_bliss()` because it has a BLISS-specific interface. A new `igraph_canonical_permutation()` function was added with a simplified interface that does not depend on BLISS. +- `igraph_subisomorphic_lad()` does not have a CPU time limit parameter any more. If you wish to stop the calculation from another thread or a higher level interface, use igraph's interruption mechanism. +- The semantics of the `igraph_permute_vertices()` permutation argument has changed: the i-th element of the vector now contains the index of the _original_ vertex that will be mapped to the i-th vertex in the new graph. This is now consistent with how other igraph functions treat permutations and vertex index vectors; for instance, you can now pass the result of `igraph_topological_sorting()` directly to `igraph_permute_vertices()` to obtain a new graph where the vertices are sorted topologically. +- As a consequence to the change in the semantics of the `igraph_permute_vertices()` permutation argument, the semantics of the permutations returned from `igraph_canonical_permutation()` and `igraph_canonical_permutation_bliss()` have also been inverted to maintain the invariant that the output of these functions can be fed into `igraph_permute_vertices()` directly. +- `igraph_isoclass_subgraph()` now takes a parameter of type `igraph_vs_t vids` instead of `igraph_vector_int_t vids`. Apply `igraph_vss_vector()` to the vector of vertex IDs to convert it to an `igraph_vs_t`. + +#### Centralities + +- All betweenness functions got a `normalized` parameter to support normalizing the result by the number of vertex pairs in the graph. At the same time, their parameter ordering was standardized. The following functions are affected: `igraph_betweenness()`, `igraph_betweenness_cutoff()`, `igraph_edge_betweenness()`, `igraph_edge_betweenness_cutoff()`, `igraph_betweenness_subset()`, `igraph_edge_betweenness_subset()`. +- `igraph_edge_betweenness()` and `igraph_edge_betweenness_cutoff()` now have an `eids` parameter to return only a subset of results. This makes their interface consistent with other betweenness functions. +- `igraph_eigenvector_centrality()`, `igraph_centralization_eigenvector_centrality()` and `igraph_centralization_eigenvector_centrality_tmax()` now use a `mode` parameter with possible values `IGRAPH_OUT`, `IGRAPH_IN` or `IGRAPH_ALL` to control how edge directions are considered. Previously they used a boolean `directed` parameter. +- `igraph_eigenvector_centrality()`, `igraph_centralization_eigenvector_centrality()` and `igraph_centralization_eigenvector_centrality_tmax()` no longer have a `scale` parameter. The result is now always scaled so that the largest centrality value is 1. +- `igraph_hub_and_authority_scores()` no longer has a `scale` parameter. The result is now always scaled so that the largest hub and authority scores are each 1. +- `igraph_pagerank()`, `igraph_personalized_pagerank()` and `igraph_personalized_pagerank_vs()` had their parameter ordering standardized. + +#### Cliques and independent sets + +- `igraph_cliques()`, `igraph_weighed_cliques()`, `igraph_maximal_cliques()`, `igraph_maximal_cliques_file()`, `igraph_maximal_cliques_subset()`, `igraph_independent_sets()` and `igraph_maximal_independent_sets()` received a `max_results` parameter to limit the number of returned results. Pass `1` to return a single result, or `IGRAPH_UNLIMITED` to return all results. +- `igraph_maximal_independent_sets()` received `min_size` and `max_size` parameters that control the range of independent set sizes that are returned. +- `igraph_weighted_cliques()` had its parameter ordering standardized: the `igraph_bool_t maximal` parameter now comes before the `min_weight` / `max_weight` parameters. +- `igraph_maximal_cliques_callback()` had its parameter ordering standardized: the `igraph_clique_handler_t *cliquehandler_fn, void *arg` parameter pair now comes at the end, making this function consistent with `igraph_cliques_callback()`. + +#### Layouts + +- `igraph_layout_sugiyama()` does not return an "extended graph" anymore. The bends in the edges of the layout are encoded in a list of matrices instead; each item in the list belongs to an edge of the original graph and contains the control points of the edge in a row-wise fashion. The matrix will have no rows if no control points are needed on the edge. + +#### Other network analysis + +- `igraph_similarity_jaccard()` and `igraph_similarity_dice()` now take two sets of vertices (`to` and `from` parameters) to create vertex pairs of, instead of one. Pass the same vertex set to both parameters to recover the previous behaviour. +- `igraph_minimum_spanning_tree()` takes a new `method` parameter that controls the algorithm used for finding the spanning tree. Kruskal's algorithm was added. +- `igraph_motifs_randesu_no()` and `igraph_motifs_randesu_estimate()` now take an `igraph_real_t` as their `result` argument to prevent overflows when igraph is compiled with 32-bit integers. +- The `igraph_motifs_handler_t` callback type now takes a `const igraph_vector_int_t *vids` parameter. Previously this was not formally `const`, even though it was not allowed to modify `vids`. This affects uses of `igraph_motifs_randesu_callback()`. +- The experimental functions `igraph_fundamental_cycles()` and `igraph_minimum_cycle_basis()` now use the type `igraph_real_t` for their `bfs_cutoff` parameter, and had their `weights` parameter moved to the 2nd position. + +#### Foreign formats + +- `igraph_read_graph_ncol()` and `igraph_read_graph_lgl()` now uses a default edge weight of 1 instead of 0 for files that do not contain edge weights for at least some of the edges. + +### Added + +- `igraph_setup()` performs all initialization tasks that are recommended before using the igraph library. Right now this function only initializes igraph's internal random number generator with a practically random seed, but it may also perform other tasks in the future. It is recommended to call this function before using any other function from the library (although most of the functions will work fine now even if this function is not called). +- `igraph_iea_game()` samples random multigraphs through independent edge assignment. +- `igraph_bipartite_iea_game()` samples random bipartite multigraph through independent edge assignment. +- `igraph_weighted_biadjacency()` creates a weighted graph from a bipartite adjacency matrix. +- `igraph_vector_ptr_capacity()` returns the allocated capacity of a pointer vector. +- `igraph_vector_ptr_resize_min()` deallocates unused capacity of a pointer vector. +- `igraph_strvector_fprint()` prints a string vector to a file. +- `igraph_rng_sample_dirichlet()`, `igraph_rng_sample_sphere_volume()` and `igraph_rng_sample_sphere_surface()` samples vectors from a Dirichlet distribution or from the volume or surface of a sphere while allowing the user to specify the random number generator to use. +- `igraph_nearest_neighbor_graph()` computes a neighborhood graph of spatial points based on a neighbor count, cutoff distance, and chosen metric (experimental function). Thanks to Arnór Friðriksson @Zepeacedust for implementing this in #2788! +- `igraph_delaunay_graph()` computes a Delaunay graph of a spatial point set (experimental function). Thanks to Arnór Friðriksson @Zepeacedust for implementing this in #2806! +- `igraph_gabriel_graph()` computes the Gabriel graph of a spatial point set (experimental function). Thanks to Arnór Friðriksson @Zepeacedust for implementing this in #2827! +- `igraph_relative_neighborhood_graph()` computes the relative neighborhood graph of a spatial point set (experimental function). Thanks to Arnór Friðriksson @Zepeacedust for implementing this in #2827! +- `igraph_lune_beta_skeleton()` and `igraph_circle_beta_skeleton()` compute the lune and circle based β-skeletons of a spatial point set (experimental function). Thanks to Arnór Friðriksson @Zepeacedust for implementing this in #2827! +- `igraph_beta_weighted_gabriel_graph()` computes a Gabriel graph of a spatial point set, along with a threshold β value for each edge, at which the edge ceases to be part of the lune-based β-skeleton (experimental function). Thanks to Arnór Friðriksson @Zepeacedust for implementing this in #2827! +- `igraph_spatial_edge_lengths()` computes edge lengths based on spatial vertex coordinates (experimental function). +- `igraph_community_leiden_simple()` is a simplified interface to `igraph_community_leiden()` that allows selecting the objective function to maximize directly. +- `igraph_vector_difference_and_intersection_sorted()` calculates the intersection and the differences of two vectors simultaneously. +- `IGRAPH_UNLIMITED`, defined to `-1`, is a convenience constant for use with various "size limit" parameters, such as number of cliques returned, maximum path length, number of results returned, etc. It indicates that no limit should be used. + +### Changed + +- The Pajek format reader and writer now map vertex labels to the `name` vertex attribute in igraph. The `id` attribute is no longer used. +- `igraph_minimum_size_separators()` no longer returns any separating vertex sets for complete graphs. Prior to igraph 1.0, it would return all `n - 1` size vertex subsets where `n` is the vertex count. +- `igraph_community_edge_betweenness()` now treats edges with large weights as strong connections. +- `igraph_biadjacency()` now truncates non-integer matrix entries to their integer part instead of rounding them up. This brings consistency with related functions such as `igraph_adjacency()`. +- The order of edges in the graph returned by `igraph_(weighted_)adjacency()` and `igraph_biadjacency()` has changed. Note that these functions do not guarantee any specific edge order. +- `igraph_eigenvector_centrality()` now warns about eigenvector centralities equal to zero, as these indicate a disconnected graph, for which eigenvector centrality is not meaningful. +- `igraph_hub_and_authority_scores()` now warns when a large fraction of centrality scores are zero, as this indicates a non-unique solution, and thus the returned result may not be meaningful. +- `igraph_hub_and_authority_scores()` now warns when providing an undirected graph as input, and falls back to the equivalent eigenvector centrality computation. +- `igraph_get_stochastic_sparse()` no longer throws an error when some row or column sums are zero. This brings its behaviour in line with `igraph_get_stochastic()`. +- `igraph_vector_append()`, `igraph_strvector_append()` and `igraph_vector_ptr_append()` now use a different allocation strategy: if the `to` vector has insufficient capacity, they double its capacity. Previously they reserved precisely as much capacity as needed for appending the `from` vector. +- The implementation of the Infomap algorithm behind `igraph_community_infomap()` has been updated with a more recent version (2.8.0). Isolated vertices are now supported. +- `igraph_vector_difference_sorted()` now handles multisets properly (and documents how the multiplicities are handled). + +### Finalized experimental functions + +- The following functions are not experimental any more: `igraph_count_loops()`, `igraph_count_reachable()`, `igraph_degree_correlation_vector`, `igraph_distances_cutoff()`, `igraph_distances_floyd_warshall()`, `igraph_distances_dijkstra_cutoff()`, `igraph_ecc()`, `igraph_enter_safelocale()`, `igraph_exit_safelocale()`, `igraph_feedback_vertex_set()`, `igraph_find_cycle()`, `igraph_get_shortest_path_astar()`, `igraph_graph_power()`, `igraph_hexagonal_lattice()`, `igraph_hypercube()`, `igraph_is_bipartite_coloring()`, `igraph_is_clique()`, `igraph_is_complete()`, `igraph_is_edge_coloring()`, `igraph_is_vertex_coloring()`, `igraph_is_independent_vertex_set()`, `igraph_join()`,`igraph_joint_degree_distribution()`, `igraph_joint_degree_matrix()`, `igraph_joint_type_distribution()`, `igraph_layout_align()`, `igraph_layout_merge_dla()`, `igraph_mean_degree()`, `igraph_radius()`, `igraph_realize_bipartite_degree_sequence()`, `igraph_reachability()`, `igraph_transitive_closure()`, `igraph_tree_from_parent_vector()`, `igraph_triangular_lattice()`, `igraph_vector_intersection_size_sorted()`, `igraph_voronoi()`. + +### Fixed + +- `igraph_community_spinglass_single()` now uses `igraph_real_t` for its `inner_links` and `outer_links` output parameters, as these return not simply edge counts, but the sum of the weights of some edges. Thus these results are no longer incorrectly rounded. +- `igraph_correlated_game()` and `igraph_correlated_pair_game()` validate their `permutation` argument. + +### Removed + +- Removed `igraph_Calloc()`, `igraph_Realloc()` and `igraph_Free()`. Use `IGRAPH_CALLOC()`, `IGRAPH_REALLOC()` and `IGRAPH_FREE()` instead. +- The deprecated `igraph_adjacent_triangles()` was removed. Use `igraph_count_adjacent_triangles()` instead. +- The deprecated `igraph_are_connected()` was removed. Use `igraph_are_adjacent()` instead. +- The deprecated `igraph_automorphisms()` was removed. Use `igraph_count_automorphisms()` or `igraph_count_automorphisms_bliss()` instead. +- The deprecated `igraph_convex_hull()` was removed. Use `igraph_convex_hull_2d()` instead. +- The deprecated `igraph_decompose_destroy()` was removed. +- The deprecated `igraph_hub_score()` and `igraph_authority_score()` were removed. +- The deprecated `igraph_vs_seq()`, `igraph_vss_seq()`, `igraph_es_seq()`, `igraph_ess_range()`, and `igraph_vector_init_seq()` were removed. Use the `range` alternatives instead of the old `seq` ones. +- The deprecated `igraph_erdos_renyi_game()` and `igraph_bipartite_game()` were removed. Use the corresponding functions with `_gnm()` and `_gnp()` in the name instead. +- The deprecated `igraph_tree()` was removed. Use `igraph_kary_tree()` instead. +- The deprecated `igraph_lattice()` was removed. Use `igraph_square_lattice()` instead. +- The deprecated `igraph_minimum_spanning_tree_prim()` was removed. Use `igraph_minimum_spanning_tree()` in conjunction with `igraph_subgraph_from_edges()` instead. +- The deprecated `igraph_minimum_spanning_tree_unweighted()` was removed. Use `igraph_minimum_spanning_tree()` in conjunction with `igraph_subgraph_from_edges()` instead. +- The deprecated `igraph_get_sparsemat()` was removed. Use `igraph_get_adjacency_sparse()` instead. +- The deprecated `igraph_get_stochastic_sparsemat()` was removed. Use `igraph_get_stochastic_sparse()` instead. +- The deprecated `igraph_laplacian()` was removed. Use `igraph_get_laplacian()` or `igraph_get_laplacian_sparse()` instead. +- The deprecated `igraph_subgraph_edges()` was removed. Use `igraph_subgraph_from_edges()` instead. +- The deprecated `igraph_read_graph_dimacs()` and `igraph_write_graph_dimacs()` were removed. These names may be re-used in the future. Use `igraph_read_graph_dimacs_flow()` and `igraph_write_graph_dimacs_flow()` instead. +- The deprecated `igraph_isomorphic_function_vf2()` was removed. Use `igraph_get_isomorphisms_vf2_callback()` instead. +- The deprecated `igraph_subisomorphic_function_vf2()` was removed. Use `igraph_get_subisomorphisms_vf2_callback()` instead. +- The deprecated `igraph_isomorphic_34()` was removed. Its functionality is accessible through `igraph_isomorphic()`. +- The deprecated `igraph_transitive_closure_dag()` was removed. Use `igraph_transitive_closure()` instead, which works for all graphs, not just DAGs. +- The deprecated `igraph_sparsemat_copy()` was removed. Use `igraph_sparsemat_init_copy()` instead. +- The deprecated `igraph_sparsemat_eye()` was removed. Use `igraph_sparsemat_init_eye()` instead. +- The deprecated `igraph_sparsemat_diag()` was removed. Use `igraph_sparsemat_init_diag()` instead. +- The deprecated `igraph_sparsemat()` and `igraph_weighted_sparsemat()` functions were removed; use `igraph_get_adjacency_sparse()` instead. +- The deprecated `igraph_random_edge_walk()` was removed. Its functionality is incorporated in `igraph_random_walk()`. +- The deprecated `igraph_vector_qsort_ind()` was removed. Use `igraph_vector_sort_ind()` instead. +- The deprecated `igraph_vector_binsearch2()` was removed. Use `igraph_vector_contains_sorted()` instead. +- The deprecated `igraph_vector_copy()` and `igraph_matrix_copy()` were removed. Use `igraph_vector_init_copy()` and `igraph_matrix_init_copy()` instead. +- The deprecated `igraph_vector_e()`, `igraph_vector_e_ptr()`, `igraph_matrix_e()` and `igraph_matrix_e_ptr()` were removed. Use the alternatives ending in `_get()` and `_get_ptr()` instead. +- The deprecated `igraph_vector_move_interval2()` was removed. +- The deprecated `igraph_rng_get_dirichlet()` function was removed. +- The deprecated `igraph_zeroin()` was removed. +- The deprecated `igraph_deterministic_optimal_imitation()`, `igraph_moran_process()`, `igraph_roulette_wheel_imitation()` and `igraph_stochastic_imitation()` functions were removed. +- `igraph_sample_dirichlet()`, `igraph_sample_sphere_surface()` and `igraph_sample_sphere_volume()` were removed in favour of `igraph_rng_sample_dirichlet()`, `igraph_rng_sample_sphere_surface()` and `igraph_rng_sample_sphere_volume()`, which allow the user to specify the random number generator to use. +- The unused enum type `igraph_fileformat_type_t` was removed. +- The macros `IGRAPH_POSINFINITY` and `IGRAPH_NEGINFINITY` were removed. Use `IGRAPH_INFINITY` and `-IGRAPH_INFINITY` instead. +- Removed `igraph_sparsemat_view()` as its design was broken and required the user to reach into the internals of `igraph_sparmsemat_t` to destroy it properly. + +### Deprecated + +- `igraph_delete_vertices_idx()` is now deprecated in favour of `igraph_delete_vertices_map()`, which is functionally equivalent but has a name that is consistent with `igraph_induced_subgraph_map()`. + +### Other + +- The documentation was reorganized. +- Various documentation improvements. +- Improved performance when creating graphs from dense adjacency matrices (`igraph_adjacency()` and `igraph_weighted_adjacency()`). + ## [0.10.17] - 2025-09-19 ### Added @@ -595,8 +865,6 @@ Some of the highlights are: - `igraph_community_walktrap()` now uses `igraph_integer_t` for its `steps` argument. - `igraph_coreness()` now uses an `igraph_vector_int_t` to return the coreness values. -- `igraph_convex_hull()` now uses an `igraph_vector_int_t` to return the indices of the input vertices that were chosen to be in the convex hull. -- `igraph_correlated_game()` and `igraph_correlated_pair_game()` now take an `igraph_vector_int_t` as the permutation vector, not an `igraph_vector_t`. - `igraph_create()` now uses an `igraph_vector_int_t` for its `edges` parameter. - `igraph_create_bipartite()` now uses an `igraph_vector_int_t` for its `edges` parameter. - `igraph_compose()` now returns the edge maps in an `igraph_vector_int_t` instead of an `igraph_vector_t`. @@ -874,8 +1142,6 @@ Some of the highlights are: - `igraph_matrix_copy()` is now deprecated; use `igraph_matrix_init_copy()` instead. The new name emphasizes that the function _initializes_ the first argument instead of expecting an already-initialized target matrix. The old name will be removed in 0.11. - `igraph_matrix_e()` and `igraph_matrix_e_ptr()` have been renamed to `igraph_matrix_get()` and `igraph_matrix_get_ptr()`. The old names are deprecated and will be removed in 0.11. - `igraph_random_edge_walk()` has been deprecated by `igraph_random_walk()` to support edges and/or vertices for the random walk in a single function. It will be removed in 0.11. -- `igraph_read_graph_dimacs()` has been renamed to `igraph_read_graph_dimacs_flow()`; the old name is deprecated and might be re-used as a generic DIMACS reader in the future. Also, the function now uses `igraph_integer_t` as the source and target vertex IDs instead of a `long int`. -- `igraph_shortest_paths()` and related functions were renamed to `igraph_distances()`; the old name was unfortunate because these functions calculated _path lengths_ only and not the paths themselves. The old names are deprecated and will be removed in 0.11. - `igraph_sparsemat_copy()`, `igraph_sparsemat_diag()` and `igraph_sparsemat_eye()` have been renamed to `igraph_sparsemat_init_copy()`, `igraph_sparsemat_init_diag()` and `igraph_sparsemat_init_eye()` to indicate that they _initialize_ a new sparse matrix. The old names are deprecated and will be removed in 0.11. - `igraph_strvector_add()` has been renamed to `igraph_strvector_push_back()` for sake of consistency with other vector-like data structures; the old name is deprecated and will be removed in 0.11. - `igraph_strvector_copy()` has been renamed to `igraph_strvector_init_copy()` for sake of consistency with other vector-like data structures; the old name is deprecated and will be removed in 0.11. @@ -1528,6 +1794,8 @@ Some of the highlights are: - Provide proper support for Windows, using `__declspec(dllexport)` and `__declspec(dllimport)` for `DLL`s and static usage by using `#define IGRAPH_STATIC 1`. - Provided integer versions of `dqueue` and `stack` data types. +[main]: https://github.com/igraph/igraph/compare/1.0.0..main +[1.0.0]: https://github.com/igraph/igraph/compare/0.10.17..1.0.0 [0.10.17]: https://github.com/igraph/igraph/compare/0.10.16..0.10.17 [0.10.16]: https://github.com/igraph/igraph/compare/0.10.15..0.10.16 [0.10.15]: https://github.com/igraph/igraph/compare/0.10.13..0.10.15 diff --git a/src/vendor/cigraph/CMakeLists.txt b/src/vendor/cigraph/CMakeLists.txt index 46d0339c1ba..13a2d4704ff 100644 --- a/src/vendor/cigraph/CMakeLists.txt +++ b/src/vendor/cigraph/CMakeLists.txt @@ -59,7 +59,7 @@ set(CMAKE_CXX_VISIBILITY_PRESET hidden) # Set C and C++ standard version set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED True) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) # Expose the BUILD_SHARED_LIBS option in the ccmake UI @@ -143,7 +143,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND IGRAPH_ENABLE_CODE_COVERAGE) # The following works with 'Ninja'. For 'Unix Makefiles', this requires ${PROJECT_BINARY_DIR}/src. BASE_DIRECTORY "${PROJECT_BINARY_DIR}" # /Applications and /Library/Developer are for macOS -- they exclude files from the macOS SDK. - EXCLUDE "/Applications/Xcode*" "/Library/Developer/*" "examples/*" "interfaces/*" "tests/*" "vendor/pcg/*" + EXCLUDE "/Applications/Xcode*" "/Library/Developer/*" "examples/*" "interfaces/*" "tests/*" "vendor/infomap/*" "vendor/pcg/*" # These errors, present with lcov 2.x, are likely due to incompatibility with llvm-cov on macOS. LCOV_ARGS --ignore-errors inconsistent,format,unused GENHTML_ARGS --ignore-errors inconsistent,corrupt,category,unmapped diff --git a/src/vendor/cigraph/CONTRIBUTING.md b/src/vendor/cigraph/CONTRIBUTING.md index 5e123223e8c..89336213f1d 100644 --- a/src/vendor/cigraph/CONTRIBUTING.md +++ b/src/vendor/cigraph/CONTRIBUTING.md @@ -32,6 +32,7 @@ experienced with C, you can contribute in a number of ways: adhere to our [Code of Conduct](https://igraph.org/code-of-conduct.html). + ## Bug reports A bug is a _demonstrable problem_ that is caused by the code in the repository. @@ -53,7 +54,7 @@ Guidelines for bug reports: reported. 3. **Check if the issue has been fixed** — try to reproduce it using the - latest `master` or development branch in the repository. + latest `main` or development branch in the repository. 4. **Isolate the problem** — create a [short, self-contained, correct example](http://sscce.org/). @@ -127,7 +128,7 @@ Follow the following steps if you would like to make a new pull request: ``` 2. Please checkout the section on [branching](#branching) to see whether you - need to branch off from the `master` branch or the `develop` branch. + need to branch off from the `main` branch or the `develop` branch. If you cloned a while ago, get the latest changes from upstream: @@ -180,9 +181,10 @@ owner to license your work under the same license as that used by the project, see also [Legal Stuff](#legal). + ### Branching -In short, always ask whether your contribution should target the `master` or +In short, always ask whether your contribution should target the `main` or `develop` branch _before_ starting any work. Read on for more details on how this is decided. @@ -191,30 +193,30 @@ currently still in the development release (0.x), which in principle is a mark that the public API is not yet stable. Regardless, we try to maintain semantic versioning also for the development releases. We do so as follows. Any released minor version (0.x.z) will be API backwards-compatible with any previous release -of the *same* minor version (0.x.y, with y < z). This means that *if* there is +of the _same_ minor version (0.x.y, with y < z). This means that _if_ there is an API incompatible change, we will increase the minor version. For example, release 0.8.1 is API backwards-compatible with release 0.8.0, while release 0.9.0 might be API incompatible with version 0.8.1. Note that this only concerns -the *public* API, internal functions may change also within a minor version. +the _public_ API, internal functions may change also within a minor version. There will always be two versions of `igraph`: the most recent released version, and the next upcoming minor release, which is by definition not yet released. -The most recent release version is in the `master` branch, while the next +The most recent release version is in the `main` branch, while the next upcoming minor release is in the `develop` branch. If you make a change that is API incompatible with the most recent release, it **must** be merged to the `develop` branch. If the change is API backwards-compatible, it **can** be -merged to the `master` branch. It is possible that you build on recent +merged to the `main` branch. It is possible that you build on recent improvements in the `develop` branch, in which case your change should of course target the `develop` branch. If you only add new functionality, but do not change anything of the existing API, this should be backwards-compatible, and -can be merged in the `master` branch. +can be merged in the `main` branch. When you make a new pull request, please specify the correct target branch. The maintainers of `igraph` may decide to retarget your pull request to the correct branch. Retargeting you pull request may result in merge conflicts, so it is always good to decide **before** starting to work on something whether you -should start from the `master` branch or from the `develop` branch. In most -cases, changes in the `master` branch will also be merged to the `develop` +should start from the `main` branch or from the `develop` branch. In most +cases, changes in the `main` branch will also be merged to the `develop` branch by the maintainers. diff --git a/src/vendor/cigraph/CONTRIBUTORS.md b/src/vendor/cigraph/CONTRIBUTORS.md index fe9ef760b40..faec64de7a9 100644 --- a/src/vendor/cigraph/CONTRIBUTORS.md +++ b/src/vendor/cigraph/CONTRIBUTORS.md @@ -102,6 +102,13 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Sarah Rashidi
Sarah Rashidi

💻 Zara Zong
Zara Zong

💻 Arnór Friðriksson
Arnór Friðriksson

💻 + Varun Rajesh
Varun Rajesh

💻 + Steve Sajeev
Steve Sajeev

💻 + Rohith Sudheer
Rohith Sudheer

💻 + + + Grisha
Grisha

💻 + Michael Antonov
Michael Antonov

💻 diff --git a/src/vendor/cigraph/CONTRIBUTORS.txt b/src/vendor/cigraph/CONTRIBUTORS.txt index 70fd5644106..016f6a99c83 100644 --- a/src/vendor/cigraph/CONTRIBUTORS.txt +++ b/src/vendor/cigraph/CONTRIBUTORS.txt @@ -74,6 +74,11 @@ Lucas Lopes Felipe (@lucaslopes) Sarah Rashidi (@its-serah) Zara Zong (@minifinity) Arnór Friðriksson (@Zepeacedust) +Varun Rajesh (@VRajesh7649) +Steve Sajeev (@stevesajeev1) +Rohith Sudheer (@RohithS98) +Grisha (@GrishaVar) +Michael Antonov (@Antonov548) This project follows the [all-contributors][1] specification. Contributions of any kind welcome! diff --git a/src/vendor/cigraph/README.md b/src/vendor/cigraph/README.md index 185df33b5b0..8eadfd71388 100644 --- a/src/vendor/cigraph/README.md +++ b/src/vendor/cigraph/README.md @@ -1,6 +1,6 @@ -[![Build Status on Azure Pipelines](https://dev.azure.com/igraph-team/igraph/_apis/build/status/igraph.igraph?branchName=master)](https://dev.azure.com/igraph-team/igraph/_build/latest?definitionId=1&branchName=master) -![Build Status on Github Actions](https://github.com/igraph/igraph/workflows/MINGW/badge.svg?branch=master) -[![codecov](https://codecov.io/gh/igraph/igraph/branch/master/graph/badge.svg?token=xGFabHJE2I)](https://codecov.io/gh/igraph/igraph) +[![Build Status on Azure Pipelines](https://dev.azure.com/igraph-team/igraph/_apis/build/status/igraph.igraph?branchName=main)](https://dev.azure.com/igraph-team/igraph/_build/latest?definitionId=1&branchName=main) +![Build Status on Github Actions](https://github.com/igraph/igraph/workflows/MINGW/badge.svg?branch=main) +[![codecov](https://codecov.io/gh/igraph/igraph/branch/main/graph/badge.svg?token=xGFabHJE2I)](https://codecov.io/gh/igraph/igraph) [![DOI](https://zenodo.org/badge/8546198.svg)](https://zenodo.org/badge/latestdoi/8546198) The igraph library diff --git a/src/vendor/cigraph/VERSIONING.md b/src/vendor/cigraph/VERSIONING.md new file mode 100644 index 00000000000..b29b2333b1e --- /dev/null +++ b/src/vendor/cigraph/VERSIONING.md @@ -0,0 +1,58 @@ +# Versioning and stability + +This document is provided for informational purposes only, to help igraph users understand how igraph's programming interface is evolving, and what stability guaratees you can rely on. It concerns the igraph C library only. igraph's high level interfaces (R, Python, Mathematica) have their own separate versioning schemes and compatibility policies. + +## Versioning + +Starting with version 1.0, igraph follows the spirit of semantic versioning, with some differences, as described below. The version number consists of three parts in the `MAJOR.MINOR.PATCH` format. + +- `MAJOR` is incremented after making _incompatible changes_ to the stable programming interface. Major releases are intended to be infrequent, and are accompanied by release notes where we make the effort to provide detailed guidance on adapting to incompatible changes. +- `MINOR` is incremented after making _additions_ to the stable programming interface. Minor releases are issued regularly. +- `PATCH` is incremented when making changes that do not affect compatibility (usually bug fixes, documentation improvements, or build systems changes). + +The three version parts are available at compile time as the macros `IGRAPH_VERSION_MAJOR`, `IGRAPH_VERSION_MINOR` and `IGRAPH_VERSION_PATCH`, or at runtime through the `igraph_version()` function. + +The majority of public, documented functions are considered to be part of the _stable programming interface_, but there are some notable exceptions: + +- **Experimental functions** may change at any time without notice. These are clearly marked in their documentation ([example](https://igraph.org/c/html/0.10.13/igraph-Generators.html#igraph_chung_lu_game)). They are also marked in igraph's header files with the `IGRAPH_EXPERIMENTAL` macro ([example](https://github.com/igraph/igraph/blob/3629c46b2784cb10fc27fc6e9fab4404a13d031c/include/igraph_cycles.h#L49-L53)). Most newly added functions start out as _experimental_, and stay in this state until we are confident in their design, typically for one or two minor releases. User feedback about experimental functions is particularly welcome. We make the effort to avoid changes to experimental functions in patch releases, but do not guarantee this. +- **Internal and undocumented functions** are not part of the stable programming interface, not even if they are present in public headers. They may change at any time. The names of internal functions usually start with the prefix `igraph_i_` (capitalized for macros), while public functions start with `igraph_`. + +## Symbol lifecycle + +Most new symbols start out as _experimental_ in minor releases. Eventually, their API is declared stable, and the experimental marker is removed from their declaration and documentation in an upcoming minor release. + +Symbols go through a deprecation phase before they are removed. Deprecated symbols are marked in their documentation ([example](https://igraph.org/c/html/0.10.13/igraph-Structural.html#igraph_clusters)), and functions are prefixed with `IGRAPH_DEPRECATED` in the public headers ([example](https://github.com/igraph/igraph/blob/997f59ad742892fff199824a248fab382b40f526/include/igraph_components.h#L45-L47)). With GCC-compatible compilers, use the `-Wdeprecated` flag to get a warning for the use of deprecated functions, but keep in mind that deprecation warnings are not supported for all symbol types (e.g. macros) with all compilers. The ultimate reference for deprecations is the [changelog][1]. + +## Stability of behaviour + +Whether changes in function behaviour are considered breaking is somewhat subjective, and is decided on a case-by-case basis. Expect some changes within minor releases. For example, a function that ignored edge multiplicities may gain support for multigraphs in a new minor release. Do not rely on details of behaviour that are not explicitly documented. + +A notable case is stochastic functions: we do not guarantee that the same output is returned across different releases (even patch releases) for the same random seed. We only guarantee the same statistical properties. + +## Advice to users and package maintainers + +**Users:** + +For as long as you don't use _experimental_ functions, you can be confident that your code will continue to work with future releases having the same major version. If you do use _experimental_ functions, it is your responsibility to check the [release notes][1] of each igraph release and adapt accordingly. The use of _internal_ functions is completely unsupported: if you feel you need them, please talk to us. + +If you do use _experimental_ functions, make this clear in your README file for the benefit of package maintainers. + +While igraph comes with multiple header files, only `#include ` is supported. The rest of the headers exist for internal organizational purposes only, and may change without notice. + +**Package maintainers:** + +Software that does not use experimental functions from igraph can safely link to future igraph versions with the same major version. Ask the developer of any software you are packaging if they are using experimental igraph functions. + +The high-level interfaces of igraph do use both experimental and internal functions. Each high-level interface release is only guaranteed to be compatible with one specific release of C/igraph. As of this writing, this is a concern only for the Python interface, as the other interfaces (R and Mathematica) cannot link dynamically to C/igraph. + +We provide the `IGRAPH_WARN_EXPERIMENTAL` compile-time macro to help maintainers in determining whether a piece of software uses experimental igraph functions or not. Compilers that support `__attribute__((__warning(...)))` clauses will issue a warning when `IGRAPH_WARN_EXPERIMENTAL` is defined to a non-zero value at compile-time and an experimental function is used somewhere in the code. + +## Notes + +For the purposes of this document, "API compatibility" means that the same sources can be compiled using headers from different igraph versions. "ABI compatibility" means that a program that only uses stable API can be linked to a different version of the igraph shared library than what it was compiled with. + +We strive to maintain both API and ABI compatibility. + +However, it must be pointed out that we do not support manipulating the same in-memory igraph data structures with different igraph versions (for example, if two libraries that exchange data are each statically linked to different igraph versions). + + [1]: https://github.com/igraph/igraph/blob/main/CHANGELOG.md diff --git a/src/vendor/cigraph/azure-pipelines.yml b/src/vendor/cigraph/azure-pipelines.yml index 72c60b489d0..86ffc5cad9b 100644 --- a/src/vendor/cigraph/azure-pipelines.yml +++ b/src/vendor/cigraph/azure-pipelines.yml @@ -1,5 +1,5 @@ pool: - vmImage: 'ubuntu-latest' + vmImage: "ubuntu-latest" variables: CMAKE_COLOR_DIAGNOSTICS: ON @@ -9,7 +9,7 @@ variables: ASAN_OPTIONS: detect_stack_use_after_return=1:color=always UBSAN_OPTIONS: print_stacktrace=1:color=always OMP_NUM_THREADS: 1 - CTEST_PARALLEL_LEVEL: 0 # Since CMake 3.29, a setting of 0 will try to use all available resources + CTEST_PARALLEL_LEVEL: 4 jobs: # In this test we install and generate locales so that igraph_enter/exit_safelocale() can be tested @@ -52,7 +52,7 @@ jobs: int_arpack: false int_gmp: false int_glpk: false - extra_cmake_args: '-DBLA_VENDOR=OpenBLAS' + extra_cmake_args: "-DBLA_VENDOR=OpenBLAS" - job: linux_shared_vendored steps: @@ -75,7 +75,7 @@ jobs: int_arpack: false int_gmp: false int_glpk: false - extra_cmake_args: '-DBLA_VENDOR=OpenBLAS' + extra_cmake_args: "-DBLA_VENDOR=OpenBLAS" build_shared: true - job: linux_clang_22 @@ -99,7 +99,8 @@ jobs: - template: .azure/build.yml parameters: - extra_cmake_args: '-DCMAKE_C_FLAGS="-mfpmath=387" -DCMAKE_CXX_FLAGS="-mfpmath=387"' + build_type: Debug + extra_cmake_args: '-DUSE_SANITIZER=Address\;Undefined -DCMAKE_C_FLAGS="-mfpmath=387" -DCMAKE_CXX_FLAGS="-mfpmath=387"' - job: linux_alpine steps: @@ -129,20 +130,20 @@ jobs: - job: windows_static pool: - vmImage: windows-latest + vmImage: windows-latest steps: - template: .azure/build-win.yml - job: windows_shared pool: - vmImage: windows-latest + vmImage: windows-latest steps: - template: .azure/build-win.yml parameters: build_shared: true - vsver: '14.4' # latest VS2022 + vsver: "14.4" # latest VS2022 vcpkg_target_triplet: x64-windows - job: documentation @@ -155,9 +156,9 @@ jobs: - task: CMake@1 displayName: CMake inputs: - cmakeArgs: '..' + cmakeArgs: ".." - task: CMake@1 displayName: Doc build inputs: - cmakeArgs: '--build . --target doc' + cmakeArgs: "--build . --target doc" diff --git a/src/vendor/cigraph/codecov.yml b/src/vendor/cigraph/codecov.yml index 2b1d197b4fa..6369e9ab134 100644 --- a/src/vendor/cigraph/codecov.yml +++ b/src/vendor/cigraph/codecov.yml @@ -28,4 +28,5 @@ comment: ignore: - "tests" - "examples" + - "vendor/infomap" - "vendor/pcg" diff --git a/src/vendor/cigraph/etc/cmake/compilers.cmake b/src/vendor/cigraph/etc/cmake/compilers.cmake index 503f681cf71..c25a1e79e29 100644 --- a/src/vendor/cigraph/etc/cmake/compilers.cmake +++ b/src/vendor/cigraph/etc/cmake/compilers.cmake @@ -8,6 +8,17 @@ include(CheckCCompilerFlag) # - https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html add_compile_definitions(_POSIX_C_SOURCE=200809L) +# On some Apple systems, with some compilers, defining _POSIX_C_SOURCE causes compilation +# failures when including C++ headers. Defining _DARWIN_C_SOURCE explicitly usually fixes +# this. Refs: https://trac.macports.org/ticket/60655 and https://trac.macports.org/ticket/73145 +# This is claimed to be due to _POSIX_C_SOURCE disabling APIs that C++ headers rely on +# on some systems. _DARWIN_C_SOURCE re-enables these APIs, but _GNU_SOURCE alone does not +# necessarily do so. Using different global defined for C and C++ is problematic with CMake, +# so instead of restricting _POSIX_C_SOURCE to C, we define _DARWIN_C_SOURCE. +if(APPLE) + add_compile_definitions(_DARWIN_C_SOURCE) +endif() + if(MSVC) add_compile_options(/FS) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) # necessary to compile for UWP @@ -63,7 +74,7 @@ macro(use_all_warnings TARGET_NAME) $<$:-Werror> -Wall -Wextra -pedantic -Wstrict-prototypes - -Wno-unused-function -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-sign-compare -Wno-constant-logical-operand -Wno-uninitialized-const-pointer + -Wno-unused-function -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-sign-compare -Wno-constant-logical-operand > $<$:-Wno-unknown-warning-option> # Intel compiler: diff --git a/src/vendor/cigraph/etc/cmake/cpack_install_script.cmake b/src/vendor/cigraph/etc/cmake/cpack_install_script.cmake index ba50ad5f508..48af65c65b6 100644 --- a/src/vendor/cigraph/etc/cmake/cpack_install_script.cmake +++ b/src/vendor/cigraph/etc/cmake/cpack_install_script.cmake @@ -79,4 +79,9 @@ if(CPACK_SOURCE_INSTALLED_DIRECTORIES) "${CPACK_PACKAGE_DIRECTORY}/doc/html" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/doc" ) + file( + INSTALL + "${CPACK_PACKAGE_DIRECTORY}/doc/igraph-docs.info" + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/doc" + ) endif() diff --git a/src/vendor/cigraph/etc/cmake/dependencies.cmake b/src/vendor/cigraph/etc/cmake/dependencies.cmake index 3e7df4ff069..f550308c49b 100644 --- a/src/vendor/cigraph/etc/cmake/dependencies.cmake +++ b/src/vendor/cigraph/etc/cmake/dependencies.cmake @@ -9,11 +9,11 @@ include(FindThreads) macro(find_dependencies) # Declare the list of dependencies that _may_ be vendored - set(VENDORABLE_DEPENDENCIES BLAS GLPK LAPACK ARPACK GMP PLFIT) + set(VENDORABLE_DEPENDENCIES BLAS GLPK LAPACK ARPACK GMP PLFIT INFOMAP) # Declare optional dependencies associated with IGRAPH_..._SUPPORT flags - # Note that GLPK is both vendorable and optional - set(OPTIONAL_DEPENDENCIES GLPK OpenMP) + # Note that GLPK and INFOMAP are both vendorable and optional + set(OPTIONAL_DEPENDENCIES GLPK OpenMP INFOMAP) # Declare configuration options for dependencies tristate(IGRAPH_USE_INTERNAL_GMP "Compile igraph with internal Mini-GMP" AUTO) @@ -23,6 +23,10 @@ macro(find_dependencies) tristate(IGRAPH_USE_INTERNAL_LAPACK "Compile igraph with internal LAPACK" AUTO) tristate(IGRAPH_USE_INTERNAL_PLFIT "Compile igraph with internal plfit" AUTO) + # Infomap currently does not support being built as an external library, so will + # only be supported through the internal vendored build + set(IGRAPH_USE_INTERNAL_INFOMAP ON) + # Declare dependencies set(REQUIRED_DEPENDENCIES "") set(OPTIONAL_DEPENDENCIES FLEX BISON OpenMP) @@ -46,7 +50,6 @@ macro(find_dependencies) set(IGRAPH_USE_INTERNAL_${LIBNAME_UPPER} ON) endif() endif() - if(IGRAPH_USE_INTERNAL_${LIBNAME_UPPER}) list(APPEND VENDORED_DEPENDENCIES ${DEPENDENCY}) else() @@ -87,6 +90,10 @@ macro(find_dependencies) endif() endif() + if(NOT IGRAPH_INFOMAP_SUPPORT) + list(REMOVE_ITEM VENDORED_DEPENDENCIES INFOMAP) + endif() + if(IGRAPH_GRAPHML_SUPPORT) list(APPEND REQUIRED_DEPENDENCIES LibXml2) endif() @@ -132,6 +139,7 @@ macro(find_dependencies) # Export some aliases that will be used in config.h set(HAVE_GLPK ${GLPK_FOUND}) + set(HAVE_INFOMAP ${INFOMAP_FOUND}) set(HAVE_GMP ${GMP_FOUND}) set(HAVE_LIBXML ${LIBXML2_FOUND}) diff --git a/src/vendor/cigraph/etc/cmake/features.cmake b/src/vendor/cigraph/etc/cmake/features.cmake index 66631025bac..0863f4fac42 100644 --- a/src/vendor/cigraph/etc/cmake/features.cmake +++ b/src/vendor/cigraph/etc/cmake/features.cmake @@ -4,6 +4,7 @@ include(tls) include(lto) option(IGRAPH_GLPK_SUPPORT "Compile igraph with GLPK support" ON) +option(IGRAPH_INFOMAP_SUPPORT "Compile igraph with Infomap support" ON) tristate(IGRAPH_GRAPHML_SUPPORT "Compile igraph with GraphML support" AUTO) tristate(IGRAPH_OPENMP_SUPPORT "Use OpenMP for parallelization" AUTO) diff --git a/src/vendor/cigraph/etc/cmake/packaging.cmake b/src/vendor/cigraph/etc/cmake/packaging.cmake index 4887b6c4b48..ec52c93d289 100644 --- a/src/vendor/cigraph/etc/cmake/packaging.cmake +++ b/src/vendor/cigraph/etc/cmake/packaging.cmake @@ -4,7 +4,7 @@ set(CPACK_PACKAGE_VENDOR "The igraph development team") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING") -if(TARGET html) +if(TARGET html AND TARGET info) # Alias "dist" to "package_source" add_custom_target(dist COMMAND "${CMAKE_COMMAND}" @@ -14,13 +14,13 @@ if(TARGET html) USES_TERMINAL ) - # We want to include the HTML docs in the source package so add a dependency - add_dependencies(dist html) + # Add dependencies to "dist" + add_dependencies(dist html info) else() add_custom_target(dist COMMAND "${CMAKE_COMMAND}" -E false COMMENT - "Cannot build source tarball since the HTML documentation was not built." + "Cannot build source tarball since the HTML or the Texinfo documentation was not built." VERBATIM USES_TERMINAL ) @@ -31,7 +31,7 @@ endif() ############################################################################# # Set source package name and format -set(CPACK_SOURCE_PACKAGE_FILE_NAME "igraph-${CMAKE_PROJECT_VERSION}") +set(CPACK_SOURCE_PACKAGE_FILE_NAME "igraph-${PACKAGE_VERSION}") set(CPACK_SOURCE_GENERATOR "TGZ") # Declare what to include in the source tarball. Unfortunately we can only diff --git a/src/vendor/cigraph/etc/cmake/summary.cmake b/src/vendor/cigraph/etc/cmake/summary.cmake index 4c189f1395b..348b7d31e72 100644 --- a/src/vendor/cigraph/etc/cmake/summary.cmake +++ b/src/vendor/cigraph/etc/cmake/summary.cmake @@ -35,13 +35,13 @@ else() message(STATUS "Library type: static") endif() if(${IGRAPH_INTEGER_SIZE} STREQUAL "AUTO") - print_str("igraph_integer_t size" "auto") + print_str("igraph_int_t size" "auto") elseif(${IGRAPH_INTEGER_SIZE} STREQUAL 64) - print_str("igraph_integer_t size" "64 bits") + print_str("igraph_int_t size" "64 bits") elseif(${IGRAPH_INTEGER_SIZE} STREQUAL 32) - print_str("igraph_integer_t size" "32 bits") + print_str("igraph_int_t size" "32 bits") else() - print_str("igraph_integer_t size" "INVALID") + print_str("igraph_int_t size" "INVALID") endif() if(USE_CCACHE) if(CCACHE_PROGRAM) @@ -54,6 +54,7 @@ endif() message(STATUS " ") message(STATUS "----------[ Features ]----------") print_bool("GLPK for optimization" IGRAPH_GLPK_SUPPORT) +print_bool("Infomap community detection" IGRAPH_INFOMAP_SUPPORT) print_bool("Reading GraphML files" IGRAPH_GRAPHML_SUPPORT) print_bool("Thread-local storage" IGRAPH_ENABLE_TLS) print_bool("Link-time optimization" IGRAPH_ENABLE_LTO) @@ -64,7 +65,9 @@ foreach(DEPENDENCY ${ALL_DEPENDENCIES}) list(FIND VENDORED_DEPENDENCIES "${DEPENDENCY}" INDEX) if(INDEX EQUAL -1) print_bool("${DEPENDENCY}" ${DEPENDENCY}_FOUND) - else() + # This is a hack to skip printing Infomap, until + # support for linking to an external version is added + elseif(NOT "${DEPENDENCY}" STREQUAL "INFOMAP") print_str("${DEPENDENCY}" "vendored") endif() endforeach() diff --git a/src/vendor/cigraph/include/igraph.h b/src/vendor/cigraph/include/igraph.h index 30c88267f3e..72b827cc133 100644 --- a/src/vendor/cigraph/include/igraph.h +++ b/src/vendor/cigraph/include/igraph.h @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2003-2024 The igraph development team + igraph library. + Copyright (C) 2003-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA + along with this program. If not, see . */ #ifndef IGRAPH_H @@ -26,13 +24,13 @@ #include "igraph_error.h" #include "igraph_random.h" #include "igraph_progress.h" +#include "igraph_setup.h" #include "igraph_statusbar.h" #include "igraph_types.h" #include "igraph_complex.h" #include "igraph_vector.h" #include "igraph_matrix.h" -#include "igraph_array.h" #include "igraph_bitset.h" #include "igraph_dqueue.h" #include "igraph_stack.h" @@ -51,14 +49,13 @@ #include "igraph_interface.h" #include "igraph_constructors.h" #include "igraph_games.h" -#include "igraph_microscopic_update.h" #include "igraph_centrality.h" #include "igraph_paths.h" #include "igraph_components.h" #include "igraph_structural.h" #include "igraph_transitivity.h" #include "igraph_neighborhood.h" -#include "igraph_topology.h" +#include "igraph_isomorphism.h" #include "igraph_bipartite.h" #include "igraph_cliques.h" #include "igraph_layout.h" @@ -94,5 +91,7 @@ #include "igraph_graphicality.h" #include "igraph_cycles.h" #include "igraph_reachability.h" +#include "igraph_spatial.h" +#include "igraph_sampling.h" #endif diff --git a/src/vendor/cigraph/include/igraph_adjlist.h b/src/vendor/cigraph/include/igraph_adjlist.h index e6125fab4c2..175de6dfb00 100644 --- a/src/vendor/cigraph/include/igraph_adjlist.h +++ b/src/vendor/cigraph/include/igraph_adjlist.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,42 +13,39 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_ADJLIST_H #define IGRAPH_ADJLIST_H #include "igraph_decls.h" +#include "igraph_datatype.h" #include "igraph_constants.h" #include "igraph_error.h" #include "igraph_types.h" -#include "igraph_datatype.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS typedef struct igraph_adjlist_t { - igraph_integer_t length; + igraph_int_t length; igraph_vector_int_t *adjs; } igraph_adjlist_t; typedef struct igraph_inclist_t { - igraph_integer_t length; + igraph_int_t length; igraph_vector_int_t *incs; } igraph_inclist_t; IGRAPH_EXPORT igraph_error_t igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al, igraph_neimode_t mode, igraph_loops_t loops, - igraph_multiple_t multiple); -IGRAPH_EXPORT igraph_error_t igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_integer_t no_of_nodes); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_adjlist_size(const igraph_adjlist_t *al); + igraph_bool_t multiple); +IGRAPH_EXPORT igraph_error_t igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_int_t no_of_nodes); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_adjlist_size(const igraph_adjlist_t *al); IGRAPH_EXPORT igraph_error_t igraph_adjlist_init_complementer(const igraph_t *graph, igraph_adjlist_t *al, igraph_neimode_t mode, - igraph_bool_t loops); + igraph_loops_t loops); IGRAPH_EXPORT igraph_error_t igraph_adjlist_init_from_inclist( const igraph_t *graph, igraph_adjlist_t *al, const igraph_inclist_t *il); IGRAPH_EXPORT void igraph_adjlist_destroy(igraph_adjlist_t *al); @@ -59,8 +54,8 @@ IGRAPH_EXPORT void igraph_adjlist_sort(igraph_adjlist_t *al); IGRAPH_EXPORT igraph_error_t igraph_adjlist_simplify(igraph_adjlist_t *al); IGRAPH_EXPORT igraph_error_t igraph_adjlist_print(const igraph_adjlist_t *al); IGRAPH_EXPORT igraph_error_t igraph_adjlist_fprint(const igraph_adjlist_t *al, FILE *outfile); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_adjlist_has_edge(igraph_adjlist_t* al, igraph_integer_t from, igraph_integer_t to, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_adjlist_replace_edge(igraph_adjlist_t* al, igraph_integer_t from, igraph_integer_t oldto, igraph_integer_t newto, igraph_bool_t directed); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_adjlist_has_edge(igraph_adjlist_t* al, igraph_int_t from, igraph_int_t to, igraph_bool_t directed); +IGRAPH_EXPORT igraph_error_t igraph_adjlist_replace_edge(igraph_adjlist_t* al, igraph_int_t from, igraph_int_t oldto, igraph_int_t newto, igraph_bool_t directed); /** * \define igraph_adjlist_get @@ -75,7 +70,7 @@ IGRAPH_EXPORT igraph_error_t igraph_adjlist_replace_edge(igraph_adjlist_t* al, i * * Time complexity: O(1). */ -#define igraph_adjlist_get(al,no) (&(al)->adjs[(igraph_integer_t)(no)]) +#define igraph_adjlist_get(al,no) (&(al)->adjs[(igraph_int_t)(no)]) IGRAPH_EXPORT igraph_error_t igraph_adjlist(igraph_t *graph, const igraph_adjlist_t *adjlist, igraph_neimode_t mode, igraph_bool_t duplicate); @@ -84,8 +79,8 @@ IGRAPH_EXPORT igraph_error_t igraph_inclist_init(const igraph_t *graph, igraph_inclist_t *il, igraph_neimode_t mode, igraph_loops_t loops); -IGRAPH_EXPORT igraph_error_t igraph_inclist_init_empty(igraph_inclist_t *il, igraph_integer_t n); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_inclist_size(const igraph_inclist_t *al); +IGRAPH_EXPORT igraph_error_t igraph_inclist_init_empty(igraph_inclist_t *il, igraph_int_t n); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_inclist_size(const igraph_inclist_t *al); IGRAPH_EXPORT void igraph_inclist_destroy(igraph_inclist_t *il); IGRAPH_EXPORT void igraph_inclist_clear(igraph_inclist_t *il); IGRAPH_EXPORT igraph_error_t igraph_inclist_print(const igraph_inclist_t *il); @@ -104,25 +99,25 @@ IGRAPH_EXPORT igraph_error_t igraph_inclist_fprint(const igraph_inclist_t *il, F * * Time complexity: O(1). */ -#define igraph_inclist_get(il,no) (&(il)->incs[(igraph_integer_t)(no)]) +#define igraph_inclist_get(il,no) (&(il)->incs[(igraph_int_t)(no)]) typedef struct igraph_lazy_adjlist_t { const igraph_t *graph; - igraph_integer_t length; + igraph_int_t length; igraph_vector_int_t **adjs; igraph_neimode_t mode; igraph_loops_t loops; - igraph_multiple_t multiple; + igraph_bool_t multiple; } igraph_lazy_adjlist_t; IGRAPH_EXPORT igraph_error_t igraph_lazy_adjlist_init(const igraph_t *graph, igraph_lazy_adjlist_t *al, igraph_neimode_t mode, igraph_loops_t loops, - igraph_multiple_t multiple); + igraph_bool_t multiple); IGRAPH_EXPORT void igraph_lazy_adjlist_destroy(igraph_lazy_adjlist_t *al); IGRAPH_EXPORT void igraph_lazy_adjlist_clear(igraph_lazy_adjlist_t *al); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_lazy_adjlist_size(const igraph_lazy_adjlist_t *al); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_lazy_adjlist_size(const igraph_lazy_adjlist_t *al); /** * \define igraph_lazy_adjlist_has @@ -135,7 +130,7 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_lazy_adjlist_size(con * * Time complexity: O(1). */ -#define igraph_lazy_adjlist_has(al,no) ((al)->adjs[(igraph_integer_t)(no)] != NULL) +#define igraph_lazy_adjlist_has(al,no) ((al)->adjs[(igraph_int_t)(no)] != NULL) /** * \define igraph_lazy_adjlist_get @@ -160,13 +155,13 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_lazy_adjlist_size(con * first time, O(1) for subsequent calls. */ #define igraph_lazy_adjlist_get(al,no) \ - (igraph_lazy_adjlist_has(al,no) ? ((al)->adjs[(igraph_integer_t)(no)]) \ + (igraph_lazy_adjlist_has(al,no) ? ((al)->adjs[(igraph_int_t)(no)]) \ : (igraph_i_lazy_adjlist_get_real(al, no))) -IGRAPH_EXPORT igraph_vector_int_t *igraph_i_lazy_adjlist_get_real(igraph_lazy_adjlist_t *al, igraph_integer_t no); +IGRAPH_EXPORT igraph_vector_int_t *igraph_i_lazy_adjlist_get_real(igraph_lazy_adjlist_t *al, igraph_int_t no); typedef struct igraph_lazy_inclist_t { const igraph_t *graph; - igraph_integer_t length; + igraph_int_t length; igraph_vector_int_t **incs; igraph_neimode_t mode; igraph_loops_t loops; @@ -178,7 +173,7 @@ IGRAPH_EXPORT igraph_error_t igraph_lazy_inclist_init(const igraph_t *graph, igraph_loops_t loops); IGRAPH_EXPORT void igraph_lazy_inclist_destroy(igraph_lazy_inclist_t *il); IGRAPH_EXPORT void igraph_lazy_inclist_clear(igraph_lazy_inclist_t *il); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_lazy_inclist_size(const igraph_lazy_inclist_t *il); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_lazy_inclist_size(const igraph_lazy_inclist_t *il); /** * \define igraph_lazy_inclist_has @@ -191,7 +186,7 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_lazy_inclist_size(con * * Time complexity: O(1). */ -#define igraph_lazy_inclist_has(il,no) ((il)->incs[(igraph_integer_t)(no)] != NULL) +#define igraph_lazy_inclist_has(il,no) ((il)->incs[(igraph_int_t)(no)] != NULL) /** * \define igraph_lazy_inclist_get @@ -216,10 +211,10 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_lazy_inclist_size(con * time, O(1) for subsequent calls with the same \p no argument. */ #define igraph_lazy_inclist_get(il,no) \ - (igraph_lazy_inclist_has(il,no) ? ((il)->incs[(igraph_integer_t)(no)]) \ + (igraph_lazy_inclist_has(il,no) ? ((il)->incs[(igraph_int_t)(no)]) \ : (igraph_i_lazy_inclist_get_real(il,no))) -IGRAPH_EXPORT igraph_vector_int_t *igraph_i_lazy_inclist_get_real(igraph_lazy_inclist_t *il, igraph_integer_t no); +IGRAPH_EXPORT igraph_vector_int_t *igraph_i_lazy_inclist_get_real(igraph_lazy_inclist_t *il, igraph_int_t no); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_arpack.h b/src/vendor/cigraph/include/igraph_arpack.h index 348e23dcd76..5912a66229b 100644 --- a/src/vendor/cigraph/include/igraph_arpack.h +++ b/src/vendor/cigraph/include/igraph_arpack.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2007-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_ARPACK_H @@ -30,7 +25,7 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \section about_arpack ARPACK interface in igraph @@ -291,11 +286,72 @@ typedef struct igraph_arpack_storage_t { igraph_real_t *workev; } igraph_arpack_storage_t; +/** + * \typedef igraph_arpack_error_t + * \brief Error codes from ARPACK. + * + * These error codes represent error conditions returned from ARPACK. + * They are used internally to format error messages when igraph itself + * returns an \c IGRAPH_EARPACK error code from an ARPACK-related function. + * + * \enumval IGRAPH_ARPACK_NO_ERROR No error was encountered in ARPACK. + * \enumval IGRAPH_ARPACK_PROD Matrix-vector product failed (not used any more). + * \enumval IGRAPH_ARPACK_NPOS N must be positive. + * \enumval IGRAPH_ARPACK_NEVNPOS NEV must be positive. + * \enumval IGRAPH_ARPACK_NCVSMALL NCV must be bigger. + * \enumval IGRAPH_ARPACK_NONPOSI Maximum number of iterations should be positive. + * \enumval IGRAPH_ARPACK_WHICHINV Invalid WHICH parameter. + * \enumval IGRAPH_ARPACK_BMATINV Invalid BMAT parameter. + * \enumval IGRAPH_ARPACK_WORKLSMALL WORKL is too small. + * \enumval IGRAPH_ARPACK_TRIDERR LAPACK error in tridiagonal eigenvalue calculation. + * \enumval IGRAPH_ARPACK_ZEROSTART Starting vector is zero. + * \enumval IGRAPH_ARPACK_MODEINV MODE is invalid. + * \enumval IGRAPH_ARPACK_MODEBMAT MODE and BMAT are not compatible. + * \enumval IGRAPH_ARPACK_ISHIFT ISHIFT must be 0 or 1. + * \enumval IGRAPH_ARPACK_NEVBE NEV and WHICH='BE' are incompatible. + * \enumval IGRAPH_ARPACK_NOFACT Could not build an Arnoldi factorization. + * \enumval IGRAPH_ARPACK_FAILED No eigenvalues to sufficient accuracy. + * \enumval IGRAPH_ARPACK_HOWMNY HOWMNY is invalid. + * \enumval IGRAPH_ARPACK_HOWMNYS HOWMNY='S' is not implemented. + * \enumval IGRAPH_ARPACK_EVDIFF Different number of converged Ritz values. + * \enumval IGRAPH_ARPACK_SHUR Error from calculation of a real Schur form. + * \enumval IGRAPH_ARPACK_LAPACK LAPACK (dtrevc) error for calculating eigenvectors. + * \enumval IGRAPH_ARPACK_UNKNOWN Unknown ARPACK error. + */ +typedef enum { + IGRAPH_ARPACK_NO_ERROR = 0, + IGRAPH_ARPACK_PROD = 15, + IGRAPH_ARPACK_NPOS = 16, + IGRAPH_ARPACK_NEVNPOS = 17, + IGRAPH_ARPACK_NCVSMALL = 18, + IGRAPH_ARPACK_NONPOSI = 19, + IGRAPH_ARPACK_WHICHINV = 20, + IGRAPH_ARPACK_BMATINV = 21, + IGRAPH_ARPACK_WORKLSMALL = 22, + IGRAPH_ARPACK_TRIDERR = 23, + IGRAPH_ARPACK_ZEROSTART = 24, + IGRAPH_ARPACK_MODEINV = 25, + IGRAPH_ARPACK_MODEBMAT = 26, + IGRAPH_ARPACK_ISHIFT = 27, + IGRAPH_ARPACK_NEVBE = 28, + IGRAPH_ARPACK_NOFACT = 29, + IGRAPH_ARPACK_FAILED = 30, + IGRAPH_ARPACK_HOWMNY = 31, + IGRAPH_ARPACK_HOWMNYS = 32, + IGRAPH_ARPACK_EVDIFF = 33, + IGRAPH_ARPACK_SHUR = 34, + IGRAPH_ARPACK_LAPACK = 35, + IGRAPH_ARPACK_UNKNOWN = 36, + IGRAPH_ARPACK_MAXIT = 39, + IGRAPH_ARPACK_NOSHIFT = 40, + IGRAPH_ARPACK_REORDER = 41, +} igraph_arpack_error_t; + IGRAPH_EXPORT void igraph_arpack_options_init(igraph_arpack_options_t *o); IGRAPH_EXPORT igraph_arpack_options_t* igraph_arpack_options_get_default(void); -IGRAPH_EXPORT igraph_error_t igraph_arpack_storage_init(igraph_arpack_storage_t *s, igraph_integer_t maxn, - igraph_integer_t maxncv, igraph_integer_t maxldv, igraph_bool_t symm); +IGRAPH_EXPORT igraph_error_t igraph_arpack_storage_init(igraph_arpack_storage_t *s, igraph_int_t maxn, + igraph_int_t maxncv, igraph_int_t maxldv, igraph_bool_t symm); IGRAPH_EXPORT void igraph_arpack_storage_destroy(igraph_arpack_storage_t *s); /** @@ -329,8 +385,11 @@ IGRAPH_EXPORT igraph_error_t igraph_arpack_rnsolve(igraph_arpack_function_t *fun igraph_matrix_t *values, igraph_matrix_t *vectors); IGRAPH_EXPORT igraph_error_t igraph_arpack_unpack_complex(igraph_matrix_t *vectors, igraph_matrix_t *values, - igraph_integer_t nev); + igraph_int_t nev); + +IGRAPH_EXPORT const char* igraph_arpack_error_to_string(igraph_arpack_error_t error); +IGRAPH_EXPORT igraph_arpack_error_t igraph_arpack_get_last_error(void); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_array.h b/src/vendor/cigraph/include/igraph_array.h deleted file mode 100644 index 1f098d0a3c3..00000000000 --- a/src/vendor/cigraph/include/igraph_array.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- mode: C -*- */ -/* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - -*/ - -#ifndef IGRAPH_ARRAY_H -#define IGRAPH_ARRAY_H - -#include "igraph_decls.h" -#include "igraph_error.h" -#include "igraph_vector.h" - -__BEGIN_DECLS - -/* -------------------------------------------------- */ -/* 3D array */ -/* -------------------------------------------------- */ - -#define BASE_IGRAPH_REAL -#include "igraph_pmt.h" -#include "igraph_array_pmt.h" -#include "igraph_pmt_off.h" -#undef BASE_IGRAPH_REAL - -#define BASE_INT -#include "igraph_pmt.h" -#include "igraph_array_pmt.h" -#include "igraph_pmt_off.h" -#undef BASE_INT - -#define BASE_CHAR -#include "igraph_pmt.h" -#include "igraph_array_pmt.h" -#include "igraph_pmt_off.h" -#undef BASE_CHAR - -#define BASE_BOOL -#include "igraph_pmt.h" -#include "igraph_array_pmt.h" -#include "igraph_pmt_off.h" -#undef BASE_BOOL - -__END_DECLS - -#endif diff --git a/src/vendor/cigraph/include/igraph_array_pmt.h b/src/vendor/cigraph/include/igraph_array_pmt.h deleted file mode 100644 index 8cbcfb43376..00000000000 --- a/src/vendor/cigraph/include/igraph_array_pmt.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- mode: C -*- */ -/* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - -*/ - -typedef struct TYPE(igraph_array3) { - TYPE(igraph_vector) data; - igraph_integer_t n1, n2, n3, n1n2; -} TYPE(igraph_array3); - -#ifndef IGRAPH_ARRAY3_INIT_FINALLY -#define IGRAPH_ARRAY3_INIT_FINALLY(a, n1, n2, n3) \ - do { IGRAPH_CHECK(igraph_array3_init(a, n1, n2, n3)); \ - IGRAPH_FINALLY(igraph_array3_destroy, a); } while (0) -#endif - -#ifndef ARRAY3 - #define ARRAY3(m,i,j,k) ((m).data.stor_begin[(m).n1n2*(k)+(m).n1*(j)+(i)]) -#endif - -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_array3, init)( - TYPE(igraph_array3) *a, igraph_integer_t n1, igraph_integer_t n2, - igraph_integer_t n3); -IGRAPH_DEPRECATED IGRAPH_EXPORT void FUNCTION(igraph_array3, destroy)(TYPE(igraph_array3) *a); -IGRAPH_DEPRECATED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_array3, size)(const TYPE(igraph_array3) *a); -IGRAPH_DEPRECATED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_array3, n)( - const TYPE(igraph_array3) *a, igraph_integer_t idx); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_array3, resize)( - TYPE(igraph_array3) *a, igraph_integer_t n1, igraph_integer_t n2, - igraph_integer_t n3); -IGRAPH_DEPRECATED IGRAPH_EXPORT void FUNCTION(igraph_array3, null)(TYPE(igraph_array3) *a); -IGRAPH_DEPRECATED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_array3, sum)(const TYPE(igraph_array3) *a); -IGRAPH_DEPRECATED IGRAPH_EXPORT void FUNCTION(igraph_array3, scale)(TYPE(igraph_array3) *a, BASE by); -IGRAPH_DEPRECATED IGRAPH_EXPORT void FUNCTION(igraph_array3, fill)(TYPE(igraph_array3) *a, BASE e); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_array3, update)(TYPE(igraph_array3) *to, - const TYPE(igraph_array3) *from); diff --git a/src/vendor/cigraph/include/igraph_attributes.h b/src/vendor/cigraph/include/igraph_attributes.h index 985b55a3aa4..db0a3e64341 100644 --- a/src/vendor/cigraph/include/igraph_attributes.h +++ b/src/vendor/cigraph/include/igraph_attributes.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2005-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2005-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_ATTRIBUTES_H @@ -34,114 +29,140 @@ #include "igraph_vector_ptr.h" #include "igraph_iterators.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Attributes */ /* -------------------------------------------------- */ -/** - * \section about_attributes - * - * Attributes are numbers, boolean values or strings associated with - * the vertices or edges of a graph, or with the graph itself. E.g. you may - * label vertices with symbolic names or attach numeric weights to the edges - * of a graph. In addition to these three basic types, a custom object - * type is supported as well. - * - * igraph attributes are designed to be flexible and extensible. - * In igraph attributes are implemented via an interface abstraction: - * any type implementing the functions in the interface, can be used - * for storing vertex, edge and graph attributes. This means that - * different attribute implementations can be used together with - * igraph. This is reasonable: if igraph is used from Python attributes can be - * of any Python type, from R all R types are allowed. There is also an - * experimental attribute implementation to be used when programming - * in C, but by default it is currently turned off. - * - * First we briefly look over how attribute handlers can be - * implemented. This is not something a user does every day. It is - * rather typically the job of the high level interface writers. (But - * it is possible to write an interface without implementing - * attributes.) Then we show the experimental C attribute handler. - */ - -/** - * \section about_attribute_table - * It is possible to attach an attribute handling - * interface to \a igraph. This is simply a table of functions, of - * type \ref igraph_attribute_table_t. These functions are invoked to - * notify the attribute handling code about the structural changes in - * a graph. See the documentation of this type for details. - * - * By default there is no attribute interface attached to \a igraph. - * To attach one, call \ref igraph_set_attribute_table with your new - * table. This is normally done on program startup, and is kept untouched - * for the program's lifetime. It must be done before any graph object - * is created, as graphs created with a given attribute handler - * cannot be manipulated while a different attribute handler is - * active. - */ - -/** - * \section about_attribute_combination - * - * Several graph operations may collapse multiple vertices or edges into - * a single one. Attribute combination lists are used to indicate to the attribute - * handler how to combine the attributes of the original vertices or edges and - * how to derive the final attribute value that is to be assigned to the collapsed - * vertex or edge. For example, \ref igraph_simplify() removes loops and combines - * multiple edges into a single one; in case of a graph with an edge attribute - * named \c weight the attribute combination list can tell the attribute handler - * whether the weight of a collapsed edge should be the sum, the mean or some other - * function of the weights of the original edges that were collapsed into one. - * - * One attribute combination list may contain several attribute combination - * records, one for each vertex or edge attribute that is to be handled during the - * operation. - */ - /** * \typedef igraph_attribute_type_t - * The possible types of the attributes. - * - * Note that this is only the - * type communicated by the attribute interface towards igraph - * functions. E.g. in the R attribute handler, it is safe to say - * that all complex R object attributes are strings, as long as this - * interface is able to serialize them into strings. See also \ref - * igraph_attribute_table_t. + * \brief The possible types of the attributes. + * + * Values of this enum are used by the attribute interface to communicate the + * type of an attribute to igraph's C core. When igraph is integrated in a + * high-level language, the attribute type reported by the interface may not + * necessarily have to match the exact data type in the high-level language as + * long as the attribute interface can provide a conversion from the native + * high-level attribute value to one of the data types listed here. When the + * high-level data type is complex and has no suitable conversion to one of the + * atomic igraph attribute types (numeric, string or Boolean), the attribute + * interface should report the attribute as having an "object" type, which is + * ignored by the C core. See also \ref igraph_attribute_table_t. + * * \enumval IGRAPH_ATTRIBUTE_UNSPECIFIED Currently used internally * as a "null value" or "placeholder value" in some algorithms. * Attribute records with this type must not be passed to igraph * functions. * \enumval IGRAPH_ATTRIBUTE_NUMERIC Numeric attribute. * \enumval IGRAPH_ATTRIBUTE_BOOLEAN Logical values, true or false. - * \enumval IGRAPH_ATTRIBUTE_STRING Attribute that can be converted to - * a string. + * \enumval IGRAPH_ATTRIBUTE_STRING String attribute. * \enumval IGRAPH_ATTRIBUTE_OBJECT Custom attribute type, to be * used for special data types by client applications. The R and * Python interfaces use this for attributes that hold R or Python * objects. Usually ignored by igraph functions. */ -typedef enum { IGRAPH_ATTRIBUTE_UNSPECIFIED = 0, - IGRAPH_ATTRIBUTE_DEFAULT IGRAPH_DEPRECATED_ENUMVAL = IGRAPH_ATTRIBUTE_UNSPECIFIED, - IGRAPH_ATTRIBUTE_NUMERIC = 1, - IGRAPH_ATTRIBUTE_BOOLEAN = 2, - IGRAPH_ATTRIBUTE_STRING = 3, - IGRAPH_ATTRIBUTE_OBJECT = 127 - } igraph_attribute_type_t; +typedef enum { + IGRAPH_ATTRIBUTE_UNSPECIFIED = 0, + IGRAPH_ATTRIBUTE_NUMERIC = 1, + IGRAPH_ATTRIBUTE_BOOLEAN = 2, + IGRAPH_ATTRIBUTE_STRING = 3, + IGRAPH_ATTRIBUTE_OBJECT = 127 +} igraph_attribute_type_t; + +/** + * \typedef igraph_attribute_elemtype_t + * \brief Types of objects to which attributes can be attached. + * + * \enumval IGRAPH_ATTRIBUTE_GRAPH Denotes that an attribute belongs to the + * entire graph. + * \enumval IGRAPH_ATTRIBUTE_VERTEX Denotes that an attribute belongs to the + * vertices of a graph. + * \enumval IGRAPH_ATTRIBUTE_EDGE Denotes that an attribute belongs to the + * edges of a graph. + */ +typedef enum { + IGRAPH_ATTRIBUTE_GRAPH = 0, + IGRAPH_ATTRIBUTE_VERTEX, + IGRAPH_ATTRIBUTE_EDGE +} igraph_attribute_elemtype_t; + +/* -------------------------------------------------- */ +/* Attribute records */ +/* -------------------------------------------------- */ +/** + * \typedef igraph_attribute_record_t + * \brief An attribute record holding the name, type and values of an attribute. + * + * This composite data type is used in the attribute interface to specify a + * name-type-value triplet where the name is the name of a graph, vertex or + * edge attribute, the type is the corresponding igraph type of the attribute + * and the value is a \em vector of attribute values. Note that for graph + * attributes we use a vector of length 1. The type of the vector depends on + * the attribute type: it is \ref igraph_vector_t for numeric attributes, + * \c igraph_strvector_t for string attributes and \c igraph_vector_bool_t + * for Boolean attributes. + * + * + * The record also stores default values for the attribute. The default values + * are used when the value vector of the record is resized with + * \ref igraph_attribute_record_resize(). It is important that the record + * stores \em one default value only, corresponding to the type of the + * attribute record. The default value is \em cleared when the type of the + * record is changed. + */ typedef struct igraph_attribute_record_t { - const char *name; + char *name; igraph_attribute_type_t type; - const void *value; + union { + void *as_raw; + igraph_vector_t *as_vector; + igraph_strvector_t *as_strvector; + igraph_vector_bool_t *as_vector_bool; + } value; + union { + igraph_real_t numeric; + igraph_bool_t boolean; + char *string; + } default_value; } igraph_attribute_record_t; -typedef enum { IGRAPH_ATTRIBUTE_GRAPH = 0, - IGRAPH_ATTRIBUTE_VERTEX, - IGRAPH_ATTRIBUTE_EDGE - } igraph_attribute_elemtype_t; +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_init( + igraph_attribute_record_t *attr, const char* name, igraph_attribute_type_t type +); +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_init_copy( + igraph_attribute_record_t *to, const igraph_attribute_record_t *from +); +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_check_type( + const igraph_attribute_record_t *attr, igraph_attribute_type_t type +); +IGRAPH_EXPORT igraph_int_t igraph_attribute_record_size( + const igraph_attribute_record_t *attr +); +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_resize( + igraph_attribute_record_t *attr, igraph_int_t new_size +); +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_set_name( + igraph_attribute_record_t *attr, const char* name +); +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_set_default_numeric( + igraph_attribute_record_t *attr, igraph_real_t value +); +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_set_default_boolean( + igraph_attribute_record_t *attr, igraph_bool_t value +); +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_set_default_string( + igraph_attribute_record_t *attr, const char* value +); +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_set_type( + igraph_attribute_record_t *attr, igraph_attribute_type_t type +); +IGRAPH_EXPORT void igraph_attribute_record_destroy(igraph_attribute_record_t *attr); + +/* -------------------------------------------------- */ +/* Attribute combinations */ +/* -------------------------------------------------- */ /** * \typedef igraph_attribute_combination_type_t @@ -206,6 +227,22 @@ IGRAPH_EXPORT igraph_error_t igraph_attribute_combination_query(const igraph_att igraph_attribute_combination_type_t *type, igraph_function_pointer_t *func); +/* -------------------------------------------------- */ +/* List of attribute records */ +/* -------------------------------------------------- */ + +#define ATTRIBUTE_RECORD_LIST +#define BASE_ATTRIBUTE_RECORD +#include "igraph_pmt.h" +#include "igraph_typed_list_pmt.h" +#include "igraph_pmt_off.h" +#undef BASE_ATTRIBUTE_RECORD +#undef ATTRIBUTE_RECORD_LIST + +/* -------------------------------------------------- */ +/* Attribute handler interface */ +/* -------------------------------------------------- */ + /** * \struct igraph_attribute_table_t * \brief Table of functions to perform operations on attributes. @@ -217,54 +254,71 @@ IGRAPH_EXPORT igraph_error_t igraph_attribute_combination_query(const igraph_att * created, right after it is created but before any vertices or * edges are added. It is supposed to set the \c attr member of the \c * igraph_t object, which is guaranteed to be set to a null pointer - * before this function is called. It is expected to return an error code. + * before this function is called. It is expected to set the \c attr member + * to a non-null value \em or return an error code. Leaving the \c attr + * member at a null value while returning success is invalid and will trigger + * an error in the C core of igraph itself. * \member destroy This function is called whenever the graph object * is destroyed, right before freeing the allocated memory. It is supposed * to do any cleanup operations that are need to dispose of the \c attr * member of the \c igraph_t object properly. The caller will set the * \c attr member to a null pointer after this function returns. - * \member copy This function is called when copying a graph with \ref - * igraph_copy, after the structure of the graph has been already - * copied. It is supposed to populate the \c attr member of the target - * \c igraph_t object. The \c attr member of the target is guaranteed to be - * set to a null pointer before this function is called. It is expected to - * return an error code. - * \member add_vertices Called when vertices are added to a - * graph, before adding the vertices themselves. - * The number of vertices to add is supplied as an - * argument. Expected to return an error code. + * \member copy This function is called when the C core wants to populate the + * attributes of a graph from another graph. The structure of the target + * graph is already initialized by the time this function is called, and the + * \c attr member of the graph is set to a null pointer. The function is + * supposed to populate the \c attr member of the target \c igraph_t object + * to a non-null value \em or return an error code. Leaving the \c attr + * member at a null value while returning success is invalid and will trigger + * an error in the C core of igraph itself. + * \member add_vertices Called when vertices are added to a graph, after the + * base data structure was modified. The number of vertices that were added is + * supplied as an argument. The function is supposed to set up default values + * for each vertex attribute that is currently registered on the graph, for + * all the newly added vertices. Expected to return an error code. * \member permute_vertices Called when a new graph is created based on an * existing one such that there is a mapping from the vertices of the new * graph back to the vertices of the old graph (e.g. if vertices are removed * from a graph). The supplied index vector defines which old vertex - * a new vertex corresponds to. Its length must be the same as the - * number of vertices in the new graph. Note that the old and the new graph - * may be the same. If the two graph instances are \em not the same, implementors - * may safely assume that the new graph has no vertex attributes yet (but it - * may already have graph or edge attributes by the time this function is - * called). + * a new vertex corresponds to. Its length is the same as the number of + * vertices in the new graph, and for each new vertex it provides the ID + * of the corresponding vertex in the old graph. The function is supposed to + * set up the values of the vertex attributes of the new graph based on the + * attributes of the old graph and the provided index vector. Note that the + * old and the new graph \em may be the same, in which case it is the + * responsibility of the function to ensure that the operation can safely be + * performed in-place. If the two graph instances are \em not the same, + * implementors may safely assume that the new graph has no vertex attributes + * yet (but it may already have graph or edge attributes by the time this + * function is called). * \member combine_vertices This function is called when the creation * of a new graph involves a merge (contraction, etc.) of vertices - * from another graph. The function is after the new graph was created. + * from another graph. The function is called after the new graph was created. * An argument specifies how several vertices from the old graph map to a * single vertex in the new graph. It is guaranteed that the old and the * new graph instances are different when this callback is called. * Implementors may safely assume that the new graph has no vertex attributes * yet (but it may already have graph or edge attributes by the time this * function is called). - * \member add_edges Called when new edges have been added. The number - * of new edges are supplied as well. It is expected to return an - * error code. - * \member permute_edges Called when a new graph is created and - * some of the new edges should carry the attributes of some of the - * old edges. The idx vector shows the mapping between the old edges and - * the new ones. Its length is the same as the number of edges in the new - * graph, and for each edge it gives the ID of the old edge (the edge in - * the old graph). Note that the old and the new graph instances \em may - * be the same. If the two graph instances are \em not the same, implementors - * may safely assume that the new graph has no edge attributes yet (but it - * may already have graph or vertex attributes by the time this function is - * called). + * \member add_edges Called when new edges are added to a graph, after the + * base data structure was modified. A vector containing the endpoints of the + * new edges are supplied as an argument. The function is supposed to set up + * default values for each edge attribute that is currently registered on the + * graph, for all the newly added edges. Expected to return an error code. + * \member permute_edges Called when a new graph is created based on an + * existing one such that some of the edges in the new graph should copy the + * attributes of some edges from the old graph (this also includes the + * deletion of edges). The supplied index vector defines which old edge a new + * edge corresponds to. Its length is the same as the number of edges in the + * new graph, and for each edge it provides the ID of the corresponding edge + * in the old graph. The function is supposed to set up the values of the + * edge attributes of the new graph based on the attributes of the old graph + * and the provided index vector. Note that the old and the new graph \em may + * be the same, in which case it is the responsibility of the function to + * ensure that the operation can safely be performed in-place. If the two + * graph instances are \em not the same, implementors may safely assume that + * the new graph has no edge attributes yet (but it may already have graph or + * vertex attributes by the time this function is called). * \member combine_edges This function is called when the creation * of a new graph involves a merge (contraction, etc.) of edges * from another graph. The function is after the new graph was created. @@ -278,43 +332,60 @@ IGRAPH_EXPORT igraph_error_t igraph_attribute_combination_query(const igraph_att * types should be returned. * \member has_attr Check whether a graph has the named * graph/vertex/edge attribute. - * \member gettype Query the type of a graph/vertex/edge attribute. + * \member get_type Query the type of a graph/vertex/edge attribute. * \member get_numeric_graph_attr Query a numeric graph attribute. The - * value should be placed as the first element of the \p value - * vector. + * value should be appended to the provided \p value vector. No assumptions + * should be made about the initial contents of the \p value vector and it is + * not guaranteed to be empty. * \member get_string_graph_attr Query a string graph attribute. The - * value should be placed as the first element of the \p value - * string vector. + * value should be appended to the provided \p value vector. No assumptions + * should be made about the initial contents of the \p value vector and it is + * not guaranteed to be empty. * \member get_bool_graph_attr Query a boolean graph attribute. The - * value should be placed as the first element of the \p value - * boolean vector. + * value should be appended to the provided \p value vector. No assumptions + * should be made about the initial contents of the \p value vector and it is + * not guaranteed to be empty. * \member get_numeric_vertex_attr Query a numeric vertex attribute, - * for the vertices included in \p vs. + * for the vertices included in \p vs. The attribute values should be + * appended to the provided \p value vector. No assumptions should be made + * about the initial contents of the \p value vector and it is not guaranteed + * to be empty. * \member get_string_vertex_attr Query a string vertex attribute, - * for the vertices included in \p vs. + * for the vertices included in \p vs. The attribute values should be + * appended to the provided \p value vector. No assumptions should be made + * about the initial contents of the \p value vector and it is not guaranteed + * to be empty. * \member get_bool_vertex_attr Query a boolean vertex attribute, - * for the vertices included in \p vs. + * for the vertices included in \p vs. The attribute values should be + * appended to the provided \p value vector. No assumptions should be made + * about the initial contents of the \p value vector and it is not guaranteed + * to be empty. * \member get_numeric_edge_attr Query a numeric edge attribute, for - * the edges included in \p es. + * the edges included in \p es. The attribute values should be appended + * to the provided \p value vector. No assumptions should be made + * about the initial contents of the \p value vector and it is not guaranteed + * to be empty. * \member get_string_edge_attr Query a string edge attribute, for the - * edges included in \p es. + * the edges included in \p es. The attribute values should be appended + * to the provided \p value vector. No assumptions should be made + * about the initial contents of the \p value vector and it is not guaranteed + * to be empty. * \member get_bool_edge_attr Query a boolean edge attribute, for the - * edges included in \p es. - * - * Note that the get_*_*_attr are allowed to - * convert the attributes to numeric or string. E.g. if a vertex attribute - * is a GNU R complex data type, then - * get_string_vertex_attribute may serialize it - * into a string, but this probably makes sense only if - * add_vertices is able to deserialize it. + * the edges included in \p es. The attribute values should be appended + * to the provided \p value vector. No assumptions should be made + * about the initial contents of the \p value vector and it is not guaranteed + * to be empty. */ typedef struct igraph_attribute_table_t { - igraph_error_t (*init)(igraph_t *graph, igraph_vector_ptr_t *attr); + igraph_error_t (*init)(igraph_t *graph, const igraph_attribute_record_list_t *attr); void (*destroy)(igraph_t *graph); igraph_error_t (*copy)(igraph_t *to, const igraph_t *from, igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea); - igraph_error_t (*add_vertices)(igraph_t *graph, igraph_integer_t nv, igraph_vector_ptr_t *attr); + igraph_error_t (*add_vertices)( + igraph_t *graph, igraph_int_t nv, + const igraph_attribute_record_list_t *attr + ); igraph_error_t (*permute_vertices)(const igraph_t *graph, igraph_t *newgraph, const igraph_vector_int_t *idx); @@ -322,8 +393,10 @@ typedef struct igraph_attribute_table_t { igraph_t *newgraph, const igraph_vector_int_list_t *merges, const igraph_attribute_combination_t *comb); - igraph_error_t (*add_edges)(igraph_t *graph, const igraph_vector_int_t *edges, - igraph_vector_ptr_t *attr); + igraph_error_t (*add_edges)( + igraph_t *graph, const igraph_vector_int_t *edges, + const igraph_attribute_record_list_t *attr + ); igraph_error_t (*permute_edges)(const igraph_t *graph, igraph_t *newgraph, const igraph_vector_int_t *idx); igraph_error_t (*combine_edges)(const igraph_t *graph, @@ -336,7 +409,7 @@ typedef struct igraph_attribute_table_t { igraph_strvector_t *enames, igraph_vector_int_t *etypes); igraph_bool_t (*has_attr)(const igraph_t *graph, igraph_attribute_elemtype_t type, const char *name); - igraph_error_t (*gettype)(const igraph_t *graph, igraph_attribute_type_t *type, + igraph_error_t (*get_type)(const igraph_t *graph, igraph_attribute_type_t *type, igraph_attribute_elemtype_t elemtype, const char *name); igraph_error_t (*get_numeric_graph_attr)(const igraph_t *graph, const char *name, igraph_vector_t *value); @@ -364,7 +437,6 @@ typedef struct igraph_attribute_table_t { igraph_vector_bool_t *value); } igraph_attribute_table_t; -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_attribute_table_t * igraph_i_set_attribute_table(const igraph_attribute_table_t * table); IGRAPH_EXPORT igraph_attribute_table_t * igraph_set_attribute_table(const igraph_attribute_table_t * table); IGRAPH_EXPORT igraph_bool_t igraph_has_attribute_table(void); @@ -377,17 +449,17 @@ IGRAPH_EXPORT igraph_real_t igraph_cattribute_GAN(const igraph_t *graph, const c IGRAPH_EXPORT igraph_bool_t igraph_cattribute_GAB(const igraph_t *graph, const char *name); IGRAPH_EXPORT const char* igraph_cattribute_GAS(const igraph_t *graph, const char *name); IGRAPH_EXPORT igraph_real_t igraph_cattribute_VAN(const igraph_t *graph, const char *name, - igraph_integer_t vid); + igraph_int_t vid); IGRAPH_EXPORT igraph_bool_t igraph_cattribute_VAB(const igraph_t *graph, const char *name, - igraph_integer_t vid); + igraph_int_t vid); IGRAPH_EXPORT const char* igraph_cattribute_VAS(const igraph_t *graph, const char *name, - igraph_integer_t vid); + igraph_int_t vid); IGRAPH_EXPORT igraph_real_t igraph_cattribute_EAN(const igraph_t *graph, const char *name, - igraph_integer_t eid); + igraph_int_t eid); IGRAPH_EXPORT igraph_bool_t igraph_cattribute_EAB(const igraph_t *graph, const char *name, - igraph_integer_t eid); + igraph_int_t eid); IGRAPH_EXPORT const char* igraph_cattribute_EAS(const igraph_t *graph, const char *name, - igraph_integer_t eid); + igraph_int_t eid); IGRAPH_EXPORT igraph_error_t igraph_cattribute_VANV(const igraph_t *graph, const char *name, igraph_vs_t vids, igraph_vector_t *result); @@ -417,17 +489,17 @@ IGRAPH_EXPORT igraph_error_t igraph_cattribute_GAB_set(igraph_t *graph, const ch IGRAPH_EXPORT igraph_error_t igraph_cattribute_GAS_set(igraph_t *graph, const char *name, const char *value); IGRAPH_EXPORT igraph_error_t igraph_cattribute_VAN_set(igraph_t *graph, const char *name, - igraph_integer_t vid, igraph_real_t value); + igraph_int_t vid, igraph_real_t value); IGRAPH_EXPORT igraph_error_t igraph_cattribute_VAB_set(igraph_t *graph, const char *name, - igraph_integer_t vid, igraph_bool_t value); + igraph_int_t vid, igraph_bool_t value); IGRAPH_EXPORT igraph_error_t igraph_cattribute_VAS_set(igraph_t *graph, const char *name, - igraph_integer_t vid, const char *value); + igraph_int_t vid, const char *value); IGRAPH_EXPORT igraph_error_t igraph_cattribute_EAN_set(igraph_t *graph, const char *name, - igraph_integer_t eid, igraph_real_t value); + igraph_int_t eid, igraph_real_t value); IGRAPH_EXPORT igraph_error_t igraph_cattribute_EAB_set(igraph_t *graph, const char *name, - igraph_integer_t eid, igraph_bool_t value); + igraph_int_t eid, igraph_bool_t value); IGRAPH_EXPORT igraph_error_t igraph_cattribute_EAS_set(igraph_t *graph, const char *name, - igraph_integer_t eid, const char *value); + igraph_int_t eid, const char *value); IGRAPH_EXPORT igraph_error_t igraph_cattribute_VAN_setv(igraph_t *graph, const char *name, const igraph_vector_t *v); @@ -854,6 +926,6 @@ IGRAPH_EXPORT void igraph_cattribute_remove_all(igraph_t *graph, igraph_bool_t g */ #define DELALL(graph) (igraph_cattribute_remove_all((graph),1,1,1)) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_bipartite.h b/src/vendor/cigraph/include/igraph_bipartite.h index f32fe8aa7fb..d1a0ee4d375 100644 --- a/src/vendor/cigraph/include/igraph_bipartite.h +++ b/src/vendor/cigraph/include/igraph_bipartite.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_BIPARTITE_H @@ -28,11 +23,12 @@ #include "igraph_datatype.h" #include "igraph_constants.h" #include "igraph_error.h" +#include "igraph_graphicality.h" #include "igraph_types.h" #include "igraph_vector.h" #include "igraph_matrix.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Bipartite networks */ @@ -40,7 +36,7 @@ __BEGIN_DECLS IGRAPH_EXPORT igraph_error_t igraph_full_bipartite(igraph_t *graph, igraph_vector_bool_t *types, - igraph_integer_t n1, igraph_integer_t n2, + igraph_int_t n1, igraph_int_t n2, igraph_bool_t directed, igraph_neimode_t mode); @@ -50,10 +46,10 @@ IGRAPH_EXPORT igraph_error_t igraph_create_bipartite(igraph_t *g, const igraph_v IGRAPH_EXPORT igraph_error_t igraph_bipartite_projection_size(const igraph_t *graph, const igraph_vector_bool_t *types, - igraph_integer_t *vcount1, - igraph_integer_t *ecount1, - igraph_integer_t *vcount2, - igraph_integer_t *ecount2); + igraph_int_t *vcount1, + igraph_int_t *ecount1, + igraph_int_t *vcount2, + igraph_int_t *ecount2); IGRAPH_EXPORT igraph_error_t igraph_bipartite_projection(const igraph_t *graph, const igraph_vector_bool_t *types, @@ -61,52 +57,56 @@ IGRAPH_EXPORT igraph_error_t igraph_bipartite_projection(const igraph_t *graph, igraph_t *proj2, igraph_vector_int_t *multiplicity1, igraph_vector_int_t *multiplicity2, - igraph_integer_t probe1); - -IGRAPH_EXPORT igraph_error_t igraph_biadjacency(igraph_t *graph, igraph_vector_bool_t *types, - const igraph_matrix_t *input, igraph_bool_t directed, - igraph_neimode_t mode, igraph_bool_t multiple); + igraph_int_t probe1); + +IGRAPH_EXPORT igraph_error_t igraph_biadjacency( + igraph_t *graph, + igraph_vector_bool_t *types, + const igraph_matrix_t *biadjmatrix, + igraph_bool_t directed, + igraph_neimode_t mode, + igraph_bool_t multiple); + +IGRAPH_EXPORT igraph_error_t igraph_weighted_biadjacency( + igraph_t *graph, + igraph_vector_bool_t *types, + igraph_vector_t *weights, + const igraph_matrix_t *biadjmatrix, + igraph_bool_t directed, + igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_get_biadjacency(const igraph_t *graph, - const igraph_vector_bool_t *types, - igraph_matrix_t *res, - igraph_vector_int_t *row_ids, - igraph_vector_int_t *col_ids); + const igraph_vector_bool_t *types, + const igraph_vector_t *weights, + igraph_matrix_t *res, + igraph_vector_int_t *row_ids, + igraph_vector_int_t *col_ids); IGRAPH_EXPORT igraph_error_t igraph_is_bipartite(const igraph_t *graph, igraph_bool_t *res, igraph_vector_bool_t *types); -IGRAPH_EXPORT igraph_error_t igraph_bipartite_game_gnp(igraph_t *graph, igraph_vector_bool_t *types, - igraph_integer_t n1, igraph_integer_t n2, - igraph_real_t p, igraph_bool_t directed, - igraph_neimode_t mode); - -IGRAPH_EXPORT igraph_error_t igraph_bipartite_game_gnm(igraph_t *graph, igraph_vector_bool_t *types, - igraph_integer_t n1, igraph_integer_t n2, - igraph_integer_t m, igraph_bool_t directed, - igraph_neimode_t mode); - -/* Deprecated functions: */ - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_incidence( - igraph_t *graph, igraph_vector_bool_t *types, const igraph_matrix_t *incidence, - igraph_bool_t directed, igraph_neimode_t mode, igraph_bool_t multiple -); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_get_incidence( - const igraph_t *graph, const igraph_vector_bool_t *types, igraph_matrix_t *res, - igraph_vector_int_t *row_ids, igraph_vector_int_t *col_ids -); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_bipartite_game( +IGRAPH_EXPORT igraph_error_t igraph_bipartite_game_gnp( + igraph_t *graph, + igraph_vector_bool_t *types, + igraph_int_t n1, igraph_int_t n2, igraph_real_t p, + igraph_bool_t directed, igraph_neimode_t mode, + igraph_edge_type_sw_t allowed_edge_types, + igraph_bool_t edge_labeled); + +IGRAPH_EXPORT igraph_error_t igraph_bipartite_game_gnm( + igraph_t *graph, + igraph_vector_bool_t *types, + igraph_int_t n1, igraph_int_t n2, igraph_int_t m, + igraph_bool_t directed, igraph_neimode_t mode, + igraph_edge_type_sw_t allowed_edge_types, + igraph_bool_t edge_labeled); + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_bipartite_iea_game( igraph_t *graph, igraph_vector_bool_t *types, - igraph_erdos_renyi_t type, - igraph_integer_t n1, igraph_integer_t n2, - igraph_real_t p, igraph_integer_t m, - igraph_bool_t directed, igraph_neimode_t mode -); + igraph_int_t n1, igraph_int_t n2, igraph_int_t m, + igraph_bool_t directed, igraph_neimode_t mode); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_bitset.h b/src/vendor/cigraph/include/igraph_bitset.h index a1e028409ea..26962435132 100644 --- a/src/vendor/cigraph/include/igraph_bitset.h +++ b/src/vendor/cigraph/include/igraph_bitset.h @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2024 The igraph development team + igraph library. + Copyright (C) 2024-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA + along with this program. If not, see . */ #ifndef IGRAPH_BITSET_H @@ -24,13 +22,14 @@ #include "igraph_decls.h" #include "igraph_error.h" #include "igraph_vector.h" +#include "igraph_types.h" /* Required for MSVC intrinsics such as __popcnt and __popcnt64 */ #ifdef _MSC_VER #include "intrin.h" #endif -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \ingroup bitset @@ -159,7 +158,7 @@ __BEGIN_DECLS * * Time complexity: O(1). */ -#define IGRAPH_BIT_NSLOTS(nbits) ((nbits + IGRAPH_INTEGER_SIZE - (igraph_integer_t)(1)) / IGRAPH_INTEGER_SIZE) +#define IGRAPH_BIT_NSLOTS(nbits) ((nbits + IGRAPH_INTEGER_SIZE - (igraph_int_t)(1)) / IGRAPH_INTEGER_SIZE) #if defined(__GNUC__) @@ -184,24 +183,24 @@ __BEGIN_DECLS #ifdef HAVE__POPCNT #define IGRAPH_I_POPCOUNT32(x) __popcnt(x) #else - igraph_integer_t igraph_i_popcnt(igraph_uint_t x); + igraph_int_t igraph_i_popcnt(igraph_uint_t x); #define IGRAPH_I_POPCOUNT32(x) igraph_i_popcnt(x) #endif #elif IGRAPH_INTEGER_SIZE == 64 #ifdef HAVE__POPCNT64 #define IGRAPH_I_POPCOUNT64(x) __popcnt64(x) #else - igraph_integer_t igraph_i_popcnt(igraph_uint_t x); + igraph_int_t igraph_i_popcnt(igraph_uint_t x); #define IGRAPH_I_POPCOUNT64(x) igraph_i_popcnt(x) #endif #else #error "Unexpected IGRAPH_INTEGER_SIZE value." #endif - igraph_integer_t igraph_i_ctz32(igraph_uint_t x); - igraph_integer_t igraph_i_ctz64(igraph_uint_t x); - igraph_integer_t igraph_i_clz32(igraph_uint_t x); - igraph_integer_t igraph_i_clz64(igraph_uint_t x); + igraph_int_t igraph_i_ctz32(igraph_uint_t x); + igraph_int_t igraph_i_ctz64(igraph_uint_t x); + igraph_int_t igraph_i_clz32(igraph_uint_t x); + igraph_int_t igraph_i_clz64(igraph_uint_t x); #define IGRAPH_I_CTZ32(x) igraph_i_ctz32(x) #define IGRAPH_I_CTZ64(x) igraph_i_ctz64(x) #define IGRAPH_I_CLZ32(x) igraph_i_clz32(x) @@ -226,24 +225,24 @@ __BEGIN_DECLS #define IGRAPH_CTO(x) IGRAPH_CTZ(~(x)) typedef struct { - igraph_integer_t size; + igraph_int_t size; igraph_uint_t *stor_begin; igraph_uint_t *stor_end; } igraph_bitset_t; -IGRAPH_EXPORT igraph_error_t igraph_bitset_init(igraph_bitset_t *bitset, igraph_integer_t size); +IGRAPH_EXPORT igraph_error_t igraph_bitset_init(igraph_bitset_t *bitset, igraph_int_t size); IGRAPH_EXPORT void igraph_bitset_destroy(igraph_bitset_t *bitset); IGRAPH_EXPORT igraph_error_t igraph_bitset_init_copy(igraph_bitset_t *dest, const igraph_bitset_t *src); IGRAPH_EXPORT igraph_error_t igraph_bitset_update(igraph_bitset_t *dest, const igraph_bitset_t *src); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_bitset_capacity(const igraph_bitset_t *bitset); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_bitset_size(const igraph_bitset_t *bitset); -IGRAPH_EXPORT igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_integer_t capacity); -IGRAPH_EXPORT igraph_error_t igraph_bitset_resize(igraph_bitset_t *bitset, igraph_integer_t new_size); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_bitset_popcount(const igraph_bitset_t *bitset); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_bitset_countl_zero(const igraph_bitset_t *bitset); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_bitset_countl_one(const igraph_bitset_t *bitset); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_bitset_countr_zero(const igraph_bitset_t *bitset); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_bitset_countr_one(const igraph_bitset_t *bitset); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_capacity(const igraph_bitset_t *bitset); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_size(const igraph_bitset_t *bitset); +IGRAPH_EXPORT igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_int_t capacity); +IGRAPH_EXPORT igraph_error_t igraph_bitset_resize(igraph_bitset_t *bitset, igraph_int_t new_size); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_popcount(const igraph_bitset_t *bitset); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_countl_zero(const igraph_bitset_t *bitset); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_countl_one(const igraph_bitset_t *bitset); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_countr_zero(const igraph_bitset_t *bitset); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_countr_one(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_bitset_is_all_zero(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_bitset_is_all_one(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_bitset_is_any_zero(const igraph_bitset_t *bitset); @@ -261,6 +260,6 @@ IGRAPH_EXPORT igraph_error_t igraph_bitset_print(const igraph_bitset_t *bitset); do { IGRAPH_CHECK(igraph_bitset_init(bitset, size)); \ IGRAPH_FINALLY(igraph_bitset_destroy, bitset); } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_BITSET_H */ diff --git a/src/vendor/cigraph/include/igraph_bitset_list.h b/src/vendor/cigraph/include/igraph_bitset_list.h index 68629d73d83..dd97dda28ff 100644 --- a/src/vendor/cigraph/include/igraph_bitset_list.h +++ b/src/vendor/cigraph/include/igraph_bitset_list.h @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2024 The igraph development team + igraph library. + Copyright (C) 2024-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA + along with this program. If not, see . */ #ifndef IGRAPH_BITSET_LIST_H @@ -24,9 +22,8 @@ #include "igraph_bitset.h" #include "igraph_decls.h" #include "igraph_error.h" -#include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* List of graphs */ @@ -44,6 +41,6 @@ __BEGIN_DECLS do { IGRAPH_CHECK(igraph_bitset_list_init(v, size)); \ IGRAPH_FINALLY(igraph_bitset_list_destroy, v); } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_blas.h b/src/vendor/cigraph/include/igraph_blas.h index ae7daa47d24..f10a2ca0e0d 100644 --- a/src/vendor/cigraph/include/igraph_blas.h +++ b/src/vendor/cigraph/include/igraph_blas.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2007-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_BLAS_H @@ -30,7 +25,7 @@ #include "igraph_vector.h" #include "igraph_matrix.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \section about_blas BLAS interface in igraph @@ -67,6 +62,6 @@ IGRAPH_EXPORT igraph_real_t igraph_blas_dnrm2(const igraph_vector_t *v); IGRAPH_EXPORT igraph_error_t igraph_blas_ddot(const igraph_vector_t *v1, const igraph_vector_t *v2, igraph_real_t *res); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_centrality.h b/src/vendor/cigraph/include/igraph_centrality.h index 816815b135a..04fe3251c5b 100644 --- a/src/vendor/cigraph/include/igraph_centrality.h +++ b/src/vendor/cigraph/include/igraph_centrality.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,24 +13,21 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_CENTRALITY_H #define IGRAPH_CENTRALITY_H #include "igraph_decls.h" +#include "igraph_arpack.h" #include "igraph_constants.h" -#include "igraph_error.h" -#include "igraph_types.h" #include "igraph_datatype.h" #include "igraph_iterators.h" -#include "igraph_arpack.h" +#include "igraph_error.h" +#include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Centrality */ @@ -40,45 +35,62 @@ __BEGIN_DECLS IGRAPH_EXPORT igraph_error_t igraph_closeness(const igraph_t *graph, igraph_vector_t *res, igraph_vector_int_t *reachable_count, igraph_bool_t *all_reachable, - const igraph_vs_t vids, igraph_neimode_t mode, + igraph_vs_t vids, igraph_neimode_t mode, const igraph_vector_t *weights, igraph_bool_t normalized); IGRAPH_EXPORT igraph_error_t igraph_closeness_cutoff(const igraph_t *graph, igraph_vector_t *res, igraph_vector_int_t *reachable_count, igraph_bool_t *all_reachable, - const igraph_vs_t vids, igraph_neimode_t mode, + igraph_vs_t vids, igraph_neimode_t mode, const igraph_vector_t *weights, igraph_bool_t normalized, igraph_real_t cutoff); IGRAPH_EXPORT igraph_error_t igraph_harmonic_centrality(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, igraph_neimode_t mode, + igraph_vs_t vids, igraph_neimode_t mode, const igraph_vector_t *weights, igraph_bool_t normalized); IGRAPH_EXPORT igraph_error_t igraph_harmonic_centrality_cutoff(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, igraph_neimode_t mode, + igraph_vs_t vids, igraph_neimode_t mode, const igraph_vector_t *weights, igraph_bool_t normalized, igraph_real_t cutoff); -IGRAPH_EXPORT igraph_error_t igraph_betweenness(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, igraph_bool_t directed, - const igraph_vector_t *weights); -IGRAPH_EXPORT igraph_error_t igraph_betweenness_cutoff(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, igraph_bool_t directed, - const igraph_vector_t *weights, igraph_real_t cutoff); -IGRAPH_EXPORT igraph_error_t igraph_edge_betweenness(const igraph_t *graph, igraph_vector_t *result, - igraph_bool_t directed, - const igraph_vector_t *weights); -IGRAPH_EXPORT igraph_error_t igraph_edge_betweenness_cutoff(const igraph_t *graph, igraph_vector_t *result, - igraph_bool_t directed, - const igraph_vector_t *weights, igraph_real_t cutoff); -IGRAPH_EXPORT igraph_error_t igraph_betweenness_subset(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, igraph_bool_t directed, - const igraph_vs_t sources, const igraph_vs_t targets, - const igraph_vector_t *weights); -IGRAPH_EXPORT igraph_error_t igraph_edge_betweenness_subset(const igraph_t *graph, igraph_vector_t *res, - const igraph_es_t eids, igraph_bool_t directed, - const igraph_vs_t sources, const igraph_vs_t targets, - const igraph_vector_t *weights); +IGRAPH_EXPORT igraph_error_t igraph_betweenness( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, + igraph_vs_t vids, + igraph_bool_t directed, igraph_bool_t normalized); + +IGRAPH_EXPORT igraph_error_t igraph_betweenness_cutoff( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, + igraph_vs_t vids, + igraph_bool_t directed, igraph_bool_t normalized, + igraph_real_t cutoff); + +IGRAPH_EXPORT igraph_error_t igraph_edge_betweenness( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, igraph_es_t eids, + igraph_bool_t directed, igraph_bool_t normalized); + +IGRAPH_EXPORT igraph_error_t igraph_edge_betweenness_cutoff( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, igraph_es_t eids, + igraph_bool_t directed, igraph_bool_t normalized, + igraph_real_t cutoff); + +IGRAPH_EXPORT igraph_error_t igraph_betweenness_subset( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, + igraph_vs_t sources, igraph_vs_t targets, + igraph_vs_t vids, + igraph_bool_t directed, igraph_bool_t normalized); + +IGRAPH_EXPORT igraph_error_t igraph_edge_betweenness_subset( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, + igraph_vs_t sources, igraph_vs_t targets, + igraph_es_t eids, + igraph_bool_t directed, igraph_bool_t normalized); /** * \typedef igraph_pagerank_algo_t @@ -97,36 +109,42 @@ typedef enum { IGRAPH_PAGERANK_ALGO_PRPACK = 2 } igraph_pagerank_algo_t; -IGRAPH_EXPORT igraph_error_t igraph_pagerank(const igraph_t *graph, igraph_pagerank_algo_t algo, - igraph_vector_t *vector, - igraph_real_t *value, const igraph_vs_t vids, - igraph_bool_t directed, igraph_real_t damping, - const igraph_vector_t *weights, igraph_arpack_options_t *options); -IGRAPH_EXPORT igraph_error_t igraph_personalized_pagerank(const igraph_t *graph, - igraph_pagerank_algo_t algo, igraph_vector_t *vector, - igraph_real_t *value, const igraph_vs_t vids, - igraph_bool_t directed, igraph_real_t damping, - const igraph_vector_t *reset, - const igraph_vector_t *weights, igraph_arpack_options_t *options); -IGRAPH_EXPORT igraph_error_t igraph_personalized_pagerank_vs(const igraph_t *graph, - igraph_pagerank_algo_t algo, - igraph_vector_t *vector, - igraph_real_t *value, const igraph_vs_t vids, - igraph_bool_t directed, igraph_real_t damping, - igraph_vs_t reset_vids, - const igraph_vector_t *weights, igraph_arpack_options_t *options); +IGRAPH_EXPORT igraph_error_t igraph_pagerank( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *vector, igraph_real_t *value, + igraph_real_t damping, igraph_bool_t directed, + igraph_vs_t vids, + igraph_pagerank_algo_t algo, + igraph_arpack_options_t *options); + +IGRAPH_EXPORT igraph_error_t igraph_personalized_pagerank( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *vector, igraph_real_t *value, + const igraph_vector_t *reset, + igraph_real_t damping, igraph_bool_t directed, + igraph_vs_t vids, + igraph_pagerank_algo_t algo, + igraph_arpack_options_t *options); + +IGRAPH_EXPORT igraph_error_t igraph_personalized_pagerank_vs( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *vector, igraph_real_t *value, + igraph_vs_t reset_vids, igraph_real_t damping, + igraph_bool_t directed, igraph_vs_t vids, + igraph_pagerank_algo_t algo, + igraph_arpack_options_t *options); IGRAPH_EXPORT igraph_error_t igraph_eigenvector_centrality(const igraph_t *graph, igraph_vector_t *vector, - igraph_real_t *value, - igraph_bool_t directed, igraph_bool_t scale, - const igraph_vector_t *weights, - igraph_arpack_options_t *options); + igraph_real_t *value, + igraph_neimode_t mode, + const igraph_vector_t *weights, + igraph_arpack_options_t *options); IGRAPH_EXPORT igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, igraph_vector_t *hub_vector, - igraph_vector_t *authority_vector, - igraph_real_t *value, igraph_bool_t scale, - const igraph_vector_t *weights, - igraph_arpack_options_t *options); + igraph_vector_t *authority_vector, + igraph_real_t *value, + const igraph_vector_t *weights, + igraph_arpack_options_t *options); IGRAPH_EXPORT igraph_error_t igraph_constraint(const igraph_t *graph, igraph_vector_t *res, igraph_vs_t vids, const igraph_vector_t *weights); @@ -139,14 +157,14 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t igraph_centralization(const igr igraph_bool_t normalized); IGRAPH_EXPORT igraph_error_t igraph_centralization_degree(const igraph_t *graph, igraph_vector_t *res, - igraph_neimode_t mode, igraph_bool_t loops, + igraph_neimode_t mode, igraph_loops_t loops, igraph_real_t *centralization, igraph_real_t *theoretical_max, igraph_bool_t normalized); IGRAPH_EXPORT igraph_error_t igraph_centralization_degree_tmax(const igraph_t *graph, - igraph_integer_t nodes, + igraph_int_t nodes, igraph_neimode_t mode, - igraph_bool_t loops, + igraph_loops_t loops, igraph_real_t *res); IGRAPH_EXPORT igraph_error_t igraph_centralization_betweenness(const igraph_t *graph, @@ -156,7 +174,7 @@ IGRAPH_EXPORT igraph_error_t igraph_centralization_betweenness(const igraph_t *g igraph_real_t *theoretical_max, igraph_bool_t normalized); IGRAPH_EXPORT igraph_error_t igraph_centralization_betweenness_tmax(const igraph_t *graph, - igraph_integer_t nodes, + igraph_int_t nodes, igraph_bool_t directed, igraph_real_t *res); @@ -167,38 +185,23 @@ IGRAPH_EXPORT igraph_error_t igraph_centralization_closeness(const igraph_t *gra igraph_real_t *theoretical_max, igraph_bool_t normalized); IGRAPH_EXPORT igraph_error_t igraph_centralization_closeness_tmax(const igraph_t *graph, - igraph_integer_t nodes, + igraph_int_t nodes, igraph_neimode_t mode, igraph_real_t *res); -IGRAPH_EXPORT igraph_error_t igraph_centralization_eigenvector_centrality( - const igraph_t *graph, - igraph_vector_t *vector, - igraph_real_t *value, - igraph_bool_t directed, - igraph_bool_t scale, - igraph_arpack_options_t *options, - igraph_real_t *centralization, - igraph_real_t *theoretical_max, - igraph_bool_t normalized); -IGRAPH_EXPORT igraph_error_t igraph_centralization_eigenvector_centrality_tmax( - const igraph_t *graph, - igraph_integer_t nodes, - igraph_bool_t directed, - igraph_bool_t scale, - igraph_real_t *res); - -/* Deprecated functions: */ - -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_hub_score(const igraph_t *graph, igraph_vector_t *vector, - igraph_real_t *value, igraph_bool_t scale, - const igraph_vector_t *weights, - igraph_arpack_options_t *options); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_authority_score(const igraph_t *graph, igraph_vector_t *vector, - igraph_real_t *value, igraph_bool_t scale, - const igraph_vector_t *weights, - igraph_arpack_options_t *options); - -__END_DECLS +IGRAPH_EXPORT igraph_error_t igraph_centralization_eigenvector_centrality(const igraph_t *graph, + igraph_vector_t *vector, + igraph_real_t *value, + igraph_neimode_t mode, + igraph_arpack_options_t *options, + igraph_real_t *centralization, + igraph_real_t *theoretical_max, + igraph_bool_t normalized); +IGRAPH_EXPORT igraph_error_t igraph_centralization_eigenvector_centrality_tmax(const igraph_t *graph, + igraph_int_t nodes, + igraph_neimode_t mode, + igraph_real_t *res); + +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_cliques.h b/src/vendor/cigraph/include/igraph_cliques.h index 141dd261f23..c76ebd147bb 100644 --- a/src/vendor/cigraph/include/igraph_cliques.h +++ b/src/vendor/cigraph/include/igraph_cliques.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_CLIQUES_H @@ -30,57 +25,86 @@ #include "igraph_datatype.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Cliques, maximal independent vertex sets */ /* -------------------------------------------------- */ IGRAPH_EXPORT igraph_error_t igraph_maximal_cliques( - const igraph_t *graph, igraph_vector_int_list_t *res, - igraph_integer_t min_size, igraph_integer_t max_size -); -IGRAPH_EXPORT igraph_error_t igraph_maximal_cliques_file(const igraph_t *graph, - FILE *outfile, - igraph_integer_t min_size, - igraph_integer_t max_size); -IGRAPH_EXPORT igraph_error_t igraph_maximal_cliques_count(const igraph_t *graph, - igraph_integer_t *res, - igraph_integer_t min_size, - igraph_integer_t max_size); + const igraph_t *graph, igraph_vector_int_list_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +IGRAPH_EXPORT igraph_error_t igraph_maximal_cliques_file( + const igraph_t *graph, + FILE *outfile, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +IGRAPH_EXPORT igraph_error_t igraph_maximal_cliques_count( + const igraph_t *graph, + igraph_int_t *res, + igraph_int_t min_size, igraph_int_t max_size); + IGRAPH_EXPORT igraph_error_t igraph_maximal_cliques_subset( - const igraph_t *graph, const igraph_vector_int_t *subset, - igraph_vector_int_list_t *res, igraph_integer_t *no, - FILE *outfile, igraph_integer_t min_size, igraph_integer_t max_size -); -IGRAPH_EXPORT igraph_error_t igraph_maximal_cliques_hist(const igraph_t *graph, - igraph_vector_t *hist, - igraph_integer_t min_size, - igraph_integer_t max_size); - -IGRAPH_EXPORT igraph_error_t igraph_cliques(const igraph_t *graph, igraph_vector_int_list_t *res, - igraph_integer_t min_size, igraph_integer_t max_size); -IGRAPH_EXPORT igraph_error_t igraph_clique_size_hist(const igraph_t *graph, igraph_vector_t *hist, - igraph_integer_t min_size, igraph_integer_t max_size); -IGRAPH_EXPORT igraph_error_t igraph_largest_cliques(const igraph_t *graph, - igraph_vector_int_list_t *cliques); -IGRAPH_EXPORT igraph_error_t igraph_clique_number(const igraph_t *graph, igraph_integer_t *no); -IGRAPH_EXPORT igraph_error_t igraph_weighted_cliques(const igraph_t *graph, - const igraph_vector_t *vertex_weights, igraph_vector_int_list_t *res, - igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal); -IGRAPH_EXPORT igraph_error_t igraph_largest_weighted_cliques(const igraph_t *graph, - const igraph_vector_t *vertex_weights, igraph_vector_int_list_t *res); -IGRAPH_EXPORT igraph_error_t igraph_weighted_clique_number(const igraph_t *graph, - const igraph_vector_t *vertex_weights, igraph_real_t *res); -IGRAPH_EXPORT igraph_error_t igraph_independent_vertex_sets(const igraph_t *graph, - igraph_vector_int_list_t *res, - igraph_integer_t min_size, - igraph_integer_t max_size); -IGRAPH_EXPORT igraph_error_t igraph_largest_independent_vertex_sets(const igraph_t *graph, - igraph_vector_int_list_t *res); -IGRAPH_EXPORT igraph_error_t igraph_maximal_independent_vertex_sets(const igraph_t *graph, - igraph_vector_int_list_t *res); -IGRAPH_EXPORT igraph_error_t igraph_independence_number(const igraph_t *graph, igraph_integer_t *no); + const igraph_t *graph, const igraph_vector_int_t *subset, + igraph_vector_int_list_t *res, igraph_int_t *no, FILE *outfile, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +IGRAPH_EXPORT igraph_error_t igraph_maximal_cliques_hist( + const igraph_t *graph, + igraph_vector_t *hist, + igraph_int_t min_size, igraph_int_t max_size); + +IGRAPH_EXPORT igraph_error_t igraph_cliques( + const igraph_t *graph, igraph_vector_int_list_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +IGRAPH_EXPORT igraph_error_t igraph_clique_size_hist( + const igraph_t *graph, igraph_vector_t *hist, + igraph_int_t min_size, igraph_int_t max_size); + +IGRAPH_EXPORT igraph_error_t igraph_largest_cliques( + const igraph_t *graph, + igraph_vector_int_list_t *cliques); + +IGRAPH_EXPORT igraph_error_t igraph_clique_number(const igraph_t *graph, igraph_int_t *no); + +IGRAPH_EXPORT igraph_error_t igraph_weighted_cliques( + const igraph_t *graph, const igraph_vector_t *vertex_weights, + igraph_vector_int_list_t *res, + igraph_bool_t maximal, + igraph_real_t min_weight, igraph_real_t max_weight, + igraph_int_t max_results); + +IGRAPH_EXPORT igraph_error_t igraph_largest_weighted_cliques( + const igraph_t *graph, const igraph_vector_t *vertex_weights, + igraph_vector_int_list_t *res); + +IGRAPH_EXPORT igraph_error_t igraph_weighted_clique_number( + const igraph_t *graph, const igraph_vector_t *vertex_weights, + igraph_real_t *res); + +IGRAPH_EXPORT igraph_error_t igraph_independent_vertex_sets( + const igraph_t *graph, + igraph_vector_int_list_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +IGRAPH_EXPORT igraph_error_t igraph_largest_independent_vertex_sets( + const igraph_t *graph, + igraph_vector_int_list_t *res); + +IGRAPH_EXPORT igraph_error_t igraph_maximal_independent_vertex_sets( + const igraph_t *graph, + igraph_vector_int_list_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +IGRAPH_EXPORT igraph_error_t igraph_independence_number(const igraph_t *graph, igraph_int_t *no); /** * \typedef igraph_clique_handler_t @@ -102,15 +126,16 @@ IGRAPH_EXPORT igraph_error_t igraph_independence_number(const igraph_t *graph, i */ typedef igraph_error_t igraph_clique_handler_t(const igraph_vector_int_t *clique, void *arg); -IGRAPH_EXPORT igraph_error_t igraph_cliques_callback(const igraph_t *graph, - igraph_integer_t min_size, igraph_integer_t max_size, - igraph_clique_handler_t *cliquehandler_fn, void *arg); - -IGRAPH_EXPORT igraph_error_t igraph_maximal_cliques_callback(const igraph_t *graph, - igraph_clique_handler_t *cliquehandler_fn, void *arg, - igraph_integer_t min_size, igraph_integer_t max_size); +IGRAPH_EXPORT igraph_error_t igraph_cliques_callback( + const igraph_t *graph, + igraph_int_t min_size, igraph_int_t max_size, + igraph_clique_handler_t *cliquehandler_fn, void *arg); +IGRAPH_EXPORT igraph_error_t igraph_maximal_cliques_callback( + const igraph_t *graph, + igraph_int_t min_size, igraph_int_t max_size, + igraph_clique_handler_t *cliquehandler_fn, void *arg); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_cocitation.h b/src/vendor/cigraph/include/igraph_cocitation.h index 4dfd406ab94..706ca9a8828 100644 --- a/src/vendor/cigraph/include/igraph_cocitation.h +++ b/src/vendor/cigraph/include/igraph_cocitation.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_COCITATION_H @@ -31,37 +26,37 @@ #include "igraph_datatype.h" #include "igraph_iterators.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Cocitation and other similarity measures */ /* -------------------------------------------------- */ IGRAPH_EXPORT igraph_error_t igraph_cocitation(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t vids); + igraph_vs_t vids); IGRAPH_EXPORT igraph_error_t igraph_bibcoupling(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t vids); + igraph_vs_t vids); IGRAPH_EXPORT igraph_error_t igraph_similarity_jaccard(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t vids, igraph_neimode_t mode, - igraph_bool_t loops); + igraph_vs_t vit_from, igraph_vs_t vit_to, + igraph_neimode_t mode, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_similarity_jaccard_pairs(const igraph_t *graph, igraph_vector_t *res, const igraph_vector_int_t *pairs, igraph_neimode_t mode, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_similarity_jaccard_es(const igraph_t *graph, igraph_vector_t *res, - const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops); + igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_similarity_dice(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t vids, igraph_neimode_t mode, - igraph_bool_t loops); + igraph_vs_t vit_from, igraph_vs_t vit_to, + igraph_neimode_t mode, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_similarity_dice_pairs(const igraph_t *graph, igraph_vector_t *res, const igraph_vector_int_t *pairs, igraph_neimode_t mode, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_similarity_dice_es(const igraph_t *graph, igraph_vector_t *res, - const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops); + igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_similarity_inverse_log_weighted(const igraph_t *graph, - igraph_matrix_t *res, const igraph_vs_t vids, + igraph_matrix_t *res, igraph_vs_t vids, igraph_neimode_t mode); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_cohesive_blocks.h b/src/vendor/cigraph/include/igraph_cohesive_blocks.h index a52cf68f733..924da037a62 100644 --- a/src/vendor/cigraph/include/igraph_cohesive_blocks.h +++ b/src/vendor/cigraph/include/igraph_cohesive_blocks.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2010-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2010-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_COHESIVE_BLOCKS_H @@ -30,7 +25,7 @@ #include "igraph_vector.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_EXPORT igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, igraph_vector_int_list_t *blocks, @@ -38,6 +33,6 @@ IGRAPH_EXPORT igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, igraph_vector_int_t *parent, igraph_t *block_tree); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_coloring.h b/src/vendor/cigraph/include/igraph_coloring.h index d22611e8006..1831ad61fa1 100644 --- a/src/vendor/cigraph/include/igraph_coloring.h +++ b/src/vendor/cigraph/include/igraph_coloring.h @@ -1,21 +1,19 @@ /* - Heuristic graph coloring algorithms. - Copyright (C) 2017 Szabolcs Horvat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA + igraph library. + Copyright (C) 2017-2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #ifndef IGRAPH_COLORING_H @@ -25,7 +23,7 @@ #include "igraph_datatype.h" #include "igraph_error.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \typedef igraph_coloring_greedy_t @@ -54,6 +52,6 @@ IGRAPH_EXPORT igraph_error_t igraph_is_vertex_coloring(const igraph_t *graph, co IGRAPH_EXPORT igraph_error_t igraph_is_bipartite_coloring(const igraph_t *graph, const igraph_vector_bool_t *types, igraph_bool_t *res, igraph_neimode_t *mode); IGRAPH_EXPORT igraph_error_t igraph_is_edge_coloring(const igraph_t *graph, const igraph_vector_int_t *types, igraph_bool_t *res); -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_COLORING_H */ diff --git a/src/vendor/cigraph/include/igraph_community.h b/src/vendor/cigraph/include/igraph_community.h index c38cef130b2..c8cab386534 100644 --- a/src/vendor/cigraph/include/igraph_community.h +++ b/src/vendor/cigraph/include/igraph_community.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_COMMUNITY_H @@ -33,7 +28,7 @@ #include "igraph_types.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* K-Cores and K-Truss */ @@ -53,9 +48,10 @@ IGRAPH_EXPORT igraph_error_t igraph_trussness( /* TODO: */ IGRAPH_EXPORT igraph_error_t igraph_community_optimal_modularity(const igraph_t *graph, - igraph_real_t *modularity, - igraph_vector_int_t *membership, - const igraph_vector_t *weights); + const igraph_vector_t *weights, + igraph_real_t resolution, + igraph_real_t *modularity, + igraph_vector_int_t *membership); IGRAPH_EXPORT igraph_error_t igraph_community_spinglass(const igraph_t *graph, const igraph_vector_t *weights, @@ -63,7 +59,7 @@ IGRAPH_EXPORT igraph_error_t igraph_community_spinglass(const igraph_t *graph, igraph_real_t *temperature, igraph_vector_int_t *membership, igraph_vector_int_t *csize, - igraph_integer_t spins, + igraph_int_t spins, igraph_bool_t parupdate, igraph_real_t starttemp, igraph_real_t stoptemp, @@ -75,27 +71,29 @@ IGRAPH_EXPORT igraph_error_t igraph_community_spinglass(const igraph_t *graph, IGRAPH_EXPORT igraph_error_t igraph_community_spinglass_single(const igraph_t *graph, const igraph_vector_t *weights, - igraph_integer_t vertex, + igraph_int_t vertex, igraph_vector_int_t *community, igraph_real_t *cohesion, igraph_real_t *adhesion, - igraph_integer_t *inner_links, - igraph_integer_t *outer_links, - igraph_integer_t spins, + igraph_real_t *inner_links, + igraph_real_t *outer_links, + igraph_int_t spins, igraph_spincomm_update_t update_rule, igraph_real_t gamma); IGRAPH_EXPORT igraph_error_t igraph_community_walktrap(const igraph_t *graph, const igraph_vector_t *weights, - igraph_integer_t steps, + igraph_int_t steps, igraph_matrix_int_t *merges, igraph_vector_t *modularity, igraph_vector_int_t *membership); -IGRAPH_EXPORT igraph_error_t igraph_community_infomap(const igraph_t * graph, - const igraph_vector_t *e_weights, - const igraph_vector_t *v_weights, - igraph_integer_t nb_trials, +IGRAPH_EXPORT igraph_error_t igraph_community_infomap(const igraph_t *graph, + const igraph_vector_t *edge_weights, + const igraph_vector_t *vertex_weights, + igraph_int_t nb_trials, + igraph_bool_t is_regularized, + igraph_real_t regularization_strength, igraph_vector_int_t *membership, igraph_real_t *codelength); @@ -107,9 +105,10 @@ IGRAPH_EXPORT igraph_error_t igraph_community_edge_betweenness(const igraph_t *g igraph_vector_t *modularity, igraph_vector_int_t *membership, igraph_bool_t directed, - const igraph_vector_t *weights); + const igraph_vector_t *weights, + const igraph_vector_t *lengths); IGRAPH_EXPORT igraph_error_t igraph_community_eb_get_merges(const igraph_t *graph, - const igraph_bool_t directed, + igraph_bool_t directed, const igraph_vector_int_t *edges, const igraph_vector_t *weights, igraph_matrix_int_t *merges, @@ -124,16 +123,16 @@ IGRAPH_EXPORT igraph_error_t igraph_community_fastgreedy(const igraph_t *graph, igraph_vector_int_t *membership); IGRAPH_EXPORT igraph_error_t igraph_community_to_membership(const igraph_matrix_int_t *merges, - igraph_integer_t nodes, - igraph_integer_t steps, + igraph_int_t nodes, + igraph_int_t steps, igraph_vector_int_t *membership, igraph_vector_int_t *csize); IGRAPH_EXPORT igraph_error_t igraph_le_community_to_membership(const igraph_matrix_int_t *merges, - igraph_integer_t steps, + igraph_int_t steps, igraph_vector_int_t *membership, igraph_vector_int_t *csize); -IGRAPH_EXPORT igraph_error_t igraph_community_voronoi( +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_community_voronoi( const igraph_t *graph, igraph_vector_int_t *membership, igraph_vector_int_t *generators, igraph_real_t *modularity, const igraph_vector_t *lengths, const igraph_vector_t *weights, @@ -142,19 +141,19 @@ IGRAPH_EXPORT igraph_error_t igraph_community_voronoi( IGRAPH_EXPORT igraph_error_t igraph_modularity(const igraph_t *graph, const igraph_vector_int_t *membership, const igraph_vector_t *weights, - const igraph_real_t resolution, - const igraph_bool_t directed, + igraph_real_t resolution, + igraph_bool_t directed, igraph_real_t *modularity); IGRAPH_EXPORT igraph_error_t igraph_modularity_matrix(const igraph_t *graph, const igraph_vector_t *weights, - const igraph_real_t resolution, + igraph_real_t resolution, igraph_matrix_t *modmat, igraph_bool_t directed); IGRAPH_EXPORT igraph_error_t igraph_reindex_membership(igraph_vector_int_t *membership, igraph_vector_int_t *new_to_old, - igraph_integer_t *nb_clusters); + igraph_int_t *nb_clusters); typedef enum { IGRAPH_LEVC_HIST_SPLIT = 1, IGRAPH_LEVC_HIST_FAILED, @@ -192,7 +191,7 @@ typedef enum { IGRAPH_LEVC_HIST_SPLIT = 1, typedef igraph_error_t igraph_community_leading_eigenvector_callback_t( const igraph_vector_int_t *membership, - igraph_integer_t comm, + igraph_int_t comm, igraph_real_t eigenvalue, const igraph_vector_t *eigenvector, igraph_arpack_function_t *arpack_multiplier, @@ -203,44 +202,66 @@ IGRAPH_EXPORT igraph_error_t igraph_community_leading_eigenvector(const igraph_t const igraph_vector_t *weights, igraph_matrix_int_t *merges, igraph_vector_int_t *membership, - igraph_integer_t steps, + igraph_int_t steps, igraph_arpack_options_t *options, igraph_real_t *modularity, igraph_bool_t start, igraph_vector_t *eigenvalues, igraph_vector_list_t *eigenvectors, - igraph_vector_t *history, + igraph_vector_int_t *history, igraph_community_leading_eigenvector_callback_t *callback, void *callback_extra); IGRAPH_EXPORT igraph_error_t igraph_community_fluid_communities(const igraph_t *graph, - igraph_integer_t no_of_communities, + igraph_int_t no_of_communities, igraph_vector_int_t *membership); + IGRAPH_EXPORT igraph_error_t igraph_community_label_propagation(const igraph_t *graph, igraph_vector_int_t *membership, igraph_neimode_t mode, const igraph_vector_t *weights, const igraph_vector_int_t *initial, - const igraph_vector_bool_t *fixed); + const igraph_vector_bool_t *fixed, + igraph_lpa_variant_t variant); IGRAPH_EXPORT igraph_error_t igraph_community_multilevel(const igraph_t *graph, const igraph_vector_t *weights, - const igraph_real_t resolution, + igraph_real_t resolution, igraph_vector_int_t *membership, igraph_matrix_int_t *memberships, igraph_vector_t *modularity); -IGRAPH_EXPORT igraph_error_t igraph_community_leiden(const igraph_t *graph, - const igraph_vector_t *edge_weights, - const igraph_vector_t *node_weights, - const igraph_real_t resolution_parameter, - const igraph_real_t beta, - const igraph_bool_t start, - const igraph_integer_t n_iterations, - igraph_vector_int_t *membership, - igraph_integer_t *nb_clusters, - igraph_real_t *quality); +typedef enum { + IGRAPH_LEIDEN_OBJECTIVE_MODULARITY = 0, + IGRAPH_LEIDEN_OBJECTIVE_CPM, + IGRAPH_LEIDEN_OBJECTIVE_ER +} igraph_leiden_objective_t; + +IGRAPH_EXPORT igraph_error_t igraph_community_leiden( + const igraph_t *graph, + const igraph_vector_t *edge_weights, + const igraph_vector_t *vertex_out_weights, + const igraph_vector_t *vertex_in_weights, + igraph_real_t resolution, + igraph_real_t beta, + igraph_bool_t start, + igraph_int_t n_iterations, + igraph_vector_int_t *membership, + igraph_int_t *nb_clusters, igraph_real_t *quality); + +IGRAPH_EXPORT igraph_error_t igraph_community_leiden_simple( + const igraph_t *graph, + const igraph_vector_t *weights, + igraph_leiden_objective_t objective, + igraph_real_t resolution, + igraph_real_t beta, + igraph_bool_t start, + igraph_int_t n_iterations, + igraph_vector_int_t *membership, + igraph_int_t *nb_clusters, + igraph_real_t *quality); + /* -------------------------------------------------- */ /* Community Structure Comparison */ /* -------------------------------------------------- */ @@ -251,9 +272,9 @@ IGRAPH_EXPORT igraph_error_t igraph_compare_communities(const igraph_vector_int_ igraph_community_comparison_t method); IGRAPH_EXPORT igraph_error_t igraph_split_join_distance(const igraph_vector_int_t *comm1, const igraph_vector_int_t *comm2, - igraph_integer_t* distance12, - igraph_integer_t* distance21); + igraph_int_t* distance12, + igraph_int_t* distance21); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_complex.h b/src/vendor/cigraph/include/igraph_complex.h index 6288d6576ad..36d3f2b572b 100644 --- a/src/vendor/cigraph/include/igraph_complex.h +++ b/src/vendor/cigraph/include/igraph_complex.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2010-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2010-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_COMPLEX_H @@ -27,7 +22,7 @@ #include "igraph_decls.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS typedef struct igraph_complex_t { igraph_real_t dat[2]; @@ -40,13 +35,9 @@ typedef struct igraph_complex_t { IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_complex_t igraph_complex(igraph_real_t x, igraph_real_t y); IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_complex_t igraph_complex_polar(igraph_real_t r, igraph_real_t theta); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_bool_t igraph_complex_eq_tol(igraph_complex_t z1, - igraph_complex_t z2, - igraph_real_t tol); - IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_bool_t igraph_complex_almost_equals(igraph_complex_t z1, - igraph_complex_t z2, - igraph_real_t eps); + igraph_complex_t z2, + igraph_real_t eps); IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_real_t igraph_complex_arg(igraph_complex_t z); @@ -108,6 +99,6 @@ IGRAPH_EXPORT int igraph_complex_printf_aligned(int width, igraph_complex_t val) IGRAPH_EXPORT int igraph_complex_fprintf_aligned(FILE *file, int width, igraph_complex_t val); IGRAPH_EXPORT int igraph_complex_snprintf(char *str, size_t size, igraph_complex_t val); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_components.h b/src/vendor/cigraph/include/igraph_components.h index c00c4f675b0..e784c04f921 100644 --- a/src/vendor/cigraph/include/igraph_components.h +++ b/src/vendor/cigraph/include/igraph_components.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_COMPONENTS_H @@ -33,30 +28,25 @@ #include "igraph_types.h" #include "igraph_vector.h" #include "igraph_vector_list.h" -#include "igraph_vector_ptr.h" /* because of igraph_decompose_destroy() */ -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Components */ /* -------------------------------------------------- */ -/* Deprecated alias to igraph_connected_components; will be removed in 0.11 */ -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_clusters(const igraph_t *graph, igraph_vector_int_t *membership, - igraph_vector_int_t *csize, igraph_integer_t *no, - igraph_connectedness_t mode); IGRAPH_EXPORT igraph_error_t igraph_connected_components(const igraph_t *graph, igraph_vector_int_t *membership, - igraph_vector_int_t *csize, igraph_integer_t *no, + igraph_vector_int_t *csize, igraph_int_t *no, igraph_connectedness_t mode); IGRAPH_EXPORT igraph_error_t igraph_is_connected(const igraph_t *graph, igraph_bool_t *res, igraph_connectedness_t mode); IGRAPH_EXPORT igraph_error_t igraph_decompose(const igraph_t *graph, igraph_graph_list_t *components, igraph_connectedness_t mode, - igraph_integer_t maxcompno, igraph_integer_t minelements); + igraph_int_t maxcompno, igraph_int_t minelements); IGRAPH_EXPORT igraph_error_t igraph_articulation_points(const igraph_t *graph, igraph_vector_int_t *res); IGRAPH_EXPORT igraph_error_t igraph_biconnected_components(const igraph_t *graph, - igraph_integer_t *no, + igraph_int_t *no, igraph_vector_int_list_t *tree_edges, igraph_vector_int_list_t *component_edges, igraph_vector_int_list_t *components, @@ -64,25 +54,21 @@ IGRAPH_EXPORT igraph_error_t igraph_biconnected_components(const igraph_t *graph IGRAPH_EXPORT igraph_error_t igraph_is_biconnected(const igraph_t *graph, igraph_bool_t *result); IGRAPH_EXPORT igraph_error_t igraph_bridges(const igraph_t *graph, igraph_vector_int_t *bridges); -IGRAPH_EXPORT igraph_error_t igraph_bond_percolation( +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_bond_percolation( const igraph_t *graph, igraph_vector_int_t *giant_size, igraph_vector_int_t *vertex_count, const igraph_vector_int_t *edge_order); -IGRAPH_EXPORT igraph_error_t igraph_site_percolation( +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_site_percolation( const igraph_t *graph, igraph_vector_int_t *giant_size, igraph_vector_int_t *edge_count, const igraph_vector_int_t *vertex_order); -IGRAPH_EXPORT igraph_error_t igraph_edgelist_percolation( +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_edgelist_percolation( const igraph_vector_int_t *edges, igraph_vector_int_t *giant_size, igraph_vector_int_t *vertex_count); -/* Deprecated in igraph 0.10 when we switched to igraph_graph_list_t. Will be - * removed in 0.11 */ -IGRAPH_EXPORT IGRAPH_DEPRECATED void igraph_decompose_destroy(igraph_vector_ptr_t *complist); - -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_config.h.in b/src/vendor/cigraph/include/igraph_config.h.in index 99e6feeecf9..d8c910cdd2c 100644 --- a/src/vendor/cigraph/include/igraph_config.h.in +++ b/src/vendor/cigraph/include/igraph_config.h.in @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2011-2022 The igraph development team + igraph library. + Copyright (C) 2011-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_CONFIG_H @@ -25,7 +21,7 @@ #include "igraph_decls.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \define IGRAPH_INTEGER_SIZE @@ -50,6 +46,6 @@ __BEGIN_DECLS */ #define IGRAPH_BOOL_TYPE bool -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_constants.h b/src/vendor/cigraph/include/igraph_constants.h index 8c5dfadc288..a9381ab7c40 100644 --- a/src/vendor/cigraph/include/igraph_constants.h +++ b/src/vendor/cigraph/include/igraph_constants.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,41 +13,97 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_CONSTANTS_H #define IGRAPH_CONSTANTS_H -#include "igraph_config.h" #include "igraph_decls.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Constants */ /* -------------------------------------------------- */ -typedef enum { IGRAPH_UNDIRECTED = 0, IGRAPH_DIRECTED = 1 } igraph_i_directed_t; - -/* Note for the enum below: yes, IGRAPH_LOOPS_TWICE is 1, and IGRAPH_LOOPS_ONCE +/** + * \define IGRAPH_UNLIMITED + * \brief Constant for "do not limit results". + * + * A constant signifying that no limitation should be used with various cutoff, + * size limit or result set size parameters, such as minimum or maximum clique + * size, number of results returned, cutoff for path lengths, etc. Currently + * defined to -1. + */ +#define IGRAPH_UNLIMITED (-1) +/* Note to maintainers: IGRAPH_UNLIMITED is intended to support readability + * when *negative* parameter values indicate "no limit". Do not test + * directly against IGRAPH_UNLIMITED in implementations, test for negative + * values instead. */ + +/* These constants are meant to be used for sake of readability */ +enum { IGRAPH_UNDIRECTED = 0, IGRAPH_DIRECTED = 1 }; +enum { IGRAPH_NO_MULTIPLE = 0, IGRAPH_MULTIPLE = 1 }; +enum { IGRAPH_EDGE_UNLABELED = 0, IGRAPH_EDGE_LABELED = 1 }; + +/** + * \typedef igraph_loops_t + * \brief How to interpret self-loops in undirected graphs? + * + * Controls the interpretation of self-loops in undirected graphs, typically + * in the context of adjacency matrices or degrees. + * + * These constants are also used to improve readability in + * boolean contexts, with \c IGRAPH_NO_LOOPS, equivalent to \c false, + * signifying that loops should be ignored and \c IGRAPH_LOOPS, equivalent + * to \c true, that loops should be considered. + * + * \enumval IGRAPH_NO_LOOPS Self-loops are ignored. + * \enumval IGRAPH_LOOPS_TWICE Self-loops are considered, and counted twice + * in undirected graphs. For example, a self-loop contributes two to the + * degree of a vertex and to diagonal entries of adjacency matrices. This + * is the standard interpretation in graph theory, thus \c IGRAPH_LOOPS + * serves as an alias for this option. + * \enumval IGRAPH_LOOPS_ONCE Self-loops are considered, and counted only + * once in undirected graphs. + */ +typedef enum { + IGRAPH_NO_LOOPS = 0, + IGRAPH_LOOPS_TWICE = 1, + IGRAPH_LOOPS_ONCE = 2, + IGRAPH_LOOPS = IGRAPH_LOOPS_TWICE +} igraph_loops_t; +/* Note for the enum above: yes, IGRAPH_LOOPS_TWICE is 1, and IGRAPH_LOOPS_ONCE * is 2. This is intentional, for the sake of backwards compatibility with * earlier versions where we only had IGRAPH_LOOPS and it meant * IGRAPH_LOOPS_TWICE */ -typedef enum { IGRAPH_NO_LOOPS = 0, IGRAPH_LOOPS = 1, IGRAPH_LOOPS_TWICE = 1, IGRAPH_LOOPS_ONCE = 2 } igraph_loops_t; - -typedef enum { IGRAPH_NO_MULTIPLE = 0, IGRAPH_MULTIPLE = 1 } igraph_multiple_t; typedef enum { IGRAPH_ASCENDING = 0, IGRAPH_DESCENDING = 1 } igraph_order_t; -typedef enum { IGRAPH_MINIMUM = 0, IGRAPH_MAXIMUM = 1 } igraph_optimal_t; - -/* Do not renumber the following values! Some internal code treats them as bitmasks +/** + * \typedef igraph_neimode_t + * \brief How to interpret edge directions in directed graphs? + * + * These "neighbor mode" constants are typically used to specify the treatment + * of edge directions in directed graphs, or which vertices to consider as + * adjacent to (i.e. neighbor of) a vertex. It is typically ignored in undirected + * graphs. + * + * \enumval IGRAPH_OUT Follow edge directions in directed graphs, or consider + * out-neighbors of vertices. + * \enumval IGRAPH_IN Follow edges in the reverse direction in directed graphs, + * or consider in-neighbors of vertices. + * \enumval IGRAPH_ALL Ignore edge directions in directed graphs, or consider + * all neighbours (both out and in-neighbors) of vertices. + */ +typedef enum { + IGRAPH_OUT = 1, + IGRAPH_IN = 2, + IGRAPH_ALL = 3 +} igraph_neimode_t; +/* Do not renumber the vaues above! Some internal code treats them as bitmasks * and assumes that IGRAPH_ALL == IGRAPH_IN | IGRAPH_OUT and IGRAPH_IN & IGRAPH_OUT == 0. */ -typedef enum { IGRAPH_OUT = 1, IGRAPH_IN = 2, IGRAPH_ALL = 3 } igraph_neimode_t; /* Reverse IGRAPH_OUT to IGRAPH_IN and vice versa. Leave other values alone. */ #define IGRAPH_REVERSE_MODE(mode) \ @@ -82,10 +136,6 @@ typedef enum { IGRAPH_TREE_OUT = 0, IGRAPH_TREE_IN, IGRAPH_TREE_UNDIRECTED } igraph_tree_mode_t; -typedef enum { IGRAPH_ERDOS_RENYI_GNP = 0, - IGRAPH_ERDOS_RENYI_GNM - } igraph_erdos_renyi_t; - typedef enum { IGRAPH_GET_ADJACENCY_UPPER = 0, IGRAPH_GET_ADJACENCY_LOWER, IGRAPH_GET_ADJACENCY_BOTH @@ -96,11 +146,6 @@ typedef enum { IGRAPH_DEGSEQ_CONFIGURATION = 0, /* Configuration model, allo IGRAPH_DEGSEQ_FAST_HEUR_SIMPLE, /* Fast heuristic, generates simple graphs */ IGRAPH_DEGSEQ_CONFIGURATION_SIMPLE, /* Configuration model, generates simple graphs */ IGRAPH_DEGSEQ_EDGE_SWITCHING_SIMPLE, /* Edge-switching MCMC, generates simple graphs */ - - /* Deprecated, kept for backwards compatibility: */ - IGRAPH_DEGSEQ_SIMPLE IGRAPH_DEPRECATED_ENUMVAL = IGRAPH_DEGSEQ_CONFIGURATION, - IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE IGRAPH_DEPRECATED_ENUMVAL = IGRAPH_DEGSEQ_FAST_HEUR_SIMPLE, - IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE_UNIFORM IGRAPH_DEPRECATED_ENUMVAL = IGRAPH_DEGSEQ_CONFIGURATION_SIMPLE } igraph_degseq_t; typedef enum { IGRAPH_REALIZE_DEGSEQ_SMALLEST = 0, @@ -112,17 +157,6 @@ typedef enum { IGRAPH_RANDOM_TREE_PRUFER = 0, IGRAPH_RANDOM_TREE_LERW } igraph_random_tree_t; -typedef enum { IGRAPH_FILEFORMAT_EDGELIST = 0, - IGRAPH_FILEFORMAT_NCOL, - IGRAPH_FILEFORMAT_PAJEK, - IGRAPH_FILEFORMAT_LGL, - IGRAPH_FILEFORMAT_GRAPHML - } igraph_fileformat_type_t; - -typedef enum { IGRAPH_REWIRING_SIMPLE = 0, - IGRAPH_REWIRING_SIMPLE_LOOPS - } igraph_rewiring_t; - typedef enum { IGRAPH_EDGEORDER_ID = 0, IGRAPH_EDGEORDER_FROM, IGRAPH_EDGEORDER_TO @@ -149,10 +183,6 @@ typedef enum { IGRAPH_SPINCOMM_UPDATE_SIMPLE = 0, IGRAPH_SPINCOMM_UPDATE_CONFIG } igraph_spincomm_update_t; -typedef enum { IGRAPH_DONT_SIMPLIFY = 0, - IGRAPH_SIMPLIFY - } igraph_lazy_adlist_simplify_t; - typedef enum { IGRAPH_TRANSITIVITY_NAN = 0, IGRAPH_TRANSITIVITY_ZERO } igraph_transitivity_mode_t; @@ -192,11 +222,6 @@ typedef enum { IGRAPH_SUBGRAPH_AUTO = 0, IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH } igraph_subgraph_implementation_t; -typedef enum { IGRAPH_IMITATE_AUGMENTED = 0, - IGRAPH_IMITATE_BLIND, - IGRAPH_IMITATE_CONTRACTED - } igraph_imitate_algorithm_t; - typedef enum { IGRAPH_LAYOUT_GRID = 0, IGRAPH_LAYOUT_NOGRID, IGRAPH_LAYOUT_AUTOGRID @@ -220,6 +245,12 @@ typedef enum { IGRAPH_ROW_MAJOR = 0, IGRAPH_COLUMN_MAJOR = 1 } igraph_matrix_storage_t; +typedef enum { IGRAPH_MST_AUTOMATIC = 0, + IGRAPH_MST_UNWEIGHTED, + IGRAPH_MST_PRIM, + IGRAPH_MST_KRUSKAL + } igraph_mst_algorithm_t; + typedef enum { IGRAPH_PRODUCT_CARTESIAN = 0, IGRAPH_PRODUCT_LEXICOGRAPHIC, IGRAPH_PRODUCT_STRONG, @@ -227,6 +258,21 @@ typedef enum { IGRAPH_PRODUCT_CARTESIAN = 0, IGRAPH_PRODUCT_MODULAR } igraph_product_t; -__END_DECLS +/** + * \typedef igraph_lpa_variant_t + * \brief Label propagation algorithm variants of implementation + * + * Variants to run the label propagation algorithm. + * \enumval IGRAPH_LPA_DOMINANCE Check for dominance of all nodes after each iteration + * \enumval IGRAPH_LPA_RETENTION Keep current label if among dominant labels, only check if labels changed + * \enumval IGRAPH_LPA_FAST Sample from dominant labels, only check neighbors + */ +typedef enum { + IGRAPH_LPA_DOMINANCE = 0, /* Sample from dominant labels, check for dominance after each iteration. */ + IGRAPH_LPA_RETENTION, /* Keep current label if among dominant labels, only check if labels changed. */ + IGRAPH_LPA_FAST /* Sample from dominant labels, only check neighbors. */ +} igraph_lpa_variant_t; + +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_constructors.h b/src/vendor/cigraph/include/igraph_constructors.h index 895eb309c87..f2a22ecfbf6 100644 --- a/src/vendor/cigraph/include/igraph_constructors.h +++ b/src/vendor/cigraph/include/igraph_constructors.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_CONSTRUCTORS_H @@ -33,15 +28,15 @@ #include "igraph_graphicality.h" #include "igraph_sparsemat.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Constructors, deterministic */ /* -------------------------------------------------- */ -IGRAPH_EXPORT igraph_error_t igraph_create(igraph_t *graph, const igraph_vector_int_t *edges, igraph_integer_t n, +IGRAPH_EXPORT igraph_error_t igraph_create(igraph_t *graph, const igraph_vector_int_t *edges, igraph_int_t n, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_small(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, +IGRAPH_EXPORT igraph_error_t igraph_small(igraph_t *graph, igraph_int_t n, igraph_bool_t directed, int first, ...); IGRAPH_EXPORT igraph_error_t igraph_adjacency( igraph_t *graph, const igraph_matrix_t *adjmatrix, igraph_adjacency_t mode, @@ -51,64 +46,60 @@ IGRAPH_EXPORT igraph_error_t igraph_weighted_adjacency( igraph_vector_t *weights, igraph_loops_t loops); IGRAPH_EXPORT igraph_error_t igraph_sparse_adjacency(igraph_t *graph, igraph_sparsemat_t *adjmatrix, igraph_adjacency_t mode, igraph_loops_t loops); IGRAPH_EXPORT igraph_error_t igraph_sparse_weighted_adjacency(igraph_t *graph, igraph_sparsemat_t *adjmatrix, igraph_adjacency_t mode, igraph_vector_t *weights, igraph_loops_t loops); -IGRAPH_EXPORT igraph_error_t igraph_star(igraph_t *graph, igraph_integer_t n, igraph_star_mode_t mode, - igraph_integer_t center); -IGRAPH_EXPORT igraph_error_t igraph_wheel(igraph_t *graph, igraph_integer_t n, igraph_wheel_mode_t mode, - igraph_integer_t center); +IGRAPH_EXPORT igraph_error_t igraph_star(igraph_t *graph, igraph_int_t n, igraph_star_mode_t mode, + igraph_int_t center); +IGRAPH_EXPORT igraph_error_t igraph_wheel(igraph_t *graph, igraph_int_t n, igraph_wheel_mode_t mode, + igraph_int_t center); IGRAPH_EXPORT igraph_error_t igraph_hypercube(igraph_t *graph, - igraph_integer_t n, igraph_bool_t directed); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_lattice(igraph_t *graph, const igraph_vector_int_t *dimvector, igraph_integer_t nei, - igraph_bool_t directed, igraph_bool_t mutual, igraph_bool_t circular); -IGRAPH_EXPORT igraph_error_t igraph_square_lattice(igraph_t *graph, const igraph_vector_int_t *dimvector, igraph_integer_t nei, + igraph_int_t n, igraph_bool_t directed); +IGRAPH_EXPORT igraph_error_t igraph_square_lattice(igraph_t *graph, const igraph_vector_int_t *dimvector, igraph_int_t nei, igraph_bool_t directed, igraph_bool_t mutual, const igraph_vector_bool_t *circular); -IGRAPH_EXPORT igraph_error_t igraph_ring(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, +IGRAPH_EXPORT igraph_error_t igraph_ring(igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_bool_t mutual, igraph_bool_t circular); IGRAPH_EXPORT igraph_error_t igraph_path_graph( - igraph_t *graph, igraph_integer_t n, + igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_bool_t mutual); IGRAPH_EXPORT igraph_error_t igraph_cycle_graph( - igraph_t *graph, igraph_integer_t n, + igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_bool_t mutual); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_tree(igraph_t *graph, igraph_integer_t n, igraph_integer_t children, - igraph_tree_mode_t type); -IGRAPH_EXPORT igraph_error_t igraph_kary_tree(igraph_t *graph, igraph_integer_t n, igraph_integer_t children, +IGRAPH_EXPORT igraph_error_t igraph_kary_tree(igraph_t *graph, igraph_int_t n, igraph_int_t children, igraph_tree_mode_t type); IGRAPH_EXPORT igraph_error_t igraph_symmetric_tree(igraph_t *graph, const igraph_vector_int_t *branches, igraph_tree_mode_t type); -IGRAPH_EXPORT igraph_error_t igraph_regular_tree(igraph_t *graph, igraph_integer_t h, igraph_integer_t k, +IGRAPH_EXPORT igraph_error_t igraph_regular_tree(igraph_t *graph, igraph_int_t h, igraph_int_t k, igraph_tree_mode_t type); IGRAPH_EXPORT igraph_error_t igraph_tree_from_parent_vector(igraph_t *graph, const igraph_vector_int_t *parents, igraph_tree_mode_t mode); IGRAPH_EXPORT igraph_error_t igraph_from_prufer(igraph_t *graph, const igraph_vector_int_t *prufer); -IGRAPH_EXPORT igraph_error_t igraph_full(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, igraph_bool_t loops); +IGRAPH_EXPORT igraph_error_t igraph_full(igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_full_multipartite(igraph_t *graph, igraph_vector_int_t *types, const igraph_vector_int_t *n, igraph_bool_t directed, igraph_neimode_t mode); -IGRAPH_EXPORT igraph_error_t igraph_turan(igraph_t *graph, igraph_vector_int_t *types, igraph_integer_t n, igraph_integer_t r); -IGRAPH_EXPORT igraph_error_t igraph_full_citation(igraph_t *graph, igraph_integer_t n, +IGRAPH_EXPORT igraph_error_t igraph_turan(igraph_t *graph, igraph_vector_int_t *types, igraph_int_t n, igraph_int_t r); +IGRAPH_EXPORT igraph_error_t igraph_full_citation(igraph_t *graph, igraph_int_t n, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_atlas(igraph_t *graph, igraph_integer_t number); -IGRAPH_EXPORT igraph_error_t igraph_extended_chordal_ring(igraph_t *graph, igraph_integer_t nodes, +IGRAPH_EXPORT igraph_error_t igraph_atlas(igraph_t *graph, igraph_int_t number); +IGRAPH_EXPORT igraph_error_t igraph_extended_chordal_ring(igraph_t *graph, igraph_int_t nodes, const igraph_matrix_int_t *W, igraph_bool_t directed); IGRAPH_EXPORT igraph_error_t igraph_linegraph(const igraph_t *graph, igraph_t *linegraph); -IGRAPH_EXPORT igraph_error_t igraph_de_bruijn(igraph_t *graph, igraph_integer_t m, igraph_integer_t n); -IGRAPH_EXPORT igraph_error_t igraph_circulant(igraph_t *graph, igraph_integer_t n, const igraph_vector_int_t *l, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_generalized_petersen(igraph_t *graph, igraph_integer_t n, igraph_integer_t k); -IGRAPH_EXPORT igraph_error_t igraph_kautz(igraph_t *graph, igraph_integer_t m, igraph_integer_t n); +IGRAPH_EXPORT igraph_error_t igraph_de_bruijn(igraph_t *graph, igraph_int_t m, igraph_int_t n); +IGRAPH_EXPORT igraph_error_t igraph_circulant(igraph_t *graph, igraph_int_t n, const igraph_vector_int_t *l, igraph_bool_t directed); +IGRAPH_EXPORT igraph_error_t igraph_generalized_petersen(igraph_t *graph, igraph_int_t n, igraph_int_t k); +IGRAPH_EXPORT igraph_error_t igraph_kautz(igraph_t *graph, igraph_int_t m, igraph_int_t n); IGRAPH_EXPORT igraph_error_t igraph_famous(igraph_t *graph, const char *name); -IGRAPH_EXPORT igraph_error_t igraph_lcf_vector(igraph_t *graph, igraph_integer_t n, - const igraph_vector_int_t *shifts, - igraph_integer_t repeats); -IGRAPH_EXPORT igraph_error_t igraph_lcf(igraph_t *graph, igraph_integer_t n, ...); +IGRAPH_EXPORT igraph_error_t igraph_lcf(igraph_t *graph, igraph_int_t n, + const igraph_vector_int_t *shifts, + igraph_int_t repeats); +IGRAPH_EXPORT igraph_error_t igraph_lcf_small(igraph_t *graph, igraph_int_t n, ...); IGRAPH_EXPORT igraph_error_t igraph_realize_degree_sequence(igraph_t *graph, const igraph_vector_int_t *outdeg, const igraph_vector_int_t *indeg, igraph_edge_type_sw_t allowed_edge_types, igraph_realize_degseq_t method); IGRAPH_EXPORT igraph_error_t igraph_triangular_lattice(igraph_t *graph, const igraph_vector_int_t *dims, igraph_bool_t directed, igraph_bool_t mutual); IGRAPH_EXPORT igraph_error_t igraph_hexagonal_lattice(igraph_t *graph, const igraph_vector_int_t *dims, igraph_bool_t directed, igraph_bool_t mutual); -IGRAPH_EXPORT igraph_error_t igraph_realize_bipartite_degree_sequence(igraph_t *graph, const igraph_vector_int_t *deg1, const igraph_vector_int_t *deg2, const igraph_edge_type_sw_t allowed_edge_types, const igraph_realize_degseq_t method); -IGRAPH_EXPORT igraph_error_t igraph_mycielski_graph(igraph_t *graph, igraph_integer_t k); +IGRAPH_EXPORT igraph_error_t igraph_realize_bipartite_degree_sequence(igraph_t *graph, const igraph_vector_int_t *deg1, const igraph_vector_int_t *deg2, igraph_edge_type_sw_t allowed_edge_types, igraph_realize_degseq_t method); +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_mycielski_graph(igraph_t *graph, igraph_int_t k); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_conversion.h b/src/vendor/cigraph/include/igraph_conversion.h index d47d7f677d9..54a93f77ff8 100644 --- a/src/vendor/cigraph/include/igraph_conversion.h +++ b/src/vendor/cigraph/include/igraph_conversion.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_CONVERSION_H @@ -33,7 +28,7 @@ #include "igraph_sparsemat.h" #include "igraph_attributes.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Conversion */ @@ -58,14 +53,6 @@ IGRAPH_EXPORT igraph_error_t igraph_get_stochastic_sparse( const igraph_vector_t *weights ); -/* Deprecated, will be removed in 0.11. Use igraph_get_adjacency_sparse() instead, paying attention to differences. */ -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_get_sparsemat(const igraph_t *graph, igraph_sparsemat_t *res); - -/* Deprecated, will be removed in 0.11. Use igraph_get_stochastic_sparse() instead, paying attention to differences. */ -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_get_stochastic_sparsemat(const igraph_t *graph, - igraph_sparsemat_t *res, - igraph_bool_t column_wise); - IGRAPH_EXPORT igraph_error_t igraph_get_edgelist(const igraph_t *graph, igraph_vector_int_t *res, igraph_bool_t bycol); IGRAPH_EXPORT igraph_error_t igraph_to_directed(igraph_t *graph, @@ -75,6 +62,6 @@ IGRAPH_EXPORT igraph_error_t igraph_to_undirected(igraph_t *graph, const igraph_attribute_combination_t *edge_comb); IGRAPH_EXPORT igraph_error_t igraph_to_prufer(const igraph_t *graph, igraph_vector_int_t *prufer); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_cycles.h b/src/vendor/cigraph/include/igraph_cycles.h index 2f38aa8d147..93e9f5ec73e 100644 --- a/src/vendor/cigraph/include/igraph_cycles.h +++ b/src/vendor/cigraph/include/igraph_cycles.h @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2022-2024 The igraph development team + igraph library. + Copyright (C) 2022-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA + along with this program. If not, see . */ #ifndef IGRAPH_CYCLES_H @@ -28,22 +26,31 @@ #include "igraph_types.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS -IGRAPH_EXPORT igraph_error_t igraph_fundamental_cycles( - const igraph_t *graph, +/* -------------------------------------------------- */ +/* Directed acyclic graphs */ +/* -------------------------------------------------- */ + +IGRAPH_EXPORT igraph_error_t igraph_topological_sorting( + const igraph_t *graph, igraph_vector_int_t *res, igraph_neimode_t mode); + +IGRAPH_EXPORT igraph_error_t igraph_is_dag(const igraph_t *graph, igraph_bool_t *res); + +/* -------------------------------------------------- */ +/* Cycle bases */ +/* -------------------------------------------------- */ + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_fundamental_cycles( + const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_int_list_t *result, - igraph_integer_t start_vid, - igraph_integer_t bfs_cutoff, - const igraph_vector_t *weights); + igraph_int_t start_vid, igraph_real_t bfs_cutoff); -IGRAPH_EXPORT igraph_error_t igraph_minimum_cycle_basis( - const igraph_t *graph, +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_minimum_cycle_basis( + const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_int_list_t *result, - igraph_integer_t bfs_cutoff, - igraph_bool_t complete, - igraph_bool_t use_cycle_order, - const igraph_vector_t *weights); + igraph_real_t bfs_cutoff, + igraph_bool_t complete, igraph_bool_t use_cycle_order); IGRAPH_EXPORT igraph_error_t igraph_find_cycle( const igraph_t *graph, @@ -69,21 +76,28 @@ typedef igraph_error_t igraph_cycle_handler_t( const igraph_vector_int_t *edges, void *arg); -IGRAPH_EXPORT igraph_error_t igraph_simple_cycles_callback( +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_simple_cycles_callback( const igraph_t *graph, igraph_neimode_t mode, - igraph_integer_t min_cycle_length, - igraph_integer_t max_cycle_length, + igraph_int_t min_cycle_length, + igraph_int_t max_cycle_length, igraph_cycle_handler_t *callback, void *arg); -IGRAPH_EXPORT igraph_error_t igraph_simple_cycles( +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_simple_cycles( const igraph_t *graph, - igraph_vector_int_list_t *vertices, - igraph_vector_int_list_t *edges, + igraph_vector_int_list_t *vertices, igraph_vector_int_list_t *edges, igraph_neimode_t mode, - igraph_integer_t min_cycle_length, - igraph_integer_t max_cycle_length); + igraph_int_t min_cycle_length, igraph_int_t max_cycle_length, + igraph_int_t max_results); + +IGRAPH_EXPORT igraph_error_t igraph_feedback_arc_set( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *weights, igraph_fas_algorithm_t algo); + +IGRAPH_EXPORT igraph_error_t igraph_feedback_vertex_set( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *vertex_weights, igraph_fvs_algorithm_t algo); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_datatype.h b/src/vendor/cigraph/include/igraph_datatype.h index c0ee080e864..1c36d1d46c7 100644 --- a/src/vendor/cigraph/include/igraph_datatype.h +++ b/src/vendor/cigraph/include/igraph_datatype.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_DATATYPE_H @@ -28,7 +23,7 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS struct igraph_i_property_cache_t; typedef struct igraph_i_property_cache_t igraph_i_property_cache_t; @@ -107,8 +102,8 @@ typedef enum { * The storage requirements for a graph with \c |V| vertices * and \c |E| edges is \c O(|E|+|V|). */ -typedef struct igraph_s { - igraph_integer_t n; +typedef struct { + igraph_int_t n; igraph_bool_t directed; igraph_vector_int_t from; igraph_vector_int_t to; @@ -122,6 +117,6 @@ typedef struct igraph_s { IGRAPH_EXPORT void igraph_invalidate_cache(const igraph_t* graph); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_decls.h b/src/vendor/cigraph/include/igraph_decls.h index 3ce51ec98f0..1c63c1f869f 100644 --- a/src/vendor/cigraph/include/igraph_decls.h +++ b/src/vendor/cigraph/include/igraph_decls.h @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2016-2024 The igraph development team + igraph library. + Copyright (C) 2016-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,19 +13,17 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA + along with this program. If not, see . */ -#undef __BEGIN_DECLS -#undef __END_DECLS +#undef IGRAPH_BEGIN_C_DECLS +#undef IGRAPH_END_C_DECLS #ifdef __cplusplus - #define __BEGIN_DECLS extern "C" { - #define __END_DECLS } + #define IGRAPH_BEGIN_C_DECLS extern "C" { + #define IGRAPH_END_C_DECLS } #else - #define __BEGIN_DECLS /* empty */ - #define __END_DECLS /* empty */ + #define IGRAPH_BEGIN_C_DECLS /* empty */ + #define IGRAPH_END_C_DECLS /* empty */ #endif /* This is to eliminate gcc warnings about unused parameters */ @@ -78,3 +76,12 @@ /* Used instead of IGRAPH_EXPORT with functions that need to be tested, * but are not part of the public API. */ #define IGRAPH_PRIVATE_EXPORT IGRAPH_EXPORT + +/* Marks experimental functions. If IGRAPH_WARN_EXPERIMENTAL is defined to a + * nonzero value, supported compilers will emit a warning when these functions + * are used. */ +#if defined(__GNUC__) && IGRAPH_WARN_EXPERIMENTAL +#define IGRAPH_EXPERIMENTAL __attribute__((__warning__("Experimental function."))) +#else +#define IGRAPH_EXPERIMENTAL /* empty */ +#endif diff --git a/src/vendor/cigraph/include/igraph_dqueue.h b/src/vendor/cigraph/include/igraph_dqueue.h index 53c8b0e4ba7..d96bc94199f 100644 --- a/src/vendor/cigraph/include/igraph_dqueue.h +++ b/src/vendor/cigraph/include/igraph_dqueue.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_DQUEUE_H @@ -28,7 +23,7 @@ #include "igraph_error.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* double ended queue, very useful */ @@ -66,6 +61,6 @@ __BEGIN_DECLS do { IGRAPH_CHECK(igraph_dqueue_int_init(q, capacity)); \ IGRAPH_FINALLY(igraph_dqueue_int_destroy, q); } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_dqueue_pmt.h b/src/vendor/cigraph/include/igraph_dqueue_pmt.h index 1db6cd64fdd..d547cd892bf 100644 --- a/src/vendor/cigraph/include/igraph_dqueue_pmt.h +++ b/src/vendor/cigraph/include/igraph_dqueue_pmt.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2007-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ /** @@ -33,12 +28,12 @@ typedef struct TYPE(igraph_dqueue) { BASE *stor_end; } TYPE(igraph_dqueue); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_dqueue, init)(TYPE(igraph_dqueue)* q, igraph_integer_t capacity); +IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_dqueue, init)(TYPE(igraph_dqueue)* q, igraph_int_t capacity); IGRAPH_EXPORT void FUNCTION(igraph_dqueue, destroy)(TYPE(igraph_dqueue)* q); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_dqueue, empty)(const TYPE(igraph_dqueue)* q); IGRAPH_EXPORT void FUNCTION(igraph_dqueue, clear)(TYPE(igraph_dqueue)* q); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_dqueue, full)(TYPE(igraph_dqueue)* q); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_dqueue, size)(const TYPE(igraph_dqueue)* q); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_dqueue, size)(const TYPE(igraph_dqueue)* q); IGRAPH_EXPORT BASE FUNCTION(igraph_dqueue, pop)(TYPE(igraph_dqueue)* q); IGRAPH_EXPORT BASE FUNCTION(igraph_dqueue, pop_back)(TYPE(igraph_dqueue)* q); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_dqueue, head)(const TYPE(igraph_dqueue)* q); @@ -46,5 +41,4 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_dqueue, back)(const TYPE IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_dqueue, push)(TYPE(igraph_dqueue)* q, BASE elem); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_dqueue, print)(const TYPE(igraph_dqueue)* q); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_dqueue, fprint)(const TYPE(igraph_dqueue)* q, FILE *file); -IGRAPH_EXPORT BASE FUNCTION(igraph_dqueue, get)(const TYPE(igraph_dqueue) *q, igraph_integer_t idx); -IGRAPH_DEPRECATED IGRAPH_EXPORT BASE FUNCTION(igraph_dqueue, e)(const TYPE(igraph_dqueue) *q, igraph_integer_t idx); +IGRAPH_EXPORT BASE FUNCTION(igraph_dqueue, get)(const TYPE(igraph_dqueue) *q, igraph_int_t idx); diff --git a/src/vendor/cigraph/include/igraph_eigen.h b/src/vendor/cigraph/include/igraph_eigen.h index 122eeb8a3a8..281b83a9020 100644 --- a/src/vendor/cigraph/include/igraph_eigen.h +++ b/src/vendor/cigraph/include/igraph_eigen.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2010-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2010-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,45 +13,44 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_EIGEN_H #define IGRAPH_EIGEN_H #include "igraph_decls.h" +#include "igraph_datatype.h" #include "igraph_arpack.h" #include "igraph_error.h" #include "igraph_lapack.h" #include "igraph_sparsemat.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS -typedef enum { IGRAPH_EIGEN_AUTO = 0, - IGRAPH_EIGEN_LAPACK, - IGRAPH_EIGEN_ARPACK, - IGRAPH_EIGEN_COMP_AUTO, - IGRAPH_EIGEN_COMP_LAPACK, - IGRAPH_EIGEN_COMP_ARPACK - } igraph_eigen_algorithm_t; +typedef enum { + IGRAPH_EIGEN_AUTO = 0, + IGRAPH_EIGEN_LAPACK, + IGRAPH_EIGEN_ARPACK, + IGRAPH_EIGEN_COMP_AUTO, + IGRAPH_EIGEN_COMP_LAPACK, + IGRAPH_EIGEN_COMP_ARPACK +} igraph_eigen_algorithm_t; -typedef enum { IGRAPH_EIGEN_LM = 0, - IGRAPH_EIGEN_SM, /* 1 */ - IGRAPH_EIGEN_LA, /* 2 */ - IGRAPH_EIGEN_SA, /* 3 */ - IGRAPH_EIGEN_BE, /* 4 */ - IGRAPH_EIGEN_LR, /* 5 */ - IGRAPH_EIGEN_SR, /* 6 */ - IGRAPH_EIGEN_LI, /* 7 */ - IGRAPH_EIGEN_SI, /* 8 */ - IGRAPH_EIGEN_ALL, /* 9 */ - IGRAPH_EIGEN_INTERVAL, /* 10 */ - IGRAPH_EIGEN_SELECT - } /* 11 */ -igraph_eigen_which_position_t; +typedef enum { + IGRAPH_EIGEN_LM = 0, + IGRAPH_EIGEN_SM, /* 1 */ + IGRAPH_EIGEN_LA, /* 2 */ + IGRAPH_EIGEN_SA, /* 3 */ + IGRAPH_EIGEN_BE, /* 4 */ + IGRAPH_EIGEN_LR, /* 5 */ + IGRAPH_EIGEN_SR, /* 6 */ + IGRAPH_EIGEN_LI, /* 7 */ + IGRAPH_EIGEN_SI, /* 8 */ + IGRAPH_EIGEN_ALL, /* 9 */ + IGRAPH_EIGEN_INTERVAL, /* 10 */ + IGRAPH_EIGEN_SELECT /* 11 */ +} igraph_eigen_which_position_t; typedef struct igraph_eigen_which_t { igraph_eigen_which_position_t pos; @@ -96,6 +93,6 @@ IGRAPH_EXPORT igraph_error_t igraph_eigen_adjacency(const igraph_t *graph, igraph_vector_complex_t *cmplxvalues, igraph_matrix_complex_t *cmplxvectors); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_embedding.h b/src/vendor/cigraph/include/igraph_embedding.h index 2462b010c88..2fa8ff6f462 100644 --- a/src/vendor/cigraph/include/igraph_embedding.h +++ b/src/vendor/cigraph/include/igraph_embedding.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2013 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2013-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_EMBEDDING_H @@ -30,10 +25,10 @@ #include "igraph_arpack.h" #include "igraph_eigen.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_EXPORT igraph_error_t igraph_adjacency_spectral_embedding(const igraph_t *graph, - igraph_integer_t no, + igraph_int_t no, const igraph_vector_t *weights, igraph_eigen_which_position_t which, igraph_bool_t scaled, @@ -51,7 +46,7 @@ typedef enum { } igraph_laplacian_spectral_embedding_type_t; IGRAPH_EXPORT igraph_error_t igraph_laplacian_spectral_embedding(const igraph_t *graph, - igraph_integer_t no, + igraph_int_t no, const igraph_vector_t *weights, igraph_eigen_which_position_t which, igraph_laplacian_spectral_embedding_type_t type, @@ -61,8 +56,8 @@ IGRAPH_EXPORT igraph_error_t igraph_laplacian_spectral_embedding(const igraph_t igraph_vector_t *D, igraph_arpack_options_t *options); -IGRAPH_EXPORT igraph_error_t igraph_dim_select(const igraph_vector_t *sv, igraph_integer_t *dim); +IGRAPH_EXPORT igraph_error_t igraph_dim_select(const igraph_vector_t *sv, igraph_int_t *dim); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_epidemics.h b/src/vendor/cigraph/include/igraph_epidemics.h index a13f8cbcd0f..361f38cf5de 100644 --- a/src/vendor/cigraph/include/igraph_epidemics.h +++ b/src/vendor/cigraph/include/igraph_epidemics.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2014 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2014-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_EPIDEMICS_H @@ -30,7 +25,7 @@ #include "igraph_vector.h" #include "igraph_vector_ptr.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \struct igraph_sir_t @@ -60,9 +55,9 @@ IGRAPH_EXPORT igraph_error_t igraph_sir_init(igraph_sir_t *sir); IGRAPH_EXPORT void igraph_sir_destroy(igraph_sir_t *sir); IGRAPH_EXPORT igraph_error_t igraph_sir(const igraph_t *graph, igraph_real_t beta, - igraph_real_t gamma, igraph_integer_t no_sim, + igraph_real_t gamma, igraph_int_t no_sim, igraph_vector_ptr_t *result); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_error.h b/src/vendor/cigraph/include/igraph_error.h index f5047ea7399..33ecdb66ac6 100644 --- a/src/vendor/cigraph/include/igraph_error.h +++ b/src/vendor/cigraph/include/igraph_error.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2003-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2003-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_ERROR_H @@ -29,7 +24,7 @@ #include -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* This file contains the igraph error handling. * Most bits are taken literally from the GSL library (with the GSL_ @@ -254,61 +249,22 @@ __BEGIN_DECLS * number was specified as the number of vertices. * \enumval IGRAPH_EXISTS A graph/vertex/edge attribute is already * installed with the given name. - * \enumval IGRAPH_EINVEVECTOR Invalid vector of vertex IDs. A vertex ID - * is either negative or bigger than the number of vertices minus one. * \enumval IGRAPH_EINVVID Invalid vertex ID, negative or too big. - * \enumval IGRAPH_NONSQUARE A non-square matrix was received while a - * square matrix was expected. + * \enumval IGRAPH_EINVEID Invalid edge ID, negative or too big. * \enumval IGRAPH_EINVMODE Invalid mode parameter. * \enumval IGRAPH_EFILE A file operation failed. E.g. a file doesn't exist, * or the user has no rights to open it. * \enumval IGRAPH_UNIMPLEMENTED Attempted to call an unimplemented or * disabled (at compile-time) function. * \enumval IGRAPH_DIVERGED A numeric algorithm failed to converge. - * \enumval IGRAPH_ARPACK_PROD Matrix-vector product failed (not used any more). - * \enumval IGRAPH_ARPACK_NPOS N must be positive. - * \enumval IGRAPH_ARPACK_NEVNPOS NEV must be positive. - * \enumval IGRAPH_ARPACK_NCVSMALL NCV must be bigger. - * \enumval IGRAPH_ARPACK_NONPOSI Maximum number of iterations should be positive. - * \enumval IGRAPH_ARPACK_WHICHINV Invalid WHICH parameter. - * \enumval IGRAPH_ARPACK_BMATINV Invalid BMAT parameter. - * \enumval IGRAPH_ARPACK_WORKLSMALL WORKL is too small. - * \enumval IGRAPH_ARPACK_TRIDERR LAPACK error in tridiagonal eigenvalue calculation. - * \enumval IGRAPH_ARPACK_ZEROSTART Starting vector is zero. - * \enumval IGRAPH_ARPACK_MODEINV MODE is invalid. - * \enumval IGRAPH_ARPACK_MODEBMAT MODE and BMAT are not compatible. - * \enumval IGRAPH_ARPACK_ISHIFT ISHIFT must be 0 or 1. - * \enumval IGRAPH_ARPACK_NEVBE NEV and WHICH='BE' are incompatible. - * \enumval IGRAPH_ARPACK_NOFACT Could not build an Arnoldi factorization. - * \enumval IGRAPH_ARPACK_FAILED No eigenvalues to sufficient accuracy. - * \enumval IGRAPH_ARPACK_HOWMNY HOWMNY is invalid. - * \enumval IGRAPH_ARPACK_HOWMNYS HOWMNY='S' is not implemented. - * \enumval IGRAPH_ARPACK_EVDIFF Different number of converged Ritz values. - * \enumval IGRAPH_ARPACK_SHUR Error from calculation of a real Schur form. - * \enumval IGRAPH_ARPACK_LAPACK LAPACK (dtrevc) error for calculating eigenvectors. - * \enumval IGRAPH_ARPACK_UNKNOWN Unknown ARPACK error. + * \enumval IGRAPH_ARPACK An error happened inside a calculation implemented + * in ARPACK. The calculation involved is most likely an eigenvector-related + * calculation. * \enumval IGRAPH_ENEGCYCLE Negative cycle detected while calculating shortest paths. * \enumval IGRAPH_EINTERNAL Internal error, likely a bug in igraph. - * \enumval IGRAPH_EDIVZERO Big integer division by zero. - * \enumval IGRAPH_GLP_EBOUND GLPK error (GLP_EBOUND). - * \enumval IGRAPH_GLP_EROOT GLPK error (GLP_EROOT). - * \enumval IGRAPH_GLP_ENOPFS GLPK error (GLP_ENOPFS). - * \enumval IGRAPH_GLP_ENODFS GLPK error (GLP_ENODFS). - * \enumval IGRAPH_GLP_EFAIL GLPK error (GLP_EFAIL). - * \enumval IGRAPH_GLP_EMIPGAP GLPK error (GLP_EMIPGAP). - * \enumval IGRAPH_GLP_ETMLIM GLPK error (GLP_ETMLIM). - * \enumval IGRAPH_GLP_ESTOP GLPK error (GLP_ESTOP). - * \enumval IGRAPH_EATTRIBUTES Attribute handler error. The user is not - * expected to find this; it is signalled if some igraph function is - * not using the attribute handler interface properly. * \enumval IGRAPH_EATTRCOMBINE Unimplemented attribute combination * method for the given attribute type. - * \enumval IGRAPH_ELAPACK A LAPACK call resulted in an error. - * \enumval IGRAPH_EDRL Internal error in the DrL layout generator; not used - * any more (replaced by IGRAPH_EINTERNAL). * \enumval IGRAPH_EOVERFLOW Integer or double overflow. - * \enumval IGRAPH_EGLP Internal GLPK error. - * \enumval IGRAPH_CPUTIME CPU time exceeded. * \enumval IGRAPH_EUNDERFLOW Integer or double underflow. * \enumval IGRAPH_ERWSTUCK Random walk got stuck. * \enumval IGRAPH_ERANGE Maximum vertex or edge count exceeded. @@ -322,58 +278,35 @@ typedef enum { IGRAPH_PARSEERROR = 3, IGRAPH_EINVAL = 4, IGRAPH_EXISTS = 5, - IGRAPH_EINVEVECTOR = 6, + /* IGRAPH_EINVEVECTOR = 6, */ /* removed in 1.0 */ IGRAPH_EINVVID = 7, - IGRAPH_NONSQUARE = 8, + IGRAPH_EINVEID = 8, /* used to be IGRAPH_NONSQUARE before 1.0 */ IGRAPH_EINVMODE = 9, IGRAPH_EFILE = 10, IGRAPH_UNIMPLEMENTED = 12, IGRAPH_INTERRUPTED = 13, IGRAPH_DIVERGED = 14, - IGRAPH_ARPACK_PROD = 15, /* unused, reserved */ - IGRAPH_ARPACK_NPOS = 16, - IGRAPH_ARPACK_NEVNPOS = 17, - IGRAPH_ARPACK_NCVSMALL = 18, - IGRAPH_ARPACK_NONPOSI = 19, - IGRAPH_ARPACK_WHICHINV = 20, - IGRAPH_ARPACK_BMATINV = 21, - IGRAPH_ARPACK_WORKLSMALL = 22, - IGRAPH_ARPACK_TRIDERR = 23, - IGRAPH_ARPACK_ZEROSTART = 24, - IGRAPH_ARPACK_MODEINV = 25, - IGRAPH_ARPACK_MODEBMAT = 26, - IGRAPH_ARPACK_ISHIFT = 27, - IGRAPH_ARPACK_NEVBE = 28, - IGRAPH_ARPACK_NOFACT = 29, - IGRAPH_ARPACK_FAILED = 30, - IGRAPH_ARPACK_HOWMNY = 31, - IGRAPH_ARPACK_HOWMNYS = 32, - IGRAPH_ARPACK_EVDIFF = 33, - IGRAPH_ARPACK_SHUR = 34, - IGRAPH_ARPACK_LAPACK = 35, - IGRAPH_ARPACK_UNKNOWN = 36, + IGRAPH_EARPACK = 15, + /* ARPACK error codes from 15 to 36 were moved to igraph_arpack_error_t in 1.0 */ IGRAPH_ENEGCYCLE = 37, - IGRAPH_ENEGLOOP IGRAPH_DEPRECATED_ENUMVAL = IGRAPH_ENEGCYCLE, IGRAPH_EINTERNAL = 38, - IGRAPH_ARPACK_MAXIT = 39, - IGRAPH_ARPACK_NOSHIFT = 40, - IGRAPH_ARPACK_REORDER = 41, - IGRAPH_EDIVZERO = 42, - IGRAPH_GLP_EBOUND = 43, - IGRAPH_GLP_EROOT = 44, - IGRAPH_GLP_ENOPFS = 45, - IGRAPH_GLP_ENODFS = 46, - IGRAPH_GLP_EFAIL = 47, - IGRAPH_GLP_EMIPGAP = 48, - IGRAPH_GLP_ETMLIM = 49, - IGRAPH_GLP_ESTOP = 50, - IGRAPH_EATTRIBUTES = 51, + /* ARPACK error codes from 39 to 41 were moved to igraph_arpack_error_t in 1.0 */ + /* IGRAPH_EDIVZERO = 42, */ /* removed in 1.0 */ + /* IGRAPH_GLP_EBOUND = 43, */ /* removed in 1.0 */ + /* IGRAPH_GLP_EROOT = 44, */ /* removed in 1.0 */ + /* IGRAPH_GLP_ENOPFS = 45, */ /* removed in 1.0 */ + /* IGRAPH_GLP_ENODFS = 46, */ /* removed in 1.0 */ + /* IGRAPH_GLP_EFAIL = 47, */ /* removed in 1.0 */ + /* IGRAPH_GLP_EMIPGAP = 48, */ /* removed in 1.0 */ + /* IGRAPH_GLP_ETMLIM = 49, */ /* removed in 1.0 */ + /* IGRAPH_GLP_ESTOP = 50, */ /* removed in 1.0 */ + /* IGRAPH_EATTRIBUTES = 51, */ /* removed in 1.0 */ IGRAPH_EATTRCOMBINE = 52, - IGRAPH_ELAPACK = 53, - IGRAPH_EDRL IGRAPH_DEPRECATED_ENUMVAL = 54, + /* IGRAPH_ELAPACK = 53, */ /* removed in 1.0 */ + /* IGRAPH_EDRL = 54, */ /* deprecated in 0.10.2, removed in 1.0 */ IGRAPH_EOVERFLOW = 55, - IGRAPH_EGLP = 56, - IGRAPH_CPUTIME = 57, + /* IGRAPH_EGLP = 56, */ /* removed in 1.0 */ + /* IGRAPH_CPUTIME = 57, */ /* removed in 1.0 */ IGRAPH_EUNDERFLOW = 58, IGRAPH_ERWSTUCK = 59, IGRAPH_STOP = 60, @@ -544,7 +477,7 @@ IGRAPH_EXPORT igraph_error_t igraph_errorvf(const char *reason, const char *file int line, igraph_error_t igraph_errno, va_list ap); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE const char *igraph_strerror(const igraph_error_t igraph_errno); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE const char *igraph_strerror(igraph_error_t igraph_errno); #define IGRAPH_ERROR_SELECT_2(a,b) ((a) != IGRAPH_SUCCESS ? (a) : ((b) != IGRAPH_SUCCESS ? (b) : IGRAPH_SUCCESS)) #define IGRAPH_ERROR_SELECT_3(a,b,c) ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_2(b,c)) @@ -994,6 +927,6 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_NORETURN void igraph_fatalf(const char *reason, } \ } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_eulerian.h b/src/vendor/cigraph/include/igraph_eulerian.h index bb9a089a7b4..07eafa232f2 100644 --- a/src/vendor/cigraph/include/igraph_eulerian.h +++ b/src/vendor/cigraph/include/igraph_eulerian.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2020-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_EULERIAN_H @@ -28,12 +23,12 @@ #include "igraph_datatype.h" #include "igraph_error.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_EXPORT igraph_error_t igraph_is_eulerian(const igraph_t *graph, igraph_bool_t *has_path, igraph_bool_t *has_cycle); IGRAPH_EXPORT igraph_error_t igraph_eulerian_path(const igraph_t *graph, igraph_vector_int_t *edge_res, igraph_vector_int_t *vertex_res); IGRAPH_EXPORT igraph_error_t igraph_eulerian_cycle(const igraph_t *graph, igraph_vector_int_t *edge_res, igraph_vector_int_t *vertex_res); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_flow.h b/src/vendor/cigraph/include/igraph_flow.h index 354f29f7e7b..8b5e59fe44e 100644 --- a/src/vendor/cigraph/include/igraph_flow.h +++ b/src/vendor/cigraph/include/igraph_flow.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2003-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2003-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_FLOW_H @@ -31,7 +26,7 @@ #include "igraph_datatype.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Maximum flows, minimum cuts & such */ @@ -54,27 +49,27 @@ __BEGIN_DECLS */ typedef struct { - igraph_integer_t nopush, norelabel, nogap, nogapnodes, nobfs; + igraph_int_t nopush, norelabel, nogap, nogapnodes, nobfs; } igraph_maxflow_stats_t; IGRAPH_EXPORT igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, igraph_vector_t *flow, igraph_vector_int_t *cut, igraph_vector_int_t *partition, igraph_vector_int_t *partition2, - igraph_integer_t source, igraph_integer_t target, + igraph_int_t source, igraph_int_t target, const igraph_vector_t *capacity, igraph_maxflow_stats_t *stats); IGRAPH_EXPORT igraph_error_t igraph_maxflow_value(const igraph_t *graph, igraph_real_t *value, - igraph_integer_t source, igraph_integer_t target, + igraph_int_t source, igraph_int_t target, const igraph_vector_t *capacity, igraph_maxflow_stats_t *stats); IGRAPH_EXPORT igraph_error_t igraph_st_mincut(const igraph_t *graph, igraph_real_t *value, igraph_vector_int_t *cut, igraph_vector_int_t *partition, igraph_vector_int_t *partition2, - igraph_integer_t source, igraph_integer_t target, + igraph_int_t source, igraph_int_t target, const igraph_vector_t *capacity); IGRAPH_EXPORT igraph_error_t igraph_st_mincut_value(const igraph_t *graph, igraph_real_t *res, - igraph_integer_t source, igraph_integer_t target, + igraph_int_t source, igraph_int_t target, const igraph_vector_t *capacity); IGRAPH_EXPORT igraph_error_t igraph_mincut_value(const igraph_t *graph, igraph_real_t *res, @@ -87,29 +82,29 @@ IGRAPH_EXPORT igraph_error_t igraph_mincut(const igraph_t *graph, const igraph_vector_t *capacity); IGRAPH_EXPORT igraph_error_t igraph_st_vertex_connectivity(const igraph_t *graph, - igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target, + igraph_int_t *res, + igraph_int_t source, + igraph_int_t target, igraph_vconn_nei_t neighbors); -IGRAPH_EXPORT igraph_error_t igraph_vertex_connectivity(const igraph_t *graph, igraph_integer_t *res, +IGRAPH_EXPORT igraph_error_t igraph_vertex_connectivity(const igraph_t *graph, igraph_int_t *res, igraph_bool_t checks); -IGRAPH_EXPORT igraph_error_t igraph_st_edge_connectivity(const igraph_t *graph, igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target); -IGRAPH_EXPORT igraph_error_t igraph_edge_connectivity(const igraph_t *graph, igraph_integer_t *res, +IGRAPH_EXPORT igraph_error_t igraph_st_edge_connectivity(const igraph_t *graph, igraph_int_t *res, + igraph_int_t source, + igraph_int_t target); +IGRAPH_EXPORT igraph_error_t igraph_edge_connectivity(const igraph_t *graph, igraph_int_t *res, igraph_bool_t checks); -IGRAPH_EXPORT igraph_error_t igraph_edge_disjoint_paths(const igraph_t *graph, igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target); -IGRAPH_EXPORT igraph_error_t igraph_vertex_disjoint_paths(const igraph_t *graph, igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target); +IGRAPH_EXPORT igraph_error_t igraph_edge_disjoint_paths(const igraph_t *graph, igraph_int_t *res, + igraph_int_t source, + igraph_int_t target); +IGRAPH_EXPORT igraph_error_t igraph_vertex_disjoint_paths(const igraph_t *graph, igraph_int_t *res, + igraph_int_t source, + igraph_int_t target); -IGRAPH_EXPORT igraph_error_t igraph_adhesion(const igraph_t *graph, igraph_integer_t *res, +IGRAPH_EXPORT igraph_error_t igraph_adhesion(const igraph_t *graph, igraph_int_t *res, igraph_bool_t checks); -IGRAPH_EXPORT igraph_error_t igraph_cohesion(const igraph_t *graph, igraph_integer_t *res, +IGRAPH_EXPORT igraph_error_t igraph_cohesion(const igraph_t *graph, igraph_int_t *res, igraph_bool_t checks); /* s-t cut listing related stuff */ @@ -129,7 +124,7 @@ IGRAPH_EXPORT igraph_error_t igraph_reverse_residual_graph(const igraph_t *graph const igraph_vector_t *flow); IGRAPH_EXPORT igraph_error_t igraph_dominator_tree(const igraph_t *graph, - igraph_integer_t root, + igraph_int_t root, igraph_vector_int_t *dom, igraph_t *domtree, igraph_vector_int_t *leftout, @@ -138,14 +133,14 @@ IGRAPH_EXPORT igraph_error_t igraph_dominator_tree(const igraph_t *graph, IGRAPH_EXPORT igraph_error_t igraph_all_st_cuts(const igraph_t *graph, igraph_vector_int_list_t *cuts, igraph_vector_int_list_t *partition1s, - igraph_integer_t source, - igraph_integer_t target); + igraph_int_t source, + igraph_int_t target); IGRAPH_EXPORT igraph_error_t igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value, igraph_vector_int_list_t *cuts, igraph_vector_int_list_t *partition1s, - igraph_integer_t source, - igraph_integer_t target, + igraph_int_t source, + igraph_int_t target, const igraph_vector_t *capacity); IGRAPH_EXPORT igraph_error_t igraph_gomory_hu_tree(const igraph_t *graph, @@ -153,6 +148,6 @@ IGRAPH_EXPORT igraph_error_t igraph_gomory_hu_tree(const igraph_t *graph, igraph_vector_t *flows, const igraph_vector_t *capacity); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_foreign.h b/src/vendor/cigraph/include/igraph_foreign.h index a0625cba62b..0c9a0a25725 100644 --- a/src/vendor/cigraph/include/igraph_foreign.h +++ b/src/vendor/cigraph/include/igraph_foreign.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_FOREIGN_H @@ -33,14 +28,14 @@ #include -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Read and write foreign formats */ /* -------------------------------------------------- */ IGRAPH_EXPORT igraph_error_t igraph_read_graph_edgelist(igraph_t *graph, FILE *instream, - igraph_integer_t n, igraph_bool_t directed); + igraph_int_t n, igraph_bool_t directed); IGRAPH_EXPORT igraph_error_t igraph_read_graph_ncol(igraph_t *graph, FILE *instream, const igraph_strvector_t *predefnames, igraph_bool_t names, igraph_add_weights_t weights, igraph_bool_t directed); @@ -49,19 +44,12 @@ IGRAPH_EXPORT igraph_error_t igraph_read_graph_lgl(igraph_t *graph, FILE *instre igraph_bool_t directed); IGRAPH_EXPORT igraph_error_t igraph_read_graph_pajek(igraph_t *graph, FILE *instream); IGRAPH_EXPORT igraph_error_t igraph_read_graph_graphml(igraph_t *graph, FILE *instream, - igraph_integer_t index); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_read_graph_dimacs(igraph_t *graph, FILE *instream, - igraph_strvector_t *problem, - igraph_vector_int_t *label, - igraph_integer_t *source, - igraph_integer_t *target, - igraph_vector_t *capacity, - igraph_bool_t directed); + igraph_int_t index); IGRAPH_EXPORT igraph_error_t igraph_read_graph_dimacs_flow(igraph_t *graph, FILE *instream, igraph_strvector_t *problem, igraph_vector_int_t *label, - igraph_integer_t *source, - igraph_integer_t *target, + igraph_int_t *source, + igraph_int_t *target, igraph_vector_t *capacity, igraph_bool_t directed); IGRAPH_EXPORT igraph_error_t igraph_read_graph_graphdb(igraph_t *graph, FILE *instream, @@ -86,11 +74,8 @@ IGRAPH_EXPORT igraph_error_t igraph_write_graph_lgl(const igraph_t *graph, FILE IGRAPH_EXPORT igraph_error_t igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream, igraph_bool_t prefixattr); IGRAPH_EXPORT igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_write_graph_dimacs(const igraph_t *graph, FILE *outstream, - igraph_integer_t source, igraph_integer_t target, - const igraph_vector_t *capacity); IGRAPH_EXPORT igraph_error_t igraph_write_graph_dimacs_flow(const igraph_t *graph, FILE *outstream, - igraph_integer_t source, igraph_integer_t target, + igraph_int_t source, igraph_int_t target, const igraph_vector_t *capacity); IGRAPH_EXPORT igraph_error_t igraph_write_graph_gml(const igraph_t *graph, FILE *outstream, igraph_write_gml_sw_t options, @@ -108,6 +93,6 @@ typedef struct igraph_safelocale_s *igraph_safelocale_t; IGRAPH_EXPORT igraph_error_t igraph_enter_safelocale(igraph_safelocale_t *loc); IGRAPH_EXPORT void igraph_exit_safelocale(igraph_safelocale_t *loc); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_games.h b/src/vendor/cigraph/include/igraph_games.h index 3c4cbdb5aec..2ba1bbb8bcf 100644 --- a/src/vendor/cigraph/include/igraph_games.h +++ b/src/vendor/cigraph/include/igraph_games.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_GAMES_H @@ -28,93 +23,110 @@ #include "igraph_constants.h" #include "igraph_datatype.h" #include "igraph_error.h" +#include "igraph_graphicality.h" #include "igraph_matrix.h" #include "igraph_matrix_list.h" #include "igraph_types.h" #include "igraph_vector.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Constructors, games (=stochastic) */ /* -------------------------------------------------- */ -IGRAPH_EXPORT igraph_error_t igraph_barabasi_game(igraph_t *graph, igraph_integer_t n, +IGRAPH_EXPORT igraph_error_t igraph_barabasi_game(igraph_t *graph, igraph_int_t n, igraph_real_t power, - igraph_integer_t m, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t A, igraph_bool_t directed, igraph_barabasi_algorithm_t algo, const igraph_t *start_from); -IGRAPH_EXPORT igraph_error_t igraph_erdos_renyi_game_gnp(igraph_t *graph, igraph_integer_t n, igraph_real_t p, - igraph_bool_t directed, igraph_bool_t loops); -IGRAPH_EXPORT igraph_error_t igraph_erdos_renyi_game_gnm(igraph_t *graph, igraph_integer_t n, igraph_integer_t m, - igraph_bool_t directed, igraph_bool_t loops); + +IGRAPH_EXPORT igraph_error_t igraph_erdos_renyi_game_gnp( + igraph_t *graph, + igraph_int_t n, igraph_real_t p, + igraph_bool_t directed, + igraph_edge_type_sw_t allowed_edge_types, + igraph_bool_t edge_labeled); + +IGRAPH_EXPORT igraph_error_t igraph_erdos_renyi_game_gnm( + igraph_t *graph, + igraph_int_t n, igraph_int_t m, + igraph_bool_t directed, + igraph_edge_type_sw_t allowed_edge_types, + igraph_bool_t edge_labeled); + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_iea_game( + igraph_t *graph, + igraph_int_t n, igraph_int_t m, + igraph_bool_t directed, igraph_bool_t loops); + IGRAPH_EXPORT igraph_error_t igraph_degree_sequence_game(igraph_t *graph, const igraph_vector_int_t *out_deg, const igraph_vector_int_t *in_deg, igraph_degseq_t method); -IGRAPH_EXPORT igraph_error_t igraph_growing_random_game(igraph_t *graph, igraph_integer_t n, - igraph_integer_t m, igraph_bool_t directed, igraph_bool_t citation); +IGRAPH_EXPORT igraph_error_t igraph_growing_random_game(igraph_t *graph, igraph_int_t n, + igraph_int_t m, igraph_bool_t directed, igraph_bool_t citation); IGRAPH_EXPORT igraph_error_t igraph_barabasi_aging_game(igraph_t *graph, - igraph_integer_t nodes, - igraph_integer_t m, + igraph_int_t nodes, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t pa_exp, igraph_real_t aging_exp, - igraph_integer_t aging_bin, + igraph_int_t aging_bin, igraph_real_t zero_deg_appeal, igraph_real_t zero_age_appeal, igraph_real_t deg_coef, igraph_real_t age_coef, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_integer_t n, +IGRAPH_EXPORT igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_int_t n, igraph_real_t power, - igraph_integer_t window, - igraph_integer_t m, + igraph_int_t window, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t zero_appeal, igraph_bool_t directed); IGRAPH_EXPORT igraph_error_t igraph_recent_degree_aging_game(igraph_t *graph, - igraph_integer_t nodes, - igraph_integer_t m, + igraph_int_t nodes, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t pa_exp, igraph_real_t aging_exp, - igraph_integer_t aging_bin, - igraph_integer_t window, + igraph_int_t aging_bin, + igraph_int_t window, igraph_real_t zero_appeal, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_callaway_traits_game(igraph_t *graph, igraph_integer_t nodes, - igraph_integer_t types, igraph_integer_t edges_per_step, +IGRAPH_EXPORT igraph_error_t igraph_callaway_traits_game(igraph_t *graph, igraph_int_t nodes, + igraph_int_t types, igraph_int_t edges_per_step, const igraph_vector_t *type_dist, const igraph_matrix_t *pref_matrix, igraph_bool_t directed, igraph_vector_int_t *node_type_vec); -IGRAPH_EXPORT igraph_error_t igraph_establishment_game(igraph_t *graph, igraph_integer_t nodes, - igraph_integer_t types, igraph_integer_t k, +IGRAPH_EXPORT igraph_error_t igraph_establishment_game(igraph_t *graph, igraph_int_t nodes, + igraph_int_t types, igraph_int_t k, const igraph_vector_t *type_dist, const igraph_matrix_t *pref_matrix, igraph_bool_t directed, igraph_vector_int_t *node_type_vec); -IGRAPH_EXPORT igraph_error_t igraph_grg_game(igraph_t *graph, igraph_integer_t nodes, +IGRAPH_EXPORT igraph_error_t igraph_grg_game(igraph_t *graph, igraph_int_t nodes, igraph_real_t radius, igraph_bool_t torus, igraph_vector_t *x, igraph_vector_t *y); -IGRAPH_EXPORT igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, - igraph_integer_t types, +IGRAPH_EXPORT igraph_error_t igraph_preference_game(igraph_t *graph, igraph_int_t nodes, + igraph_int_t types, const igraph_vector_t *type_dist, igraph_bool_t fixed_sizes, const igraph_matrix_t *pref_matrix, igraph_vector_int_t *node_type_vec, igraph_bool_t directed, igraph_bool_t loops); -IGRAPH_EXPORT igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_integer_t nodes, - igraph_integer_t out_types, - igraph_integer_t in_types, +IGRAPH_EXPORT igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_int_t nodes, + igraph_int_t out_types, + igraph_int_t in_types, const igraph_matrix_t *type_dist_matrix, const igraph_matrix_t *pref_matrix, igraph_vector_int_t *node_type_out_vec, @@ -122,114 +134,96 @@ IGRAPH_EXPORT igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_rewire_edges(igraph_t *graph, igraph_real_t prob, - igraph_bool_t loops, igraph_bool_t multiple); + igraph_edge_type_sw_t allowed_edge_types); IGRAPH_EXPORT igraph_error_t igraph_rewire_directed_edges(igraph_t *graph, igraph_real_t prob, igraph_bool_t loops, igraph_neimode_t mode); -IGRAPH_EXPORT igraph_error_t igraph_watts_strogatz_game(igraph_t *graph, igraph_integer_t dim, - igraph_integer_t size, igraph_integer_t nei, - igraph_real_t p, igraph_bool_t loops, - igraph_bool_t multiple); +IGRAPH_EXPORT igraph_error_t igraph_watts_strogatz_game(igraph_t *graph, igraph_int_t dim, + igraph_int_t size, igraph_int_t nei, + igraph_real_t p, + igraph_edge_type_sw_t allowed_edge_types); IGRAPH_EXPORT igraph_error_t igraph_lastcit_game(igraph_t *graph, - igraph_integer_t nodes, igraph_integer_t edges_per_node, - igraph_integer_t agebins, + igraph_int_t nodes, igraph_int_t edges_per_node, + igraph_int_t agebins, const igraph_vector_t *preference, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_cited_type_game(igraph_t *graph, igraph_integer_t nodes, +IGRAPH_EXPORT igraph_error_t igraph_cited_type_game(igraph_t *graph, igraph_int_t nodes, const igraph_vector_int_t *types, const igraph_vector_t *pref, - igraph_integer_t edges_per_step, + igraph_int_t edges_per_step, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_citing_cited_type_game(igraph_t *graph, igraph_integer_t nodes, +IGRAPH_EXPORT igraph_error_t igraph_citing_cited_type_game(igraph_t *graph, igraph_int_t nodes, const igraph_vector_int_t *types, const igraph_matrix_t *pref, - igraph_integer_t edges_per_step, + igraph_int_t edges_per_step, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes, +IGRAPH_EXPORT igraph_error_t igraph_forest_fire_game(igraph_t *graph, igraph_int_t nodes, igraph_real_t fw_prob, igraph_real_t bw_factor, - igraph_integer_t ambs, igraph_bool_t directed); + igraph_int_t ambs, igraph_bool_t directed); IGRAPH_EXPORT igraph_error_t igraph_simple_interconnected_islands_game( igraph_t *graph, - igraph_integer_t islands_n, - igraph_integer_t islands_size, + igraph_int_t islands_n, + igraph_int_t islands_size, igraph_real_t islands_pin, - igraph_integer_t n_inter); + igraph_int_t n_inter); -IGRAPH_EXPORT igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_of_edges, +IGRAPH_EXPORT igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_int_t no_of_edges, const igraph_vector_t *fitness_out, const igraph_vector_t *fitness_in, - igraph_bool_t loops, igraph_bool_t multiple); + igraph_edge_type_sw_t allowed_edge_types); IGRAPH_EXPORT igraph_error_t igraph_static_power_law_game(igraph_t *graph, - igraph_integer_t no_of_nodes, igraph_integer_t no_of_edges, + igraph_int_t no_of_nodes, igraph_int_t no_of_edges, igraph_real_t exponent_out, igraph_real_t exponent_in, - igraph_bool_t loops, igraph_bool_t multiple, + igraph_edge_type_sw_t allowed_edge_types, igraph_bool_t finite_size_correction); -IGRAPH_EXPORT igraph_error_t igraph_chung_lu_game(igraph_t *graph, +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_chung_lu_game(igraph_t *graph, const igraph_vector_t *expected_out_deg, const igraph_vector_t *expected_in_deg, igraph_bool_t loops, igraph_chung_lu_t variant); IGRAPH_EXPORT igraph_error_t igraph_k_regular_game(igraph_t *graph, - igraph_integer_t no_of_nodes, igraph_integer_t k, + igraph_int_t no_of_nodes, igraph_int_t k, igraph_bool_t directed, igraph_bool_t multiple); -IGRAPH_EXPORT igraph_error_t igraph_sbm_game(igraph_t *graph, igraph_integer_t n, - const igraph_matrix_t *pref_matrix, - const igraph_vector_int_t *block_sizes, - igraph_bool_t directed, igraph_bool_t loops); +IGRAPH_EXPORT igraph_error_t igraph_sbm_game( + igraph_t *graph, + const igraph_matrix_t *pref_matrix, + const igraph_vector_int_t *block_sizes, + igraph_bool_t directed, + igraph_edge_type_sw_t allowed_edge_types); -IGRAPH_EXPORT igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, - igraph_integer_t m, const igraph_vector_t *rho, +IGRAPH_EXPORT igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_int_t n, + igraph_int_t m, const igraph_vector_t *rho, const igraph_matrix_t *C, igraph_real_t p); -IGRAPH_EXPORT igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n, +IGRAPH_EXPORT igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_int_t n, const igraph_vector_int_t *mlist, const igraph_vector_list_t *rholist, const igraph_matrix_list_t *Clist, igraph_real_t p); -IGRAPH_EXPORT igraph_error_t igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_graph, +IGRAPH_EXPORT igraph_error_t igraph_correlated_game(igraph_t *new_graph, const igraph_t *old_graph, igraph_real_t corr, igraph_real_t p, const igraph_vector_int_t *permutation); IGRAPH_EXPORT igraph_error_t igraph_correlated_pair_game(igraph_t *graph1, igraph_t *graph2, - igraph_integer_t n, igraph_real_t corr, igraph_real_t p, + igraph_int_t n, igraph_real_t corr, igraph_real_t p, igraph_bool_t directed, const igraph_vector_int_t *permutation); -IGRAPH_EXPORT igraph_error_t igraph_tree_game(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, +IGRAPH_EXPORT igraph_error_t igraph_tree_game(igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_random_tree_t method); IGRAPH_EXPORT igraph_error_t igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *vecs, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_sample_sphere_surface(igraph_integer_t dim, igraph_integer_t n, - igraph_real_t radius, - igraph_bool_t positive, - igraph_matrix_t *res); - -IGRAPH_EXPORT igraph_error_t igraph_sample_sphere_volume(igraph_integer_t dim, igraph_integer_t n, - igraph_real_t radius, - igraph_bool_t positive, - igraph_matrix_t *res); - -IGRAPH_EXPORT igraph_error_t igraph_sample_dirichlet(igraph_integer_t n, const igraph_vector_t *alpha, - igraph_matrix_t *res); - -/* Deprecated functions: */ - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_erdos_renyi_game( - igraph_t *graph, igraph_erdos_renyi_t type, igraph_integer_t n, - igraph_real_t p_or_m, igraph_bool_t directed, igraph_bool_t loops -); - -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_graph_list.h b/src/vendor/cigraph/include/igraph_graph_list.h index 7f8232621a0..ec0f5adb7b7 100644 --- a/src/vendor/cigraph/include/igraph_graph_list.h +++ b/src/vendor/cigraph/include/igraph_graph_list.h @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2022 The igraph development team + igraph library. + Copyright (C) 2022-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,22 +13,18 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_GRAPH_LIST_H #define IGRAPH_GRAPH_LIST_H -#include "igraph_datatype.h" #include "igraph_decls.h" +#include "igraph_datatype.h" #include "igraph_error.h" #include "igraph_types.h" -#include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* List of graphs */ @@ -55,6 +50,6 @@ void igraph_graph_list_set_directed(igraph_graph_list_t* list, igraph_bool_t dir do { IGRAPH_CHECK(igraph_graph_list_init(v, size)); \ IGRAPH_FINALLY(igraph_graph_list_destroy, v); } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_graphicality.h b/src/vendor/cigraph/include/igraph_graphicality.h index f639217b5b1..6890b690f08 100644 --- a/src/vendor/cigraph/include/igraph_graphicality.h +++ b/src/vendor/cigraph/include/igraph_graphicality.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. - Copyright (C) 2009-2020 Gabor Csardi + igraph library. + Copyright (C) 2020-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,8 +23,26 @@ #include "igraph_error.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS +/** + * \typedef igraph_edge_type_sw_t + * \brief What types of non-simple edges to allow? + * + * This type is used with multiple functions to specify what types of non-simple + * edges to allow, create or consider a graph. The constants below are treated + * as "switches" that can be turned on individually and combined using the + * bitwise-or operator. For example, + * IGRAPH_LOOPS_SW + * allows only self-loops but not multi-edges, while + * IGRAPH_LOOPS_SW | IGRAPH_MULTI_SW + * allows both. + * + * \enumval IGRAPH_SIMPLE_SW A shorthand for simple graphs only, which is the default + * assumption. + * \enumval IGRAPH_LOOPS_SW Allow or consider self-loops. + * \enumval IGRAPH_MULTI_SW Allow or consider multi-edges. + */ typedef unsigned int igraph_edge_type_sw_t; /* @@ -42,14 +58,14 @@ enum { IGRAPH_EXPORT igraph_error_t igraph_is_graphical(const igraph_vector_int_t *out_degrees, const igraph_vector_int_t *in_degrees, - const igraph_edge_type_sw_t allowed_edge_types, + igraph_edge_type_sw_t allowed_edge_types, igraph_bool_t *res); IGRAPH_EXPORT igraph_error_t igraph_is_bigraphical(const igraph_vector_int_t *degrees1, const igraph_vector_int_t *degrees2, - const igraph_edge_type_sw_t allowed_edge_types, + igraph_edge_type_sw_t allowed_edge_types, igraph_bool_t *res); -__END_DECLS +IGRAPH_END_C_DECLS #endif // IGRAPH_GRAPHICALITY_H diff --git a/src/vendor/cigraph/include/igraph_graphlets.h b/src/vendor/cigraph/include/igraph_graphlets.h index b80165a6966..64b39274903 100644 --- a/src/vendor/cigraph/include/igraph_graphlets.h +++ b/src/vendor/cigraph/include/igraph_graphlets.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2013 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2013-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_GRAPHLETS_H @@ -30,7 +25,7 @@ #include "igraph_error.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_EXPORT igraph_error_t igraph_graphlets_candidate_basis(const igraph_t *graph, const igraph_vector_t *weights, @@ -41,13 +36,13 @@ IGRAPH_EXPORT igraph_error_t igraph_graphlets_project(const igraph_t *graph, const igraph_vector_t *weights, const igraph_vector_int_list_t *cliques, igraph_vector_t *Mu, igraph_bool_t startMu, - igraph_integer_t niter); + igraph_int_t niter); IGRAPH_EXPORT igraph_error_t igraph_graphlets(const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_int_list_t *cliques, - igraph_vector_t *Mu, igraph_integer_t niter); + igraph_vector_t *Mu, igraph_int_t niter); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_heap.h b/src/vendor/cigraph/include/igraph_heap.h index 3eb81c2f972..12093279a31 100644 --- a/src/vendor/cigraph/include/igraph_heap.h +++ b/src/vendor/cigraph/include/igraph_heap.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_HEAP_H @@ -28,7 +23,7 @@ #include "igraph_error.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Heap */ @@ -80,6 +75,6 @@ __BEGIN_DECLS #define IGRAPH_HEAP_NULL { 0,0,0 } -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_heap_pmt.h b/src/vendor/cigraph/include/igraph_heap_pmt.h index d501700d34b..3d6f77a7b4f 100644 --- a/src/vendor/cigraph/include/igraph_heap_pmt.h +++ b/src/vendor/cigraph/include/igraph_heap_pmt.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2007-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,26 +13,22 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ typedef struct TYPE(igraph_heap) { BASE* stor_begin; BASE* stor_end; BASE* end; - igraph_bool_t destroy; } TYPE(igraph_heap); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_heap, init)(TYPE(igraph_heap)* h, igraph_integer_t capacity); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_heap, init_array)(TYPE(igraph_heap) *t, const BASE *data, igraph_integer_t len); +IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_heap, init)(TYPE(igraph_heap)* h, igraph_int_t capacity); +IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_heap, init_array)(TYPE(igraph_heap) *t, const BASE *data, igraph_int_t len); IGRAPH_EXPORT void FUNCTION(igraph_heap, destroy)(TYPE(igraph_heap)* h); IGRAPH_EXPORT void FUNCTION(igraph_heap, clear)(TYPE(igraph_heap)* h); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_heap, empty)(const TYPE(igraph_heap)* h); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_heap, push)(TYPE(igraph_heap)* h, BASE elem); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_heap, top)(const TYPE(igraph_heap)* h); IGRAPH_EXPORT BASE FUNCTION(igraph_heap, delete_top)(TYPE(igraph_heap)* h); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_heap, size)(const TYPE(igraph_heap)* h); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_heap, reserve)(TYPE(igraph_heap)* h, igraph_integer_t capacity); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_heap, size)(const TYPE(igraph_heap)* h); +IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_heap, reserve)(TYPE(igraph_heap)* h, igraph_int_t capacity); diff --git a/src/vendor/cigraph/include/igraph_hrg.h b/src/vendor/cigraph/include/igraph_hrg.h index 6ceeb4cac24..ce9cd7e0c77 100644 --- a/src/vendor/cigraph/include/igraph_hrg.h +++ b/src/vendor/cigraph/include/igraph_hrg.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,23 +13,19 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_HRG_H #define IGRAPH_HRG_H #include "igraph_decls.h" - #include "igraph_datatype.h" #include "igraph_error.h" #include "igraph_graph_list.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \struct igraph_hrg_t @@ -75,14 +69,14 @@ typedef struct igraph_hrg_t { igraph_vector_int_t edges; } igraph_hrg_t; -IGRAPH_EXPORT igraph_error_t igraph_hrg_init(igraph_hrg_t *hrg, igraph_integer_t n); +IGRAPH_EXPORT igraph_error_t igraph_hrg_init(igraph_hrg_t *hrg, igraph_int_t n); IGRAPH_EXPORT void igraph_hrg_destroy(igraph_hrg_t *hrg); -IGRAPH_EXPORT igraph_integer_t igraph_hrg_size(const igraph_hrg_t *hrg); -IGRAPH_EXPORT igraph_error_t igraph_hrg_resize(igraph_hrg_t *hrg, igraph_integer_t newsize); +IGRAPH_EXPORT igraph_int_t igraph_hrg_size(const igraph_hrg_t *hrg); +IGRAPH_EXPORT igraph_error_t igraph_hrg_resize(igraph_hrg_t *hrg, igraph_int_t newsize); IGRAPH_EXPORT igraph_error_t igraph_hrg_fit( const igraph_t *graph, igraph_hrg_t *hrg, igraph_bool_t start, - igraph_integer_t steps + igraph_int_t steps ); IGRAPH_EXPORT igraph_error_t igraph_hrg_sample( @@ -91,7 +85,7 @@ IGRAPH_EXPORT igraph_error_t igraph_hrg_sample( IGRAPH_EXPORT igraph_error_t igraph_hrg_sample_many( const igraph_hrg_t *hrg, igraph_graph_list_t *samples, - igraph_integer_t num_samples + igraph_int_t num_samples ); IGRAPH_EXPORT igraph_error_t igraph_hrg_game( @@ -107,15 +101,15 @@ IGRAPH_EXPORT igraph_error_t igraph_hrg_consensus(const igraph_t *graph, igraph_vector_t *weights, igraph_hrg_t *hrg, igraph_bool_t start, - igraph_integer_t num_samples); + igraph_int_t num_samples); IGRAPH_EXPORT igraph_error_t igraph_hrg_predict(const igraph_t *graph, igraph_vector_int_t *edges, igraph_vector_t *prob, igraph_hrg_t *hrg, igraph_bool_t start, - igraph_integer_t num_samples, - igraph_integer_t num_bins); + igraph_int_t num_samples, + igraph_int_t num_bins); IGRAPH_EXPORT igraph_error_t igraph_hrg_create(igraph_hrg_t *hrg, const igraph_t *graph, @@ -127,6 +121,6 @@ IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_hrg_dendrogram( igraph_t *graph, const igraph_hrg_t *hrg ); -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_HRG_H */ diff --git a/src/vendor/cigraph/include/igraph_interface.h b/src/vendor/cigraph/include/igraph_interface.h index 27c642a3e1c..25b19ccc63e 100644 --- a/src/vendor/cigraph/include/igraph_interface.h +++ b/src/vendor/cigraph/include/igraph_interface.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,64 +13,77 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_INTERFACE_H #define IGRAPH_INTERFACE_H #include "igraph_decls.h" -#include "igraph_types.h" +#include "igraph_attributes.h" #include "igraph_datatype.h" #include "igraph_error.h" #include "igraph_iterators.h" +#include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Interface */ /* -------------------------------------------------- */ -IGRAPH_EXPORT igraph_error_t igraph_empty(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_empty_attrs(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, void *attr); +IGRAPH_EXPORT igraph_error_t igraph_empty(igraph_t *graph, igraph_int_t n, igraph_bool_t directed); +IGRAPH_EXPORT igraph_error_t igraph_empty_attrs( + igraph_t *graph, igraph_int_t n, igraph_bool_t directed, + const igraph_attribute_record_list_t* attr +); IGRAPH_EXPORT void igraph_destroy(igraph_t *graph); IGRAPH_EXPORT igraph_error_t igraph_copy(igraph_t *to, const igraph_t *from); -IGRAPH_EXPORT igraph_error_t igraph_add_edges(igraph_t *graph, const igraph_vector_int_t *edges, - void *attr); -IGRAPH_EXPORT igraph_error_t igraph_add_vertices(igraph_t *graph, igraph_integer_t nv, - void *attr); +IGRAPH_EXPORT igraph_error_t igraph_add_edges( + igraph_t *graph, const igraph_vector_int_t *edges, + const igraph_attribute_record_list_t* attr +); +IGRAPH_EXPORT igraph_error_t igraph_add_vertices( + igraph_t *graph, igraph_int_t nv, + const igraph_attribute_record_list_t* attr +); IGRAPH_EXPORT igraph_error_t igraph_delete_edges(igraph_t *graph, igraph_es_t edges); -IGRAPH_EXPORT igraph_error_t igraph_delete_vertices(igraph_t *graph, const igraph_vs_t vertices); -IGRAPH_EXPORT igraph_error_t igraph_delete_vertices_idx(igraph_t *graph, const igraph_vs_t vertices, - igraph_vector_int_t *idx, - igraph_vector_int_t *invidx); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_vcount(const igraph_t *graph); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_ecount(const igraph_t *graph); -IGRAPH_EXPORT igraph_error_t igraph_neighbors(const igraph_t *graph, igraph_vector_int_t *neis, igraph_integer_t vid, - igraph_neimode_t mode); +IGRAPH_EXPORT igraph_error_t igraph_delete_vertices(igraph_t *graph, igraph_vs_t vertices); +IGRAPH_EXPORT igraph_error_t igraph_delete_vertices_map( + igraph_t *graph, igraph_vs_t vertices, igraph_vector_int_t *map, + igraph_vector_int_t *invmap +); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_vcount(const igraph_t *graph); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_ecount(const igraph_t *graph); +IGRAPH_EXPORT igraph_error_t igraph_neighbors( + const igraph_t *graph, igraph_vector_int_t *neis, igraph_int_t vid, + igraph_neimode_t mode, igraph_loops_t loops, igraph_bool_t multiple +); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_is_directed(const igraph_t *graph); -IGRAPH_EXPORT igraph_error_t igraph_degree_1(const igraph_t *graph, igraph_integer_t *deg, - igraph_integer_t vid, igraph_neimode_t mode, igraph_bool_t loops); -IGRAPH_EXPORT igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res, - const igraph_vs_t vids, igraph_neimode_t mode, - igraph_bool_t loops); -IGRAPH_EXPORT igraph_error_t igraph_edge(const igraph_t *graph, igraph_integer_t eid, - igraph_integer_t *from, igraph_integer_t *to); +IGRAPH_EXPORT igraph_error_t igraph_degree_1( + const igraph_t *graph, igraph_int_t *deg, igraph_int_t vid, + igraph_neimode_t mode, igraph_loops_t loops +); +IGRAPH_EXPORT igraph_error_t igraph_degree( + const igraph_t *graph, igraph_vector_int_t *res, igraph_vs_t vids, + igraph_neimode_t mode, igraph_loops_t loops +); +IGRAPH_EXPORT igraph_error_t igraph_edge(const igraph_t *graph, igraph_int_t eid, + igraph_int_t *from, igraph_int_t *to); IGRAPH_EXPORT igraph_error_t igraph_edges(const igraph_t *graph, igraph_es_t eids, - igraph_vector_int_t *edges); -IGRAPH_EXPORT igraph_error_t igraph_get_eid(const igraph_t *graph, igraph_integer_t *eid, - igraph_integer_t from, igraph_integer_t to, + igraph_vector_int_t *edges, igraph_bool_t bycol); +IGRAPH_EXPORT igraph_error_t igraph_get_eid(const igraph_t *graph, igraph_int_t *eid, + igraph_int_t from, igraph_int_t to, igraph_bool_t directed, igraph_bool_t error); IGRAPH_EXPORT igraph_error_t igraph_get_eids(const igraph_t *graph, igraph_vector_int_t *eids, const igraph_vector_int_t *pairs, igraph_bool_t directed, igraph_bool_t error); IGRAPH_EXPORT igraph_error_t igraph_get_all_eids_between(const igraph_t *graph, igraph_vector_int_t *eids, - igraph_integer_t source, igraph_integer_t target, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_incident(const igraph_t *graph, igraph_vector_int_t *eids, igraph_integer_t vid, - igraph_neimode_t mode); + igraph_int_t source, igraph_int_t target, igraph_bool_t directed); +IGRAPH_EXPORT igraph_error_t igraph_incident( + const igraph_t *graph, igraph_vector_int_t *eids, igraph_int_t pnode, + igraph_neimode_t mode, igraph_loops_t loops +); IGRAPH_EXPORT igraph_error_t igraph_is_same_graph(const igraph_t *graph1, const igraph_t *graph2, igraph_bool_t *res); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_i_property_cache_get_bool(const igraph_t *graph, igraph_cached_property_t prop); @@ -101,7 +112,7 @@ IGRAPH_EXPORT void igraph_i_property_cache_invalidate_all(const igraph_t *graph) * \return The source vertex of the edge. * \sa \ref igraph_edge() if error checking is desired. */ -#define IGRAPH_FROM(graph,eid) ((igraph_integer_t)(VECTOR((graph)->from)[(igraph_integer_t)(eid)])) +#define IGRAPH_FROM(graph,eid) ((igraph_int_t)(VECTOR((graph)->from)[(igraph_int_t)(eid)])) /** * \define IGRAPH_TO @@ -114,7 +125,7 @@ IGRAPH_EXPORT void igraph_i_property_cache_invalidate_all(const igraph_t *graph) * \return The target vertex of the edge. * \sa \ref igraph_edge() if error checking is desired. */ -#define IGRAPH_TO(graph,eid) ((igraph_integer_t)(VECTOR((graph)->to) [(igraph_integer_t)(eid)])) +#define IGRAPH_TO(graph,eid) ((igraph_int_t)(VECTOR((graph)->to) [(igraph_int_t)(eid)])) /** * \define IGRAPH_OTHER @@ -132,8 +143,13 @@ IGRAPH_EXPORT void igraph_i_property_cache_invalidate_all(const igraph_t *graph) * of directed edges. */ #define IGRAPH_OTHER(graph,eid,vid) \ - ((igraph_integer_t)(IGRAPH_TO(graph,(eid))==(vid) ? IGRAPH_FROM((graph),(eid)) : IGRAPH_TO((graph),(eid)))) + ((igraph_int_t)(IGRAPH_TO(graph,(eid))==(vid) ? IGRAPH_FROM((graph),(eid)) : IGRAPH_TO((graph),(eid)))) + +IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_delete_vertices_idx( + igraph_t *graph, igraph_vs_t vertices, igraph_vector_int_t *idx, + igraph_vector_int_t *invidx +); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_interrupt.h b/src/vendor/cigraph/include/igraph_interrupt.h index 6d8fb85ca8a..f1bf1977283 100644 --- a/src/vendor/cigraph/include/igraph_interrupt.h +++ b/src/vendor/cigraph/include/igraph_interrupt.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2003-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2003-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,19 +13,16 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_INTERRUPT_H #define IGRAPH_INTERRUPT_H #include "igraph_decls.h" -#include "igraph_error.h" +#include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* This file contains the igraph interruption handling. */ @@ -102,11 +97,11 @@ __BEGIN_DECLS * * This is the type of the interruption handler functions. * - * \param data reserved for possible future use - * \return \c IGRAPH_SUCCESS if the calculation should go on, anything else otherwise. + * \return false if the calculation should go on, true if the calculation + * should be interrupted. */ -typedef igraph_error_t igraph_interruption_handler_t (void* data); +typedef igraph_bool_t igraph_interruption_handler_t(void); /** * \function igraph_allow_interruption @@ -115,14 +110,14 @@ typedef igraph_error_t igraph_interruption_handler_t (void* data); * \ref IGRAPH_ALLOW_INTERRUPTION macro) if \a igraph is checking for interruption * requests. * - * \param data reserved for possible future use, now it is always \c NULL - * \return \c IGRAPH_SUCCESS if the calculation should go on, anything else otherwise. + * \return false if the calculation should go on, true if the calculation + * should be interrupted. */ -IGRAPH_EXPORT igraph_error_t igraph_allow_interruption(void* data); +IGRAPH_EXPORT igraph_bool_t igraph_allow_interruption(void); IGRAPH_EXPORT igraph_interruption_handler_t * igraph_set_interruption_handler (igraph_interruption_handler_t * new_handler); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_topology.h b/src/vendor/cigraph/include/igraph_isomorphism.h similarity index 80% rename from src/vendor/cigraph/include/igraph_topology.h rename to src/vendor/cigraph/include/igraph_isomorphism.h index baff051b239..32f1eb74896 100644 --- a/src/vendor/cigraph/include/igraph_topology.h +++ b/src/vendor/cigraph/include/igraph_isomorphism.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,33 +13,21 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ -#ifndef IGRAPH_TOPOLOGY_H -#define IGRAPH_TOPOLOGY_H +#ifndef IGRAPH_ISOMORPHISM_H +#define IGRAPH_ISOMORPHISM_H #include "igraph_decls.h" -#include "igraph_constants.h" #include "igraph_datatype.h" #include "igraph_error.h" +#include "igraph_iterators.h" #include "igraph_types.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS -/* -------------------------------------------------- */ -/* Directed acyclic graphs */ -/* -------------------------------------------------- */ - -IGRAPH_EXPORT igraph_error_t igraph_topological_sorting( - const igraph_t *graph, igraph_vector_int_t *res, igraph_neimode_t mode); -IGRAPH_EXPORT igraph_error_t igraph_is_dag(const igraph_t *graph, igraph_bool_t *res); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_transitive_closure_dag(const igraph_t *graph, - igraph_t *closure); /* -------------------------------------------------- */ /* Graph isomorphisms */ @@ -59,12 +45,23 @@ IGRAPH_EXPORT igraph_error_t igraph_isomorphic(const igraph_t *graph1, const igr igraph_bool_t *iso); IGRAPH_EXPORT igraph_error_t igraph_subisomorphic(const igraph_t *graph1, const igraph_t *graph2, igraph_bool_t *iso); +IGRAPH_EXPORT igraph_error_t igraph_count_automorphisms( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_real_t *result); +IGRAPH_EXPORT igraph_error_t igraph_automorphism_group( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_vector_int_list_t *generators +); +IGRAPH_EXPORT igraph_error_t igraph_canonical_permutation( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_vector_int_t *labeling +); /* LAD */ IGRAPH_EXPORT igraph_error_t igraph_subisomorphic_lad( const igraph_t *pattern, const igraph_t *target, const igraph_vector_int_list_t *domains, igraph_bool_t *iso, igraph_vector_int_t *map, igraph_vector_int_list_t *maps, - igraph_bool_t induced, igraph_integer_t time_limit + igraph_bool_t induced ); /* VF2 family*/ @@ -115,8 +112,8 @@ typedef igraph_error_t igraph_isohandler_t(const igraph_vector_int_t *map12, typedef igraph_bool_t igraph_isocompat_t(const igraph_t *graph1, const igraph_t *graph2, - const igraph_integer_t g1_num, - const igraph_integer_t g2_num, + const igraph_int_t g1_num, + const igraph_int_t g2_num, void *arg); IGRAPH_EXPORT igraph_error_t igraph_isomorphic_vf2(const igraph_t *graph1, const igraph_t *graph2, @@ -135,7 +132,7 @@ IGRAPH_EXPORT igraph_error_t igraph_count_isomorphisms_vf2(const igraph_t *graph const igraph_vector_int_t *vertex_color2, const igraph_vector_int_t *edge_color1, const igraph_vector_int_t *edge_color2, - igraph_integer_t *count, + igraph_int_t *count, igraph_isocompat_t *node_compat_fn, igraph_isocompat_t *edge_compat_fn, void *arg); @@ -157,17 +154,6 @@ IGRAPH_EXPORT igraph_error_t igraph_get_isomorphisms_vf2_callback( igraph_isohandler_t *isohandler_fn, igraph_isocompat_t *node_compat_fn, igraph_isocompat_t *edge_compat_fn, void *arg ); - -/* Deprecated alias to igraph_get_isomorphisms_vf2_callback(), will be removed in 0.11 */ -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_isomorphic_function_vf2( - const igraph_t *graph1, const igraph_t *graph2, - const igraph_vector_int_t *vertex_color1, const igraph_vector_int_t *vertex_color2, - const igraph_vector_int_t *edge_color1, const igraph_vector_int_t *edge_color2, - igraph_vector_int_t *map12, igraph_vector_int_t *map21, - igraph_isohandler_t *isohandler_fn, igraph_isocompat_t *node_compat_fn, - igraph_isocompat_t *edge_compat_fn, void *arg -); - IGRAPH_EXPORT igraph_error_t igraph_subisomorphic_vf2(const igraph_t *graph1, const igraph_t *graph2, const igraph_vector_int_t *vertex_color1, const igraph_vector_int_t *vertex_color2, @@ -184,7 +170,7 @@ IGRAPH_EXPORT igraph_error_t igraph_count_subisomorphisms_vf2(const igraph_t *gr const igraph_vector_int_t *vertex_color2, const igraph_vector_int_t *edge_color1, const igraph_vector_int_t *edge_color2, - igraph_integer_t *count, + igraph_int_t *count, igraph_isocompat_t *node_compat_fn, igraph_isocompat_t *edge_compat_fn, void *arg); @@ -207,16 +193,6 @@ IGRAPH_EXPORT igraph_error_t igraph_get_subisomorphisms_vf2_callback( igraph_isocompat_t *edge_compat_fn, void *arg ); -/* Deprecated alias to igraph_get_subisomorphisms_vf2_callback(), will be removed in 0.11 */ -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_subisomorphic_function_vf2( - const igraph_t *graph1, const igraph_t *graph2, - const igraph_vector_int_t *vertex_color1, const igraph_vector_int_t *vertex_color2, - const igraph_vector_int_t *edge_color1, const igraph_vector_int_t *edge_color2, - igraph_vector_int_t *map12, igraph_vector_int_t *map21, - igraph_isohandler_t *isohandler_fn, igraph_isocompat_t *node_compat_fn, - igraph_isocompat_t *edge_compat_fn, void *arg -); - /* BLISS family */ /** * \struct igraph_bliss_info_t @@ -266,7 +242,7 @@ typedef struct igraph_bliss_info_t { * \enumval IGRAPH_BLISS_FLM Largest maximally non-trivially connected * non-singleton cell. * \enumval IGRAPH_BLISS_FSM Smallest maximally non-trivially - * connected non-singletion cell. + * connected non-singleton cell. */ typedef enum { IGRAPH_BLISS_F = 0, IGRAPH_BLISS_FL, @@ -274,7 +250,7 @@ typedef enum { IGRAPH_BLISS_F = 0, IGRAPH_BLISS_FL, IGRAPH_BLISS_FLM, IGRAPH_BLISS_FSM } igraph_bliss_sh_t; -IGRAPH_EXPORT igraph_error_t igraph_canonical_permutation(const igraph_t *graph, const igraph_vector_int_t *colors, igraph_vector_int_t *labeling, +IGRAPH_EXPORT igraph_error_t igraph_canonical_permutation_bliss(const igraph_t *graph, const igraph_vector_int_t *colors, igraph_vector_int_t *labeling, igraph_bliss_sh_t sh, igraph_bliss_info_t *info); IGRAPH_EXPORT igraph_error_t igraph_isomorphic_bliss(const igraph_t *graph1, const igraph_t *graph2, const igraph_vector_int_t *colors1, const igraph_vector_int_t *colors2, @@ -283,35 +259,24 @@ IGRAPH_EXPORT igraph_error_t igraph_isomorphic_bliss(const igraph_t *graph1, con igraph_bliss_sh_t sh, igraph_bliss_info_t *info1, igraph_bliss_info_t *info2); -IGRAPH_EXPORT igraph_error_t igraph_count_automorphisms( +IGRAPH_EXPORT igraph_error_t igraph_count_automorphisms_bliss( const igraph_t *graph, const igraph_vector_int_t *colors, igraph_bliss_sh_t sh, igraph_bliss_info_t *info); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_automorphisms( - const igraph_t *graph, const igraph_vector_int_t *colors, - igraph_bliss_sh_t sh, igraph_bliss_info_t *info); - -IGRAPH_EXPORT igraph_error_t igraph_automorphism_group( +IGRAPH_EXPORT igraph_error_t igraph_automorphism_group_bliss( const igraph_t *graph, const igraph_vector_int_t *colors, igraph_vector_int_list_t *generators, igraph_bliss_sh_t sh, igraph_bliss_info_t *info ); /* Functions for small graphs (<= 4 vertices for directed graphs, <= 6 for undirected graphs) */ -IGRAPH_EXPORT igraph_error_t igraph_isoclass(const igraph_t *graph, igraph_integer_t *isoclass); -IGRAPH_EXPORT igraph_error_t igraph_isoclass_subgraph(const igraph_t *graph, const igraph_vector_int_t *vids, - igraph_integer_t *isoclass); -IGRAPH_EXPORT igraph_error_t igraph_isoclass_create(igraph_t *graph, igraph_integer_t size, - igraph_integer_t number, igraph_bool_t directed); - -IGRAPH_EXPORT igraph_error_t igraph_graph_count(igraph_integer_t n, igraph_bool_t directed, igraph_integer_t *count); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_isomorphic_34( - const igraph_t *graph1, const igraph_t *graph2, igraph_bool_t *iso -); - +IGRAPH_EXPORT igraph_error_t igraph_isoclass(const igraph_t *graph, igraph_int_t *isoclass); +IGRAPH_EXPORT igraph_error_t igraph_isoclass_subgraph(const igraph_t *graph, igraph_vs_t vids, + igraph_int_t *isoclass); +IGRAPH_EXPORT igraph_error_t igraph_isoclass_create(igraph_t *graph, igraph_int_t size, + igraph_int_t number, igraph_bool_t directed); +IGRAPH_EXPORT igraph_error_t igraph_graph_count(igraph_int_t n, igraph_bool_t directed, igraph_int_t *count); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_iterators.h b/src/vendor/cigraph/include/igraph_iterators.h index 144b435e8e5..c43e34ade7d 100644 --- a/src/vendor/cigraph/include/igraph_iterators.h +++ b/src/vendor/cigraph/include/igraph_iterators.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_ITERATORS_H @@ -31,7 +26,7 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Vertex selectors */ @@ -51,15 +46,17 @@ typedef enum { typedef struct igraph_vs_t { igraph_vs_type_t type; union { - igraph_integer_t vid; /* single vertex */ + igraph_int_t vid; /* single vertex */ const igraph_vector_int_t *vecptr; /* vector of vertices */ struct { - igraph_integer_t vid; + igraph_int_t vid; igraph_neimode_t mode; + igraph_loops_t loops; + igraph_bool_t multiple; } adj; /* adjacent vertices */ struct { - igraph_integer_t start; /* first index (inclusive) */ - igraph_integer_t end; /* last index (exclusive) */ + igraph_int_t start; /* first index (inclusive) */ + igraph_int_t end; /* last index (exclusive) */ } range; /* range of vertices */ } data; } igraph_vs_t; @@ -67,17 +64,19 @@ typedef struct igraph_vs_t { IGRAPH_EXPORT igraph_error_t igraph_vs_all(igraph_vs_t *vs); IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_vs_t igraph_vss_all(void); -IGRAPH_EXPORT igraph_error_t igraph_vs_adj(igraph_vs_t *vs, - igraph_integer_t vid, igraph_neimode_t mode); +IGRAPH_EXPORT igraph_error_t igraph_vs_adj( + igraph_vs_t *vs, igraph_int_t vid, igraph_neimode_t mode, + igraph_loops_t loops, igraph_bool_t multiple +); -IGRAPH_EXPORT igraph_error_t igraph_vs_nonadj(igraph_vs_t *vs, igraph_integer_t vid, +IGRAPH_EXPORT igraph_error_t igraph_vs_nonadj(igraph_vs_t *vs, igraph_int_t vid, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_vs_none(igraph_vs_t *vs); IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_vs_t igraph_vss_none(void); -IGRAPH_EXPORT igraph_error_t igraph_vs_1(igraph_vs_t *vs, igraph_integer_t vid); -IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_vs_t igraph_vss_1(igraph_integer_t vid); +IGRAPH_EXPORT igraph_error_t igraph_vs_1(igraph_vs_t *vs, igraph_int_t vid); +IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_vs_t igraph_vss_1(igraph_int_t vid); IGRAPH_EXPORT igraph_error_t igraph_vs_vector(igraph_vs_t *vs, const igraph_vector_int_t *v); @@ -88,11 +87,8 @@ IGRAPH_EXPORT igraph_error_t igraph_vs_vector_small(igraph_vs_t *vs, ...); IGRAPH_EXPORT igraph_error_t igraph_vs_vector_copy(igraph_vs_t *vs, const igraph_vector_int_t *v); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_vs_seq(igraph_vs_t *vs, igraph_integer_t from, igraph_integer_t to); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_vs_t igraph_vss_seq(igraph_integer_t from, igraph_integer_t to); - -IGRAPH_EXPORT igraph_error_t igraph_vs_range(igraph_vs_t *vs, igraph_integer_t start, igraph_integer_t end); -IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_vs_t igraph_vss_range(igraph_integer_t start, igraph_integer_t end); +IGRAPH_EXPORT igraph_error_t igraph_vs_range(igraph_vs_t *vs, igraph_int_t start, igraph_int_t end); +IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_vs_t igraph_vss_range(igraph_int_t start, igraph_int_t end); IGRAPH_EXPORT void igraph_vs_destroy(igraph_vs_t *vs); @@ -103,7 +99,7 @@ IGRAPH_EXPORT igraph_error_t igraph_vs_copy(igraph_vs_t* dest, const igraph_vs_t IGRAPH_EXPORT igraph_error_t igraph_vs_as_vector(const igraph_t *graph, igraph_vs_t vs, igraph_vector_int_t *v); IGRAPH_EXPORT igraph_error_t igraph_vs_size(const igraph_t *graph, const igraph_vs_t *vs, - igraph_integer_t *result); + igraph_int_t *result); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_vs_type_t igraph_vs_type(const igraph_vs_t *vs); /* -------------------------------------------------- */ @@ -118,9 +114,9 @@ typedef enum { typedef struct igraph_vit_t { igraph_vit_type_t type; - igraph_integer_t pos; - igraph_integer_t start; /* first index */ - igraph_integer_t end; /* one past last index */ + igraph_int_t pos; + igraph_int_t start; /* first index */ + igraph_int_t end; /* one past last index */ const igraph_vector_int_t *vec; } igraph_vit_t; @@ -215,7 +211,7 @@ typedef struct igraph_vit_t { * Time complexity: O(1). */ #define IGRAPH_VIT_GET(vit) \ - ((igraph_integer_t)(((vit).type == IGRAPH_VIT_RANGE) ? (vit).pos : \ + ((igraph_int_t)(((vit).type == IGRAPH_VIT_RANGE) ? (vit).pos : \ VECTOR(*(vit).vec)[(vit).pos])) IGRAPH_EXPORT igraph_error_t igraph_vit_create(const igraph_t *graph, @@ -240,31 +236,31 @@ typedef enum { IGRAPH_ES_RANGE, IGRAPH_ES_PAIRS, IGRAPH_ES_PATH, - IGRAPH_ES_UNUSED_WAS_MULTIPAIRS, /* placeholder for deprecated IGRAPH_ES_MULTIPAIRS from igraph 0.10 */ IGRAPH_ES_ALL_BETWEEN, } igraph_es_type_t; typedef struct igraph_es_t { igraph_es_type_t type; union { - igraph_integer_t vid; - igraph_integer_t eid; + igraph_int_t vid; + igraph_int_t eid; const igraph_vector_int_t *vecptr; struct { - igraph_integer_t vid; + igraph_int_t vid; igraph_neimode_t mode; + igraph_loops_t loops; } incident; struct { - igraph_integer_t start; /* first index (inclusive) */ - igraph_integer_t end; /* last index (exclusive) */ + igraph_int_t start; /* first index (inclusive) */ + igraph_int_t end; /* last index (exclusive) */ } range; struct { const igraph_vector_int_t *ptr; igraph_bool_t mode; } path; struct { - igraph_integer_t from; - igraph_integer_t to; + igraph_int_t from; + igraph_int_t to; igraph_bool_t directed; } between; } data; @@ -274,24 +270,23 @@ IGRAPH_EXPORT igraph_error_t igraph_es_all(igraph_es_t *es, igraph_edgeorder_type_t order); IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_es_t igraph_ess_all(igraph_edgeorder_type_t order); -IGRAPH_EXPORT igraph_error_t igraph_es_incident(igraph_es_t *es, - igraph_integer_t vid, igraph_neimode_t mode); +IGRAPH_EXPORT igraph_error_t igraph_es_incident( + igraph_es_t *es, igraph_int_t vid, igraph_neimode_t mode, + igraph_loops_t loops +); IGRAPH_EXPORT igraph_error_t igraph_es_none(igraph_es_t *es); IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_es_t igraph_ess_none(void); -IGRAPH_EXPORT igraph_error_t igraph_es_1(igraph_es_t *es, igraph_integer_t eid); -IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_es_t igraph_ess_1(igraph_integer_t eid); +IGRAPH_EXPORT igraph_error_t igraph_es_1(igraph_es_t *es, igraph_int_t eid); +IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_es_t igraph_ess_1(igraph_int_t eid); IGRAPH_EXPORT igraph_error_t igraph_es_vector(igraph_es_t *es, const igraph_vector_int_t *v); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_es_t igraph_ess_vector(const igraph_vector_int_t *v); -IGRAPH_EXPORT igraph_error_t igraph_es_range(igraph_es_t *es, igraph_integer_t from, igraph_integer_t to); -IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_es_t igraph_ess_range(igraph_integer_t from, igraph_integer_t to); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_es_seq(igraph_es_t *es, igraph_integer_t from, igraph_integer_t to); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_es_t igraph_ess_seq(igraph_integer_t from, igraph_integer_t to); +IGRAPH_EXPORT igraph_error_t igraph_es_range(igraph_es_t *es, igraph_int_t from, igraph_int_t to); +IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_es_t igraph_ess_range(igraph_int_t from, igraph_int_t to); IGRAPH_EXPORT igraph_error_t igraph_es_vector_copy(igraph_es_t *es, const igraph_vector_int_t *v); @@ -304,7 +299,7 @@ IGRAPH_EXPORT igraph_error_t igraph_es_path(igraph_es_t *es, const igraph_vector IGRAPH_EXPORT igraph_error_t igraph_es_path_small(igraph_es_t *es, igraph_bool_t directed, int first, ...); IGRAPH_EXPORT igraph_error_t igraph_es_all_between( - igraph_es_t *es, igraph_integer_t from, igraph_integer_t to, + igraph_es_t *es, igraph_int_t from, igraph_int_t to, igraph_bool_t directed ); @@ -317,7 +312,7 @@ IGRAPH_EXPORT igraph_error_t igraph_es_copy(igraph_es_t* dest, const igraph_es_t IGRAPH_EXPORT igraph_error_t igraph_es_as_vector(const igraph_t *graph, igraph_es_t es, igraph_vector_int_t *v); IGRAPH_EXPORT igraph_error_t igraph_es_size(const igraph_t *graph, const igraph_es_t *es, - igraph_integer_t *result); + igraph_int_t *result); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_es_type_t igraph_es_type(const igraph_es_t *es); @@ -333,9 +328,9 @@ typedef enum { typedef struct igraph_eit_t { igraph_eit_type_t type; - igraph_integer_t pos; - igraph_integer_t start; /* first index */ - igraph_integer_t end; /* one past last index */ + igraph_int_t pos; + igraph_int_t start; /* first index */ + igraph_int_t end; /* one past last index */ const igraph_vector_int_t *vec; } igraph_eit_t; @@ -407,7 +402,7 @@ typedef struct igraph_eit_t { * Time complexity: O(1). */ #define IGRAPH_EIT_GET(eit) \ - (igraph_integer_t)((((eit).type == IGRAPH_EIT_RANGE) ? (eit).pos : \ + (igraph_int_t)((((eit).type == IGRAPH_EIT_RANGE) ? (eit).pos : \ VECTOR(*(eit).vec)[(eit).pos])) IGRAPH_EXPORT igraph_error_t igraph_eit_create(const igraph_t *graph, @@ -416,6 +411,6 @@ IGRAPH_EXPORT void igraph_eit_destroy(const igraph_eit_t *eit); IGRAPH_EXPORT igraph_error_t igraph_eit_as_vector(const igraph_eit_t *eit, igraph_vector_int_t *v); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_lapack.h b/src/vendor/cigraph/include/igraph_lapack.h index 76b30f37dd0..aa712f2a3d7 100644 --- a/src/vendor/cigraph/include/igraph_lapack.h +++ b/src/vendor/cigraph/include/igraph_lapack.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2010-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2010-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_LAPACK_H @@ -29,7 +24,7 @@ #include "igraph_vector.h" #include "igraph_matrix.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \section about_lapack LAPACK interface in igraph @@ -107,6 +102,6 @@ IGRAPH_EXPORT igraph_error_t igraph_lapack_dgehrd(const igraph_matrix_t *A, int ilo, int ihi, igraph_matrix_t *result); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_layout.h b/src/vendor/cigraph/include/igraph_layout.h index 7c50781ffc3..00812f02f4d 100644 --- a/src/vendor/cigraph/include/igraph_layout.h +++ b/src/vendor/cigraph/include/igraph_layout.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,28 +13,24 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_LAYOUT_H #define IGRAPH_LAYOUT_H #include "igraph_decls.h" - #include "igraph_constants.h" #include "igraph_datatype.h" #include "igraph_error.h" #include "igraph_iterators.h" +#include "igraph_matrix.h" #include "igraph_matrix_list.h" #include "igraph_types.h" #include "igraph_vector.h" #include "igraph_vector_ptr.h" -#include "igraph_matrix.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \section about_layouts @@ -58,12 +52,12 @@ IGRAPH_EXPORT igraph_error_t igraph_layout_random(const igraph_t *graph, igraph_ IGRAPH_EXPORT igraph_error_t igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res, igraph_vs_t order); IGRAPH_EXPORT igraph_error_t igraph_layout_star(const igraph_t *graph, igraph_matrix_t *res, - igraph_integer_t center, const igraph_vector_int_t *order); -IGRAPH_EXPORT igraph_error_t igraph_layout_grid(const igraph_t *graph, igraph_matrix_t *res, igraph_integer_t width); + igraph_int_t center, const igraph_vector_int_t *order); +IGRAPH_EXPORT igraph_error_t igraph_layout_grid(const igraph_t *graph, igraph_matrix_t *res, igraph_int_t width); IGRAPH_EXPORT igraph_error_t igraph_layout_fruchterman_reingold(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, - igraph_integer_t niter, + igraph_int_t niter, igraph_real_t start_temp, igraph_layout_grid_t grid, const igraph_vector_t *weights, @@ -73,16 +67,16 @@ IGRAPH_EXPORT igraph_error_t igraph_layout_fruchterman_reingold(const igraph_t * const igraph_vector_t *maxy); IGRAPH_EXPORT igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t *res, - igraph_bool_t use_seed, igraph_integer_t maxiter, + igraph_bool_t use_seed, igraph_int_t maxiter, igraph_real_t epsilon, igraph_real_t kkconst, const igraph_vector_t *weights, const igraph_vector_t *minx, const igraph_vector_t *maxx, const igraph_vector_t *miny, const igraph_vector_t *maxy); IGRAPH_EXPORT igraph_error_t igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res, - igraph_integer_t maxiter, igraph_real_t maxdelta, + igraph_int_t maxiter, igraph_real_t maxdelta, igraph_real_t area, igraph_real_t coolexp, - igraph_real_t repulserad, igraph_real_t cellsize, igraph_integer_t root); + igraph_real_t repulserad, igraph_real_t cellsize, igraph_int_t root); IGRAPH_EXPORT igraph_error_t igraph_layout_reingold_tilford(const igraph_t *graph, igraph_matrix_t *res, igraph_neimode_t mode, const igraph_vector_int_t *roots, @@ -92,19 +86,19 @@ IGRAPH_EXPORT igraph_error_t igraph_layout_reingold_tilford_circular(const igrap igraph_neimode_t mode, const igraph_vector_int_t *roots, const igraph_vector_int_t *rootlevel); -IGRAPH_EXPORT igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *res, - igraph_t *extd_graph, igraph_vector_int_t *extd_to_orig_eids, - const igraph_vector_int_t* layers, igraph_real_t hgap, - igraph_real_t vgap, igraph_integer_t maxiter, const igraph_vector_t *weights); +IGRAPH_EXPORT igraph_error_t igraph_layout_sugiyama( + const igraph_t *graph, igraph_matrix_t *res, igraph_matrix_list_t *routing, + const igraph_vector_int_t* layers, igraph_real_t hgap, + igraph_real_t vgap, igraph_int_t maxiter, const igraph_vector_t *weights); IGRAPH_EXPORT igraph_error_t igraph_layout_random_3d(const igraph_t *graph, igraph_matrix_t *res); IGRAPH_EXPORT igraph_error_t igraph_layout_sphere(const igraph_t *graph, igraph_matrix_t *res); IGRAPH_EXPORT igraph_error_t igraph_layout_grid_3d(const igraph_t *graph, igraph_matrix_t *res, - igraph_integer_t width, igraph_integer_t height); + igraph_int_t width, igraph_int_t height); IGRAPH_EXPORT igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, - igraph_integer_t niter, + igraph_int_t niter, igraph_real_t start_temp, const igraph_vector_t *weights, const igraph_vector_t *minx, @@ -115,7 +109,7 @@ IGRAPH_EXPORT igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_ const igraph_vector_t *maxz); IGRAPH_EXPORT igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matrix_t *res, - igraph_bool_t use_seed, igraph_integer_t maxiter, + igraph_bool_t use_seed, igraph_int_t maxiter, igraph_real_t epsilon, igraph_real_t kkconst, const igraph_vector_t *weights, const igraph_vector_t *minx, const igraph_vector_t *maxx, @@ -123,7 +117,7 @@ IGRAPH_EXPORT igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph const igraph_vector_t *minz, const igraph_vector_t *maxz); IGRAPH_EXPORT igraph_error_t igraph_layout_graphopt(const igraph_t *graph, - igraph_matrix_t *res, igraph_integer_t niter, + igraph_matrix_t *res, igraph_int_t niter, igraph_real_t node_charge, igraph_real_t node_mass, igraph_real_t spring_length, igraph_real_t spring_constant, @@ -131,30 +125,30 @@ IGRAPH_EXPORT igraph_error_t igraph_layout_graphopt(const igraph_t *graph, igraph_bool_t use_seed); IGRAPH_EXPORT igraph_error_t igraph_layout_mds(const igraph_t *graph, igraph_matrix_t *res, - const igraph_matrix_t *dist, igraph_integer_t dim); + const igraph_matrix_t *dist, igraph_int_t dim); IGRAPH_EXPORT igraph_error_t igraph_layout_bipartite(const igraph_t *graph, const igraph_vector_bool_t *types, igraph_matrix_t *res, igraph_real_t hgap, - igraph_real_t vgap, igraph_integer_t maxiter); + igraph_real_t vgap, igraph_int_t maxiter); -IGRAPH_EXPORT igraph_error_t igraph_layout_umap(const igraph_t *graph, +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_layout_umap(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, const igraph_vector_t *distances, igraph_real_t min_dist, - igraph_integer_t epochs, + igraph_int_t epochs, igraph_bool_t distances_are_weights); -IGRAPH_EXPORT igraph_error_t igraph_layout_umap_3d(const igraph_t *graph, +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_layout_umap_3d(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, const igraph_vector_t *distances, igraph_real_t min_dist, - igraph_integer_t epochs, + igraph_int_t epochs, igraph_bool_t distances_are_weights); -IGRAPH_EXPORT igraph_error_t igraph_layout_umap_compute_weights(const igraph_t *graph, +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_layout_umap_compute_weights(const igraph_t *graph, const igraph_vector_t *distances, igraph_vector_t *weights); @@ -198,27 +192,27 @@ IGRAPH_EXPORT igraph_error_t igraph_layout_umap_compute_weights(const igraph_t * typedef struct igraph_layout_drl_options_t { igraph_real_t edge_cut; - igraph_integer_t init_iterations; + igraph_int_t init_iterations; igraph_real_t init_temperature; igraph_real_t init_attraction; igraph_real_t init_damping_mult; - igraph_integer_t liquid_iterations; + igraph_int_t liquid_iterations; igraph_real_t liquid_temperature; igraph_real_t liquid_attraction; igraph_real_t liquid_damping_mult; - igraph_integer_t expansion_iterations; + igraph_int_t expansion_iterations; igraph_real_t expansion_temperature; igraph_real_t expansion_attraction; igraph_real_t expansion_damping_mult; - igraph_integer_t cooldown_iterations; + igraph_int_t cooldown_iterations; igraph_real_t cooldown_temperature; igraph_real_t cooldown_attraction; igraph_real_t cooldown_damping_mult; - igraph_integer_t crunch_iterations; + igraph_int_t crunch_iterations; igraph_real_t crunch_temperature; igraph_real_t crunch_attraction; igraph_real_t crunch_damping_mult; - igraph_integer_t simmer_iterations; + igraph_int_t simmer_iterations; igraph_real_t simmer_temperature; igraph_real_t simmer_attraction; igraph_real_t simmer_damping_mult; @@ -262,13 +256,13 @@ IGRAPH_EXPORT igraph_error_t igraph_layout_merge_dla(const igraph_vector_ptr_t * igraph_matrix_t *res); IGRAPH_EXPORT igraph_error_t igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res, - igraph_bool_t use_seed, igraph_integer_t maxiter, + igraph_bool_t use_seed, igraph_int_t maxiter, igraph_real_t temp_max, igraph_real_t temp_min, igraph_real_t temp_init); IGRAPH_EXPORT igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix_t *res, - igraph_bool_t use_seed, igraph_integer_t maxiter, - igraph_integer_t fineiter, igraph_real_t cool_fact, + igraph_bool_t use_seed, igraph_int_t maxiter, + igraph_int_t fineiter, igraph_real_t cool_fact, igraph_real_t weight_node_dist, igraph_real_t weight_border, igraph_real_t weight_edge_lengths, igraph_real_t weight_edge_crossings, @@ -294,6 +288,6 @@ IGRAPH_EXPORT igraph_error_t igraph_roots_for_tree_layout( IGRAPH_EXPORT igraph_error_t igraph_layout_align(const igraph_t *graph, igraph_matrix_t *layout); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_lsap.h b/src/vendor/cigraph/include/igraph_lsap.h index 61898d40ca5..64a7fdf8623 100644 --- a/src/vendor/cigraph/include/igraph_lsap.h +++ b/src/vendor/cigraph/include/igraph_lsap.h @@ -1,3 +1,20 @@ +/* + igraph library. + Copyright (C) 2014-2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ #ifndef IGRAPH_LSAP_H #define IGRAPH_LSAP_H @@ -8,11 +25,11 @@ #include "igraph_vector.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS -IGRAPH_EXPORT igraph_error_t igraph_solve_lsap(const igraph_matrix_t *c, igraph_integer_t n, +IGRAPH_EXPORT igraph_error_t igraph_solve_lsap(const igraph_matrix_t *c, igraph_int_t n, igraph_vector_int_t *p); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_matching.h b/src/vendor/cigraph/include/igraph_matching.h index 44b9082f488..bd9ad0a5424 100644 --- a/src/vendor/cigraph/include/igraph_matching.h +++ b/src/vendor/cigraph/include/igraph_matching.h @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2012 Tamas Nepusz + igraph library. + Copyright (C) 2012-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_MATCHING_H @@ -29,7 +25,7 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Matchings in graphs */ @@ -43,10 +39,10 @@ IGRAPH_EXPORT igraph_error_t igraph_is_maximal_matching(const igraph_t* graph, igraph_bool_t* result); IGRAPH_EXPORT igraph_error_t igraph_maximum_bipartite_matching(const igraph_t* graph, - const igraph_vector_bool_t* types, igraph_integer_t* matching_size, + const igraph_vector_bool_t* types, igraph_int_t* matching_size, igraph_real_t* matching_weight, igraph_vector_int_t* matching, const igraph_vector_t* weights, igraph_real_t eps); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_matrix.h b/src/vendor/cigraph/include/igraph_matrix.h index f092d7a0789..0644c4876ff 100644 --- a/src/vendor/cigraph/include/igraph_matrix.h +++ b/src/vendor/cigraph/include/igraph_matrix.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_MATRIX_H @@ -28,7 +23,7 @@ #include "igraph_error.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Matrix, very similar to vector */ @@ -87,9 +82,6 @@ __BEGIN_DECLS */ #define MATRIX(m,i,j) ((m).data.stor_begin[(m).nrow*(j)+(i)]) -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_bool_t igraph_matrix_all_e_tol(const igraph_matrix_t *lhs, - const igraph_matrix_t *rhs, - igraph_real_t tol); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_matrix_all_almost_e(const igraph_matrix_t *lhs, const igraph_matrix_t *rhs, @@ -98,6 +90,6 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_matrix_all_almost_e(cons IGRAPH_EXPORT igraph_error_t igraph_matrix_zapsmall(igraph_matrix_t *m, igraph_real_t tol); IGRAPH_EXPORT igraph_error_t igraph_matrix_complex_zapsmall(igraph_matrix_complex_t *m, igraph_real_t tol); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_matrix_list.h b/src/vendor/cigraph/include/igraph_matrix_list.h index 1e44cf8d405..e2f1dd1e422 100644 --- a/src/vendor/cigraph/include/igraph_matrix_list.h +++ b/src/vendor/cigraph/include/igraph_matrix_list.h @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2022 The igraph development team + igraph library. + Copyright (C) 2022-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_MATRIX_LIST_H @@ -28,7 +24,7 @@ #include "igraph_matrix.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Flexible list of matrices */ @@ -54,6 +50,6 @@ __BEGIN_DECLS do { IGRAPH_CHECK(igraph_matrix_list_init(v, size)); \ IGRAPH_FINALLY(igraph_matrix_list_destroy, v); } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_matrix_pmt.h b/src/vendor/cigraph/include/igraph_matrix_pmt.h index 32697530ee9..6ca4c452738 100644 --- a/src/vendor/cigraph/include/igraph_matrix_pmt.h +++ b/src/vendor/cigraph/include/igraph_matrix_pmt.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2007-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,15 +13,12 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ typedef struct TYPE(igraph_matrix) { TYPE(igraph_vector) data; - igraph_integer_t nrow, ncol; + igraph_int_t nrow, ncol; } TYPE(igraph_matrix); /*---------------*/ @@ -31,32 +26,25 @@ typedef struct TYPE(igraph_matrix) { /*---------------*/ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, init)( - TYPE(igraph_matrix) *m, igraph_integer_t nrow, igraph_integer_t ncol); + TYPE(igraph_matrix) *m, igraph_int_t nrow, igraph_int_t ncol); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, init_array)( - TYPE(igraph_matrix)* m, const BASE* data, igraph_integer_t nrow, igraph_integer_t ncol, igraph_matrix_storage_t storage); + TYPE(igraph_matrix)* m, const BASE* data, igraph_int_t nrow, igraph_int_t ncol, igraph_matrix_storage_t storage); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, init_copy)( TYPE(igraph_matrix) *to, const TYPE(igraph_matrix) *from); IGRAPH_EXPORT void FUNCTION(igraph_matrix, destroy)(TYPE(igraph_matrix) *m); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_matrix, capacity)(const TYPE(igraph_matrix) *m); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t FUNCTION(igraph_matrix, copy)( - TYPE(igraph_matrix) *to, const TYPE(igraph_matrix) *from); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_matrix, capacity)(const TYPE(igraph_matrix) *m); /*--------------------*/ /* Accessing elements */ /*--------------------*/ /* MATRIX */ -IGRAPH_EXPORT IGRAPH_DEPRECATED BASE FUNCTION(igraph_matrix, e)( - const TYPE(igraph_matrix) *m, igraph_integer_t row, igraph_integer_t col); -IGRAPH_EXPORT IGRAPH_DEPRECATED BASE* FUNCTION(igraph_matrix, e_ptr)( - const TYPE(igraph_matrix) *m, igraph_integer_t row, igraph_integer_t col); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_matrix, get)( - const TYPE(igraph_matrix) *m, igraph_integer_t row, igraph_integer_t col); + const TYPE(igraph_matrix) *m, igraph_int_t row, igraph_int_t col); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE* FUNCTION(igraph_matrix, get_ptr)( - const TYPE(igraph_matrix) *m, igraph_integer_t row, igraph_integer_t col); + const TYPE(igraph_matrix) *m, igraph_int_t row, igraph_int_t col); IGRAPH_EXPORT void FUNCTION(igraph_matrix, set)( - TYPE(igraph_matrix)* m, igraph_integer_t row, igraph_integer_t col, BASE value); + TYPE(igraph_matrix)* m, igraph_int_t row, igraph_int_t col, BASE value); /*------------------------------*/ /* Initializing matrix elements */ @@ -69,39 +57,39 @@ IGRAPH_EXPORT void FUNCTION(igraph_matrix, fill)(TYPE(igraph_matrix) *m, BASE e) /* Matrix views */ /*-----------------------*/ -IGRAPH_EXPORT const TYPE(igraph_matrix) *FUNCTION(igraph_matrix, view)( - const TYPE(igraph_matrix) *m, const BASE *data, - igraph_integer_t nrow, igraph_integer_t ncol); -IGRAPH_EXPORT const TYPE(igraph_matrix) *FUNCTION(igraph_matrix, view_from_vector)( - const TYPE(igraph_matrix) *m, const TYPE(igraph_vector) *v, - igraph_integer_t ncol +IGRAPH_EXPORT TYPE(igraph_matrix) FUNCTION(igraph_matrix, view)( + const BASE *data, + igraph_int_t nrow, igraph_int_t ncol); +IGRAPH_EXPORT TYPE(igraph_matrix) FUNCTION(igraph_matrix, view_from_vector)( + const TYPE(igraph_vector) *v, + igraph_int_t ncol ); /*------------------*/ /* Copying matrices */ /*------------------*/ -IGRAPH_EXPORT void FUNCTION(igraph_matrix, copy_to)(const TYPE(igraph_matrix) *m, BASE *to); +IGRAPH_EXPORT void FUNCTION(igraph_matrix, copy_to)(const TYPE(igraph_matrix) *m, BASE *to, igraph_matrix_storage_t storage); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, update)(TYPE(igraph_matrix) *to, const TYPE(igraph_matrix) *from); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, rbind)(TYPE(igraph_matrix) *to, const TYPE(igraph_matrix) *from); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, cbind)(TYPE(igraph_matrix) *to, const TYPE(igraph_matrix) *from); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, swap)(TYPE(igraph_matrix) *m1, TYPE(igraph_matrix) *m2); +IGRAPH_EXPORT void FUNCTION(igraph_matrix, swap)(TYPE(igraph_matrix) *m1, TYPE(igraph_matrix) *m2); /*--------------------------*/ /* Copying rows and columns */ /*--------------------------*/ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, get_row)( - const TYPE(igraph_matrix) *m, TYPE(igraph_vector) *res, igraph_integer_t index); + const TYPE(igraph_matrix) *m, TYPE(igraph_vector) *res, igraph_int_t index); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, get_col)( - const TYPE(igraph_matrix) *m, TYPE(igraph_vector) *res, igraph_integer_t index); + const TYPE(igraph_matrix) *m, TYPE(igraph_vector) *res, igraph_int_t index); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, set_row)( - TYPE(igraph_matrix) *m, const TYPE(igraph_vector) *v, igraph_integer_t index); + TYPE(igraph_matrix) *m, const TYPE(igraph_vector) *v, igraph_int_t index); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, set_col)( - TYPE(igraph_matrix) *m, const TYPE(igraph_vector) *v, igraph_integer_t index); + TYPE(igraph_matrix) *m, const TYPE(igraph_vector) *v, igraph_int_t index); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, select_rows)( const TYPE(igraph_matrix) *m, TYPE(igraph_matrix) *res, const igraph_vector_int_t *rows); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, select_cols)( @@ -115,11 +103,11 @@ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, select_rows_cols)( /*-----------------------------*/ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, swap_rows)( - TYPE(igraph_matrix) *m, igraph_integer_t i, igraph_integer_t j); + TYPE(igraph_matrix) *m, igraph_int_t i, igraph_int_t j); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, swap_cols)( - TYPE(igraph_matrix) *m, igraph_integer_t i, igraph_integer_t j); + TYPE(igraph_matrix) *m, igraph_int_t i, igraph_int_t j); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, swap_rowcol)( - TYPE(igraph_matrix) *m, igraph_integer_t i, igraph_integer_t j); + TYPE(igraph_matrix) *m, igraph_int_t i, igraph_int_t j); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, transpose)(TYPE(igraph_matrix) *m); /*-----------------------------*/ @@ -145,14 +133,14 @@ IGRAPH_EXPORT void FUNCTION(igraph_matrix, add_constant)(TYPE(igraph_matrix) *m, IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t FUNCTION(igraph_matrix, min)(const TYPE(igraph_matrix) *m); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t FUNCTION(igraph_matrix, max)(const TYPE(igraph_matrix) *m); IGRAPH_EXPORT void FUNCTION(igraph_matrix, which_min)( - const TYPE(igraph_matrix) *m, igraph_integer_t *i, igraph_integer_t *j); + const TYPE(igraph_matrix) *m, igraph_int_t *i, igraph_int_t *j); IGRAPH_EXPORT void FUNCTION(igraph_matrix, which_max)( - const TYPE(igraph_matrix) *m, igraph_integer_t *i, igraph_integer_t *j); + const TYPE(igraph_matrix) *m, igraph_int_t *i, igraph_int_t *j); IGRAPH_EXPORT void FUNCTION(igraph_matrix, minmax)( const TYPE(igraph_matrix) *m, BASE *min, BASE *max); IGRAPH_EXPORT void FUNCTION(igraph_matrix, which_minmax)( - const TYPE(igraph_matrix) *m, igraph_integer_t *imin, igraph_integer_t *jmin, - igraph_integer_t *imax, igraph_integer_t *jmax); + const TYPE(igraph_matrix) *m, igraph_int_t *imin, igraph_int_t *jmin, + igraph_int_t *imax, igraph_int_t *jmax); #endif /*------------------------------*/ @@ -178,9 +166,9 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_matrix, all_ge) IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_matrix, isnull)(const TYPE(igraph_matrix) *m); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_matrix, empty)(const TYPE(igraph_matrix) *m); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_matrix, size)(const TYPE(igraph_matrix) *m); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_matrix, nrow)(const TYPE(igraph_matrix) *m); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_matrix, ncol)(const TYPE(igraph_matrix) *m); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_matrix, size)(const TYPE(igraph_matrix) *m); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_matrix, nrow)(const TYPE(igraph_matrix) *m); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_matrix, ncol)(const TYPE(igraph_matrix) *m); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_matrix, is_symmetric)(const TYPE(igraph_matrix) *m); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_matrix, sum)(const TYPE(igraph_matrix) *m); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_matrix, prod)(const TYPE(igraph_matrix) *m); @@ -202,25 +190,25 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t FUNCTION(igraph_matrix, maxdiff IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_matrix, contains)( const TYPE(igraph_matrix) *m, BASE e); IGRAPH_EXPORT igraph_bool_t FUNCTION(igraph_matrix, search)( - const TYPE(igraph_matrix) *m, igraph_integer_t from, BASE what, - igraph_integer_t *pos, igraph_integer_t *row, igraph_integer_t *col); + const TYPE(igraph_matrix) *m, igraph_int_t from, BASE what, + igraph_int_t *pos, igraph_int_t *row, igraph_int_t *col); /*------------------------*/ /* Resizing operations */ /*------------------------*/ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, resize)( - TYPE(igraph_matrix) *m, igraph_integer_t nrow, igraph_integer_t ncol); + TYPE(igraph_matrix) *m, igraph_int_t nrow, igraph_int_t ncol); IGRAPH_EXPORT void FUNCTION(igraph_matrix, resize_min)( TYPE(igraph_matrix) *m); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, add_cols)( - TYPE(igraph_matrix) *m, igraph_integer_t n); + TYPE(igraph_matrix) *m, igraph_int_t n); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, add_rows)( - TYPE(igraph_matrix) *m, igraph_integer_t n); + TYPE(igraph_matrix) *m, igraph_int_t n); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, remove_col)( - TYPE(igraph_matrix) *m, igraph_integer_t col); + TYPE(igraph_matrix) *m, igraph_int_t col); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, remove_row)( - TYPE(igraph_matrix) *m, igraph_integer_t row); + TYPE(igraph_matrix) *m, igraph_int_t row); /*------------------------*/ /* Print as text */ @@ -260,4 +248,4 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_matrix_complex_all_almos #endif /* BASE_COMPLEX */ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_matrix, permdelete_rows)( - TYPE(igraph_matrix) *m, igraph_integer_t *index, igraph_integer_t nremove); + TYPE(igraph_matrix) *m, igraph_int_t *index, igraph_int_t nremove); diff --git a/src/vendor/cigraph/include/igraph_memory.h b/src/vendor/cigraph/include/igraph_memory.h index 46048b41706..81bdf6cd9de 100644 --- a/src/vendor/cigraph/include/igraph_memory.h +++ b/src/vendor/cigraph/include/igraph_memory.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2003-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2003-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_MEMORY_H @@ -29,7 +24,7 @@ #include #include -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* Helper macro to check if n*sizeof(t) overflows in IGRAPH_CALLOC and IGRAPH_REALLOC */ #define IGRAPH_I_ALLOC_CHECK_OVERFLOW(n,t,expr) \ @@ -40,17 +35,11 @@ __BEGIN_DECLS #define IGRAPH_REALLOC(p,n,t) IGRAPH_I_ALLOC_CHECK_OVERFLOW(n, t, realloc((void*)(p), sizeof(t) * ((n) > 0 ? (n) : 1))) #define IGRAPH_FREE(p) (free( (void *)(p) ), (p) = NULL) -/* These are deprecated and scheduled for removal in 0.11 */ -#define igraph_Calloc IGRAPH_CALLOC -#define igraph_Realloc IGRAPH_REALLOC -#define igraph_Free IGRAPH_FREE -/* Deprecated section ends here */ - IGRAPH_EXPORT void *igraph_calloc(size_t count, size_t size); IGRAPH_EXPORT void *igraph_malloc(size_t size); IGRAPH_EXPORT void *igraph_realloc(void* ptr, size_t size); IGRAPH_EXPORT void igraph_free(void *ptr); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_microscopic_update.h b/src/vendor/cigraph/include/igraph_microscopic_update.h deleted file mode 100644 index b400468b7b0..00000000000 --- a/src/vendor/cigraph/include/igraph_microscopic_update.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- mode: C -*- */ -/* - Microscopic update rules for dealing with agent-level strategy revision. - Copyright (C) 2011 Minh Van Nguyen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA -*/ - -#ifndef IGRAPH_MICROSCOPIC_UPDATE_H -#define IGRAPH_MICROSCOPIC_UPDATE_H - -#include "igraph_decls.h" -#include "igraph_constants.h" -#include "igraph_datatype.h" -#include "igraph_error.h" -#include "igraph_iterators.h" -#include "igraph_types.h" -#include "igraph_vector.h" - -__BEGIN_DECLS - -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_deterministic_optimal_imitation(const igraph_t *graph, - igraph_integer_t vid, - igraph_optimal_t optimality, - const igraph_vector_t *quantities, - igraph_vector_int_t *strategies, - igraph_neimode_t mode); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_moran_process(const igraph_t *graph, - const igraph_vector_t *weights, - igraph_vector_t *quantities, - igraph_vector_int_t *strategies, - igraph_neimode_t mode); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_roulette_wheel_imitation(const igraph_t *graph, - igraph_integer_t vid, - igraph_bool_t islocal, - const igraph_vector_t *quantities, - igraph_vector_int_t *strategies, - igraph_neimode_t mode); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_stochastic_imitation(const igraph_t *graph, - igraph_integer_t vid, - igraph_imitate_algorithm_t algo, - const igraph_vector_t *quantities, - igraph_vector_int_t *strategies, - igraph_neimode_t mode); - -__END_DECLS - -#endif diff --git a/src/vendor/cigraph/include/igraph_mixing.h b/src/vendor/cigraph/include/igraph_mixing.h index b69a6c8f777..c0028a6f1c5 100644 --- a/src/vendor/cigraph/include/igraph_mixing.h +++ b/src/vendor/cigraph/include/igraph_mixing.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_MIXING_H @@ -31,20 +26,19 @@ #include "igraph_vector.h" #include "igraph_matrix.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS -IGRAPH_EXPORT igraph_error_t igraph_assortativity_nominal(const igraph_t *graph, - const igraph_vector_int_t *types, - igraph_real_t *res, - igraph_bool_t directed, - igraph_bool_t normalized); +IGRAPH_EXPORT igraph_error_t igraph_assortativity_nominal( + const igraph_t *graph, const igraph_vector_t *weights, + const igraph_vector_int_t *types, + igraph_real_t *res, + igraph_bool_t directed, igraph_bool_t normalized); -IGRAPH_EXPORT igraph_error_t igraph_assortativity(const igraph_t *graph, - const igraph_vector_t *values, - const igraph_vector_t *values_in, - igraph_real_t *res, - igraph_bool_t directed, - igraph_bool_t normalized); +IGRAPH_EXPORT igraph_error_t igraph_assortativity( + const igraph_t *graph, const igraph_vector_t *weights, + const igraph_vector_t *values, const igraph_vector_t *values_in, + igraph_real_t *res, + igraph_bool_t directed, igraph_bool_t normalized); IGRAPH_EXPORT igraph_error_t igraph_assortativity_degree(const igraph_t *graph, igraph_real_t *res, @@ -53,14 +47,14 @@ IGRAPH_EXPORT igraph_error_t igraph_assortativity_degree(const igraph_t *graph, IGRAPH_EXPORT igraph_error_t igraph_joint_degree_matrix( const igraph_t *graph, const igraph_vector_t *weights, igraph_matrix_t *jdm, - igraph_integer_t dout, igraph_integer_t din); + igraph_int_t dout, igraph_int_t din); IGRAPH_EXPORT igraph_error_t igraph_joint_degree_distribution( const igraph_t *graph, const igraph_vector_t *weights, igraph_matrix_t *p, igraph_neimode_t from_mode, igraph_neimode_t to_mode, igraph_bool_t directed_neighbors, igraph_bool_t normalized, - igraph_integer_t max_from_degree, igraph_integer_t max_to_degree); + igraph_int_t max_from_degree, igraph_int_t max_to_degree); IGRAPH_EXPORT igraph_error_t igraph_joint_type_distribution( const igraph_t *graph, const igraph_vector_t *weights, @@ -68,6 +62,6 @@ IGRAPH_EXPORT igraph_error_t igraph_joint_type_distribution( const igraph_vector_int_t *from_types, const igraph_vector_int_t *to_types, igraph_bool_t directed, igraph_bool_t normalized); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_motifs.h b/src/vendor/cigraph/include/igraph_motifs.h index 74de61a9c27..c46d3546521 100644 --- a/src/vendor/cigraph/include/igraph_motifs.h +++ b/src/vendor/cigraph/include/igraph_motifs.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_MOTIFS_H @@ -30,7 +25,7 @@ #include "igraph_error.h" #include "igraph_iterators.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Graph motifs */ @@ -66,24 +61,24 @@ __BEGIN_DECLS */ typedef igraph_error_t igraph_motifs_handler_t(const igraph_t *graph, - igraph_vector_int_t *vids, - igraph_integer_t isoclass, - void* extra); + const igraph_vector_int_t *vids, + igraph_int_t isoclass, + void *extra); IGRAPH_EXPORT igraph_error_t igraph_motifs_randesu(const igraph_t *graph, igraph_vector_t *hist, - igraph_integer_t size, const igraph_vector_t *cut_prob); + igraph_int_t size, const igraph_vector_t *cut_prob); -IGRAPH_EXPORT igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_integer_t size, +IGRAPH_EXPORT igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_int_t size, const igraph_vector_t *cut_prob, igraph_motifs_handler_t *callback, void* extra); -IGRAPH_EXPORT igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_integer_t *est, - igraph_integer_t size, const igraph_vector_t *cut_prob, - igraph_integer_t sample_size, +IGRAPH_EXPORT igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_real_t *est, + igraph_int_t size, const igraph_vector_t *cut_prob, + igraph_int_t sample_size, const igraph_vector_int_t *sample); -IGRAPH_EXPORT igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t *no, - igraph_integer_t size, const igraph_vector_t *cut_prob); +IGRAPH_EXPORT igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_real_t *no, + igraph_int_t size, const igraph_vector_t *cut_prob); IGRAPH_EXPORT igraph_error_t igraph_dyad_census(const igraph_t *graph, igraph_real_t *mut, igraph_real_t *asym, igraph_real_t *null); @@ -91,17 +86,13 @@ IGRAPH_EXPORT igraph_error_t igraph_triad_census(const igraph_t *igraph, igraph_ IGRAPH_EXPORT igraph_error_t igraph_count_adjacent_triangles(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_adjacent_triangles(const igraph_t *graph, - igraph_vector_t *res, - const igraph_vs_t vids); + igraph_vs_t vids); IGRAPH_EXPORT igraph_error_t igraph_list_triangles(const igraph_t *graph, igraph_vector_int_t *res); IGRAPH_EXPORT igraph_error_t igraph_count_triangles(const igraph_t *graph, igraph_real_t *res); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_neighborhood.h b/src/vendor/cigraph/include/igraph_neighborhood.h index d96d22c9cf9..da5e089a630 100644 --- a/src/vendor/cigraph/include/igraph_neighborhood.h +++ b/src/vendor/cigraph/include/igraph_neighborhood.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_NEIGHBORHOOD_H @@ -31,19 +26,19 @@ #include "igraph_iterators.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_EXPORT igraph_error_t igraph_neighborhood_size(const igraph_t *graph, igraph_vector_int_t *res, - igraph_vs_t vids, igraph_integer_t order, - igraph_neimode_t mode, igraph_integer_t mindist); + igraph_vs_t vids, igraph_int_t order, + igraph_neimode_t mode, igraph_int_t mindist); IGRAPH_EXPORT igraph_error_t igraph_neighborhood(const igraph_t *graph, igraph_vector_int_list_t *res, - igraph_vs_t vids, igraph_integer_t order, - igraph_neimode_t mode, igraph_integer_t mindist); + igraph_vs_t vids, igraph_int_t order, + igraph_neimode_t mode, igraph_int_t mindist); IGRAPH_EXPORT igraph_error_t igraph_neighborhood_graphs(const igraph_t *graph, igraph_graph_list_t *res, - igraph_vs_t vids, igraph_integer_t order, + igraph_vs_t vids, igraph_int_t order, igraph_neimode_t mode, - igraph_integer_t mindist); + igraph_int_t mindist); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_nongraph.h b/src/vendor/cigraph/include/igraph_nongraph.h index b84755d21b4..2be9cef3e8b 100644 --- a/src/vendor/cigraph/include/igraph_nongraph.h +++ b/src/vendor/cigraph/include/igraph_nongraph.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_NONGRAPH_H @@ -26,11 +21,10 @@ #include "igraph_decls.h" #include "igraph_error.h" -#include "igraph_matrix.h" #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \def IGRAPH_SHORTEST_PATH_EPSILON @@ -40,13 +34,6 @@ __BEGIN_DECLS */ #define IGRAPH_SHORTEST_PATH_EPSILON 1e-10 -typedef igraph_real_t igraph_scalar_function_t(const igraph_vector_t *var, - const igraph_vector_t *par, - void* extra); -typedef void igraph_vector_function_t(const igraph_vector_t *var, - const igraph_vector_t *par, - igraph_vector_t* res, void* extra); - /* -------------------------------------------------- */ /* Other, not graph related */ /* -------------------------------------------------- */ @@ -89,11 +76,9 @@ typedef struct igraph_plfit_result_t { } igraph_plfit_result_t; IGRAPH_EXPORT igraph_error_t igraph_running_mean(const igraph_vector_t *data, igraph_vector_t *res, - igraph_integer_t binwidth); -IGRAPH_EXPORT igraph_error_t igraph_random_sample(igraph_vector_int_t *res, igraph_integer_t l, igraph_integer_t h, - igraph_integer_t length); -IGRAPH_EXPORT igraph_error_t igraph_convex_hull_2d(const igraph_matrix_t *data, igraph_vector_int_t *resverts, - igraph_matrix_t *rescoords); + igraph_int_t binwidth); +IGRAPH_EXPORT igraph_error_t igraph_random_sample(igraph_vector_int_t *res, igraph_int_t l, igraph_int_t h, + igraph_int_t length); IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST igraph_bool_t igraph_almost_equals(double a, double b, double eps); IGRAPH_EXPORT IGRAPH_FUNCATTR_CONST int igraph_cmp_epsilon(double a, double b, double eps); @@ -105,15 +90,6 @@ IGRAPH_EXPORT igraph_error_t igraph_plfit_result_calculate_p_value( const igraph_plfit_result_t* model, igraph_real_t* result, igraph_real_t precision ); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_zeroin( - igraph_real_t *ax, igraph_real_t *bx, igraph_real_t (*f)(igraph_real_t x, void *info), - void *info, igraph_real_t *Tol, int *Maxit, igraph_real_t *res -); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_convex_hull( - const igraph_matrix_t *data, igraph_vector_int_t *resverts, - igraph_matrix_t *rescoords); - -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_operators.h b/src/vendor/cigraph/include/igraph_operators.h index 0e080336b1e..5e6100f8d95 100644 --- a/src/vendor/cigraph/include/igraph_operators.h +++ b/src/vendor/cigraph/include/igraph_operators.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,32 +13,47 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_OPERATORS_H #define IGRAPH_OPERATORS_H #include "igraph_decls.h" - #include "igraph_attributes.h" #include "igraph_constants.h" #include "igraph_datatype.h" #include "igraph_error.h" +#include "igraph_graphicality.h" #include "igraph_types.h" #include "igraph_vector_list.h" #include "igraph_vector_ptr.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Graph operators */ /* -------------------------------------------------- */ -IGRAPH_EXPORT igraph_error_t igraph_add_edge(igraph_t *graph, igraph_integer_t from, igraph_integer_t to); +/** + * \typedef igraph_rewiring_stats_t + * \brief Data structure holding statistics from graph rewiring. + * + * \param successful_swaps Number of successful rewiring trials (successful swaps). + */ + +typedef struct { + igraph_int_t successful_swaps; + + /* unused members added at the end to allow us to extend the stats in the future + * without breaking ABI compatibility. Do not use these fields in your own code */ + + igraph_int_t unused1_; + igraph_int_t unused2_; + igraph_int_t unused3_; +} igraph_rewiring_stats_t; + +IGRAPH_EXPORT igraph_error_t igraph_add_edge(igraph_t *graph, igraph_int_t from, igraph_int_t to); IGRAPH_EXPORT igraph_error_t igraph_disjoint_union(igraph_t *res, const igraph_t *left, const igraph_t *right); IGRAPH_EXPORT igraph_error_t igraph_disjoint_union_many(igraph_t *res, @@ -69,42 +82,37 @@ IGRAPH_EXPORT igraph_error_t igraph_contract_vertices(igraph_t *graph, const igraph_attribute_combination_t *vertex_comb); IGRAPH_EXPORT igraph_error_t igraph_permute_vertices(const igraph_t *graph, igraph_t *res, const igraph_vector_int_t *permutation); -IGRAPH_EXPORT igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t order, +IGRAPH_EXPORT igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_int_t order, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_graph_power(const igraph_t *graph, igraph_t *res, - igraph_integer_t order, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode); + igraph_int_t order, igraph_bool_t directed); +IGRAPH_EXPORT igraph_error_t igraph_rewire(igraph_t *graph, igraph_int_t n, igraph_edge_type_sw_t allowed_edge_types, + igraph_rewiring_stats_t *stats); IGRAPH_EXPORT igraph_error_t igraph_simplify(igraph_t *graph, igraph_bool_t remove_multiple, igraph_bool_t remove_loops, const igraph_attribute_combination_t *edge_comb); IGRAPH_EXPORT igraph_error_t igraph_induced_subgraph_map(const igraph_t *graph, igraph_t *res, - const igraph_vs_t vids, + igraph_vs_t vids, igraph_subgraph_implementation_t impl, igraph_vector_int_t *map, igraph_vector_int_t *invmap); IGRAPH_EXPORT igraph_error_t igraph_induced_subgraph(const igraph_t *graph, igraph_t *res, - const igraph_vs_t vids, igraph_subgraph_implementation_t impl); + igraph_vs_t vids, igraph_subgraph_implementation_t impl); IGRAPH_EXPORT igraph_error_t igraph_induced_subgraph_edges( const igraph_t *graph, igraph_vs_t vids, igraph_vector_int_t *edges); IGRAPH_EXPORT igraph_error_t igraph_subgraph_from_edges(const igraph_t *graph, igraph_t *res, - const igraph_es_t eids, igraph_bool_t delete_vertices); -IGRAPH_EXPORT igraph_error_t igraph_reverse_edges(igraph_t *graph, const igraph_es_t eids); - -IGRAPH_EXPORT igraph_error_t igraph_product(igraph_t *res, + igraph_es_t eids, igraph_bool_t delete_vertices); +IGRAPH_EXPORT igraph_error_t igraph_reverse_edges(igraph_t *graph, igraph_es_t eids); +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_product(igraph_t *res, const igraph_t *g1, const igraph_t *g2, igraph_product_t type); -IGRAPH_EXPORT igraph_error_t igraph_rooted_product(igraph_t *res, +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_rooted_product(igraph_t *res, const igraph_t *g1, const igraph_t *g2, - const igraph_integer_t root); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_subgraph_edges( - const igraph_t *graph, igraph_t *res, const igraph_es_t eids, - igraph_bool_t delete_vertices -); - -IGRAPH_EXPORT igraph_error_t igraph_mycielskian(const igraph_t *graph, igraph_t *res, igraph_integer_t k); + igraph_int_t root); +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_mycielskian(const igraph_t *graph, igraph_t *res, igraph_int_t k); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_paths.h b/src/vendor/cigraph/include/igraph_paths.h index 015c489866c..d15d274c97b 100644 --- a/src/vendor/cigraph/include/igraph_paths.h +++ b/src/vendor/cigraph/include/igraph_paths.h @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2021 The igraph development team + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,9 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA + along with this program. If not, see . */ #ifndef IGRAPH_PATHS_H @@ -32,7 +29,7 @@ #include "igraph_vector.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \typedef igraph_astar_heuristic_func_t @@ -62,7 +59,7 @@ __BEGIN_DECLS */ typedef igraph_error_t igraph_astar_heuristic_func_t( igraph_real_t *result, - igraph_integer_t from, igraph_integer_t to, + igraph_int_t from, igraph_int_t to, void *extra); typedef enum { @@ -71,50 +68,35 @@ typedef enum { IGRAPH_FLOYD_WARSHALL_TREE = 2 } igraph_floyd_warshall_algorithm_t; -IGRAPH_EXPORT igraph_error_t igraph_diameter(const igraph_t *graph, igraph_real_t *res, - igraph_integer_t *from, igraph_integer_t *to, - igraph_vector_int_t *vertex_path, igraph_vector_int_t *edge_path, - igraph_bool_t directed, igraph_bool_t unconn); -IGRAPH_EXPORT igraph_error_t igraph_diameter_dijkstra(const igraph_t *graph, - const igraph_vector_t *weights, - igraph_real_t *res, - igraph_integer_t *from, - igraph_integer_t *to, - igraph_vector_int_t *vertex_path, - igraph_vector_int_t *edge_path, - igraph_bool_t directed, - igraph_bool_t unconn); - -IGRAPH_EXPORT igraph_error_t igraph_distances_cutoff(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t from, const igraph_vs_t to, - igraph_neimode_t mode, igraph_real_t cutoff); -IGRAPH_EXPORT igraph_error_t igraph_distances(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t from, const igraph_vs_t to, - igraph_neimode_t mode); +IGRAPH_EXPORT igraph_error_t igraph_diameter( + const igraph_t *graph, const igraph_vector_t *weights, igraph_real_t *res, + igraph_int_t *from, igraph_int_t *to, + igraph_vector_int_t *vertex_path, igraph_vector_int_t *edge_path, + igraph_bool_t directed, igraph_bool_t unconn +); + +IGRAPH_EXPORT igraph_error_t igraph_distances( + const igraph_t *graph, const igraph_vector_t *weights, igraph_matrix_t *res, + igraph_vs_t from, igraph_vs_t to, igraph_neimode_t mode +); IGRAPH_EXPORT igraph_error_t igraph_distances_bellman_ford(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, + igraph_vs_t from, + igraph_vs_t to, const igraph_vector_t *weights, igraph_neimode_t mode); -IGRAPH_EXPORT igraph_error_t igraph_distances_dijkstra_cutoff(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights, - igraph_neimode_t mode, - igraph_real_t cutoff); IGRAPH_EXPORT igraph_error_t igraph_distances_dijkstra(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, + igraph_vs_t from, + igraph_vs_t to, const igraph_vector_t *weights, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_distances_johnson(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights); + igraph_vs_t from, + igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_distances_floyd_warshall(const igraph_t *graph, igraph_matrix_t *res, igraph_vs_t from, @@ -122,38 +104,26 @@ IGRAPH_EXPORT igraph_error_t igraph_distances_floyd_warshall(const igraph_t *gra const igraph_vector_t *weights, igraph_neimode_t mode, igraph_floyd_warshall_algorithm_t method); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_shortest_paths(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t from, const igraph_vs_t to, - igraph_neimode_t mode); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_shortest_paths_bellman_ford(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights, - igraph_neimode_t mode); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_shortest_paths_dijkstra(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights, - igraph_neimode_t mode); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_shortest_paths_johnson(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights); -IGRAPH_EXPORT igraph_error_t igraph_get_shortest_paths(const igraph_t *graph, - igraph_vector_int_list_t *vertices, - igraph_vector_int_list_t *edges, - igraph_integer_t from, const igraph_vs_t to, - igraph_neimode_t mode, - igraph_vector_int_t *parents, - igraph_vector_int_t *inbound_edges); +IGRAPH_EXPORT igraph_error_t igraph_distances_cutoff( + const igraph_t *graph, const igraph_vector_t *weights, igraph_matrix_t *res, + igraph_vs_t from, igraph_vs_t to, igraph_neimode_t mode, igraph_real_t cutoff +); +IGRAPH_EXPORT igraph_error_t igraph_distances_dijkstra_cutoff( + const igraph_t *graph, igraph_matrix_t *res, igraph_vs_t from, igraph_vs_t to, + const igraph_vector_t *weights, igraph_neimode_t mode, igraph_real_t cutoff +); + +IGRAPH_EXPORT igraph_error_t igraph_get_shortest_paths( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_int_list_t *vertices, igraph_vector_int_list_t *edges, + igraph_int_t from, igraph_vs_t to, igraph_neimode_t mode, + igraph_vector_int_t *parents, igraph_vector_int_t *inbound_edges +); IGRAPH_EXPORT igraph_error_t igraph_get_shortest_paths_bellman_ford(const igraph_t *graph, igraph_vector_int_list_t *vertices, igraph_vector_int_list_t *edges, - igraph_integer_t from, + igraph_int_t from, igraph_vs_t to, const igraph_vector_t *weights, igraph_neimode_t mode, @@ -162,143 +132,120 @@ IGRAPH_EXPORT igraph_error_t igraph_get_shortest_paths_bellman_ford(const igraph IGRAPH_EXPORT igraph_error_t igraph_get_shortest_paths_dijkstra(const igraph_t *graph, igraph_vector_int_list_t *vertices, igraph_vector_int_list_t *edges, - igraph_integer_t from, + igraph_int_t from, igraph_vs_t to, const igraph_vector_t *weights, igraph_neimode_t mode, igraph_vector_int_t *parents, igraph_vector_int_t *inbound_edges); -IGRAPH_EXPORT igraph_error_t igraph_get_shortest_path(const igraph_t *graph, - igraph_vector_int_t *vertices, - igraph_vector_int_t *edges, - igraph_integer_t from, - igraph_integer_t to, - igraph_neimode_t mode); +IGRAPH_EXPORT igraph_error_t igraph_get_shortest_path( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_int_t *vertices, igraph_vector_int_t *edges, + igraph_int_t from, igraph_int_t to, igraph_neimode_t mode +); IGRAPH_EXPORT igraph_error_t igraph_get_shortest_path_bellman_ford(const igraph_t *graph, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t from, - igraph_integer_t to, + igraph_int_t from, + igraph_int_t to, const igraph_vector_t *weights, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_get_shortest_path_dijkstra(const igraph_t *graph, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t from, - igraph_integer_t to, + igraph_int_t from, + igraph_int_t to, const igraph_vector_t *weights, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_get_shortest_path_astar(const igraph_t *graph, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t from, - igraph_integer_t to, + igraph_int_t from, + igraph_int_t to, const igraph_vector_t *weights, igraph_neimode_t mode, igraph_astar_heuristic_func_t *heuristic, void *extra); -IGRAPH_EXPORT igraph_error_t igraph_get_all_shortest_paths(const igraph_t *graph, - igraph_vector_int_list_t *vertices, - igraph_vector_int_list_t *edges, - igraph_vector_int_t *nrgeo, - igraph_integer_t from, const igraph_vs_t to, - igraph_neimode_t mode); +IGRAPH_EXPORT igraph_error_t igraph_get_all_shortest_paths( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_int_list_t *vertices, igraph_vector_int_list_t *edges, + igraph_vector_int_t *nrgeo, igraph_int_t from, igraph_vs_t to, + igraph_neimode_t mode +); IGRAPH_EXPORT igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, igraph_vector_int_list_t *vertices, igraph_vector_int_list_t *edges, igraph_vector_int_t *nrgeo, - igraph_integer_t from, igraph_vs_t to, + igraph_int_t from, igraph_vs_t to, const igraph_vector_t *weights, igraph_neimode_t mode); -IGRAPH_EXPORT igraph_error_t igraph_average_path_length(const igraph_t *graph, - igraph_real_t *res, igraph_real_t *unconn_pairs, - igraph_bool_t directed, igraph_bool_t unconn); -IGRAPH_EXPORT igraph_error_t igraph_average_path_length_dijkstra(const igraph_t *graph, - igraph_real_t *res, igraph_real_t *unconn_pairs, - const igraph_vector_t *weights, - igraph_bool_t directed, igraph_bool_t unconn); +IGRAPH_EXPORT igraph_error_t igraph_average_path_length( + const igraph_t *graph, const igraph_vector_t *weights, igraph_real_t *res, + igraph_real_t *unconn_pairs, igraph_bool_t directed, igraph_bool_t unconn +); IGRAPH_EXPORT igraph_error_t igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *res, igraph_real_t *unconnected, igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_global_efficiency(const igraph_t *graph, igraph_real_t *res, - const igraph_vector_t *weights, - igraph_bool_t directed); -IGRAPH_EXPORT igraph_error_t igraph_local_efficiency(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, - const igraph_vector_t *weights, - igraph_bool_t directed, igraph_neimode_t mode); -IGRAPH_EXPORT igraph_error_t igraph_average_local_efficiency(const igraph_t *graph, igraph_real_t *res, - const igraph_vector_t *weights, - igraph_bool_t directed, igraph_neimode_t mode); - -IGRAPH_EXPORT igraph_error_t igraph_eccentricity(const igraph_t *graph, - igraph_vector_t *res, - igraph_vs_t vids, - igraph_neimode_t mode); - -IGRAPH_EXPORT igraph_error_t igraph_eccentricity_dijkstra(const igraph_t *graph, - const igraph_vector_t *weights, - igraph_vector_t *res, - igraph_vs_t vids, - igraph_neimode_t mode); - -IGRAPH_EXPORT igraph_error_t igraph_radius(const igraph_t *graph, igraph_real_t *radius, - igraph_neimode_t mode); - -IGRAPH_EXPORT igraph_error_t igraph_radius_dijkstra(const igraph_t *graph, const igraph_vector_t *weights, - igraph_real_t *radius, igraph_neimode_t mode); - -IGRAPH_EXPORT igraph_error_t igraph_graph_center(const igraph_t *graph, - igraph_vector_int_t *res, - igraph_neimode_t mode); - -IGRAPH_EXPORT igraph_error_t igraph_graph_center_dijkstra( +IGRAPH_EXPORT igraph_error_t igraph_global_efficiency( + const igraph_t *graph, const igraph_vector_t *weights, igraph_real_t *res, + igraph_bool_t directed +); +IGRAPH_EXPORT igraph_error_t igraph_local_efficiency( + const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_t *res, + igraph_vs_t vids, igraph_bool_t directed, igraph_neimode_t mode +); +IGRAPH_EXPORT igraph_error_t igraph_average_local_efficiency( + const igraph_t *graph, const igraph_vector_t *weights, igraph_real_t *res, + igraph_bool_t directed, igraph_neimode_t mode +); + +IGRAPH_EXPORT igraph_error_t igraph_eccentricity( + const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_t *res, + igraph_vs_t vids, igraph_neimode_t mode +); + +IGRAPH_EXPORT igraph_error_t igraph_radius( + const igraph_t *graph, const igraph_vector_t *weights, igraph_real_t *radius, + igraph_neimode_t mode +); + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_graph_center( const igraph_t *graph, const igraph_vector_t *weights, - igraph_vector_int_t *res, igraph_neimode_t mode); + igraph_vector_int_t *res, igraph_neimode_t mode +); -IGRAPH_EXPORT igraph_error_t igraph_pseudo_diameter(const igraph_t *graph, - igraph_real_t *diameter, - igraph_integer_t vid_start, - igraph_integer_t *from, - igraph_integer_t *to, - igraph_bool_t directed, - igraph_bool_t unconn); -IGRAPH_EXPORT igraph_error_t igraph_pseudo_diameter_dijkstra(const igraph_t *graph, - const igraph_vector_t *weights, - igraph_real_t *diameter, - igraph_integer_t vid_start, - igraph_integer_t *from, - igraph_integer_t *to, - igraph_bool_t directed, - igraph_bool_t unconn); +IGRAPH_EXPORT igraph_error_t igraph_pseudo_diameter( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_real_t *diameter, igraph_int_t vid_start, + igraph_int_t *from, igraph_int_t *to, + igraph_bool_t directed, igraph_bool_t unconn +); -IGRAPH_EXPORT igraph_error_t igraph_get_all_simple_paths(const igraph_t *graph, - igraph_vector_int_t *res, - igraph_integer_t from, - const igraph_vs_t to, - igraph_integer_t cutoff, - igraph_neimode_t mode); +IGRAPH_EXPORT igraph_error_t +igraph_get_all_simple_paths(const igraph_t *graph, igraph_vector_int_list_t *res, igraph_int_t from, + const igraph_vs_t to, igraph_neimode_t mode, igraph_int_t minlen, + igraph_int_t maxlen, igraph_int_t max_results); IGRAPH_EXPORT igraph_error_t igraph_random_walk(const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t start, + igraph_int_t start, igraph_neimode_t mode, - igraph_integer_t steps, + igraph_int_t steps, igraph_random_walk_stuck_t stuck); IGRAPH_EXPORT igraph_error_t igraph_get_k_shortest_paths(const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_int_list_t *vertex_paths, igraph_vector_int_list_t *edge_paths, - igraph_integer_t k, - igraph_integer_t from, - igraph_integer_t to, + igraph_int_t k, + igraph_int_t from, + igraph_int_t to, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_spanner(const igraph_t *graph, @@ -309,7 +256,7 @@ IGRAPH_EXPORT igraph_error_t igraph_spanner(const igraph_t *graph, IGRAPH_EXPORT igraph_error_t igraph_get_widest_paths(const igraph_t *graph, igraph_vector_int_list_t *vertices, igraph_vector_int_list_t *edges, - igraph_integer_t from, + igraph_int_t from, igraph_vs_t to, const igraph_vector_t *weights, igraph_neimode_t mode, @@ -318,20 +265,20 @@ IGRAPH_EXPORT igraph_error_t igraph_get_widest_paths(const igraph_t *graph, IGRAPH_EXPORT igraph_error_t igraph_get_widest_path(const igraph_t *graph, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t from, - igraph_integer_t to, + igraph_int_t from, + igraph_int_t to, const igraph_vector_t *weights, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_widest_path_widths_floyd_warshall(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, + igraph_vs_t from, + igraph_vs_t to, const igraph_vector_t *weights, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_widest_path_widths_dijkstra(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, + igraph_vs_t from, + igraph_vs_t to, const igraph_vector_t *weights, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_voronoi(const igraph_t *graph, @@ -345,20 +292,10 @@ IGRAPH_EXPORT igraph_error_t igraph_voronoi(const igraph_t *graph, IGRAPH_EXPORT igraph_error_t igraph_expand_path_to_pairs(igraph_vector_int_t *path); IGRAPH_EXPORT igraph_error_t igraph_vertex_path_from_edge_path( - const igraph_t *graph, igraph_integer_t start, + const igraph_t *graph, igraph_int_t start, const igraph_vector_int_t *edge_path, igraph_vector_int_t *vertex_path, igraph_neimode_t mode); -/* Deprecated functions: */ - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_random_edge_walk(const igraph_t *graph, - const igraph_vector_t *weights, - igraph_vector_int_t *edgewalk, - igraph_integer_t start, - igraph_neimode_t mode, - igraph_integer_t steps, - igraph_random_walk_stuck_t stuck); - -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_pmt.h b/src/vendor/cigraph/include/igraph_pmt.h index de90c1ee3da..1032cce93f6 100644 --- a/src/vendor/cigraph/include/igraph_pmt.h +++ b/src/vendor/cigraph/include/igraph_pmt.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2007-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #define CONCAT2x(a,b) a ## _ ## b @@ -68,7 +63,7 @@ #define EQ(a,b) ((a && b) || (!a && !b)) #elif defined(BASE_INT) - #define BASE igraph_integer_t + #define BASE igraph_int_t #define BASE_VECTOR igraph_vector_int_t #define BASE_MATRIX igraph_matrix_int_t #define SHORT int @@ -116,6 +111,9 @@ #elif defined(BASE_GRAPH) #define BASE igraph_t +#elif defined(BASE_ATTRIBUTE_RECORD) + #define BASE igraph_attribute_record_t + #elif defined(BASE_BITSET) #define BASE igraph_bitset_t @@ -159,11 +157,14 @@ #define FUNCTION(c) CONCAT2x(igraph_graph_list,c) #define INTERNAL_FUNCTION(c) CONCAT2x(igraph_i_graph_list,c) #define TYPE igraph_graph_list_t +#elif defined(ATTRIBUTE_RECORD_LIST) + #define FUNCTION(c) CONCAT2x(igraph_attribute_record_list,c) + #define INTERNAL_FUNCTION(c) CONCAT2x(igraph_i_attribute_record_list,c) + #define TYPE igraph_attribute_record_list_t #elif defined(BITSET_LIST) #define FUNCTION(c) CONCAT2x(igraph_bitset_list,c) #define INTERNAL_FUNCTION(c) CONCAT2x(igraph_i_bitset_list,c) #define TYPE igraph_bitset_list_t - #else #if defined(BASE_IGRAPH_REAL) #define FUNCTION(a,c) CONCAT2(a,c) diff --git a/src/vendor/cigraph/include/igraph_pmt_off.h b/src/vendor/cigraph/include/igraph_pmt_off.h index 03ef43c7fd3..14be2b8d39a 100644 --- a/src/vendor/cigraph/include/igraph_pmt_off.h +++ b/src/vendor/cigraph/include/igraph_pmt_off.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2007-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifdef ATOMIC diff --git a/src/vendor/cigraph/include/igraph_progress.h b/src/vendor/cigraph/include/igraph_progress.h index f85139a412d..48055af0c69 100644 --- a/src/vendor/cigraph/include/igraph_progress.h +++ b/src/vendor/cigraph/include/igraph_progress.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_PROGRESS_H @@ -28,7 +23,7 @@ #include "igraph_error.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \section about_progress_handlers About progress handlers @@ -138,9 +133,8 @@ __BEGIN_DECLS * reporting, and then pass some meaningfull context here. * \return If the return value of the progress handler is not * \c IGRAPH_SUCCESS, then \ref igraph_progress() returns the - * error code \c IGRAPH_INTERRUPTED. The \ref IGRAPH_PROGRESS() - * macro frees all memory and finishes the igraph function with - * error code \c IGRAPH_INTERRUPTED in this case. + * error code from the progress handler intact. The \ref IGRAPH_PROGRESS() + * macro also frees all allocated memory. */ typedef igraph_error_t igraph_progress_handler_t(const char *message, igraph_real_t percent, @@ -157,7 +151,7 @@ IGRAPH_EXPORT igraph_error_t igraph_progressf(const char *message, igraph_real_t /** * \define IGRAPH_PROGRESS - * \brief Report progress. + * \brief Report the progress of a calculation from an igraph function (macro variant). * * The standard way to report progress from an igraph function * \param message A string, a textual message that references the @@ -165,20 +159,39 @@ IGRAPH_EXPORT igraph_error_t igraph_progressf(const char *message, igraph_real_t * \param percent Numeric scalar, the percentage that is complete. * \param data User-defined data, this can be used in user-defined * progress handler functions, from user-written igraph functions. - * \return If the progress handler returns with \c IGRAPH_INTERRUPTED, - * then this macro frees up the igraph allocated memory for - * temporary data and returns to the caller with \c - * IGRAPH_INTERRUPTED. + * \return If the return value of the progress handler is not + * \c IGRAPH_SUCCESS, then \ref igraph_progress() returns the + * error code from the progress handler intact. The \ref IGRAPH_PROGRESS() + * macro also frees all allocated memory. */ #define IGRAPH_PROGRESS(message, percent, data) \ do { \ - if (igraph_progress((message), (percent), (data)) != IGRAPH_SUCCESS) { \ - IGRAPH_FINALLY_FREE(); \ - return IGRAPH_INTERRUPTED; \ - } \ + IGRAPH_CHECK(igraph_progress((message), (percent), (data))); \ + } while (0) + +/** + * \define IGRAPH_PROGRESSF + * \brief Report the progress of a calculation from an igraph function, printf-like (macro variant). + * + * This is the more flexible version of \ref IGRAPH_PROGRESS(), + * having a printf-like syntax. As this macro takes variable + * number of arguments, they must be all supplied as a single + * argument, enclosed in parentheses. \ref igraph_progressf() is then + * called with the given arguments. + * + * \param args The arguments to pass to \ref igraph_progressf(). + * \return If the progress handler returns with a value other than + * \c IGRAPH_SUCCESS, then the function that called this + * macro returns as well, with the same error code, after + * cleaning up all allocated memory as needed. + */ + +#define IGRAPH_PROGRESSF(args) \ + do { \ + IGRAPH_CHECK(igraph_progressf args); \ } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_psumtree.h b/src/vendor/cigraph/include/igraph_psumtree.h index 2588680f7af..5e3d5e731bf 100644 --- a/src/vendor/cigraph/include/igraph_psumtree.h +++ b/src/vendor/cigraph/include/igraph_psumtree.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_PSUMTREE_H @@ -28,25 +23,25 @@ #include "igraph_error.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS typedef struct { igraph_vector_t v; - igraph_integer_t size; - igraph_integer_t offset; + igraph_int_t size; + igraph_int_t offset; } igraph_psumtree_t; -IGRAPH_EXPORT igraph_error_t igraph_psumtree_init(igraph_psumtree_t *t, igraph_integer_t size); +IGRAPH_EXPORT igraph_error_t igraph_psumtree_init(igraph_psumtree_t *t, igraph_int_t size); IGRAPH_EXPORT void igraph_psumtree_reset(igraph_psumtree_t *t); IGRAPH_EXPORT void igraph_psumtree_destroy(igraph_psumtree_t *t); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t igraph_psumtree_get(const igraph_psumtree_t *t, igraph_integer_t idx); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_psumtree_size(const igraph_psumtree_t *t); -IGRAPH_EXPORT igraph_error_t igraph_psumtree_search(const igraph_psumtree_t *t, igraph_integer_t *idx, +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t igraph_psumtree_get(const igraph_psumtree_t *t, igraph_int_t idx); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_psumtree_size(const igraph_psumtree_t *t); +IGRAPH_EXPORT igraph_error_t igraph_psumtree_search(const igraph_psumtree_t *t, igraph_int_t *idx, igraph_real_t elem); -IGRAPH_EXPORT igraph_error_t igraph_psumtree_update(igraph_psumtree_t *t, igraph_integer_t idx, +IGRAPH_EXPORT igraph_error_t igraph_psumtree_update(igraph_psumtree_t *t, igraph_int_t idx, igraph_real_t new_value); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t igraph_psumtree_sum(const igraph_psumtree_t *t); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_qsort.h b/src/vendor/cigraph/include/igraph_qsort.h index 94e5e7f6777..9992727e029 100644 --- a/src/vendor/cigraph/include/igraph_qsort.h +++ b/src/vendor/cigraph/include/igraph_qsort.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2011-2012 Gabor Csardi - 334 Harvard st, Cambridge, MA 02139, USA + igraph library. + Copyright (C) 2011-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_QSORT_H @@ -28,13 +23,13 @@ #include -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_EXPORT void igraph_qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *)); IGRAPH_EXPORT void igraph_qsort_r(void *base, size_t nel, size_t width, void *thunk, int (*compar)(void *, const void *, const void *)); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_random.h b/src/vendor/cigraph/include/igraph_random.h index 6d8af083b23..c3efc387447 100644 --- a/src/vendor/cigraph/include/igraph_random.h +++ b/src/vendor/cigraph/include/igraph_random.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2003-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2003-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,24 +13,20 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_RANDOM_H #define IGRAPH_RANDOM_H #include "igraph_decls.h" +#include "igraph_error.h" #include "igraph_types.h" -#include "igraph_vector.h" #include #include -#include -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* The new RNG interface is (somewhat) modelled on the GSL */ @@ -73,7 +67,7 @@ __BEGIN_DECLS * the caller is responsible for ensuring that this is the case. You can always * assume that hi > lo. Note that both endpoints are _inclusive_, and you must * make sure that your generation scheme works for both 32-bit and 64-bit - * versions of igraph_integer_t as igraph can be compiled for both cases. If + * versions of igraph_int_t as igraph can be compiled for both cases. If * you are unsure, leave get_int() unimplemented and igraph will provide its * own implementation based on get(). */ @@ -94,11 +88,11 @@ typedef struct igraph_rng_type_t { /* Optional generators; defaults are provided by igraph that rely solely * on get() */ - igraph_integer_t (*get_int)(void *state, igraph_integer_t l, igraph_integer_t h); + igraph_int_t (*get_int)(void *state, igraph_int_t l, igraph_int_t h); igraph_real_t (*get_real)(void *state); igraph_real_t (*get_norm)(void *state); igraph_real_t (*get_geom)(void *state, igraph_real_t p); - igraph_real_t (*get_binom)(void *state, igraph_integer_t n, igraph_real_t p); + igraph_real_t (*get_binom)(void *state, igraph_int_t n, igraph_real_t p); igraph_real_t (*get_exp)(void *state, igraph_real_t rate); igraph_real_t (*get_gamma)(void *state, igraph_real_t shape, igraph_real_t scale); @@ -117,13 +111,13 @@ IGRAPH_EXPORT igraph_error_t igraph_rng_init(igraph_rng_t *rng, const igraph_rng IGRAPH_EXPORT void igraph_rng_destroy(igraph_rng_t *rng); IGRAPH_EXPORT igraph_error_t igraph_rng_seed(igraph_rng_t *rng, igraph_uint_t seed); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_rng_bits(const igraph_rng_t* rng); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_rng_bits(const igraph_rng_t* rng); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_uint_t igraph_rng_max(const igraph_rng_t *rng); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE const char *igraph_rng_name(const igraph_rng_t *rng); IGRAPH_EXPORT igraph_bool_t igraph_rng_get_bool(igraph_rng_t *rng) ; -IGRAPH_EXPORT igraph_integer_t igraph_rng_get_integer( - igraph_rng_t *rng, igraph_integer_t l, igraph_integer_t h +IGRAPH_EXPORT igraph_int_t igraph_rng_get_integer( + igraph_rng_t *rng, igraph_int_t l, igraph_int_t h ); IGRAPH_EXPORT igraph_real_t igraph_rng_get_normal( igraph_rng_t *rng, igraph_real_t m, igraph_real_t s @@ -134,15 +128,13 @@ IGRAPH_EXPORT igraph_real_t igraph_rng_get_unif( IGRAPH_EXPORT igraph_real_t igraph_rng_get_unif01(igraph_rng_t *rng); IGRAPH_EXPORT igraph_real_t igraph_rng_get_geom(igraph_rng_t *rng, igraph_real_t p); IGRAPH_EXPORT igraph_real_t igraph_rng_get_binom( - igraph_rng_t *rng, igraph_integer_t n, igraph_real_t p + igraph_rng_t *rng, igraph_int_t n, igraph_real_t p ); IGRAPH_EXPORT igraph_real_t igraph_rng_get_exp(igraph_rng_t *rng, igraph_real_t rate); IGRAPH_EXPORT igraph_real_t igraph_rng_get_gamma( igraph_rng_t *rng, igraph_real_t shape, igraph_real_t scale ); IGRAPH_EXPORT igraph_real_t igraph_rng_get_pois(igraph_rng_t *rng, igraph_real_t rate); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_rng_get_dirichlet( - igraph_rng_t *rng, const igraph_vector_t *alpha, igraph_vector_t *result); /* --------------------------------- */ @@ -152,28 +144,10 @@ IGRAPH_EXPORT extern const igraph_rng_type_t igraph_rngtype_pcg32; IGRAPH_EXPORT extern const igraph_rng_type_t igraph_rngtype_pcg64; IGRAPH_EXPORT igraph_rng_t *igraph_rng_default(void); -IGRAPH_EXPORT void igraph_rng_set_default(igraph_rng_t *rng); +IGRAPH_EXPORT igraph_rng_t *igraph_rng_set_default(igraph_rng_t *rng); /* --------------------------------- */ -#ifdef USING_R - -void GetRNGstate(void); -void PutRNGstate(void); -#define RNG_BEGIN() GetRNGstate() -#define RNG_END() PutRNGstate() - -#else - -#define RNG_BEGIN() \ - do { if (!igraph_rng_default()->is_seeded) { \ - igraph_rng_seed(igraph_rng_default(), time(0)); \ - igraph_rng_default()->is_seeded = true; \ - } } while (0) -#define RNG_END() \ - do { /* nothing */ } while (0) -#endif - #define RNG_BOOL() (igraph_rng_get_bool(igraph_rng_default())) #define RNG_INTEGER(l,h) (igraph_rng_get_integer(igraph_rng_default(),(l),(h))) #define RNG_NORMAL(m,s) (igraph_rng_get_normal(igraph_rng_default(),(m),(s))) @@ -186,6 +160,6 @@ void PutRNGstate(void); #define RNG_GAMMA(shape, scale) \ (igraph_rng_get_gamma(igraph_rng_default(), (shape), (scale))) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_reachability.h b/src/vendor/cigraph/include/igraph_reachability.h index 472655e8b9a..b51f99888f5 100644 --- a/src/vendor/cigraph/include/igraph_reachability.h +++ b/src/vendor/cigraph/include/igraph_reachability.h @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2024 The igraph development team + igraph library. + Copyright (C) 2024-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,13 +25,13 @@ #include "igraph_error.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_EXPORT igraph_error_t igraph_reachability( const igraph_t *graph, igraph_vector_int_t *membership, igraph_vector_int_t *csize, - igraph_integer_t *no_of_components, + igraph_int_t *no_of_components, igraph_bitset_list_t *reach, igraph_neimode_t mode); @@ -44,6 +44,6 @@ IGRAPH_EXPORT igraph_error_t igraph_count_reachable( IGRAPH_EXPORT igraph_error_t igraph_transitive_closure(const igraph_t *graph, igraph_t* closure); -__END_DECLS +IGRAPH_END_C_DECLS #endif // IGRAPH_REACHABILITY_H diff --git a/src/vendor/cigraph/include/igraph_sampling.h b/src/vendor/cigraph/include/igraph_sampling.h new file mode 100644 index 00000000000..322e7ced09c --- /dev/null +++ b/src/vendor/cigraph/include/igraph_sampling.h @@ -0,0 +1,45 @@ +/* + igraph library. + Copyright (C) 2003-2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef IGRAPH_SAMPLING_H +#define IGRAPH_SAMPLING_H + +#include "igraph_decls.h" +#include "igraph_error.h" +#include "igraph_matrix.h" +#include "igraph_random.h" + +IGRAPH_BEGIN_C_DECLS + +IGRAPH_EXPORT igraph_error_t igraph_rng_sample_sphere_surface( + igraph_rng_t* rng, igraph_int_t dim, igraph_int_t n, igraph_real_t radius, + igraph_bool_t positive, igraph_matrix_t *res +); + +IGRAPH_EXPORT igraph_error_t igraph_rng_sample_sphere_volume( + igraph_rng_t* rng, igraph_int_t dim, igraph_int_t n, igraph_real_t radius, + igraph_bool_t positive, igraph_matrix_t *res +); + +IGRAPH_EXPORT igraph_error_t igraph_rng_sample_dirichlet( + igraph_rng_t* rng, igraph_int_t n, const igraph_vector_t *alpha, igraph_matrix_t *res +); + +IGRAPH_END_C_DECLS + +#endif diff --git a/src/vendor/cigraph/include/igraph_scan.h b/src/vendor/cigraph/include/igraph_scan.h index bfc47c46626..c3eb73c4ca0 100644 --- a/src/vendor/cigraph/include/igraph_scan.h +++ b/src/vendor/cigraph/include/igraph_scan.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2013 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2013-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_SCAN_H @@ -30,7 +25,7 @@ #include "igraph_error.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_EXPORT igraph_error_t igraph_local_scan_0(const igraph_t *graph, igraph_vector_t *res, const igraph_vector_t *weights, igraph_neimode_t mode); @@ -49,13 +44,13 @@ IGRAPH_EXPORT igraph_error_t igraph_local_scan_1_ecount_them(const igraph_t *us, const igraph_vector_t *weights, igraph_neimode_t mode); -IGRAPH_EXPORT igraph_error_t igraph_local_scan_k_ecount(const igraph_t *graph, igraph_integer_t k, +IGRAPH_EXPORT igraph_error_t igraph_local_scan_k_ecount(const igraph_t *graph, igraph_int_t k, igraph_vector_t *res, const igraph_vector_t *weights, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_local_scan_k_ecount_them(const igraph_t *us, const igraph_t *them, - igraph_integer_t k, igraph_vector_t *res, + igraph_int_t k, igraph_vector_t *res, const igraph_vector_t *weights_them, igraph_neimode_t mode); @@ -67,6 +62,6 @@ IGRAPH_EXPORT igraph_error_t igraph_local_scan_subset_ecount(const igraph_t *gra igraph_vector_t *res, const igraph_vector_t *weights, const igraph_vector_int_list_t *neighborhoods); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_separators.h b/src/vendor/cigraph/include/igraph_separators.h index 7008d9261b1..1108a01c973 100644 --- a/src/vendor/cigraph/include/igraph_separators.h +++ b/src/vendor/cigraph/include/igraph_separators.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2010-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2010-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,39 +13,35 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_SEPARATORS_H #define IGRAPH_SEPARATORS_H #include "igraph_decls.h" - #include "igraph_datatype.h" #include "igraph_error.h" #include "igraph_iterators.h" #include "igraph_types.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_EXPORT igraph_error_t igraph_is_separator(const igraph_t *graph, - const igraph_vs_t candidate, + igraph_vs_t candidate, igraph_bool_t *res); IGRAPH_EXPORT igraph_error_t igraph_all_minimal_st_separators(const igraph_t *graph, igraph_vector_int_list_t *separators); IGRAPH_EXPORT igraph_error_t igraph_is_minimal_separator(const igraph_t *graph, - const igraph_vs_t candidate, + igraph_vs_t candidate, igraph_bool_t *res); IGRAPH_EXPORT igraph_error_t igraph_minimum_size_separators(const igraph_t *graph, igraph_vector_int_list_t *separators); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_setup.h b/src/vendor/cigraph/include/igraph_setup.h new file mode 100644 index 00000000000..90532d146f8 --- /dev/null +++ b/src/vendor/cigraph/include/igraph_setup.h @@ -0,0 +1,31 @@ +/* + igraph library. + Copyright (C) 2003-2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef IGRAPH_SETUP_H +#define IGRAPH_SETUP_H + +#include "igraph_decls.h" +#include "igraph_error.h" + +IGRAPH_BEGIN_C_DECLS + +IGRAPH_EXPORT igraph_error_t igraph_setup(void); + +IGRAPH_END_C_DECLS + +#endif diff --git a/src/vendor/cigraph/include/igraph_sparsemat.h b/src/vendor/cigraph/include/igraph_sparsemat.h index f054a1d4038..1ea5778ecb6 100644 --- a/src/vendor/cigraph/include/igraph_sparsemat.h +++ b/src/vendor/cigraph/include/igraph_sparsemat.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2010-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_SPARSEMAT_H @@ -28,15 +23,14 @@ #include "igraph_error.h" #include "igraph_types.h" #include "igraph_vector.h" -#include "igraph_datatype.h" #include "igraph_arpack.h" #include -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* - * These types are private to igraph, and customized to use igraph_integer_t. + * These types are private to igraph, and customized to use igraph_int_t. * Do not attempt to access them using a separate copy of the CXSparse library. * Use the public igraph_sparsemat_... types instead. */ @@ -62,29 +56,29 @@ typedef enum { IGRAPH_SPARSEMAT_TRIPLET, typedef struct { const igraph_sparsemat_t *mat; - igraph_integer_t pos; - igraph_integer_t col; + igraph_int_t pos; + igraph_int_t col; } igraph_sparsemat_iterator_t; IGRAPH_EXPORT igraph_error_t igraph_sparsemat_init( - igraph_sparsemat_t *A, igraph_integer_t rows, igraph_integer_t cols, - igraph_integer_t nzmax + igraph_sparsemat_t *A, igraph_int_t rows, igraph_int_t cols, + igraph_int_t nzmax ); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_init_copy( igraph_sparsemat_t *to, const igraph_sparsemat_t *from); IGRAPH_EXPORT void igraph_sparsemat_destroy(igraph_sparsemat_t *A); -IGRAPH_EXPORT igraph_error_t igraph_sparsemat_realloc(igraph_sparsemat_t *A, igraph_integer_t nzmax); +IGRAPH_EXPORT igraph_error_t igraph_sparsemat_realloc(igraph_sparsemat_t *A, igraph_int_t nzmax); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_init_eye(igraph_sparsemat_t *A, - igraph_integer_t n, igraph_integer_t nzmax, + igraph_int_t n, igraph_int_t nzmax, igraph_real_t value, igraph_bool_t compress); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_init_diag(igraph_sparsemat_t *A, - igraph_integer_t nzmax, const igraph_vector_t *values, + igraph_int_t nzmax, const igraph_vector_t *values, igraph_bool_t compress); -IGRAPH_EXPORT igraph_integer_t igraph_sparsemat_nrow(const igraph_sparsemat_t *A); -IGRAPH_EXPORT igraph_integer_t igraph_sparsemat_ncol(const igraph_sparsemat_t *B); +IGRAPH_EXPORT igraph_int_t igraph_sparsemat_nrow(const igraph_sparsemat_t *A); +IGRAPH_EXPORT igraph_int_t igraph_sparsemat_ncol(const igraph_sparsemat_t *B); IGRAPH_EXPORT igraph_sparsemat_type_t igraph_sparsemat_type(const igraph_sparsemat_t *A); IGRAPH_EXPORT igraph_bool_t igraph_sparsemat_is_triplet(const igraph_sparsemat_t *A); IGRAPH_EXPORT igraph_bool_t igraph_sparsemat_is_cc(const igraph_sparsemat_t *A); @@ -95,7 +89,7 @@ IGRAPH_EXPORT igraph_error_t igraph_sparsemat_permute(const igraph_sparsemat_t * igraph_sparsemat_t *res); IGRAPH_EXPORT igraph_real_t igraph_sparsemat_get( - const igraph_sparsemat_t *A, igraph_integer_t row, igraph_integer_t col + const igraph_sparsemat_t *A, igraph_int_t row, igraph_int_t col ); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_index(const igraph_sparsemat_t *A, const igraph_vector_int_t *p, @@ -104,7 +98,7 @@ IGRAPH_EXPORT igraph_error_t igraph_sparsemat_index(const igraph_sparsemat_t *A, igraph_real_t *constres); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_entry(igraph_sparsemat_t *A, - igraph_integer_t row, igraph_integer_t col, igraph_real_t elem); + igraph_int_t row, igraph_int_t col, igraph_real_t elem); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_compress(const igraph_sparsemat_t *A, igraph_sparsemat_t *res); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_transpose( @@ -113,7 +107,7 @@ IGRAPH_EXPORT igraph_error_t igraph_sparsemat_transpose( IGRAPH_EXPORT igraph_error_t igraph_sparsemat_is_symmetric(const igraph_sparsemat_t *A, igraph_bool_t *result); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_dupl(igraph_sparsemat_t *A); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_fkeep(igraph_sparsemat_t *A, - igraph_integer_t (*fkeep)(igraph_integer_t, igraph_integer_t, igraph_real_t, void*), + igraph_int_t (*fkeep)(igraph_int_t, igraph_int_t, igraph_real_t, void*), void *other); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_dropzeros(igraph_sparsemat_t *A); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_droptol(igraph_sparsemat_t *A, igraph_real_t tol); @@ -145,24 +139,17 @@ IGRAPH_EXPORT igraph_error_t igraph_sparsemat_utsolve(const igraph_sparsemat_t * IGRAPH_EXPORT igraph_error_t igraph_sparsemat_cholsol(const igraph_sparsemat_t *A, const igraph_vector_t *b, igraph_vector_t *res, - igraph_integer_t order); + igraph_int_t order); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_lusol(const igraph_sparsemat_t *A, const igraph_vector_t *b, igraph_vector_t *res, - igraph_integer_t order, + igraph_int_t order, igraph_real_t tol); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_print(const igraph_sparsemat_t *A, FILE *outstream); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A, - igraph_bool_t directed); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_weighted_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A, - igraph_bool_t directed, const char *attr, - igraph_bool_t loops); - IGRAPH_EXPORT igraph_error_t igraph_matrix_as_sparsemat(igraph_sparsemat_t *res, const igraph_matrix_t *mat, igraph_real_t tol); @@ -205,10 +192,10 @@ IGRAPH_EXPORT igraph_error_t igraph_sparsemat_qrresol(const igraph_sparsemat_sym const igraph_vector_t *b, igraph_vector_t *res); -IGRAPH_EXPORT igraph_error_t igraph_sparsemat_symbqr(igraph_integer_t order, const igraph_sparsemat_t *A, +IGRAPH_EXPORT igraph_error_t igraph_sparsemat_symbqr(igraph_int_t order, const igraph_sparsemat_t *A, igraph_sparsemat_symbolic_t *dis); -IGRAPH_EXPORT igraph_error_t igraph_sparsemat_symblu(igraph_integer_t order, const igraph_sparsemat_t *A, +IGRAPH_EXPORT igraph_error_t igraph_sparsemat_symblu(igraph_int_t order, const igraph_sparsemat_t *A, igraph_sparsemat_symbolic_t *dis); @@ -220,8 +207,8 @@ IGRAPH_EXPORT igraph_real_t igraph_sparsemat_min(igraph_sparsemat_t *A); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_minmax(igraph_sparsemat_t *A, igraph_real_t *min, igraph_real_t *max); -IGRAPH_EXPORT igraph_integer_t igraph_sparsemat_count_nonzero(igraph_sparsemat_t *A); -IGRAPH_EXPORT igraph_integer_t igraph_sparsemat_count_nonzerotol(igraph_sparsemat_t *A, +IGRAPH_EXPORT igraph_int_t igraph_sparsemat_count_nonzero(igraph_sparsemat_t *A); +IGRAPH_EXPORT igraph_int_t igraph_sparsemat_count_nonzerotol(igraph_sparsemat_t *A, igraph_real_t tol); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_rowsums(const igraph_sparsemat_t *A, igraph_vector_t *res); @@ -248,11 +235,11 @@ IGRAPH_EXPORT igraph_error_t igraph_sparsemat_which_min_cols(igraph_sparsemat_t IGRAPH_EXPORT igraph_error_t igraph_sparsemat_scale(igraph_sparsemat_t *A, igraph_real_t by); -IGRAPH_EXPORT igraph_error_t igraph_sparsemat_add_rows(igraph_sparsemat_t *A, igraph_integer_t n); -IGRAPH_EXPORT igraph_error_t igraph_sparsemat_add_cols(igraph_sparsemat_t *A, igraph_integer_t n); +IGRAPH_EXPORT igraph_error_t igraph_sparsemat_add_rows(igraph_sparsemat_t *A, igraph_int_t n); +IGRAPH_EXPORT igraph_error_t igraph_sparsemat_add_cols(igraph_sparsemat_t *A, igraph_int_t n); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_resize(igraph_sparsemat_t *A, - igraph_integer_t nrow, igraph_integer_t ncol, igraph_integer_t nzmax); -IGRAPH_EXPORT igraph_integer_t igraph_sparsemat_nonzero_storage(const igraph_sparsemat_t *A); + igraph_int_t nrow, igraph_int_t ncol, igraph_int_t nzmax); +IGRAPH_EXPORT igraph_int_t igraph_sparsemat_nonzero_storage(const igraph_sparsemat_t *A); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_getelements(const igraph_sparsemat_t *A, igraph_vector_int_t *i, igraph_vector_int_t *j, @@ -272,13 +259,10 @@ IGRAPH_EXPORT igraph_error_t igraph_sparsemat_dense_multiply(const igraph_matrix const igraph_sparsemat_t *B, igraph_matrix_t *res); -IGRAPH_EXPORT igraph_error_t igraph_sparsemat_view(igraph_sparsemat_t *A, igraph_integer_t nzmax, igraph_integer_t m, igraph_integer_t n, - igraph_integer_t *p, igraph_integer_t *i, igraph_real_t *x, igraph_integer_t nz); - IGRAPH_EXPORT igraph_error_t igraph_sparsemat_sort(const igraph_sparsemat_t *A, igraph_sparsemat_t *sorted); -IGRAPH_EXPORT igraph_integer_t igraph_sparsemat_nzmax(const igraph_sparsemat_t *A); +IGRAPH_EXPORT igraph_int_t igraph_sparsemat_nzmax(const igraph_sparsemat_t *A); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_neg(igraph_sparsemat_t *A); @@ -292,21 +276,12 @@ IGRAPH_EXPORT igraph_error_t igraph_sparsemat_iterator_init( ); IGRAPH_EXPORT igraph_error_t igraph_sparsemat_iterator_reset(igraph_sparsemat_iterator_t *it); IGRAPH_EXPORT igraph_bool_t igraph_sparsemat_iterator_end(const igraph_sparsemat_iterator_t *it); -IGRAPH_EXPORT igraph_integer_t igraph_sparsemat_iterator_row(const igraph_sparsemat_iterator_t *it); -IGRAPH_EXPORT igraph_integer_t igraph_sparsemat_iterator_col(const igraph_sparsemat_iterator_t *it); -IGRAPH_EXPORT igraph_integer_t igraph_sparsemat_iterator_idx(const igraph_sparsemat_iterator_t *it); +IGRAPH_EXPORT igraph_int_t igraph_sparsemat_iterator_row(const igraph_sparsemat_iterator_t *it); +IGRAPH_EXPORT igraph_int_t igraph_sparsemat_iterator_col(const igraph_sparsemat_iterator_t *it); +IGRAPH_EXPORT igraph_int_t igraph_sparsemat_iterator_idx(const igraph_sparsemat_iterator_t *it); IGRAPH_EXPORT igraph_real_t igraph_sparsemat_iterator_get(const igraph_sparsemat_iterator_t *it); -IGRAPH_EXPORT igraph_integer_t igraph_sparsemat_iterator_next(igraph_sparsemat_iterator_t *it); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_sparsemat_copy( - igraph_sparsemat_t *to, const igraph_sparsemat_t *from); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_sparsemat_diag( - igraph_sparsemat_t *A, igraph_integer_t nzmax, const igraph_vector_t *values, - igraph_bool_t compress); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_sparsemat_eye( - igraph_sparsemat_t *A, igraph_integer_t n, igraph_integer_t nzmax, - igraph_real_t value, igraph_bool_t compress); +IGRAPH_EXPORT igraph_int_t igraph_sparsemat_iterator_next(igraph_sparsemat_iterator_t *it); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_spatial.h b/src/vendor/cigraph/include/igraph_spatial.h new file mode 100644 index 00000000000..1e1ad35abbb --- /dev/null +++ b/src/vendor/cigraph/include/igraph_spatial.h @@ -0,0 +1,91 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef IGRAPH_SPATIAL_H +#define IGRAPH_SPATIAL_H + +#include "igraph_datatype.h" +#include "igraph_decls.h" +#include "igraph_types.h" +#include "igraph_error.h" +#include "igraph_matrix.h" + +IGRAPH_BEGIN_C_DECLS + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_delaunay_graph( + igraph_t *graph, + const igraph_matrix_t *points); + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_lune_beta_skeleton( + igraph_t *graph, + const igraph_matrix_t *points, + igraph_real_t beta); + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_circle_beta_skeleton( + igraph_t *graph, + const igraph_matrix_t *points, + igraph_real_t beta); + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_beta_weighted_gabriel_graph( + igraph_t *graph, + igraph_vector_t *weights, + const igraph_matrix_t *points, + igraph_real_t max_beta); + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_gabriel_graph( + igraph_t *graph, const igraph_matrix_t *points); + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_relative_neighborhood_graph( + igraph_t *graph, const igraph_matrix_t *points); + +/** + * \typedef igraph_metric_t + * \brief Metric functions for use with spatial computation. + * + * \enumval IGRAPH_METRIC_EUCLIDEAN The Euclidean distance, i.e. L2 metric. + * \enumval IGRAPH_METRIC_MANHATTAN The Manhattan distance, i.e. L1 metric. + */ +typedef enum { + IGRAPH_METRIC_EUCLIDEAN = 0, + IGRAPH_METRIC_L2 = IGRAPH_METRIC_EUCLIDEAN, + IGRAPH_METRIC_MANHATTAN = 1, + IGRAPH_METRIC_L1 = IGRAPH_METRIC_MANHATTAN +} igraph_metric_t; + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_nearest_neighbor_graph( + igraph_t *graph, + const igraph_matrix_t *points, + igraph_metric_t metric, + igraph_int_t neighbors, + igraph_real_t cutoff, + igraph_bool_t directed); + +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_spatial_edge_lengths( + const igraph_t *graph, + igraph_vector_t *lengths, + const igraph_matrix_t *points, + igraph_metric_t metric); + +IGRAPH_EXPORT igraph_error_t igraph_convex_hull_2d( + const igraph_matrix_t *data, + igraph_vector_int_t *resverts, + igraph_matrix_t *rescoords); + +IGRAPH_END_C_DECLS + +#endif diff --git a/src/vendor/cigraph/include/igraph_stack.h b/src/vendor/cigraph/include/igraph_stack.h index 30f9b44ac28..0b84a0a080c 100644 --- a/src/vendor/cigraph/include/igraph_stack.h +++ b/src/vendor/cigraph/include/igraph_stack.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_STACK_H @@ -28,7 +23,7 @@ #include "igraph_error.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Plain stack */ @@ -66,6 +61,6 @@ __BEGIN_DECLS do { IGRAPH_CHECK(igraph_stack_int_init(s, capacity)); \ IGRAPH_FINALLY(igraph_stack_int_destroy, s); } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_stack_pmt.h b/src/vendor/cigraph/include/igraph_stack_pmt.h index d0a5a25e096..4d1c320af4a 100644 --- a/src/vendor/cigraph/include/igraph_stack_pmt.h +++ b/src/vendor/cigraph/include/igraph_stack_pmt.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2007-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include @@ -34,12 +29,12 @@ typedef struct TYPE(igraph_stack) { BASE* end; } TYPE(igraph_stack); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_stack, init)(TYPE(igraph_stack)* s, igraph_integer_t capacity); +IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_stack, init)(TYPE(igraph_stack)* s, igraph_int_t capacity); IGRAPH_EXPORT void FUNCTION(igraph_stack, destroy)(TYPE(igraph_stack)* s); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_stack, reserve)(TYPE(igraph_stack)* s, igraph_integer_t capacity); +IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_stack, reserve)(TYPE(igraph_stack)* s, igraph_int_t capacity); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_stack, empty)(TYPE(igraph_stack)* s); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_stack, size)(const TYPE(igraph_stack)* s); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_stack, capacity)(const TYPE(igraph_stack)* s); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_stack, size)(const TYPE(igraph_stack)* s); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_stack, capacity)(const TYPE(igraph_stack)* s); IGRAPH_EXPORT void FUNCTION(igraph_stack, clear)(TYPE(igraph_stack)* s); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_stack, push)(TYPE(igraph_stack)* s, BASE elem); IGRAPH_EXPORT BASE FUNCTION(igraph_stack, pop)(TYPE(igraph_stack)* s); diff --git a/src/vendor/cigraph/include/igraph_statusbar.h b/src/vendor/cigraph/include/igraph_statusbar.h index c6069bfb309..d8c1bae2dbc 100644 --- a/src/vendor/cigraph/include/igraph_statusbar.h +++ b/src/vendor/cigraph/include/igraph_statusbar.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2010-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2010-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_STATUSBAR_H @@ -27,7 +22,7 @@ #include "igraph_decls.h" #include "igraph_error.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \section about_status_handlers Status reporting @@ -86,16 +81,13 @@ IGRAPH_EXPORT igraph_error_t igraph_status(const char *message, void *data); * Existing igraph functions pass a null pointer here. * \return If the status handler returns with a value other than * \c IGRAPH_SUCCESS, then the function that called this - * macro returns as well, with error code - * \c IGRAPH_INTERRUPTED. + * macro returns as well, with the same error code, after + * cleaning up all allocated memory as needed. */ #define IGRAPH_STATUS(message, data) \ do { \ - if (igraph_status((message), (data)) != IGRAPH_SUCCESS) { \ - IGRAPH_FINALLY_FREE(); \ - return IGRAPH_INTERRUPTED; \ - } \ + IGRAPH_CHECK(igraph_status((message), (data))); \ } while (0) IGRAPH_EXPORT igraph_error_t igraph_statusf(const char *message, void *data, ...); @@ -107,23 +99,21 @@ IGRAPH_EXPORT igraph_error_t igraph_statusf(const char *message, void *data, ... * This is the more flexible version of \ref IGRAPH_STATUS(), * having a printf-like syntax. As this macro takes variable * number of arguments, they must be all supplied as a single - * argument, enclosed in parentheses. Then \ref igraph_statusf() - * is called with the given arguments. + * argument, enclosed in parentheses. \ref igraph_statusf() is then + * called with the given arguments. + * * \param args The arguments to pass to \ref igraph_statusf(). * \return If the status handler returns with a value other than * \c IGRAPH_SUCCESS, then the function that called this - * macro returns as well, with error code - * \c IGRAPH_INTERRUPTED. + * macro returns as well, with the same error code, after + * cleaning up all allocated memory as needed. */ #define IGRAPH_STATUSF(args) \ do { \ - if (igraph_statusf args != IGRAPH_SUCCESS) { \ - IGRAPH_FINALLY_FREE(); \ - return IGRAPH_INTERRUPTED; \ - } \ + IGRAPH_CHECK(igraph_statusf args); \ } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_structural.h b/src/vendor/cigraph/include/igraph_structural.h index 003849cf9e8..b568422fbee 100644 --- a/src/vendor/cigraph/include/igraph_structural.h +++ b/src/vendor/cigraph/include/igraph_structural.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_STRUCTURAL_H @@ -34,54 +29,52 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Basic query functions */ /* -------------------------------------------------- */ -IGRAPH_EXPORT igraph_error_t igraph_are_adjacent(const igraph_t *graph, igraph_integer_t v1, igraph_integer_t v2, igraph_bool_t *res); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_are_connected(const igraph_t *graph, igraph_integer_t v1, igraph_integer_t v2, igraph_bool_t *res); +IGRAPH_EXPORT igraph_error_t igraph_are_adjacent(const igraph_t *graph, igraph_int_t v1, igraph_int_t v2, igraph_bool_t *res); IGRAPH_EXPORT igraph_error_t igraph_count_multiple(const igraph_t *graph, igraph_vector_int_t *res, igraph_es_t es); -IGRAPH_EXPORT igraph_error_t igraph_count_multiple_1(const igraph_t *graph, igraph_integer_t *res, igraph_integer_t eid); -IGRAPH_EXPORT igraph_error_t igraph_density(const igraph_t *graph, igraph_real_t *res, - igraph_bool_t loops); +IGRAPH_EXPORT igraph_error_t igraph_count_multiple_1(const igraph_t *graph, igraph_int_t *res, igraph_int_t eid); +IGRAPH_EXPORT igraph_error_t igraph_density(const igraph_t *graph, const igraph_vector_t *weights, + igraph_real_t *res, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_diversity(const igraph_t *graph, const igraph_vector_t *weights, - igraph_vector_t *res, const igraph_vs_t vs); + igraph_vector_t *res, igraph_vs_t vs); IGRAPH_EXPORT igraph_error_t igraph_girth(const igraph_t *graph, igraph_real_t *girth, igraph_vector_int_t *circle); IGRAPH_EXPORT igraph_error_t igraph_has_loop(const igraph_t *graph, igraph_bool_t *res); IGRAPH_EXPORT igraph_error_t igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res); -IGRAPH_EXPORT igraph_error_t igraph_count_loops(const igraph_t *graph, igraph_integer_t *loop_count); +IGRAPH_EXPORT igraph_error_t igraph_count_loops(const igraph_t *graph, igraph_int_t *loop_count); IGRAPH_EXPORT igraph_error_t igraph_is_loop(const igraph_t *graph, igraph_vector_bool_t *res, igraph_es_t es); IGRAPH_EXPORT igraph_error_t igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *res, igraph_es_t es); IGRAPH_EXPORT igraph_error_t igraph_is_mutual(const igraph_t *graph, igraph_vector_bool_t *res, igraph_es_t es, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_has_mutual(const igraph_t *graph, igraph_bool_t *res, igraph_bool_t loops); -IGRAPH_EXPORT igraph_error_t igraph_is_simple(const igraph_t *graph, igraph_bool_t *res); -IGRAPH_EXPORT igraph_error_t igraph_is_tree(const igraph_t *graph, igraph_bool_t *res, igraph_integer_t *root, igraph_neimode_t mode); +IGRAPH_EXPORT igraph_error_t igraph_is_simple(const igraph_t *graph, igraph_bool_t *res, igraph_bool_t directed); +IGRAPH_EXPORT igraph_error_t igraph_is_tree(const igraph_t *graph, igraph_bool_t *res, igraph_int_t *root, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_is_acyclic(const igraph_t *graph, igraph_bool_t *res); IGRAPH_EXPORT igraph_error_t igraph_is_forest(const igraph_t *graph, igraph_bool_t *res, igraph_vector_int_t *roots, igraph_neimode_t mode); -IGRAPH_EXPORT igraph_error_t igraph_maxdegree(const igraph_t *graph, igraph_integer_t *res, +IGRAPH_EXPORT igraph_error_t igraph_maxdegree(const igraph_t *graph, igraph_int_t *res, igraph_vs_t vids, igraph_neimode_t mode, - igraph_bool_t loops); + igraph_loops_t loops); IGRAPH_EXPORT igraph_error_t igraph_mean_degree(const igraph_t *graph, igraph_real_t *res, igraph_bool_t loops); IGRAPH_EXPORT igraph_error_t igraph_reciprocity(const igraph_t *graph, igraph_real_t *res, igraph_bool_t ignore_loops, igraph_reciprocity_t mode); -IGRAPH_EXPORT igraph_error_t igraph_strength(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, igraph_neimode_t mode, - igraph_bool_t loops, const igraph_vector_t *weights); -IGRAPH_EXPORT igraph_error_t igraph_sort_vertex_ids_by_degree(const igraph_t *graph, - igraph_vector_int_t *outvids, - igraph_vs_t vids, - igraph_neimode_t mode, - igraph_bool_t loops, - igraph_order_t order, - igraph_bool_t only_indices); +IGRAPH_EXPORT igraph_error_t igraph_strength( + const igraph_t *graph, igraph_vector_t *res, igraph_vs_t vids, + igraph_neimode_t mode, igraph_loops_t loops, const igraph_vector_t *weights +); +IGRAPH_EXPORT igraph_error_t igraph_sort_vertex_ids_by_degree( + const igraph_t *graph, igraph_vector_int_t *outvids, igraph_vs_t vids, + igraph_neimode_t mode, igraph_loops_t loops, igraph_order_t order, + igraph_bool_t only_indices +); IGRAPH_EXPORT igraph_error_t igraph_is_perfect(const igraph_t *graph, igraph_bool_t *perfect); /* -------------------------------------------------- */ @@ -93,16 +86,13 @@ IGRAPH_EXPORT igraph_error_t igraph_is_clique(const igraph_t *graph, igraph_vs_t igraph_bool_t directed, igraph_bool_t *res); IGRAPH_EXPORT igraph_error_t igraph_is_independent_vertex_set(const igraph_t *graph, igraph_vs_t candidate, igraph_bool_t *res); -IGRAPH_EXPORT igraph_error_t igraph_minimum_spanning_tree(const igraph_t *graph, igraph_vector_int_t *res, - const igraph_vector_t *weights); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_minimum_spanning_tree_unweighted(const igraph_t *graph, - igraph_t *mst); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_minimum_spanning_tree_prim(const igraph_t *graph, igraph_t *mst, - const igraph_vector_t *weights); +IGRAPH_EXPORT igraph_error_t igraph_minimum_spanning_tree( + const igraph_t *graph, igraph_vector_int_t *res, + const igraph_vector_t *weights, igraph_mst_algorithm_t method); IGRAPH_EXPORT igraph_error_t igraph_random_spanning_tree(const igraph_t *graph, igraph_vector_int_t *res, - igraph_integer_t vid); + igraph_int_t vid); -IGRAPH_EXPORT igraph_error_t igraph_subcomponent(const igraph_t *graph, igraph_vector_int_t *res, igraph_integer_t vid, +IGRAPH_EXPORT igraph_error_t igraph_subcomponent(const igraph_t *graph, igraph_vector_int_t *res, igraph_int_t vid, igraph_neimode_t mode); IGRAPH_EXPORT igraph_error_t igraph_unfold_tree(const igraph_t *graph, igraph_t *tree, @@ -131,15 +121,7 @@ IGRAPH_EXPORT igraph_error_t igraph_degree_correlation_vector( igraph_neimode_t from_mode, igraph_neimode_t to_mode, igraph_bool_t directed_neighbors); -IGRAPH_EXPORT igraph_error_t igraph_feedback_arc_set( - const igraph_t *graph, igraph_vector_int_t *result, - const igraph_vector_t *weights, igraph_fas_algorithm_t algo); - -IGRAPH_EXPORT igraph_error_t igraph_feedback_vertex_set( - const igraph_t *graph, igraph_vector_int_t *result, - const igraph_vector_t *vertex_weights, igraph_fvs_algorithm_t algo); - -IGRAPH_EXPORT igraph_error_t igraph_rich_club_sequence( +IGRAPH_EXPERIMENTAL IGRAPH_EXPORT igraph_error_t igraph_rich_club_sequence( const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_t *res, @@ -185,11 +167,7 @@ IGRAPH_EXPORT igraph_error_t igraph_get_laplacian_sparse( igraph_laplacian_normalization_t normalization, const igraph_vector_t *weights ); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_laplacian( - const igraph_t *graph, igraph_matrix_t *res, igraph_sparsemat_t *sparseres, - igraph_bool_t normalized, const igraph_vector_t *weights -); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_strvector.h b/src/vendor/cigraph/include/igraph_strvector.h index c01b695d3b0..cf671d4f5bf 100644 --- a/src/vendor/cigraph/include/igraph_strvector.h +++ b/src/vendor/cigraph/include/igraph_strvector.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_STRVECTOR_H @@ -28,7 +23,7 @@ #include "igraph_error.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * Vector of strings @@ -37,9 +32,9 @@ __BEGIN_DECLS typedef struct s_igraph_strvector { /* Empty strings "" are represented using NULL. */ - char **stor_begin; - char **stor_end; - char **end; + const char **stor_begin; + const char **stor_end; + const char **end; } igraph_strvector_t; /** @@ -51,7 +46,7 @@ typedef struct s_igraph_strvector { * element. Use \ref igraph_strvector_set() to set an element instead. * * \param sv The string vector - * \param i The the index of the element. + * \param i The index of the element. * \return The element at position \p i. * * Time complexity: O(1). @@ -67,53 +62,51 @@ typedef struct s_igraph_strvector { do { IGRAPH_CHECK(igraph_strvector_init(sv, size)); \ IGRAPH_FINALLY( igraph_strvector_destroy, sv); } while (0) -IGRAPH_EXPORT igraph_error_t igraph_strvector_init(igraph_strvector_t *sv, igraph_integer_t len); +IGRAPH_EXPORT igraph_error_t igraph_strvector_init(igraph_strvector_t *sv, igraph_int_t len); IGRAPH_EXPORT void igraph_strvector_destroy(igraph_strvector_t *sv); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_strvector_size(const igraph_strvector_t *sv); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_strvector_capacity(const igraph_strvector_t *sv); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE const char *igraph_strvector_get(const igraph_strvector_t *sv, igraph_integer_t idx); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_strvector_size(const igraph_strvector_t *sv); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_strvector_capacity(const igraph_strvector_t *sv); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE const char *igraph_strvector_get(const igraph_strvector_t *sv, igraph_int_t idx); IGRAPH_EXPORT igraph_error_t igraph_strvector_set( - igraph_strvector_t *sv, igraph_integer_t idx, const char *value); + igraph_strvector_t *sv, igraph_int_t idx, const char *value); IGRAPH_EXPORT igraph_error_t igraph_strvector_set_len( - igraph_strvector_t *sv, igraph_integer_t idx, const char *value, size_t len); + igraph_strvector_t *sv, igraph_int_t idx, const char *value, size_t len); IGRAPH_EXPORT void igraph_strvector_clear(igraph_strvector_t *sv); IGRAPH_EXPORT void igraph_strvector_remove_section( - igraph_strvector_t *v, igraph_integer_t from, igraph_integer_t to); + igraph_strvector_t *v, igraph_int_t from, igraph_int_t to); IGRAPH_EXPORT void igraph_strvector_remove( - igraph_strvector_t *v, igraph_integer_t elem); + igraph_strvector_t *v, igraph_int_t elem); IGRAPH_EXPORT igraph_error_t igraph_strvector_init_copy( igraph_strvector_t *to, const igraph_strvector_t *from); IGRAPH_EXPORT igraph_error_t igraph_strvector_append( igraph_strvector_t *to, const igraph_strvector_t *from); IGRAPH_EXPORT igraph_error_t igraph_strvector_merge( igraph_strvector_t *to, igraph_strvector_t *from); +IGRAPH_EXPORT void igraph_strvector_swap(igraph_strvector_t *v1, igraph_strvector_t *v2); +IGRAPH_EXPORT igraph_error_t igraph_strvector_update( + igraph_strvector_t *to, const igraph_strvector_t *from); IGRAPH_EXPORT igraph_error_t igraph_strvector_resize( - igraph_strvector_t* v, igraph_integer_t newsize); + igraph_strvector_t* v, igraph_int_t newsize); IGRAPH_EXPORT void igraph_strvector_resize_min(igraph_strvector_t *sv); IGRAPH_EXPORT igraph_error_t igraph_strvector_push_back(igraph_strvector_t *v, const char *value); IGRAPH_EXPORT igraph_error_t igraph_strvector_push_back_len(igraph_strvector_t *v, - const char *value, igraph_integer_t len); -IGRAPH_EXPORT igraph_error_t igraph_strvector_print(const igraph_strvector_t *v, FILE *file, - const char *sep); + const char *value, size_t len); +IGRAPH_EXPORT igraph_error_t igraph_strvector_fprint(const igraph_strvector_t *v, FILE *file, + const char *sep); +IGRAPH_EXPORT igraph_error_t igraph_strvector_print(const igraph_strvector_t *v, + const char *sep); IGRAPH_EXPORT igraph_error_t igraph_strvector_index(const igraph_strvector_t *v, igraph_strvector_t *newv, const igraph_vector_int_t *idx); IGRAPH_EXPORT igraph_error_t igraph_strvector_reserve(igraph_strvector_t *sv, - igraph_integer_t capacity); + igraph_int_t capacity); IGRAPH_EXPORT void igraph_strvector_swap_elements(igraph_strvector_t *sv, - igraph_integer_t i, igraph_integer_t j); - -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_strvector_add(igraph_strvector_t *v, const char *value); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_strvector_copy( - igraph_strvector_t *to, const igraph_strvector_t *from); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_strvector_set2( - igraph_strvector_t *sv, igraph_integer_t idx, const char *value, size_t len -); + igraph_int_t i, igraph_int_t j); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_threading.h.in b/src/vendor/cigraph/include/igraph_threading.h.in index 1ddeb118d3f..06f4d2b9921 100644 --- a/src/vendor/cigraph/include/igraph_threading.h.in +++ b/src/vendor/cigraph/include/igraph_threading.h.in @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2011-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2011-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_THREADING_H @@ -26,7 +21,7 @@ #include "igraph_decls.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * \define IGRAPH_THREAD_SAFE @@ -42,6 +37,6 @@ __BEGIN_DECLS #cmakedefine01 IGRAPH_THREAD_SAFE -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_transitivity.h b/src/vendor/cigraph/include/igraph_transitivity.h index 9566561f6a2..b2cd6f3dc49 100644 --- a/src/vendor/cigraph/include/igraph_transitivity.h +++ b/src/vendor/cigraph/include/igraph_transitivity.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_TRANSITIVITY_H @@ -30,30 +25,30 @@ #include "igraph_error.h" #include "igraph_iterators.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_EXPORT igraph_error_t igraph_transitivity_undirected(const igraph_t *graph, igraph_real_t *res, igraph_transitivity_mode_t mode); IGRAPH_EXPORT igraph_error_t igraph_transitivity_local_undirected(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, + igraph_vs_t vids, igraph_transitivity_mode_t mode); IGRAPH_EXPORT igraph_error_t igraph_transitivity_avglocal_undirected(const igraph_t *graph, igraph_real_t *res, igraph_transitivity_mode_t mode); IGRAPH_EXPORT igraph_error_t igraph_transitivity_barrat(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, + igraph_vs_t vids, const igraph_vector_t *weights, - const igraph_transitivity_mode_t mode); + igraph_transitivity_mode_t mode); IGRAPH_EXPORT igraph_error_t igraph_ecc(const igraph_t *graph, igraph_vector_t *res, igraph_es_t eids, - igraph_integer_t k, + igraph_int_t k, igraph_bool_t offset, igraph_bool_t normalize); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_typed_list_pmt.h b/src/vendor/cigraph/include/igraph_typed_list_pmt.h index 2110d5558d1..679fabf774e 100644 --- a/src/vendor/cigraph/include/igraph_typed_list_pmt.h +++ b/src/vendor/cigraph/include/igraph_typed_list_pmt.h @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2021 The igraph development team + igraph library. + Copyright (C) 2021-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #if defined(VECTOR_LIST) @@ -50,50 +46,51 @@ typedef struct { /* Allocation */ /*--------------------*/ -IGRAPH_EXPORT igraph_error_t FUNCTION(init)(TYPE* v, igraph_integer_t size); +IGRAPH_EXPORT igraph_error_t FUNCTION(init)(TYPE* v, igraph_int_t size); +IGRAPH_EXPORT igraph_error_t FUNCTION(init_copy)(TYPE* to, const TYPE* from); IGRAPH_EXPORT void FUNCTION(destroy)(TYPE* v); /*--------------------*/ /* Accessing elements */ /*--------------------*/ -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE ITEM_TYPE* FUNCTION(get_ptr)(const TYPE* v, igraph_integer_t pos); -IGRAPH_EXPORT void FUNCTION(set)(TYPE* v, igraph_integer_t pos, ITEM_TYPE* e); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE ITEM_TYPE* FUNCTION(get_ptr)(const TYPE* v, igraph_int_t pos); +IGRAPH_EXPORT void FUNCTION(set)(TYPE* v, igraph_int_t pos, ITEM_TYPE* e); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE ITEM_TYPE* FUNCTION(tail_ptr)(const TYPE *v); /*-----------------*/ /* List properties */ /*-----------------*/ -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(capacity)(const TYPE* v); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(capacity)(const TYPE* v); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(empty)(const TYPE* v); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(size)(const TYPE* v); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(size)(const TYPE* v); /*------------------------*/ /* Resizing operations */ /*------------------------*/ IGRAPH_EXPORT void FUNCTION(clear)(TYPE* v); -IGRAPH_EXPORT igraph_error_t FUNCTION(reserve)(TYPE* v, igraph_integer_t capacity); -IGRAPH_EXPORT igraph_error_t FUNCTION(resize)(TYPE* v, igraph_integer_t new_size); +IGRAPH_EXPORT igraph_error_t FUNCTION(reserve)(TYPE* v, igraph_int_t capacity); +IGRAPH_EXPORT igraph_error_t FUNCTION(resize)(TYPE* v, igraph_int_t new_size); /*------------------------*/ /* Adding/removing items */ /*------------------------*/ -IGRAPH_EXPORT void FUNCTION(discard)(TYPE* v, igraph_integer_t index); +IGRAPH_EXPORT void FUNCTION(discard)(TYPE* v, igraph_int_t index); IGRAPH_EXPORT void FUNCTION(discard_back)(TYPE* v); -IGRAPH_EXPORT void FUNCTION(discard_fast)(TYPE* v, igraph_integer_t index); -IGRAPH_EXPORT igraph_error_t FUNCTION(insert)(TYPE* v, igraph_integer_t pos, ITEM_TYPE* e); -IGRAPH_EXPORT igraph_error_t FUNCTION(insert_copy)(TYPE* v, igraph_integer_t pos, const ITEM_TYPE* e); -IGRAPH_EXPORT igraph_error_t FUNCTION(insert_new)(TYPE* v, igraph_integer_t pos, ITEM_TYPE** result); +IGRAPH_EXPORT void FUNCTION(discard_fast)(TYPE* v, igraph_int_t index); +IGRAPH_EXPORT igraph_error_t FUNCTION(insert)(TYPE* v, igraph_int_t pos, ITEM_TYPE* e); +IGRAPH_EXPORT igraph_error_t FUNCTION(insert_copy)(TYPE* v, igraph_int_t pos, const ITEM_TYPE* e); +IGRAPH_EXPORT igraph_error_t FUNCTION(insert_new)(TYPE* v, igraph_int_t pos, ITEM_TYPE** result); IGRAPH_EXPORT igraph_error_t FUNCTION(push_back)(TYPE* v, ITEM_TYPE* e); IGRAPH_EXPORT igraph_error_t FUNCTION(push_back_copy)(TYPE* v, const ITEM_TYPE* e); IGRAPH_EXPORT igraph_error_t FUNCTION(push_back_new)(TYPE* v, ITEM_TYPE** result); IGRAPH_EXPORT ITEM_TYPE FUNCTION(pop_back)(TYPE* v); -IGRAPH_EXPORT igraph_error_t FUNCTION(remove)(TYPE* v, igraph_integer_t index, ITEM_TYPE* e); -IGRAPH_EXPORT igraph_error_t FUNCTION(remove_fast)(TYPE* v, igraph_integer_t index, ITEM_TYPE* e); -IGRAPH_EXPORT void FUNCTION(replace)(TYPE* v, igraph_integer_t pos, ITEM_TYPE* e); +IGRAPH_EXPORT igraph_error_t FUNCTION(remove)(TYPE* v, igraph_int_t index, ITEM_TYPE* e); +IGRAPH_EXPORT igraph_error_t FUNCTION(remove_fast)(TYPE* v, igraph_int_t index, ITEM_TYPE* e); +IGRAPH_EXPORT void FUNCTION(replace)(TYPE* v, igraph_int_t pos, ITEM_TYPE* e); IGRAPH_EXPORT void FUNCTION(remove_consecutive_duplicates)(TYPE *v, igraph_bool_t (*eq)(const ITEM_TYPE*, const ITEM_TYPE*)); /*------------------*/ @@ -102,8 +99,8 @@ IGRAPH_EXPORT void FUNCTION(remove_consecutive_duplicates)(TYPE *v, igraph_bool_ IGRAPH_EXPORT igraph_error_t FUNCTION(permute)(TYPE *v, const igraph_vector_int_t *index); IGRAPH_EXPORT igraph_error_t FUNCTION(reverse)(TYPE *v); -IGRAPH_EXPORT igraph_error_t FUNCTION(swap)(TYPE *v1, TYPE *v2); -IGRAPH_EXPORT igraph_error_t FUNCTION(swap_elements)(TYPE* v, igraph_integer_t i, igraph_integer_t j); +IGRAPH_EXPORT void FUNCTION(swap)(TYPE *v1, TYPE *v2); +IGRAPH_EXPORT void FUNCTION(swap_elements)(TYPE* v, igraph_int_t i, igraph_int_t j); /*-----------*/ /* Sorting */ diff --git a/src/vendor/cigraph/include/igraph_types.h b/src/vendor/cigraph/include/igraph_types.h index 81f22cfe5f9..5acd293150f 100644 --- a/src/vendor/cigraph/include/igraph_types.h +++ b/src/vendor/cigraph/include/igraph_types.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2003-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2003-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_TYPES_H @@ -26,7 +21,7 @@ #include "igraph_decls.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS #ifdef __cplusplus #define __STDC_FORMAT_MACROS /* needed for PRId32 and PRId64 from inttypes.h on Linux */ @@ -45,15 +40,17 @@ __BEGIN_DECLS #if !defined(IGRAPH_INTEGER_SIZE) # error "igraph integer size not defined; check the value of IGRAPH_INTEGER_SIZE when compiling" #elif IGRAPH_INTEGER_SIZE == 64 -typedef int64_t igraph_integer_t; +typedef int64_t igraph_int_t; typedef uint64_t igraph_uint_t; #elif IGRAPH_INTEGER_SIZE == 32 -typedef int32_t igraph_integer_t; +typedef int32_t igraph_int_t; typedef uint32_t igraph_uint_t; #else # error "Invalid igraph integer size; check the value of IGRAPH_INTEGER_SIZE when compiling" #endif +typedef igraph_int_t igraph_integer_t; + typedef double igraph_real_t; /* IGRAPH_BOOL_TYPE is set to 'bool' by default, and it is not meant to be @@ -61,7 +58,7 @@ typedef double igraph_real_t; * See igraph_config.h for more info */ typedef IGRAPH_BOOL_TYPE igraph_bool_t; -/* printf format specifier for igraph_integer_t */ +/* printf format specifier for igraph_int_t */ #if IGRAPH_INTEGER_SIZE == 64 # define IGRAPH_PRId PRId64 # define IGRAPH_PRIu PRIu64 @@ -70,7 +67,7 @@ typedef IGRAPH_BOOL_TYPE igraph_bool_t; # define IGRAPH_PRIu PRIu32 #endif -/* maximum and minimum allowed values for igraph_integer_t */ +/* maximum and minimum allowed values for igraph_int_t */ #if IGRAPH_INTEGER_SIZE == 64 # define IGRAPH_INTEGER_MAX INT64_MAX # define IGRAPH_INTEGER_MIN INT64_MIN @@ -138,19 +135,8 @@ IGRAPH_EXPORT int igraph_real_fprintf_precise(FILE *file, igraph_real_t val); IGRAPH_EXPORT int igraph_real_snprintf_precise(char *str, size_t size, igraph_real_t val); #define IGRAPH_INFINITY ((double)INFINITY) -#define IGRAPH_POSINFINITY IGRAPH_INFINITY -#define IGRAPH_NEGINFINITY (-IGRAPH_INFINITY) - -IGRAPH_DEPRECATED IGRAPH_EXPORT int igraph_finite(double x); -#define IGRAPH_FINITE(x) igraph_finite(x) - -IGRAPH_DEPRECATED IGRAPH_EXPORT int igraph_is_nan(double x); -IGRAPH_DEPRECATED IGRAPH_EXPORT int igraph_is_inf(double x); -IGRAPH_DEPRECATED IGRAPH_EXPORT int igraph_is_posinf(double x); -IGRAPH_DEPRECATED IGRAPH_EXPORT int igraph_is_neginf(double x); - #define IGRAPH_NAN ((double)NAN) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_vector.h b/src/vendor/cigraph/include/igraph_vector.h index 24e86529093..16d7a9d0b64 100644 --- a/src/vendor/cigraph/include/igraph_vector.h +++ b/src/vendor/cigraph/include/igraph_vector.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_VECTOR_H @@ -30,7 +25,7 @@ #include "igraph_error.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Flexible vector */ @@ -132,13 +127,9 @@ __BEGIN_DECLS IGRAPH_EXPORT igraph_error_t igraph_vector_floor(const igraph_vector_t *from, igraph_vector_int_t *to); IGRAPH_EXPORT igraph_error_t igraph_vector_round(const igraph_vector_t *from, igraph_vector_int_t *to); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_bool_t igraph_vector_e_tol(const igraph_vector_t *lhs, - const igraph_vector_t *rhs, - igraph_real_t tol); - IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_vector_all_almost_e(const igraph_vector_t *lhs, - const igraph_vector_t *rhs, - igraph_real_t eps); + const igraph_vector_t *rhs, + igraph_real_t eps); IGRAPH_EXPORT igraph_error_t igraph_vector_zapsmall(igraph_vector_t *v, igraph_real_t tol); IGRAPH_EXPORT igraph_error_t igraph_vector_complex_zapsmall(igraph_vector_complex_t *v, igraph_real_t tol) ; @@ -148,18 +139,20 @@ IGRAPH_EXPORT igraph_error_t igraph_vector_is_nan(const igraph_vector_t *v, IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_vector_is_any_nan(const igraph_vector_t *v); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_vector_is_all_finite(const igraph_vector_t *v); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_vector_order2(igraph_vector_t *v); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_vector_rank(const igraph_vector_t *v, igraph_vector_int_t *res, - igraph_integer_t nodes); - IGRAPH_EXPORT igraph_error_t igraph_vector_int_pair_order(const igraph_vector_int_t* v, const igraph_vector_int_t *v2, - igraph_vector_int_t* res, igraph_integer_t maxval); + igraph_vector_int_t* res, igraph_int_t maxval); + +/* For internal use only: */ -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_vector_int_order1(const igraph_vector_int_t* v, - igraph_vector_int_t* res, igraph_integer_t maxval); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_vector_int_rank(const igraph_vector_int_t *v, igraph_vector_int_t *res, - igraph_integer_t nodes); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_vector_int_order( + const igraph_vector_int_t* v, + igraph_vector_int_t* res, + igraph_int_t maxval); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_vector_int_rank( + const igraph_vector_int_t *v, + igraph_vector_int_t *res, + igraph_int_t maxval); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_vector_list.h b/src/vendor/cigraph/include/igraph_vector_list.h index dc45323b18d..20b7c02da6a 100644 --- a/src/vendor/cigraph/include/igraph_vector_list.h +++ b/src/vendor/cigraph/include/igraph_vector_list.h @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2022 The igraph development team + igraph library. + Copyright (C) 2022-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_VECTOR_LIST_H @@ -27,7 +23,7 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Flexible list of vectors */ @@ -62,6 +58,6 @@ __BEGIN_DECLS do { IGRAPH_CHECK(igraph_vector_int_list_init(v, size)); \ IGRAPH_FINALLY(igraph_vector_int_list_destroy, v); } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_vector_pmt.h b/src/vendor/cigraph/include/igraph_vector_pmt.h index 3cedc0eb351..9548af4efdd 100644 --- a/src/vendor/cigraph/include/igraph_vector_pmt.h +++ b/src/vendor/cigraph/include/igraph_vector_pmt.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2007-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ /*--------------------*/ @@ -26,22 +21,19 @@ /*--------------------*/ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, init)( - TYPE(igraph_vector) *v, igraph_integer_t size); + TYPE(igraph_vector) *v, igraph_int_t size); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, init_array)( - TYPE(igraph_vector) *v, const BASE *data, igraph_integer_t length); + TYPE(igraph_vector) *v, const BASE *data, igraph_int_t length); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, init_copy)( TYPE(igraph_vector) *to, const TYPE(igraph_vector) *from); #ifndef NOTORDERED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, init_range)(TYPE(igraph_vector)*v, BASE start, BASE end); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t FUNCTION(igraph_vector, init_seq)(TYPE(igraph_vector)*v, BASE from, BASE to); #endif -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t FUNCTION(igraph_vector, copy)( - TYPE(igraph_vector) *to, const TYPE(igraph_vector) *from); IGRAPH_EXPORT void FUNCTION(igraph_vector, destroy)(TYPE(igraph_vector) *v); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_vector, capacity)(const TYPE(igraph_vector)*v); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_vector, capacity)(const TYPE(igraph_vector)*v); /*--------------------*/ /* Accessing elements */ @@ -68,11 +60,9 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_vector, capa #define VECTOR(v) ((v).stor_begin) #endif -IGRAPH_EXPORT IGRAPH_DEPRECATED BASE FUNCTION(igraph_vector, e)(const TYPE(igraph_vector) *v, igraph_integer_t pos); -IGRAPH_EXPORT IGRAPH_DEPRECATED BASE* FUNCTION(igraph_vector, e_ptr)(const TYPE(igraph_vector) *v, igraph_integer_t pos); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_vector, get)(const TYPE(igraph_vector) *v, igraph_integer_t pos); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE* FUNCTION(igraph_vector, get_ptr)(const TYPE(igraph_vector) *v, igraph_integer_t pos); -IGRAPH_EXPORT void FUNCTION(igraph_vector, set)(TYPE(igraph_vector) *v, igraph_integer_t pos, BASE value); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_vector, get)(const TYPE(igraph_vector) *v, igraph_int_t pos); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE* FUNCTION(igraph_vector, get_ptr)(const TYPE(igraph_vector) *v, igraph_int_t pos); +IGRAPH_EXPORT void FUNCTION(igraph_vector, set)(TYPE(igraph_vector) *v, igraph_int_t pos, BASE value); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_vector, tail)(const TYPE(igraph_vector) *v); /*-----------------------*/ @@ -90,9 +80,8 @@ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, range)(TYPE(igraph_vector) /* Vector views */ /*-----------------------*/ -IGRAPH_EXPORT const TYPE(igraph_vector) *FUNCTION(igraph_vector, view)(const TYPE(igraph_vector) *v, - const BASE *data, - igraph_integer_t length); +IGRAPH_EXPORT TYPE(igraph_vector) FUNCTION(igraph_vector, view)(const BASE *data, + igraph_int_t length); /*-----------------------*/ /* Copying vectors */ @@ -103,22 +92,22 @@ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, update)(TYPE(igraph_vector) const TYPE(igraph_vector) *from); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, append)(TYPE(igraph_vector) *to, const TYPE(igraph_vector) *from); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, swap)(TYPE(igraph_vector) *v1, TYPE(igraph_vector) *v2); +IGRAPH_EXPORT void FUNCTION(igraph_vector, swap)(TYPE(igraph_vector) *v1, TYPE(igraph_vector) *v2); /*-----------------------*/ /* Exchanging elements */ /*-----------------------*/ -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, swap_elements)( - TYPE(igraph_vector) *v, igraph_integer_t i, igraph_integer_t j); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, reverse)(TYPE(igraph_vector) *v); +IGRAPH_EXPORT void FUNCTION(igraph_vector, swap_elements)( + TYPE(igraph_vector) *v, igraph_int_t i, igraph_int_t j); +IGRAPH_EXPORT void FUNCTION(igraph_vector, reverse)(TYPE(igraph_vector) *v); IGRAPH_EXPORT void FUNCTION(igraph_vector, reverse_section)( - TYPE(igraph_vector) *v, igraph_integer_t from, igraph_integer_t to); + TYPE(igraph_vector) *v, igraph_int_t from, igraph_int_t to); IGRAPH_EXPORT void FUNCTION(igraph_vector, rotate_left)( - TYPE(igraph_vector) *v, igraph_integer_t n); + TYPE(igraph_vector) *v, igraph_int_t n); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, permute)(TYPE(igraph_vector) *v, const igraph_vector_int_t *ind); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, shuffle)(TYPE(igraph_vector) *v); +IGRAPH_EXPORT void FUNCTION(igraph_vector, shuffle)(TYPE(igraph_vector) *v); /*-----------------------*/ /* Vector operations */ @@ -171,12 +160,12 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE int FUNCTION(igraph_vector, colex_cmp_untyped #ifndef NOTORDERED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_vector, min)(const TYPE(igraph_vector)* v); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_vector, max)(const TYPE(igraph_vector)* v); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_vector, which_min)(const TYPE(igraph_vector)* v); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_vector, which_max)(const TYPE(igraph_vector)* v); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_vector, which_min)(const TYPE(igraph_vector)* v); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_vector, which_max)(const TYPE(igraph_vector)* v); IGRAPH_EXPORT void FUNCTION(igraph_vector, minmax)( const TYPE(igraph_vector) *v, BASE *min, BASE *max); IGRAPH_EXPORT void FUNCTION(igraph_vector, which_minmax)( - const TYPE(igraph_vector) *v, igraph_integer_t *which_min, igraph_integer_t *which_max); + const TYPE(igraph_vector) *v, igraph_int_t *which_min, igraph_int_t *which_max); #endif /*-------------------*/ @@ -184,7 +173,7 @@ IGRAPH_EXPORT void FUNCTION(igraph_vector, which_minmax)( /*-------------------*/ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_vector, empty)(const TYPE(igraph_vector)* v); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_vector, size)(const TYPE(igraph_vector)* v); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_vector, size)(const TYPE(igraph_vector)* v); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_vector, isnull)(const TYPE(igraph_vector) *v); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_vector, sum)(const TYPE(igraph_vector) *v); IGRAPH_DEPRECATED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t FUNCTION(igraph_vector, sumsq)(const TYPE(igraph_vector) *v); @@ -208,16 +197,14 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t FUNCTION(igraph_vector, maxdiff IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_vector, contains)(const TYPE(igraph_vector) *v, BASE e); IGRAPH_EXPORT igraph_bool_t FUNCTION(igraph_vector, search)( - const TYPE(igraph_vector) *v, igraph_integer_t from, BASE what, igraph_integer_t *pos); + const TYPE(igraph_vector) *v, igraph_int_t from, BASE what, igraph_int_t *pos); #ifndef NOTORDERED IGRAPH_EXPORT igraph_bool_t FUNCTION(igraph_vector, binsearch_slice)( - const TYPE(igraph_vector) *v, BASE what, igraph_integer_t *pos, - igraph_integer_t start, igraph_integer_t end); + const TYPE(igraph_vector) *v, BASE what, igraph_int_t *pos, + igraph_int_t start, igraph_int_t end); IGRAPH_EXPORT igraph_bool_t FUNCTION(igraph_vector, binsearch)( - const TYPE(igraph_vector) *v, BASE what, igraph_integer_t *pos); + const TYPE(igraph_vector) *v, BASE what, igraph_int_t *pos); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_vector, contains_sorted)( - const TYPE(igraph_vector) *v, BASE what); -IGRAPH_DEPRECATED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_vector, binsearch2)( const TYPE(igraph_vector) *v, BASE what); #endif @@ -227,20 +214,20 @@ IGRAPH_DEPRECATED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igra IGRAPH_EXPORT void FUNCTION(igraph_vector, clear)(TYPE(igraph_vector)* v); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, resize)( - TYPE(igraph_vector)* v, igraph_integer_t new_size); + TYPE(igraph_vector)* v, igraph_int_t new_size); IGRAPH_EXPORT void FUNCTION(igraph_vector, resize_min)(TYPE(igraph_vector)*v); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, reserve)( - TYPE(igraph_vector)* v, igraph_integer_t capacity); + TYPE(igraph_vector)* v, igraph_int_t capacity); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, push_back)(TYPE(igraph_vector)* v, BASE e); IGRAPH_EXPORT BASE FUNCTION(igraph_vector, pop_back)(TYPE(igraph_vector)* v); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, insert)( - TYPE(igraph_vector) *v, igraph_integer_t pos, BASE value); + TYPE(igraph_vector) *v, igraph_int_t pos, BASE value); IGRAPH_EXPORT void FUNCTION(igraph_vector, remove)( - TYPE(igraph_vector) *v, igraph_integer_t elem); + TYPE(igraph_vector) *v, igraph_int_t elem); IGRAPH_EXPORT void FUNCTION(igraph_vector, remove_fast)( - TYPE(igraph_vector) *v, igraph_integer_t elem); + TYPE(igraph_vector) *v, igraph_int_t elem); IGRAPH_EXPORT void FUNCTION(igraph_vector, remove_section)( - TYPE(igraph_vector) *v, igraph_integer_t from, igraph_integer_t to); + TYPE(igraph_vector) *v, igraph_int_t from, igraph_int_t to); /*-----------*/ /* Sorting */ @@ -253,9 +240,6 @@ IGRAPH_EXPORT void FUNCTION(igraph_vector, reverse_sort)(TYPE(igraph_vector) *v) IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, sort_ind)( const TYPE(igraph_vector) *v, igraph_vector_int_t *inds, igraph_order_t order); -IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, qsort_ind)( - const TYPE(igraph_vector) *v, igraph_vector_int_t *inds, igraph_order_t order); - #endif /*-----------*/ @@ -301,29 +285,29 @@ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, init_real_end)(TYPE(igraph_ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, init_int_end)(TYPE(igraph_vector)*v, int endmark, ...); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, move_interval)( - TYPE(igraph_vector) *v, igraph_integer_t begin, igraph_integer_t end, - igraph_integer_t to); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t FUNCTION(igraph_vector, move_interval2)( - TYPE(igraph_vector) *v, igraph_integer_t begin, igraph_integer_t end, - igraph_integer_t to); + TYPE(igraph_vector) *v, igraph_int_t begin, igraph_int_t end, + igraph_int_t to); #ifndef NOTORDERED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, filter_smaller)(TYPE(igraph_vector) *v, BASE elem); #endif IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, get_interval)( const TYPE(igraph_vector) *v, TYPE(igraph_vector) *res, - igraph_integer_t from, igraph_integer_t to); + igraph_int_t from, igraph_int_t to); #ifndef NOTORDERED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, difference_sorted)(const TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2, TYPE(igraph_vector) *result); +IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, difference_and_intersection_sorted)( + const TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2, + TYPE(igraph_vector) *vdiff12, TYPE(igraph_vector) *vdiff21, + TYPE(igraph_vector) *vinter); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, intersect_sorted)(const TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2, TYPE(igraph_vector) *result); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_vector, intersection_size_sorted)( +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t FUNCTION(igraph_vector, intersection_size_sorted)( const TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2); #endif IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, index)(const TYPE(igraph_vector) *v, TYPE(igraph_vector) *newv, const igraph_vector_int_t *idx); - -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, index_int)(TYPE(igraph_vector) *v, +IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, index_in_place)(TYPE(igraph_vector) *v, const igraph_vector_int_t *idx); diff --git a/src/vendor/cigraph/include/igraph_vector_ptr.h b/src/vendor/cigraph/include/igraph_vector_ptr.h index 77ba89cb70c..90a89ba57e8 100644 --- a/src/vendor/cigraph/include/igraph_vector_ptr.h +++ b/src/vendor/cigraph/include/igraph_vector_ptr.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_VECTOR_PTR_H @@ -28,7 +23,7 @@ #include "igraph_error.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Flexible vector, storing pointers */ @@ -51,31 +46,31 @@ typedef struct s_vector_ptr { do { IGRAPH_CHECK(igraph_vector_ptr_init(v, size)); \ IGRAPH_FINALLY(igraph_vector_ptr_destroy, v); } while (0) -IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_init(igraph_vector_ptr_t* v, igraph_integer_t size); -IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_init_array(igraph_vector_ptr_t* v, void *const *data, igraph_integer_t length); +IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_init(igraph_vector_ptr_t* v, igraph_int_t size); +IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_init_array(igraph_vector_ptr_t* v, void *const *data, igraph_int_t length); IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_init_copy(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from); -IGRAPH_EXPORT const igraph_vector_ptr_t *igraph_vector_ptr_view (const igraph_vector_ptr_t *v, - void *const *data, igraph_integer_t length); +IGRAPH_EXPORT igraph_vector_ptr_t igraph_vector_ptr_view (void *const *data, igraph_int_t length); IGRAPH_EXPORT void igraph_vector_ptr_destroy(igraph_vector_ptr_t* v); IGRAPH_EXPORT void igraph_vector_ptr_free_all(igraph_vector_ptr_t* v); IGRAPH_EXPORT void igraph_vector_ptr_destroy_all(igraph_vector_ptr_t* v); -IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_reserve(igraph_vector_ptr_t* v, igraph_integer_t capacity); +IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_reserve(igraph_vector_ptr_t* v, igraph_int_t capacity); +IGRAPH_EXPORT void igraph_vector_ptr_resize_min(igraph_vector_ptr_t* v); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_vector_ptr_empty(const igraph_vector_ptr_t* v); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_vector_ptr_size(const igraph_vector_ptr_t* v); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_vector_ptr_size(const igraph_vector_ptr_t* v); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_vector_ptr_capacity(const igraph_vector_ptr_t* v); IGRAPH_EXPORT void igraph_vector_ptr_clear(igraph_vector_ptr_t* v); IGRAPH_EXPORT void igraph_vector_ptr_null(igraph_vector_ptr_t* v); IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_push_back(igraph_vector_ptr_t* v, void* e); IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_append(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from); IGRAPH_EXPORT void *igraph_vector_ptr_pop_back(igraph_vector_ptr_t *v); -IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_insert(igraph_vector_ptr_t *v, igraph_integer_t pos, void* e); -IGRAPH_EXPORT IGRAPH_DEPRECATED void* igraph_vector_ptr_e(const igraph_vector_ptr_t* v, igraph_integer_t pos); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE void* igraph_vector_ptr_get(const igraph_vector_ptr_t* v, igraph_integer_t pos); -IGRAPH_EXPORT void igraph_vector_ptr_set(igraph_vector_ptr_t* v, igraph_integer_t pos, void* value); -IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_resize(igraph_vector_ptr_t* v, igraph_integer_t newsize); +IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_insert(igraph_vector_ptr_t *v, igraph_int_t pos, void* e); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE void *igraph_vector_ptr_get(const igraph_vector_ptr_t* v, igraph_int_t pos); +IGRAPH_EXPORT void igraph_vector_ptr_set(igraph_vector_ptr_t* v, igraph_int_t pos, void* value); +IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_resize(igraph_vector_ptr_t* v, igraph_int_t newsize); IGRAPH_EXPORT void igraph_vector_ptr_copy_to(const igraph_vector_ptr_t *v, void** to); IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_permute(igraph_vector_ptr_t* v, const igraph_vector_int_t* index); -IGRAPH_EXPORT void igraph_vector_ptr_remove(igraph_vector_ptr_t *v, igraph_integer_t pos); +IGRAPH_EXPORT void igraph_vector_ptr_remove(igraph_vector_ptr_t *v, igraph_int_t pos); IGRAPH_EXPORT void igraph_vector_ptr_sort(igraph_vector_ptr_t *v, int(*compar)(const void*, const void*)); IGRAPH_EXPORT igraph_error_t igraph_vector_ptr_sort_ind( igraph_vector_ptr_t *v, igraph_vector_int_t *inds, int(*compar)(const void*, const void*)); @@ -84,8 +79,6 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_finally_func_t* igraph_vector_ptr_get_ IGRAPH_EXPORT igraph_finally_func_t* igraph_vector_ptr_set_item_destructor(igraph_vector_ptr_t *v, igraph_finally_func_t *func); -IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_vector_ptr_copy(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from); - /** * \define IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR * \brief Sets the item destructor for this pointer vector (macro version). @@ -100,6 +93,6 @@ IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_vector_ptr_copy(igraph_vec #define IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(v, func) \ igraph_vector_ptr_set_item_destructor((v), (igraph_finally_func_t*)(func)) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_vector_type.h b/src/vendor/cigraph/include/igraph_vector_type.h index fef9d9ff735..95c39aefe12 100644 --- a/src/vendor/cigraph/include/igraph_vector_type.h +++ b/src/vendor/cigraph/include/igraph_vector_type.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2013 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2013-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ /** diff --git a/src/vendor/cigraph/include/igraph_version.h.in b/src/vendor/cigraph/include/igraph_version.h.in index fda42278d82..74bfc5e55a3 100644 --- a/src/vendor/cigraph/include/igraph_version.h.in +++ b/src/vendor/cigraph/include/igraph_version.h.in @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2010-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2010-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_VERSION_H @@ -26,7 +21,7 @@ #include "igraph_decls.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS #define IGRAPH_VERSION "@PACKAGE_VERSION@" #define IGRAPH_VERSION_MAJOR @PACKAGE_VERSION_MAJOR@ @@ -37,8 +32,8 @@ __BEGIN_DECLS IGRAPH_EXPORT void igraph_version(const char **version_string, int *major, int *minor, - int *subminor); + int *patch); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_visitor.h b/src/vendor/cigraph/include/igraph_visitor.h index 358467e3bf0..7edd3feab69 100644 --- a/src/vendor/cigraph/include/igraph_visitor.h +++ b/src/vendor/cigraph/include/igraph_visitor.h @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_VISITOR_H @@ -30,7 +25,7 @@ #include "igraph_types.h" #include "igraph_datatype.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Visitor-like functions */ @@ -72,15 +67,15 @@ __BEGIN_DECLS */ typedef igraph_error_t igraph_bfshandler_t(const igraph_t *graph, - igraph_integer_t vid, - igraph_integer_t pred, - igraph_integer_t succ, - igraph_integer_t rank, - igraph_integer_t dist, + igraph_int_t vid, + igraph_int_t pred, + igraph_int_t succ, + igraph_int_t rank, + igraph_int_t dist, void *extra); IGRAPH_EXPORT igraph_error_t igraph_bfs(const igraph_t *graph, - igraph_integer_t root, const igraph_vector_int_t *roots, + igraph_int_t root, const igraph_vector_int_t *roots, igraph_neimode_t mode, igraph_bool_t unreachable, const igraph_vector_int_t *restricted, igraph_vector_int_t *order, igraph_vector_int_t *rank, @@ -89,7 +84,7 @@ IGRAPH_EXPORT igraph_error_t igraph_bfs(const igraph_t *graph, igraph_vector_int_t *dist, igraph_bfshandler_t *callback, void *extra); -IGRAPH_EXPORT igraph_error_t igraph_bfs_simple(const igraph_t *graph, igraph_integer_t root, igraph_neimode_t mode, +IGRAPH_EXPORT igraph_error_t igraph_bfs_simple(const igraph_t *graph, igraph_int_t root, igraph_neimode_t mode, igraph_vector_int_t *order, igraph_vector_int_t *layers, igraph_vector_int_t *parents); @@ -122,11 +117,11 @@ IGRAPH_EXPORT igraph_error_t igraph_bfs_simple(const igraph_t *graph, igraph_int */ typedef igraph_error_t igraph_dfshandler_t(const igraph_t *graph, - igraph_integer_t vid, - igraph_integer_t dist, + igraph_int_t vid, + igraph_int_t dist, void *extra); -IGRAPH_EXPORT igraph_error_t igraph_dfs(const igraph_t *graph, igraph_integer_t root, +IGRAPH_EXPORT igraph_error_t igraph_dfs(const igraph_t *graph, igraph_int_t root, igraph_neimode_t mode, igraph_bool_t unreachable, igraph_vector_int_t *order, igraph_vector_int_t *order_out, igraph_vector_int_t *parents, @@ -134,6 +129,6 @@ IGRAPH_EXPORT igraph_error_t igraph_dfs(const igraph_t *graph, igraph_integer_t igraph_dfshandler_t *out_callback, void *extra); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/interfaces/functions.yaml b/src/vendor/cigraph/interfaces/functions.yaml index ed11d4fa962..8b6b5f5ce86 100644 --- a/src/vendor/cigraph/interfaces/functions.yaml +++ b/src/vendor/cigraph/interfaces/functions.yaml @@ -12,88 +12,110 @@ igraph_empty: PARAMS: OUT GRAPH graph, INTEGER n=0, BOOLEAN directed=True + FLAGS: no_rng igraph_add_edges: PARAMS: INOUT GRAPH graph, VERTEX_INDEX_PAIRS edges, ATTRIBUTES attr DEPS: edges ON graph + FLAGS: no_rng igraph_empty_attrs: PARAMS: OUT GRAPH graph, INTEGER n, BOOLEAN directed, ATTRIBUTES attr + FLAGS: no_rng igraph_add_vertices: PARAMS: INOUT GRAPH graph, INTEGER nv, ATTRIBUTES attr + FLAGS: no_rng igraph_copy: PARAMS: OUT GRAPH to, IN GRAPH from + FLAGS: no_rng igraph_delete_edges: PARAMS: INOUT GRAPH graph, EDGE_SELECTOR edges DEPS: edges ON graph + FLAGS: no_rng igraph_delete_vertices: PARAMS: INOUT GRAPH graph, VERTEX_SELECTOR vertices DEPS: vertices ON graph + FLAGS: no_rng -igraph_delete_vertices_idx: +igraph_delete_vertices_map: PARAMS: |- INOUT GRAPH graph, VERTEX_SELECTOR vertices, OPTIONAL OUT VECTOR_INT idx, OPTIONAL OUT VECTOR_INT invidx DEPS: vertices ON graph + FLAGS: no_rng igraph_vcount: PARAMS: GRAPH graph RETURN: INTEGER + FLAGS: no_rng igraph_ecount: PARAMS: GRAPH graph RETURN: INTEGER + FLAGS: no_rng igraph_neighbors: - PARAMS: GRAPH graph, OUT VERTEX_INDICES neis, VERTEX vid, NEIMODE mode=ALL + PARAMS: |- + GRAPH graph, OUT VERTEX_INDICES neis, VERTEX vid, NEIMODE mode=ALL, + LOOPS loops=TWICE, BOOLEAN multiple=True DEPS: vid ON graph, neis ON graph + FLAGS: no_rng igraph_is_directed: PARAMS: GRAPH graph RETURN: BOOLEAN + FLAGS: no_rng igraph_degree: PARAMS: |- GRAPH graph, OUT VECTOR_INT res, VERTEX_SELECTOR vids=ALL, NEIMODE mode=ALL, - BOOLEAN loops=True + LOOPS loops=TWICE DEPS: vids ON graph + FLAGS: no_rng igraph_edge: PARAMS: GRAPH graph, INTEGER eid, OUT INTEGER from, OUT INTEGER to + FLAGS: no_rng igraph_edges: - PARAMS: GRAPH graph, EDGE_SELECTOR eids, OUT VECTOR_INT edges + PARAMS: GRAPH graph, EDGE_SELECTOR eids, OUT VECTOR_INT edges, BOOLEAN bycol=False DEPS: eids ON graph + FLAGS: no_rng igraph_get_eid: PARAMS: |- GRAPH graph, OUT EDGE eid, VERTEX from, VERTEX to, BOOLEAN directed=True, BOOLEAN error=True - DEPS: from ON graph, to ON graph + DEPS: eid ON graph, from ON graph, to ON graph + FLAGS: no_rng igraph_get_eids: PARAMS: |- GRAPH graph, OUT EDGE_INDICES eids, VERTEX_INDEX_PAIRS pairs, BOOLEAN directed=True, BOOLEAN error=True - DEPS: pairs ON graph + DEPS: eids ON graph, pairs ON graph + FLAGS: no_rng igraph_get_all_eids_between: PARAMS: |- GRAPH graph, OUT EDGE_INDICES eids, VERTEX from, VERTEX to, BOOLEAN directed=True - DEPS: from ON graph, to ON graph + DEPS: eids ON graph, from ON graph, to ON graph + FLAGS: no_rng igraph_incident: - PARAMS: GRAPH graph, OUT EDGE_INDICES eids, VERTEX vid, NEIMODE mode=ALL - DEPS: vid ON graph, eids ON graph + PARAMS: GRAPH graph, OUT EDGE_INDICES eids, VERTEX vid, NEIMODE mode=ALL, LOOPS loops=TWICE + DEPS: eids ON graph, vid ON graph + FLAGS: no_rng igraph_is_same_graph: PARAMS: GRAPH graph1, GRAPH graph2, OUT BOOLEAN res + FLAGS: no_rng ####################################### # Constructors, deterministic @@ -101,6 +123,7 @@ igraph_is_same_graph: igraph_create: PARAMS: OUT GRAPH graph, VECTOR_INT edges, INTEGER n=0, BOOLEAN directed=True + FLAGS: no_rng igraph_adjacency: PARAMS: |- @@ -117,12 +140,14 @@ igraph_sparse_weighted_adjacency: # construction to eliminate duplicate elements from the representation PARAMS: |- OUT GRAPH graph, INOUT SPARSEMAT adjmatrix, ADJACENCY_MODE mode=DIRECTED, - OUT EDGEWEIGHTS weights, LOOPS loops=ONCE + OUT EDGE_WEIGHTS weights, LOOPS loops=ONCE + DEPS: weights ON graph igraph_weighted_adjacency: PARAMS: |- OUT GRAPH graph, MATRIX adjmatrix, ADJACENCY_MODE mode=DIRECTED, - OUT EDGEWEIGHTS weights, LOOPS loops=ONCE + OUT EDGE_WEIGHTS weights, LOOPS loops=ONCE + DEPS: weights ON graph igraph_star: PARAMS: OUT GRAPH graph, INTEGER n, STAR_MODE mode=OUT, INTEGER center=0 @@ -166,6 +191,7 @@ igraph_regular_tree: igraph_full: PARAMS: OUT GRAPH graph, INTEGER n, BOOLEAN directed=False, BOOLEAN loops=False + FLAGS: no_rng igraph_full_citation: PARAMS: OUT GRAPH graph, INTEGER n, BOOLEAN directed=True @@ -187,14 +213,17 @@ igraph_linegraph: igraph_de_bruijn: PARAMS: OUT GRAPH graph, INTEGER m, INTEGER n + FLAGS: no_rng igraph_kautz: PARAMS: OUT GRAPH graph, INTEGER m, INTEGER n + FLAGS: no_rng igraph_famous: PARAMS: OUT GRAPH graph, CSTRING name + FLAGS: no_rng -igraph_lcf_vector: +igraph_lcf: PARAMS: OUT GRAPH graph, INTEGER n, VECTOR_INT shifts, INTEGER repeats=1 igraph_mycielski_graph: @@ -207,9 +236,8 @@ igraph_adjlist: igraph_full_bipartite: PARAMS: |- - OUT GRAPH graph, OPTIONAL OUT ALL_BIPARTITE_TYPES types, INTEGER n1, + OUT GRAPH graph, OPTIONAL OUT BIPARTITE_TYPES types, INTEGER n1, INTEGER n2, BOOLEAN directed=False, NEIMODE mode=ALL - DEPS: types ON graph igraph_full_multipartite: PARAMS: |- @@ -236,10 +264,6 @@ igraph_turan: PARAMS: |- OUT GRAPH graph, OPTIONAL OUT INDEX_VECTOR types, INTEGER n, INTEGER r -igraph_weighted_sparsemat: - PARAMS: |- - OUT GRAPH graph, SPARSEMAT A, BOOLEAN directed, CSTRING attr, BOOLEAN loops=False - ####################################### # Constructors, games ####################################### @@ -252,9 +276,18 @@ igraph_barabasi_game: OPTIONAL GRAPH start_from igraph_erdos_renyi_game_gnp: - PARAMS: OUT GRAPH graph, INTEGER n, REAL p, BOOLEAN directed=False, BOOLEAN loops=False + PARAMS: |- + OUT GRAPH graph, INTEGER n, REAL p, BOOLEAN directed=False, + EDGE_TYPE_SW allowed_edge_types=SIMPLE, + BOOLEAN edge_labeled=False igraph_erdos_renyi_game_gnm: + PARAMS: |- + OUT GRAPH graph, INTEGER n, INTEGER m, BOOLEAN directed=False, + EDGE_TYPE_SW allowed_edge_types=SIMPLE, + BOOLEAN edge_labeled=False + +igraph_iea_game: PARAMS: OUT GRAPH graph, INTEGER n, INTEGER m, BOOLEAN directed=False, BOOLEAN loops=False igraph_degree_sequence_game: @@ -319,8 +352,8 @@ igraph_asymmetric_preference_game: igraph_rewire_edges: PARAMS: |- - INOUT GRAPH graph, REAL prob, BOOLEAN loops=False, - BOOLEAN multiple=False + INOUT GRAPH graph, REAL prob, + EDGE_TYPE_SW allowed_edge_types=SIMPLE igraph_rewire_directed_edges: PARAMS: |- @@ -330,7 +363,7 @@ igraph_rewire_directed_edges: igraph_watts_strogatz_game: PARAMS: |- OUT GRAPH graph, INTEGER dim, INTEGER size, INTEGER nei, - REAL p, BOOLEAN loops=False, BOOLEAN multiple=False + REAL p, EDGE_TYPE_SW allowed_edge_types=SIMPLE igraph_lastcit_game: PARAMS: |- @@ -366,14 +399,14 @@ igraph_chung_lu_game: igraph_static_fitness_game: PARAMS: |- OUT GRAPH graph, INTEGER no_of_edges, VECTOR fitness_out, - OPTIONAL VECTOR fitness_in, BOOLEAN loops=False, - BOOLEAN multiple=False + OPTIONAL VECTOR fitness_in, + EDGE_TYPE_SW allowed_edge_types=SIMPLE igraph_static_power_law_game: PARAMS: |- OUT GRAPH graph, INTEGER no_of_nodes, INTEGER no_of_edges, REAL exponent_out, REAL exponent_in=-1, - BOOLEAN loops=False, BOOLEAN multiple=False, + EDGE_TYPE_SW allowed_edge_types=SIMPLE, BOOLEAN finite_size_correction=True igraph_k_regular_game: @@ -383,9 +416,9 @@ igraph_k_regular_game: igraph_sbm_game: PARAMS: |- - OUT GRAPH graph, INTEGER n, MATRIX pref_matrix, + OUT GRAPH graph, MATRIX pref_matrix, VECTOR_INT block_sizes, BOOLEAN directed=False, - BOOLEAN loops=False + EDGE_TYPE_SW allowed_edge_types=SIMPLE igraph_hsbm_game: INTERNAL: true @@ -401,7 +434,7 @@ igraph_hsbm_list_game: igraph_correlated_game: PARAMS: |- - GRAPH old_graph, OUT GRAPH new_graph, + OUT GRAPH new_graph, GRAPH old_graph, REAL corr, REAL p=edge_density(old_graph), OPTIONAL INDEX_VECTOR permutation igraph_correlated_pair_game: @@ -413,19 +446,6 @@ igraph_correlated_pair_game: igraph_dot_product_game: PARAMS: OUT GRAPH graph, MATRIX vecs, BOOLEAN directed=False -igraph_sample_sphere_surface: - PARAMS: |- - INTEGER dim, INTEGER n=1, REAL radius=1, - BOOLEAN positive=True, OUT MATRIX res - -igraph_sample_sphere_volume: - PARAMS: |- - INTEGER dim, INTEGER n=1, REAL radius=1, - BOOLEAN positive=True, OUT MATRIX res - -igraph_sample_dirichlet: - PARAMS: INTEGER n, VECTOR alpha, OUT MATRIX res - ####################################### # Basic query functions ####################################### @@ -434,24 +454,13 @@ igraph_are_adjacent: PARAMS: GRAPH graph, VERTEX v1, VERTEX v2, OUT BOOLEAN res DEPS: v1 ON graph, v2 ON graph -igraph_are_connected: - PARAMS: GRAPH graph, VERTEX v1, VERTEX v2, OUT BOOLEAN res - DEPS: v1 ON graph, v2 ON graph - ####################################### # Structural properties ####################################### igraph_diameter: PARAMS: |- - GRAPH graph, OUT REAL res, OUT INTEGER from, - OUT INTEGER to, OPTIONAL OUT VECTOR_INT vertex_path, - OPTIONAL OUT VECTOR_INT edge_path, - BOOLEAN directed=True, BOOLEAN unconnected=True - -igraph_diameter_dijkstra: - PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT REAL res, OUT INTEGER from, OUT INTEGER to, OPTIONAL OUT VECTOR_INT vertex_path, OPTIONAL OUT VECTOR_INT edge_path, @@ -464,7 +473,7 @@ igraph_closeness: OPTIONAL OUT VECTOR_INT reachable_count, OPTIONAL OUT BOOLEAN all_reachable, VERTEX_SELECTOR vids=ALL, - NEIMODE mode=OUT, OPTIONAL EDGEWEIGHTS weights, + NEIMODE mode=OUT, OPTIONAL EDGE_WEIGHTS weights, BOOLEAN normalized=False DEPS: vids ON graph, weights ON graph, res ON graph vids @@ -474,84 +483,84 @@ igraph_closeness_cutoff: OPTIONAL OUT VECTOR_INT reachable_count, OPTIONAL OUT BOOLEAN all_reachable, VERTEX_SELECTOR vids=ALL, - NEIMODE mode=OUT, OPTIONAL EDGEWEIGHTS weights, - BOOLEAN normalized=False, REAL cutoff=-1 + NEIMODE mode=OUT, OPTIONAL EDGE_WEIGHTS weights, + BOOLEAN normalized=False, REAL cutoff=UNLIMITED DEPS: vids ON graph, weights ON graph, res ON graph vids igraph_distances: PARAMS: |- - GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, - VERTEX_SELECTOR to=ALL, NEIMODE mode=OUT - DEPS: from ON graph, to ON graph + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT MATRIX res, + VERTEX_SELECTOR from=ALL, VERTEX_SELECTOR to=ALL, NEIMODE mode=OUT + DEPS: weights ON graph, from ON graph, to ON graph igraph_distances_cutoff: PARAMS: |- - GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, - VERTEX_SELECTOR to=ALL, NEIMODE mode=OUT, REAL cutoff=-1 - DEPS: from ON graph, to ON graph + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT MATRIX res, + VERTEX_SELECTOR from=ALL, VERTEX_SELECTOR to=ALL, NEIMODE mode=OUT, REAL cutoff=UNLIMITED + DEPS: weights ON graph, from ON graph, to ON graph igraph_get_shortest_path: PARAMS: |- - GRAPH graph, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OPTIONAL OUT VERTEX_INDICES vertices, OPTIONAL OUT EDGE_INDICES edges, VERTEX from, VERTEX to, NEIMODE mode=OUT - DEPS: from ON graph, to ON graph, vertices ON graph, edges ON graph + DEPS: weights ON graph, from ON graph, to ON graph, vertices ON graph, edges ON graph igraph_get_shortest_path_bellman_ford: PARAMS: |- GRAPH graph, OPTIONAL OUT VERTEX_INDICES vertices, OPTIONAL OUT EDGE_INDICES edges, - VERTEX from, VERTEX to, OPTIONAL EDGEWEIGHTS weights, NEIMODE mode=OUT + VERTEX from, VERTEX to, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: from ON graph, to ON graph, weights ON graph, vertices ON graph, edges ON graph igraph_get_shortest_path_dijkstra: PARAMS: |- GRAPH graph, OPTIONAL OUT VERTEX_INDICES vertices, OPTIONAL OUT EDGE_INDICES edges, - VERTEX from, VERTEX to, OPTIONAL EDGEWEIGHTS weights, NEIMODE mode=OUT + VERTEX from, VERTEX to, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: from ON graph, to ON graph, weights ON graph, vertices ON graph, edges ON graph igraph_get_shortest_path_astar: PARAMS: |- GRAPH graph, OPTIONAL OUT VERTEX_INDICES vertices, OPTIONAL OUT EDGE_INDICES edges, - VERTEX from, VERTEX to, OPTIONAL EDGEWEIGHTS weights, NEIMODE mode=OUT, + VERTEX from, VERTEX to, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT, OPTIONAL ASTAR_HEURISTIC_FUNC heuristic, OPTIONAL EXTRA extra DEPS: from ON graph, to ON graph, weights ON graph, vertices ON graph, edges ON graph igraph_get_shortest_paths: PARAMS: |- - GRAPH graph, - OPTIONAL OUT VERTEXSET_LIST vertices, OPTIONAL OUT EDGESET_LIST edges, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OPTIONAL OUT VERTEX_INDICES_LIST vertices, OPTIONAL OUT EDGE_INDICES_LIST edges, VERTEX from, VERTEX_SELECTOR to=ALL, NEIMODE mode=OUT, OPTIONAL OUT VECTOR_INT parents, OPTIONAL OUT VECTOR_INT inbound_edges - DEPS: vertices ON graph, edges ON graph, from ON graph, to ON graph + DEPS: weights ON graph, edges ON graph, from ON graph, to ON graph igraph_get_all_shortest_paths: PARAMS: |- - GRAPH graph, OPTIONAL OUT VERTEXSET_LIST vertices, - OPTIONAL OUT EDGESET_LIST edges, OPTIONAL OUT VECTOR_INT nrgeo, - VERTEX from, VERTEX_SELECTOR to, NEIMODE mode=OUT - DEPS: vertices ON graph, edges ON graph, from ON graph, to ON graph + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OPTIONAL OUT VERTEX_INDICES_LIST vertices, OPTIONAL OUT EDGE_INDICES_LIST edges, + OPTIONAL OUT VECTOR_INT nrgeo, VERTEX from, VERTEX_SELECTOR to, NEIMODE mode=OUT + DEPS: weights ON graph, edges ON graph, from ON graph, to ON graph igraph_distances_dijkstra: PARAMS: |- GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, - VERTEX_SELECTOR to=ALL, OPTIONAL EDGEWEIGHTS weights, NEIMODE mode=OUT + VERTEX_SELECTOR to=ALL, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: from ON graph, to ON graph, weights ON graph igraph_distances_dijkstra_cutoff: PARAMS: |- GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, - VERTEX_SELECTOR to=ALL, OPTIONAL EDGEWEIGHTS weights, NEIMODE mode=OUT, REAL cutoff=-1 + VERTEX_SELECTOR to=ALL, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT, REAL cutoff=UNLIMITED DEPS: from ON graph, to ON graph, weights ON graph igraph_get_shortest_paths_dijkstra: PARAMS: |- - GRAPH graph, OPTIONAL OUT VERTEXSET_LIST vertices, - OPTIONAL OUT EDGESET_LIST edges, VERTEX from, VERTEX_SELECTOR to=ALL, - OPTIONAL EDGEWEIGHTS weights, NEIMODE mode=OUT, + GRAPH graph, OPTIONAL OUT VERTEX_INDICES_LIST vertices, + OPTIONAL OUT EDGE_INDICES_LIST edges, VERTEX from, VERTEX_SELECTOR to=ALL, + OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT, OPTIONAL OUT VECTOR_INT parents, OPTIONAL OUT VECTOR_INT inbound_edges DEPS: |- @@ -560,9 +569,9 @@ igraph_get_shortest_paths_dijkstra: igraph_get_shortest_paths_bellman_ford: PARAMS: |- - GRAPH graph, OPTIONAL OUT VERTEXSET_LIST vertices, - OPTIONAL OUT EDGESET_LIST edges, VERTEX from, VERTEX_SELECTOR to=ALL, - OPTIONAL EDGEWEIGHTS weights, NEIMODE mode=OUT, + GRAPH graph, OPTIONAL OUT VERTEX_INDICES_LIST vertices, + OPTIONAL OUT EDGE_INDICES_LIST edges, VERTEX from, VERTEX_SELECTOR to=ALL, + OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT, OPTIONAL OUT VECTOR_INT parents, OPTIONAL OUT VECTOR_INT inbound_edges DEPS: |- @@ -571,9 +580,9 @@ igraph_get_shortest_paths_bellman_ford: igraph_get_all_shortest_paths_dijkstra: PARAMS: |- - GRAPH graph, OPTIONAL OUT VERTEXSET_LIST vertices, - OPTIONAL OUT EDGESET_LIST edges, OPTIONAL OUT VECTOR_INT nrgeo, - VERTEX from, VERTEX_SELECTOR to=ALL, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OPTIONAL OUT VERTEX_INDICES_LIST vertices, + OPTIONAL OUT EDGE_INDICES_LIST edges, OPTIONAL OUT VECTOR_INT nrgeo, + VERTEX from, VERTEX_SELECTOR to=ALL, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: |- weights ON graph, from ON graph, to ON graph, vertices ON graph, edges ON graph @@ -581,39 +590,41 @@ igraph_get_all_shortest_paths_dijkstra: igraph_distances_bellman_ford: PARAMS: |- GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, - VERTEX_SELECTOR to=ALL, OPTIONAL EDGEWEIGHTS weights, NEIMODE mode=OUT + VERTEX_SELECTOR to=ALL, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: from ON graph, to ON graph, weights ON graph igraph_distances_johnson: PARAMS: |- GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, - VERTEX_SELECTOR to=ALL, OPTIONAL EDGEWEIGHTS weights + VERTEX_SELECTOR to=ALL, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: from ON graph, to ON graph, weights ON graph igraph_distances_floyd_warshall: PARAMS: |- GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, - VERTEX_SELECTOR to=ALL, OPTIONAL EDGEWEIGHTS weights, NEIMODE mode=OUT, + VERTEX_SELECTOR to=ALL, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT, FWALGORITHM method=AUTOMATIC DEPS: from ON graph, to ON graph, weights ON graph igraph_voronoi: PARAMS: |- GRAPH graph, OUT VECTOR_INT membership, OUT VECTOR distances, - VERTEX_INDICES generators, OPTIONAL EDGEWEIGHTS weights, NEIMODE mode=OUT, VORONOI_TIEBREAKER tiebreaker=RANDOM + VERTEX_INDICES generators, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT, VORONOI_TIEBREAKER tiebreaker=RANDOM DEPS: weights ON graph, generators ON graph igraph_get_all_simple_paths: PARAMS: |- - GRAPH graph, OUT VERTEX_INDICES res, VERTEX from, - VERTEX_SELECTOR to=ALL, INTEGER cutoff=-1, NEIMODE mode=OUT + GRAPH graph, OUT VERTEX_INDICES_LIST res, VERTEX from, + VERTEX_SELECTOR to=ALL, NEIMODE mode=OUT, + INTEGER minlen=UNLIMITED, INTEGER maxlen=UNLIMITED, + INTEGER max_results=UNLIMITED DEPS: from ON graph, to ON graph, res ON graph igraph_get_k_shortest_paths: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, - OPTIONAL OUT VERTEXSET_LIST vertex_paths, - OPTIONAL OUT EDGESET_LIST edge_paths, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OPTIONAL OUT VERTEX_INDICES_LIST vertex_paths, + OPTIONAL OUT EDGE_INDICES_LIST edge_paths, INTEGER k, VERTEX from, VERTEX to, NEIMODE mode=OUT DEPS: |- from ON graph, to ON graph, weights ON graph, vertex_paths ON graph, edge_paths ON graph @@ -622,15 +633,15 @@ igraph_get_widest_path: PARAMS: |- GRAPH graph, OPTIONAL OUT VERTEX_INDICES vertices, OPTIONAL OUT EDGE_INDICES edges, - VERTEX from, VERTEX to, EDGEWEIGHTS weights, NEIMODE mode=OUT + VERTEX from, VERTEX to, EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: |- from ON graph, to ON graph, weights ON graph, vertices ON graph, edges ON graph igraph_get_widest_paths: PARAMS: |- GRAPH graph, - OPTIONAL OUT VERTEXSET_LIST vertices, OPTIONAL OUT EDGESET_LIST edges, - VERTEX from, VERTEX_SELECTOR to=ALL, EDGEWEIGHTS weights, + OPTIONAL OUT VERTEX_INDICES_LIST vertices, OPTIONAL OUT EDGE_INDICES_LIST edges, + VERTEX from, VERTEX_SELECTOR to=ALL, EDGE_WEIGHTS weights, NEIMODE mode=OUT, OPTIONAL OUT VECTOR_INT parents, OPTIONAL OUT VECTOR_INT inbound_edges DEPS: |- @@ -640,18 +651,18 @@ igraph_get_widest_paths: igraph_widest_path_widths_dijkstra: PARAMS: |- GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, - VERTEX_SELECTOR to=ALL, EDGEWEIGHTS weights, NEIMODE mode=OUT + VERTEX_SELECTOR to=ALL, EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: from ON graph, to ON graph, weights ON graph igraph_widest_path_widths_floyd_warshall: PARAMS: |- GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, - VERTEX_SELECTOR to=ALL, EDGEWEIGHTS weights, NEIMODE mode=OUT + VERTEX_SELECTOR to=ALL, EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: from ON graph, to ON graph, weights ON graph igraph_spanner: PARAMS: |- - GRAPH graph, OUT EDGE_INDICES spanner, REAL stretch, OPTIONAL EDGEWEIGHTS weights + GRAPH graph, OUT EDGE_INDICES spanner, REAL stretch, OPTIONAL EDGE_WEIGHTS weights DEPS: weights ON graph igraph_subcomponent: @@ -660,64 +671,65 @@ igraph_subcomponent: igraph_betweenness: PARAMS: |- - GRAPH graph, OUT VERTEX_QTY res, VERTEX_SELECTOR vids=ALL, - BOOLEAN directed=True, OPTIONAL EDGEWEIGHTS weights + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VERTEX_QTY res, + VERTEX_SELECTOR vids=ALL, BOOLEAN directed=True, BOOLEAN normalized=False DEPS: weights ON graph, vids ON graph, res ON graph vids igraph_betweenness_cutoff: PARAMS: |- - GRAPH graph, OUT VERTEX_QTY res, VERTEX_SELECTOR vids=ALL, - BOOLEAN directed=True, OPTIONAL EDGEWEIGHTS weights, - REAL cutoff=-1 + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VERTEX_QTY res, + VERTEX_SELECTOR vids=ALL, BOOLEAN directed=True, BOOLEAN normalized=False, + REAL cutoff=UNLIMITED DEPS: vids ON graph, weights ON graph, res ON graph vids igraph_betweenness_subset: PARAMS: |- - GRAPH graph, OUT VERTEX_QTY res, VERTEX_SELECTOR vids=ALL, - BOOLEAN directed=True, VERTEX_SELECTOR sources=ALL, VERTEX_SELECTOR targets=ALL, - OPTIONAL EDGEWEIGHTS weights + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VERTEX_QTY res, + VERTEX_SELECTOR vids=ALL, VERTEX_SELECTOR sources=ALL, VERTEX_SELECTOR targets=ALL, + BOOLEAN directed=True, BOOLEAN normalized=False DEPS: |- vids ON graph, weights ON graph, res ON graph vids, sources ON graph, targets ON graph igraph_edge_betweenness: PARAMS: |- - GRAPH graph, OUT VECTOR res, BOOLEAN directed=True, - OPTIONAL EDGEWEIGHTS weights - DEPS: weights ON graph + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VECTOR res, EDGE_SELECTOR eids=ALL, + BOOLEAN directed=True, BOOLEAN normalized=False + DEPS: eids ON graph, weights ON graph, res ON graph eids igraph_edge_betweenness_cutoff: PARAMS: |- - GRAPH graph, OUT VECTOR res, BOOLEAN directed=True, - OPTIONAL EDGEWEIGHTS weights, REAL cutoff=-1 - DEPS: weights ON graph + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VECTOR res, EDGE_SELECTOR eids=ALL, + BOOLEAN directed=True, BOOLEAN normalized=False, REAL cutoff=UNLIMITED + DEPS: eids ON graph, weights ON graph, res ON graph eids igraph_edge_betweenness_subset: PARAMS: |- - GRAPH graph, OUT VECTOR res, EDGE_SELECTOR eids=ALL, - BOOLEAN directed=True, VERTEX_SELECTOR sources=ALL, VERTEX_SELECTOR targets=ALL, - OPTIONAL EDGEWEIGHTS weights + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VECTOR res, + VERTEX_SELECTOR sources=ALL, VERTEX_SELECTOR targets=ALL, EDGE_SELECTOR eids=ALL, + BOOLEAN directed=True, BOOLEAN normalized=False DEPS: |- - eids ON graph, weights ON graph, res ON graph, sources ON graph, targets ON graph + eids ON graph, weights ON graph, res ON graph eids, sources ON graph, targets ON graph igraph_harmonic_centrality: PARAMS: |- GRAPH graph, OUT VERTEX_QTY res, VERTEX_SELECTOR vids=ALL, - NEIMODE mode=OUT, OPTIONAL EDGEWEIGHTS weights, BOOLEAN normalized=False + NEIMODE mode=OUT, OPTIONAL EDGE_WEIGHTS weights, BOOLEAN normalized=False DEPS: weights ON graph, vids ON graph, res ON graph vids igraph_harmonic_centrality_cutoff: PARAMS: |- GRAPH graph, OUT VERTEX_QTY res, VERTEX_SELECTOR vids=ALL, - NEIMODE mode=OUT, OPTIONAL EDGEWEIGHTS weights, BOOLEAN normalized=False, - REAL cutoff=-1 + NEIMODE mode=OUT, OPTIONAL EDGE_WEIGHTS weights, BOOLEAN normalized=False, + REAL cutoff=UNLIMITED DEPS: vids ON graph, weights ON graph, res ON graph vids igraph_pagerank: PARAMS: |- - GRAPH graph, PAGERANKALGO algo=PRPACK, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VERTEX_QTY vector, OUT REAL value, - VERTEX_SELECTOR vids=ALL, BOOLEAN directed=True, - REAL damping=0.85, OPTIONAL EDGEWEIGHTS weights, + REAL damping=0.85, BOOLEAN directed=True, + VERTEX_SELECTOR vids=ALL, + PAGERANKALGO algo=PRPACK, OPTIONAL INOUT PAGERANKOPT options DEPS: |- vids ON graph, weights ON graph, vector ON graph vids, @@ -725,11 +737,12 @@ igraph_pagerank: igraph_personalized_pagerank: PARAMS: |- - GRAPH graph, PAGERANKALGO algo=PRPACK, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VERTEX_QTY vector, OUT REAL value, - VERTEX_SELECTOR vids=ALL, BOOLEAN directed=True, - REAL damping=0.85, OPTIONAL VECTOR personalized, - OPTIONAL EDGEWEIGHTS weights, + OPTIONAL VECTOR reset, + REAL damping=0.85, BOOLEAN directed=True, + VERTEX_SELECTOR vids=ALL, + PAGERANKALGO algo=PRPACK, OPTIONAL INOUT PAGERANKOPT options DEPS: |- vids ON graph, weights ON graph, vector ON graph vids, @@ -737,19 +750,19 @@ igraph_personalized_pagerank: igraph_personalized_pagerank_vs: PARAMS: |- - GRAPH graph, PAGERANKALGO algo=PRPACK, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, PRIMARY OUT VERTEX_QTY vector, OUT REAL value, - VERTEX_SELECTOR vids=ALL, BOOLEAN directed=True, - REAL damping=0.85, VERTEX_SELECTOR reset_vids, - OPTIONAL EDGEWEIGHTS weights, + REAL damping=0.85, BOOLEAN directed=True, + VERTEX_SELECTOR vids=ALL, + PAGERANKALGO algo=PRPACK, OPTIONAL INOUT PAGERANKOPT options DEPS: |- vids ON graph, weights ON graph, vector ON graph vids, options ON algo igraph_rewire: - PARAMS: INOUT GRAPH rewire, INTEGER n, REWIRING_MODE mode=SIMPLE + PARAMS: INOUT GRAPH rewire, INTEGER n, EDGE_TYPE_SW allowed_edge_types=SIMPLE, OPTIONAL OUT REWIRING_STATS stats igraph_induced_subgraph: PARAMS: GRAPH graph, OUT GRAPH res, VERTEX_SELECTOR vids, SUBGRAPH_IMPL impl=AUTO @@ -764,12 +777,8 @@ igraph_reverse_edges: DEPS: eids ON graph igraph_average_path_length: - PARAMS: GRAPH graph, PRIMARY OUT REAL res, OPTIONAL OUT REAL unconn_pairs, - BOOLEAN directed=True, BOOLEAN unconn=True - -igraph_average_path_length_dijkstra: - PARAMS: GRAPH graph, PRIMARY OUT REAL res, OPTIONAL OUT REAL unconn_pairs, - OPTIONAL EDGEWEIGHTS weights, BOOLEAN directed=True, BOOLEAN unconn=True + PARAMS: GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, PRIMARY OUT REAL res, + OPTIONAL OUT REAL unconn_pairs, BOOLEAN directed=True, BOOLEAN unconn=True DEPS: weights ON graph igraph_path_length_hist: @@ -796,7 +805,7 @@ igraph_transitivity_avglocal_undirected: igraph_transitivity_barrat: PARAMS: |- GRAPH graph, OUT VECTOR res, VERTEX_SELECTOR vids=ALL, - OPTIONAL EDGEWEIGHTS weights, TRANSITIVITY_MODE mode=NAN + OPTIONAL EDGE_WEIGHTS weights, TRANSITIVITY_MODE mode=NAN DEPS: res ON graph, vids ON graph, weights ON graph igraph_ecc: @@ -811,17 +820,18 @@ igraph_reciprocity: RECIP mode=DEFAULT igraph_constraint: - PARAMS: GRAPH graph, OUT VECTOR res, VERTEX_SELECTOR vids=ALL, OPTIONAL EDGEWEIGHTS weights + PARAMS: GRAPH graph, OUT VECTOR res, VERTEX_SELECTOR vids=ALL, OPTIONAL EDGE_WEIGHTS weights DEPS: vids ON graph, weights ON graph igraph_maxdegree: PARAMS: |- GRAPH graph, OUT INTEGER res, VERTEX_SELECTOR vids=ALL, NEIMODE mode=ALL, - BOOLEAN loops=True + LOOPS loops=TWICE DEPS: vids ON graph igraph_density: - PARAMS: GRAPH graph, OUT REAL res, BOOLEAN loops=False + PARAMS: GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT REAL res, BOOLEAN loops=False + DEPS: weights ON graph igraph_mean_degree: PARAMS: GRAPH graph, OUT REAL res, BOOLEAN loops=True @@ -834,7 +844,7 @@ igraph_neighborhood_size: igraph_neighborhood: PARAMS: |- - GRAPH graph, OUT VERTEXSET_LIST res, + GRAPH graph, OUT VERTEX_INDICES_LIST res, VERTEX_SELECTOR vids, INTEGER order, NEIMODE mode=ALL, INTEGER mindist=0 DEPS: res ON graph, vids ON graph @@ -852,11 +862,11 @@ igraph_topological_sorting: igraph_feedback_arc_set: # Default algorithm is the approximate method because it is faster and the # function is _not_ called igraph_minimum_feedback_arc_set - PARAMS: GRAPH graph, OUT EDGE_INDICES result, OPTIONAL EDGEWEIGHTS weights, FAS_ALGORITHM algo=APPROX_EADES + PARAMS: GRAPH graph, OUT EDGE_INDICES result, OPTIONAL EDGE_WEIGHTS weights, FAS_ALGORITHM algo=APPROX_EADES DEPS: result ON graph, weights ON graph igraph_feedback_vertex_set: - PARAMS: GRAPH graph, OUT VERTEX_INDICES result, OPTIONAL VERTEXWEIGHTS weights, FVS_ALGORITHM algo=EXACT_IP + PARAMS: GRAPH graph, OUT VERTEX_INDICES result, OPTIONAL VERTEX_WEIGHTS weights, FVS_ALGORITHM algo=EXACT_IP DEPS: result ON graph, weights ON graph igraph_is_loop: @@ -870,7 +880,7 @@ igraph_is_acyclic: PARAMS: GRAPH graph, OUT BOOLEAN res igraph_is_simple: - PARAMS: GRAPH graph, OUT BOOLEAN res + PARAMS: GRAPH graph, OUT BOOLEAN res, BOOLEAN directed=True igraph_is_multiple: PARAMS: GRAPH graph, OUT VECTOR_BOOL res, EDGE_SELECTOR es=ALL @@ -890,8 +900,8 @@ igraph_count_multiple: DEPS: es ON graph igraph_girth: - PARAMS: GRAPH graph, OUT REAL girth, OUT VERTEX_INDICES circle - DEPS: circle ON graph + PARAMS: GRAPH graph, OUT REAL girth, OUT VERTEX_INDICES cycle + DEPS: cycle ON graph igraph_is_perfect: PARAMS: GRAPH graph, OUT BOOLEAN res @@ -902,30 +912,17 @@ igraph_add_edge: igraph_eigenvector_centrality: PARAMS: |- GRAPH graph, OUT ALL_VERTEX_QTY vector, OUT REAL value, - BOOLEAN directed=False, BOOLEAN scale=True, - OPTIONAL EDGEWEIGHTS weights, - INOUT ARPACKOPT options=ARPACK_DEFAULTS - DEPS: weights ON graph, vector ON graph - -igraph_hub_score: - PARAMS: |- - GRAPH graph, OUT ALL_VERTEX_QTY vector, OUT REAL value, - BOOLEAN scale=True, OPTIONAL EDGEWEIGHTS weights, - INOUT ARPACKOPT options=ARPACK_DEFAULTS - DEPS: weights ON graph, vector ON graph - -igraph_authority_score: - PARAMS: |- - GRAPH graph, OUT ALL_VERTEX_QTY vector, OUT REAL value, - BOOLEAN scale=True, OPTIONAL EDGEWEIGHTS weights, - INOUT ARPACKOPT options=ARPACK_DEFAULTS + NEIMODE mode=OUT, + OPTIONAL EDGE_WEIGHTS weights, + INOUT ARPACK_OPTIONS options=ARPACK_DEFAULTS DEPS: weights ON graph, vector ON graph igraph_hub_and_authority_scores: PARAMS: |- GRAPH graph, OUT ALL_VERTEX_QTY hub_vector, OUT ALL_VERTEX_QTY authority_vector, - OUT REAL value, BOOLEAN scale=True, OPTIONAL EDGEWEIGHTS weights, - INOUT ARPACKOPT options=ARPACK_DEFAULTS + OUT REAL value, OPTIONAL EDGE_WEIGHTS weights, + INOUT ARPACK_OPTIONS options=ARPACK_DEFAULTS + DEPS: weights ON graph, hub_vector ON graph, authority_vector ON graph igraph_unfold_tree: PARAMS: |- @@ -955,31 +952,31 @@ igraph_avg_nearest_neighbor_degree: GRAPH graph, VERTEX_SELECTOR vids=ALL, NEIMODE mode=ALL, NEIMODE neighbor_degree_mode=ALL, OPTIONAL OUT VERTEX_QTY knn, OPTIONAL OUT VECTOR knnk, - OPTIONAL EDGEWEIGHTS weights + OPTIONAL EDGE_WEIGHTS weights DEPS: vids ON graph, weights ON graph, knn ON graph vids igraph_degree_correlation_vector: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VECTOR knnk, NEIMODE from_mode=OUT, NEIMODE to_mode=IN, BOOLEAN directed_neighbors=True DEPS: weights ON graph igraph_rich_club_sequence: - PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, - OUT VECTOR res, - INDEX_VECTOR vertex_order, - BOOLEAN normalized=True, - BOOLEAN loops=False, - BOOLEAN directed=True - DEPS: weights ON graph + PARAMS: |- + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OUT VECTOR res, + INDEX_VECTOR vertex_order, + BOOLEAN normalized=True, + BOOLEAN loops=False, + BOOLEAN directed=True + DEPS: weights ON graph igraph_strength: PARAMS: |- GRAPH graph, OUT VERTEX_QTY res, VERTEX_SELECTOR vids=ALL, - NEIMODE mode=ALL, BOOLEAN loops=True, OPTIONAL EDGEWEIGHTS weights + NEIMODE mode=ALL, LOOPS loops=TWICE, OPTIONAL EDGE_WEIGHTS weights DEPS: vids ON graph, weights ON graph, res ON graph vids igraph_centralization: @@ -989,7 +986,7 @@ igraph_centralization: igraph_centralization_degree: PARAMS: |- GRAPH graph, OUT VECTOR res, - NEIMODE mode=ALL, BOOLEAN loops=True, + NEIMODE mode=ALL, LOOPS loops=TWICE, OUT REAL centralization, OUT REAL theoretical_max, BOOLEAN normalized=True @@ -999,7 +996,7 @@ igraph_centralization_degree_tmax: # https://github.com/igraph/rigraph/issues/369#issuecomment-939893681 PARAMS: |- OPTIONAL GRAPH graph, INTEGER nodes=0, NEIMODE mode=ALL, - BOOLEAN loops, OUT REAL res + LOOPS loops, OUT REAL res igraph_centralization_betweenness: PARAMS: |- @@ -1029,50 +1026,55 @@ igraph_centralization_closeness_tmax: igraph_centralization_eigenvector_centrality: PARAMS: |- GRAPH graph, OUT VECTOR vector, OUT REAL value, - BOOLEAN directed=False, BOOLEAN scale=True, - INOUT ARPACKOPT options=ARPACK_DEFAULTS, + NEIMODE mode=OUT, + INOUT ARPACK_OPTIONS options=ARPACK_DEFAULTS, OUT REAL centralization, OUT REAL theoretical_max, BOOLEAN normalized=True igraph_centralization_eigenvector_centrality_tmax: PARAMS: |- OPTIONAL GRAPH graph, INTEGER nodes=0, - BOOLEAN directed=False, BOOLEAN scale=True, + NEIMODE mode=OUT, OUT REAL res igraph_assortativity_nominal: PARAMS: |- - GRAPH graph, INDEX_VECTOR types, OUT REAL res, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + INDEX_VECTOR types, + OUT REAL res, BOOLEAN directed=True, BOOLEAN normalized=True + DEPS: weights ON graph, types ON graph igraph_assortativity: PARAMS: |- - GRAPH graph, VECTOR values, OPTIONAL VECTOR values_in, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + VECTOR values, OPTIONAL VECTOR values_in, OUT REAL res, BOOLEAN directed=True, BOOLEAN normalized=True + DEPS: weights ON graph, values ON graph, values_in ON graph igraph_assortativity_degree: PARAMS: GRAPH graph, OUT REAL res, BOOLEAN directed=True igraph_joint_degree_matrix: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT MATRIX jdm, - INTEGER max_out_degree=-1, INTEGER max_in_degree=-1 + INTEGER max_out_degree=UNLIMITED, INTEGER max_in_degree=UNLIMITED DEPS: weights ON graph igraph_joint_degree_distribution: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT MATRIX p, NEIMODE from_mode=OUT, NEIMODE to_mode=IN, BOOLEAN directed_neighbors=True, BOOLEAN normalized=True, - INTEGER max_from_degree=-1, INTEGER max_to_degree=-1 + INTEGER max_from_degree=UNLIMITED, INTEGER max_to_degree=UNLIMITED DEPS: weights ON graph igraph_joint_type_distribution: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT MATRIX p, INDEX_VECTOR from_types, OPTIONAL INDEX_VECTOR to_types, BOOLEAN directed=True, @@ -1086,44 +1088,23 @@ igraph_contract_vertices: igraph_eccentricity: PARAMS: |- - GRAPH graph, OUT VERTEX_QTY res, VERTEX_SELECTOR vids=ALL, - NEIMODE mode=ALL - DEPS: vids ON graph, res ON graph vids - -igraph_eccentricity_dijkstra: - PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VERTEX_QTY res, VERTEX_SELECTOR vids=ALL, NEIMODE mode=ALL DEPS: weights ON graph, vids ON graph, res ON graph vids igraph_graph_center: PARAMS: |- - GRAPH graph, OUT VERTEX_INDICES res, NEIMODE mode=ALL - DEPS: res ON graph - -igraph_graph_center_dijkstra: - PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, OUT VERTEX_INDICES res, NEIMODE mode=ALL + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VERTEX_INDICES res, NEIMODE mode=ALL DEPS: weights ON graph, res ON graph igraph_radius: - PARAMS: GRAPH graph, OUT REAL radius, NEIMODE mode=ALL - -igraph_radius_dijkstra: - PARAMS: GRAPH graph, OPTIONAL EDGEWEIGHTS weights, OUT REAL radius, NEIMODE mode=ALL + PARAMS: GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT REAL radius, NEIMODE mode=ALL DEPS: weights ON graph igraph_pseudo_diameter: PARAMS: |- - GRAPH graph, OUT REAL diameter, VERTEX start_vid, - OPTIONAL OUT INTEGER from, OPTIONAL OUT INTEGER to, - BOOLEAN directed=True, BOOLEAN unconnected=True - DEPS: start_vid ON graph - -igraph_pseudo_diameter_dijkstra: - PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT REAL diameter, VERTEX start_vid, OPTIONAL OUT INTEGER from, OPTIONAL OUT INTEGER to, BOOLEAN directed=True, BOOLEAN unconnected=True @@ -1131,41 +1112,32 @@ igraph_pseudo_diameter_dijkstra: igraph_diversity: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, OUT VERTEX_QTY res, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VERTEX_QTY res, VERTEX_SELECTOR vids=ALL DEPS: weights ON graph, vids ON graph, res ON graph vids igraph_random_walk: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, OUT VERTEX_INDICES vertices, OUT EDGE_INDICES edges, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VERTEX_INDICES vertices, OUT EDGE_INDICES edges, VERTEX start, NEIMODE mode=OUT, INTEGER steps, RWSTUCK stuck=RETURN DEPS: start ON graph, weights ON graph, vertices ON graph, edges ON graph -igraph_random_edge_walk: - PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, OUT EDGE_INDICES edgewalk, - VERTEX start, NEIMODE mode=OUT, INTEGER steps, RWSTUCK stuck=RETURN - DEPS: start ON graph, weights ON graph, edgewalk ON graph - igraph_global_efficiency: - PARAMS: GRAPH graph, OUT REAL res, OPTIONAL EDGEWEIGHTS weights, BOOLEAN directed=True + PARAMS: GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT REAL res, BOOLEAN directed=True DEPS: weights ON graph igraph_local_efficiency: PARAMS: |- - GRAPH graph, OUT VERTEX_QTY res, VERTEX_SELECTOR vids=ALL, - OPTIONAL EDGEWEIGHTS weights, BOOLEAN directed=True, NEIMODE mode=ALL + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT VERTEX_QTY res, + VERTEX_SELECTOR vids=ALL, BOOLEAN directed=True, NEIMODE mode=ALL DEPS: vids ON graph, weights ON graph, res ON graph vids igraph_average_local_efficiency: PARAMS: |- - GRAPH graph, OUT REAL res, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT REAL res, BOOLEAN directed=True, NEIMODE mode=ALL DEPS: weights ON graph -igraph_transitive_closure_dag: - PARAMS: GRAPH graph, OUT GRAPH closure - igraph_transitive_closure: PARAMS: GRAPH graph, OUT GRAPH closure @@ -1244,15 +1216,25 @@ igraph_create_bipartite: igraph_biadjacency: PARAMS: |- - OUT GRAPH graph, OUT BIPARTITE_TYPES types, MATRIX incidence, + OUT GRAPH graph, OUT BIPARTITE_TYPES types, MATRIX biadjmatrix, BOOLEAN directed=False, NEIMODE mode=ALL, BOOLEAN multiple=False +igraph_weighted_biadjacency: + PARAMS: |- + OUT GRAPH graph, + OUT BIPARTITE_TYPES types, OUT EDGE_WEIGHTS weights, + MATRIX biadjmatrix, + BOOLEAN directed=False, NEIMODE mode=ALL + DEPS: |- + weights ON graph, biadjmatrix ON graph, types ON graph + igraph_get_biadjacency: PARAMS: |- - GRAPH graph, BIPARTITE_TYPES types, OUT MATRIX res, + GRAPH graph, BIPARTITE_TYPES types, OPTIONAL EDGE_WEIGHTS weights, + OUT MATRIX res, OPTIONAL OUT INDEX_VECTOR row_ids, OPTIONAL OUT INDEX_VECTOR col_ids - DEPS: types ON graph + DEPS: types ON graph, weights ON graph igraph_is_bipartite: PARAMS: GRAPH graph, OUT BOOLEAN res, OPTIONAL OUT BIPARTITE_TYPES types @@ -1260,21 +1242,24 @@ igraph_is_bipartite: igraph_bipartite_game_gnp: PARAMS: |- OUT GRAPH graph, OPTIONAL OUT BIPARTITE_TYPES types, - INTEGER n1, INTEGER n2, REAL p, BOOLEAN directed=False, - NEIMODE mode=ALL + INTEGER n1, INTEGER n2, REAL p, + BOOLEAN directed=False, NEIMODE mode=ALL, + EDGE_TYPE_SW allowed_edge_types=SIMPLE, BOOLEAN edge_labeled=False igraph_bipartite_game_gnm: PARAMS: |- OUT GRAPH graph, OPTIONAL OUT BIPARTITE_TYPES types, - INTEGER n1, INTEGER n2, INTEGER m, BOOLEAN directed=False, - NEIMODE mode=ALL + INTEGER n1, INTEGER n2, INTEGER m, + BOOLEAN directed=False, NEIMODE mode=ALL, + EDGE_TYPE_SW allowed_edge_types=SIMPLE, BOOLEAN edge_labeled=False -igraph_bipartite_game: +igraph_bipartite_iea_game: PARAMS: |- OUT GRAPH graph, OPTIONAL OUT BIPARTITE_TYPES types, - ERDOS_RENYI_TYPE type, INTEGER n1, INTEGER n2, REAL p=0.0, - INTEGER m=0, BOOLEAN directed=False, NEIMODE mode=ALL - + INTEGER n1, INTEGER n2, INTEGER m, + BOOLEAN directed=False, NEIMODE mode=ALL + DEPS: |- + types ON graph ####################################### # Spectral properties @@ -1283,13 +1268,13 @@ igraph_bipartite_game: igraph_get_laplacian: PARAMS: |- GRAPH graph, OUT MATRIX res, NEIMODE mode=OUT, - LAPLACIAN_NORMALIZATION normalization=UNNORMALIZED, OPTIONAL EDGEWEIGHTS weights + LAPLACIAN_NORMALIZATION normalization=UNNORMALIZED, OPTIONAL EDGE_WEIGHTS weights DEPS: weights ON graph igraph_get_laplacian_sparse: PARAMS: |- GRAPH graph, OUT SPARSEMAT sparseres, NEIMODE mode=OUT, - LAPLACIAN_NORMALIZATION normalization=UNNORMALIZED, OPTIONAL EDGEWEIGHTS weights + LAPLACIAN_NORMALIZATION normalization=UNNORMALIZED, OPTIONAL EDGE_WEIGHTS weights DEPS: weights ON graph ####################################### @@ -1307,7 +1292,7 @@ igraph_is_connected: igraph_decompose: PARAMS: |- GRAPH graph, OUT GRAPH_LIST components, CONNECTEDNESS mode=WEAK, - INTEGER maxcompno=-1, INTEGER minelements=1 + INTEGER maxcompno=UNLIMITED, INTEGER minelements=1 igraph_articulation_points: PARAMS: GRAPH graph, OUT VERTEX_INDICES res @@ -1316,9 +1301,9 @@ igraph_articulation_points: igraph_biconnected_components: PARAMS: |- GRAPH graph, OUT INTEGER no, - OPTIONAL OUT EDGESET_LIST tree_edges, - OPTIONAL OUT EDGESET_LIST component_edges, - OPTIONAL OUT VERTEXSET_LIST components, + OPTIONAL OUT EDGE_INDICES_LIST tree_edges, + OPTIONAL OUT EDGE_INDICES_LIST component_edges, + OPTIONAL OUT VERTEX_INDICES_LIST components, OUT VERTEX_INDICES articulation_points DEPS: |- tree_edges ON graph, component_edges ON graph, @@ -1361,8 +1346,9 @@ igraph_is_clique: igraph_cliques: PARAMS: |- - GRAPH graph, OUT VERTEXSET_LIST res, INTEGER min_size=0, - INTEGER max_size=0 + GRAPH graph, OUT VERTEX_INDICES_LIST res, + INTEGER min_size=UNLIMITED, INTEGER max_size=UNLIMITED, + INTEGER max_results=UNLIMITED DEPS: res ON graph igraph_cliques_callback: @@ -1375,23 +1361,29 @@ igraph_clique_size_hist: GRAPH graph, OUT VECTOR hist, INTEGER min_size=0, INTEGER max_size=0 igraph_largest_cliques: - PARAMS: GRAPH graph, OUT VERTEXSET_LIST res + PARAMS: GRAPH graph, OUT VERTEX_INDICES_LIST res DEPS: res ON graph igraph_maximal_cliques: - PARAMS: GRAPH graph, OUT VERTEXSET_LIST res, INTEGER min_size=0, INTEGER max_size=0 + PARAMS: |- + GRAPH graph, OUT VERTEX_INDICES_LIST res, + INTEGER min_size=UNLIMITED, INTEGER max_size=UNLIMITED, + INTEGER max_results=UNLIMITED DEPS: res ON graph igraph_maximal_cliques_subset: PARAMS: |- - GRAPH graph, VERTEX_INDICES subset, PRIMARY OUT VERTEXSET_LIST res, - OUT INTEGER no, OPTIONAL OUTFILE outfile, INTEGER min_size=0, INTEGER max_size=0 + GRAPH graph, VERTEX_INDICES subset, PRIMARY OUT VERTEX_INDICES_LIST res, + OUT INTEGER no, OPTIONAL OUTFILE outfile, + INTEGER min_size=UNLIMITED, INTEGER max_size=UNLIMITED, + INTEGER max_results=UNLIMITED DEPS: subset ON graph, res ON graph igraph_maximal_cliques_callback: PARAMS: |- - GRAPH graph, CLIQUE_FUNC cliquehandler_fn, OPTIONAL EXTRA arg, - INTEGER min_size=0, INTEGER max_size=0 + GRAPH graph, + INTEGER min_size=0, INTEGER max_size=0, + CLIQUE_FUNC cliquehandler_fn, OPTIONAL EXTRA arg igraph_maximal_cliques_count: PARAMS: |- @@ -1399,7 +1391,9 @@ igraph_maximal_cliques_count: igraph_maximal_cliques_file: PARAMS: |- - GRAPH graph, OUTFILE res, INTEGER min_size=0, INTEGER max_size=0 + GRAPH graph, OUTFILE res, + INTEGER min_size=UNLIMITED, INTEGER max_size=UNLIMITED, + INTEGER max_results=UNLIMITED igraph_maximal_cliques_hist: PARAMS: |- @@ -1410,17 +1404,19 @@ igraph_clique_number: igraph_weighted_cliques: PARAMS: |- - GRAPH graph, OPTIONAL VERTEXWEIGHTS vertex_weights, OUT VERTEXSET_LIST res, - REAL min_weight=0, REAL max_weight=0, BOOLEAN maximal=False + GRAPH graph, OPTIONAL VERTEX_WEIGHTS vertex_weights, OUT VERTEX_INDICES_LIST res, + BOOLEAN maximal=False, + REAL min_weight=UNLIMITED, REAL max_weight=UNLIMITED, + INTEGER max_results=UNLIMITED DEPS: vertex_weights ON graph, res ON graph igraph_largest_weighted_cliques: PARAMS: |- - GRAPH graph, OPTIONAL VERTEXWEIGHTS vertex_weights, OUT VERTEXSET_LIST res + GRAPH graph, OPTIONAL VERTEX_WEIGHTS vertex_weights, OUT VERTEX_INDICES_LIST res DEPS: vertex_weights ON graph, res ON graph igraph_weighted_clique_number: - PARAMS: GRAPH graph, OPTIONAL VERTEXWEIGHTS vertex_weights, OUT REAL res + PARAMS: GRAPH graph, OPTIONAL VERTEX_WEIGHTS vertex_weights, OUT REAL res DEPS: vertex_weights ON graph igraph_is_independent_vertex_set: @@ -1429,16 +1425,20 @@ igraph_is_independent_vertex_set: igraph_independent_vertex_sets: PARAMS: |- - GRAPH graph, OUT VERTEXSET_LIST res, INTEGER min_size=0, - INTEGER max_size=0 + GRAPH graph, OUT VERTEX_INDICES_LIST res, + INTEGER min_size=UNLIMITED, INTEGER max_size=UNLIMITED, + INTEGER max_results=UNLIMITED DEPS: res ON graph igraph_largest_independent_vertex_sets: - PARAMS: GRAPH graph, OUT VERTEXSET_LIST res + PARAMS: GRAPH graph, OUT VERTEX_INDICES_LIST res DEPS: res ON graph igraph_maximal_independent_vertex_sets: - PARAMS: GRAPH graph, OUT VERTEXSET_LIST res + PARAMS: |- + GRAPH graph, OUT VERTEX_INDICES_LIST res, + INTEGER min_size=UNLIMITED, INTEGER max_size=UNLIMITED, + INTEGER max_results=UNLIMITED DEPS: res ON graph igraph_independence_number: @@ -1472,7 +1472,7 @@ igraph_layout_fruchterman_reingold: GRAPH graph, OPTIONAL INOUT MATRIX coords, BOOLEAN use_seed=False, INTEGER niter=500, REAL start_temp=sqrt(vcount(graph)), - LAYOUT_GRID grid=AUTO, OPTIONAL EDGEWEIGHTS weights, + LAYOUT_GRID grid=AUTO, OPTIONAL EDGE_WEIGHTS weights, OPTIONAL VECTOR minx, OPTIONAL VECTOR maxx, OPTIONAL VECTOR miny, OPTIONAL VECTOR maxy, DEPRECATED coolexp, DEPRECATED maxdelta, DEPRECATED area, @@ -1483,7 +1483,7 @@ igraph_layout_kamada_kawai: PARAMS: |- GRAPH graph, INOUT MATRIX coords, BOOLEAN use_seed=False, INTEGER maxiter=500, REAL epsilon=0.0, - REAL kkconst=vcount(graph), OPTIONAL EDGEWEIGHTS weights, + REAL kkconst=vcount(graph), OPTIONAL EDGE_WEIGHTS weights, OPTIONAL VECTOR minx, OPTIONAL VECTOR maxx, OPTIONAL VECTOR miny, OPTIONAL VECTOR maxy DEPS: weights ON graph @@ -1522,7 +1522,7 @@ igraph_layout_fruchterman_reingold_3d: GRAPH graph, OPTIONAL INOUT MATRIX coords, BOOLEAN use_seed=False, INTEGER niter=500, REAL start_temp=sqrt(vcount(graph)), - OPTIONAL EDGEWEIGHTS weights, + OPTIONAL EDGE_WEIGHTS weights, OPTIONAL VECTOR minx, OPTIONAL VECTOR maxx, OPTIONAL VECTOR miny, OPTIONAL VECTOR maxy, OPTIONAL VECTOR minz, OPTIONAL VECTOR maxz, @@ -1534,7 +1534,7 @@ igraph_layout_kamada_kawai_3d: PARAMS: |- GRAPH graph, INOUT MATRIX coords, BOOLEAN use_seed=False, INTEGER maxiter=500, REAL epsilon=0.0, - REAL kkconst=vcount(graph), OPTIONAL EDGEWEIGHTS weights, + REAL kkconst=vcount(graph), OPTIONAL EDGE_WEIGHTS weights, OPTIONAL VECTOR minx, OPTIONAL VECTOR maxx, OPTIONAL VECTOR miny, OPTIONAL VECTOR maxy, OPTIONAL VECTOR minz, OPTIONAL VECTOR maxz @@ -1550,23 +1550,24 @@ igraph_layout_graphopt: igraph_layout_drl: PARAMS: |- GRAPH graph, INOUT MATRIX res, BOOLEAN use_seed=False, - DRL_OPTIONS options=drl_defaults$default, OPTIONAL EDGEWEIGHTS weights + DRL_OPTIONS options=drl_defaults$default, OPTIONAL EDGE_WEIGHTS weights + DEPS: weights ON graph igraph_layout_drl_3d: PARAMS: |- GRAPH graph, INOUT MATRIX res, BOOLEAN use_seed=False, - DRL_OPTIONS options=drl_defaults$default, OPTIONAL EDGEWEIGHTS weights + DRL_OPTIONS options=drl_defaults$default, OPTIONAL EDGE_WEIGHTS weights + DEPS: weights ON graph igraph_layout_merge_dla: PARAMS: GRAPH_PTR_LIST graphs, MATRIX_LIST coords, OUT MATRIX res igraph_layout_sugiyama: PARAMS: |- - GRAPH graph, OUT MATRIX res, OPTIONAL OUT GRAPH extd_graph, - OPTIONAL OUT INDEX_VECTOR extd_to_orig_eids, + GRAPH graph, OUT MATRIX res, OPTIONAL OUT MATRIX_LIST routing, OPTIONAL INDEX_VECTOR layers, REAL hgap=1, REAL vgap=1, INTEGER maxiter=100, - OPTIONAL EDGEWEIGHTS weights + OPTIONAL EDGE_WEIGHTS weights DEPS: weights ON graph igraph_layout_mds: @@ -1630,9 +1631,9 @@ igraph_bibcoupling: igraph_similarity_dice: PARAMS: |- - GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR vids=ALL, NEIMODE mode=ALL, + GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, VERTEX_SELECTOR to=ALL, NEIMODE mode=ALL, BOOLEAN loops=False - DEPS: vids ON graph + DEPS: from ON graph, to ON graph, res ON from, res ON to igraph_similarity_dice_es: PARAMS: |- @@ -1652,9 +1653,9 @@ igraph_similarity_inverse_log_weighted: igraph_similarity_jaccard: PARAMS: |- - GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR vids=ALL, NEIMODE mode=ALL, + GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, VERTEX_SELECTOR to=ALL, NEIMODE mode=ALL, BOOLEAN loops=False - DEPS: vids ON graph res, mode ON vids + DEPS: from ON graph, to ON graph, res ON from, res ON to igraph_similarity_jaccard_es: PARAMS: |- @@ -1678,7 +1679,7 @@ igraph_compare_communities: igraph_community_spinglass: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, OUT REAL modularity, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT REAL modularity, OUT REAL temperature, OUT VECTOR_INT membership, OUT VECTOR_INT csize, INTEGER spins=25, BOOLEAN parupdate=False, REAL starttemp=1, REAL stoptemp=0.01, REAL coolfact=0.99, SPINCOMMUPDATE update_rule=CONFIG, REAL gamma=1.0, @@ -1687,15 +1688,15 @@ igraph_community_spinglass: igraph_community_spinglass_single: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, INTEGER vertex, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, INTEGER vertex, OUT VECTOR_INT community, OUT REAL cohesion, OUT REAL adhesion, - OUT INTEGER inner_links, OUT INTEGER outer_links, + OUT REAL inner_links, OUT REAL outer_links, INTEGER spins=25, SPINCOMMUPDATE update_rule=CONFIG, REAL gamma=1.0 DEPS: weights ON graph igraph_community_walktrap: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, INTEGER steps=4, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, INTEGER steps=4, OUT MATRIX_INT merges, OUT VECTOR modularity, OUT VECTOR_INT membership DEPS: weights ON graph @@ -1704,19 +1705,20 @@ igraph_community_edge_betweenness: GRAPH graph, OUT VECTOR_INT removed_edges, OPTIONAL OUT VECTOR edge_betweenness, OPTIONAL OUT MATRIX_INT merges, OPTIONAL OUT INDEX_VECTOR bridges, OPTIONAL OUT VECTOR modularity, OPTIONAL OUT VECTOR_INT membership, - BOOLEAN directed=True, OPTIONAL EDGEWEIGHTS weights - DEPS: weights ON graph + BOOLEAN directed=True, + OPTIONAL EDGE_WEIGHTS weights, OPTIONAL EDGE_LENGTHS lengths + DEPS: weights ON graph, lengths ON graph, edge_betweenness ON graph igraph_community_eb_get_merges: PARAMS: |- - GRAPH graph, BOOLEAN directed, EDGE_INDICES edges, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, BOOLEAN directed, EDGE_INDICES edges, OPTIONAL EDGE_WEIGHTS weights, OPTIONAL OUT MATRIX_INT merges, OPTIONAL OUT INDEX_VECTOR bridges, OPTIONAL OUT VECTOR modularity, OPTIONAL OUT VECTOR_INT membership DEPS: weights ON graph igraph_community_fastgreedy: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, OUT MATRIX_INT merges, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, OUT MATRIX_INT merges, OPTIONAL OUT VECTOR modularity, OPTIONAL OUT VECTOR_INT membership DEPS: weights ON graph @@ -1732,14 +1734,14 @@ igraph_le_community_to_membership: igraph_modularity: PARAMS: |- - GRAPH graph, VECTOR_INT membership, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, VECTOR_INT membership, OPTIONAL EDGE_WEIGHTS weights, REAL resolution=1.0, BOOLEAN directed=True, OUT REAL modularity DEPS: weights ON graph igraph_modularity_matrix: PARAMS: |- GRAPH graph, - OPTIONAL EDGEWEIGHTS weights, + OPTIONAL EDGE_WEIGHTS weights, REAL resolution=1.0, OUT MATRIX modmat, BOOLEAN directed=True @@ -1752,16 +1754,20 @@ igraph_reindex_membership: igraph_community_leading_eigenvector: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, - OPTIONAL OUT MATRIX_INT merges, OPTIONAL OUT VECTOR_INT membership, + GRAPH graph, + OPTIONAL EDGE_WEIGHTS weights, + OPTIONAL OUT MATRIX_INT merges, + OPTIONAL OUT VECTOR_INT membership, INTEGER steps=-1, - INOUT ARPACKOPT options=ARPACK_DEFAULTS, - OPTIONAL OUT REAL modularity, BOOLEAN start=False, + INOUT ARPACK_OPTIONS options=ARPACK_DEFAULTS, + OPTIONAL OUT REAL modularity, + BOOLEAN start=False, OPTIONAL OUT VECTOR eigenvalues, OPTIONAL OUT VECTOR_LIST eigenvectors, - OPTIONAL OUT VECTOR history, - OPTIONAL LEVCFUNC callback, + OPTIONAL OUT VECTOR_INT history, + OPTIONAL LEVC_FUNC callback, OPTIONAL EXTRA callback_extra + DEPS: weights ON graph igraph_community_fluid_communities: PARAMS: |- @@ -1770,31 +1776,41 @@ igraph_community_fluid_communities: igraph_community_label_propagation: PARAMS: |- GRAPH graph, OUT VECTOR_INT membership, NEIMODE mode=ALL, - OPTIONAL EDGEWEIGHTS weights, OPTIONAL INDEX_VECTOR initial, - OPTIONAL VECTOR_BOOL fixed + OPTIONAL EDGE_WEIGHTS weights, OPTIONAL INDEX_VECTOR initial, + OPTIONAL VECTOR_BOOL fixed, LPA_VARIANT lpa_variant=DOMINANCE DEPS: weights ON graph igraph_community_multilevel: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, REAL resolution=1.0, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, REAL resolution=1.0, OUT VECTOR_INT membership, OPTIONAL OUT MATRIX_INT memberships, OPTIONAL OUT VECTOR modularity DEPS: weights ON graph igraph_community_optimal_modularity: PARAMS: |- - GRAPH graph, OUT REAL modularity, OPTIONAL OUT VECTOR_INT membership, - OPTIONAL EDGEWEIGHTS weights + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, REAL resolution=1.0, + OPTIONAL OUT REAL modularity, OPTIONAL OUT VECTOR_INT membership DEPS: weights ON graph igraph_community_leiden: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, - OPTIONAL VERTEXWEIGHTS vertex_weights, - REAL resolution, REAL beta=0.01, BOOLEAN start, INTEGER n_iterations=2, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OPTIONAL VERTEX_WEIGHTS vertex_out_weights, + OPTIONAL VERTEX_WEIGHTS vertex_in_weights, + REAL resolution, REAL beta=0.01, BOOLEAN start=False, INTEGER n_iterations=2, + OPTIONAL INOUT VECTOR_INT membership, + OUT INTEGER nb_clusters, OUT REAL quality + DEPS: weights ON graph, vertex_out_weights ON graph, vertex_in_weights ON graph + +igraph_community_leiden_simple: + PARAMS: |- + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + LEIDEN_OBJECTIVE objective, + REAL resolution, REAL beta=0.01, BOOLEAN start=False, INTEGER n_iterations=2, OPTIONAL INOUT VECTOR_INT membership, OUT INTEGER nb_clusters, OUT REAL quality - DEPS: weights ON graph, vertex_weights ON graph + DEPS: weights ON graph igraph_split_join_distance: PARAMS: |- @@ -1803,10 +1819,11 @@ igraph_split_join_distance: igraph_community_infomap: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS e_weights, - OPTIONAL VERTEXWEIGHTS v_weights, INTEGER nb_trials=10, - OUT VECTOR_INT membership, OUT REAL codelength - DEPS: e_weights ON graph, v_weights ON graph + GRAPH graph, OPTIONAL EDGE_WEIGHTS edge_weights, + OPTIONAL VERTEX_WEIGHTS vertex_weights, INTEGER nb_trials=10, + BOOLEAN is_regularized=False, REAL regularization_strength=1, + OPTIONAL OUT VECTOR_INT membership, OPTIONAL OUT REAL codelength + DEPS: edge_weights ON graph, vertex_weights ON graph igraph_community_voronoi: PARAMS: |- @@ -1814,7 +1831,7 @@ igraph_community_voronoi: OPTIONAL OUT VECTOR_INT membership, OPTIONAL OUT VERTEX_INDICES generators, OPTIONAL OUT REAL modularity, - OPTIONAL EDGE_LENGTHS lengths, OPTIONAL EDGEWEIGHTS weights, + OPTIONAL EDGE_LENGTHS lengths, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT, REAL radius=-1 DEPS: generators ON graph, weights ON graph, lengths ON graph @@ -1824,20 +1841,20 @@ igraph_community_voronoi: igraph_graphlets: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, - OUT VERTEXSET_LIST cliques, OUT VECTOR Mu, INTEGER niter=1000 + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OUT VERTEX_INDICES_LIST cliques, OUT VECTOR Mu, INTEGER niter=1000 DEPS: weights ON graph, cliques ON graph igraph_graphlets_candidate_basis: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, - OUT VERTEXSET_LIST cliques, OUT VECTOR thresholds + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OUT VERTEX_INDICES_LIST cliques, OUT VECTOR thresholds DEPS: weights ON graph, cliques ON graph igraph_graphlets_project: PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, - VERTEXSET_LIST cliques, INOUT VECTOR Muc, + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + VERTEX_INDICES_LIST cliques, INOUT VECTOR Muc, BOOLEAN startMu=False, INTEGER niter=1000 DEPS: weights ON graph @@ -1893,16 +1910,14 @@ igraph_from_hrg_dendrogram: igraph_get_adjacency: PARAMS: |- GRAPH graph, OUT MATRIX res, GETADJACENCY type=BOTH, - OPTIONAL EDGEWEIGHTS weights, LOOPS loops=ONCE - DEPS: - weights ON graph + OPTIONAL EDGE_WEIGHTS weights, LOOPS loops=ONCE + DEPS: weights ON graph igraph_get_adjacency_sparse: PARAMS: |- GRAPH graph, OUT SPARSEMAT sparsemat, GETADJACENCY type=BOTH, - OPTIONAL EDGEWEIGHTS weights, LOOPS loops=ONCE - DEPS: - weights ON graph + OPTIONAL EDGE_WEIGHTS weights, LOOPS loops=ONCE + DEPS: weights ON graph igraph_get_edgelist: PARAMS: GRAPH graph, OUT VECTOR_INT res, BOOLEAN bycol=False @@ -1910,16 +1925,14 @@ igraph_get_edgelist: igraph_get_stochastic: PARAMS: |- GRAPH graph, OUT MATRIX res, BOOLEAN column_wise=False, - OPTIONAL EDGEWEIGHTS weights - DEPS: - weights ON graph + OPTIONAL EDGE_WEIGHTS weights + DEPS: weights ON graph igraph_get_stochastic_sparse: PARAMS: |- GRAPH graph, OUT SPARSEMAT sparsemat, BOOLEAN column_wise=False, - OPTIONAL EDGEWEIGHTS weights - DEPS: - weights ON graph + OPTIONAL EDGE_WEIGHTS weights + DEPS: weights ON graph igraph_to_directed: PARAMS: INOUT GRAPH graph, TODIRECTED mode=MUTUAL @@ -2008,11 +2021,11 @@ igraph_motifs_randesu: igraph_motifs_randesu_estimate: PARAMS: |- - GRAPH graph, OUT INTEGER est, INTEGER size=3, OPTIONAL VECTOR cut_prob, + GRAPH graph, OUT REAL est, INTEGER size=3, OPTIONAL VECTOR cut_prob, INTEGER sample_size, OPTIONAL VECTOR_INT sample igraph_motifs_randesu_no: - PARAMS: GRAPH graph, OUT INTEGER no, INTEGER size=3, OPTIONAL VECTOR cut_prob + PARAMS: GRAPH graph, OUT REAL no, INTEGER size=3, OPTIONAL VECTOR cut_prob igraph_dyad_census: PARAMS: GRAPH graph, OUT REAL mut, OUT REAL asym, OUT REAL null @@ -2031,50 +2044,50 @@ igraph_count_triangles: igraph_local_scan_0: PARAMS: |- - GRAPH graph, OUT VECTOR res, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OUT VECTOR res, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: weights ON graph igraph_local_scan_0_them: PARAMS: |- GRAPH us, GRAPH them, OUT VECTOR res, - OPTIONAL EDGEWEIGHTS weights_them, NEIMODE mode=OUT + OPTIONAL EDGE_WEIGHTS weights_them, NEIMODE mode=OUT DEPS: weights_them ON them igraph_local_scan_1_ecount: PARAMS: |- - GRAPH graph, OUT VECTOR res, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, OUT VECTOR res, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: weights ON graph igraph_local_scan_1_ecount_them: PARAMS: |- GRAPH us, GRAPH them, OUT VECTOR res, - OPTIONAL EDGEWEIGHTS weights_them, NEIMODE mode=OUT + OPTIONAL EDGE_WEIGHTS weights_them, NEIMODE mode=OUT DEPS: weights_them ON them igraph_local_scan_k_ecount: PARAMS: |- - GRAPH graph, INTEGER k, OUT VECTOR res, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, INTEGER k, OUT VECTOR res, OPTIONAL EDGE_WEIGHTS weights, NEIMODE mode=OUT DEPS: weights ON graph igraph_local_scan_k_ecount_them: PARAMS: |- GRAPH us, GRAPH them, INTEGER k, OUT VECTOR res, - OPTIONAL EDGEWEIGHTS weights_them, NEIMODE mode=OUT + OPTIONAL EDGE_WEIGHTS weights_them, NEIMODE mode=OUT DEPS: weights_them ON them igraph_local_scan_neighborhood_ecount: PARAMS: |- - GRAPH graph, OUT VECTOR res, OPTIONAL EDGEWEIGHTS weights, - VERTEXSET_LIST neighborhoods + GRAPH graph, OUT VECTOR res, OPTIONAL EDGE_WEIGHTS weights, + VERTEX_INDICES_LIST neighborhoods DEPS: weights ON graph igraph_local_scan_subset_ecount: PARAMS: |- - GRAPH graph, OUT VECTOR res, OPTIONAL EDGEWEIGHTS weights, - VERTEXSET_LIST subsets + GRAPH graph, OUT VECTOR res, OPTIONAL EDGE_WEIGHTS weights, + VERTEX_INDICES_LIST subsets DEPS: weights ON graph igraph_list_triangles: @@ -2148,7 +2161,7 @@ igraph_rooted_product: ####################################### igraph_gomory_hu_tree: - PARAMS: GRAPH graph, OUT GRAPH tree, OPTIONAL OUT VECTOR flows, OPTIONAL EDGE_CAPACITY capacity + PARAMS: GRAPH graph, OUT GRAPH tree, OPTIONAL OUT VECTOR flows, OPTIONAL EDGE_CAPACITIES capacity DEPS: capacity ON graph igraph_maxflow: @@ -2156,7 +2169,7 @@ igraph_maxflow: GRAPH graph, OUT REAL value, OPTIONAL OUT VECTOR flow, OUT EDGE_INDICES cut, OPTIONAL OUT VERTEX_INDICES partition1, OPTIONAL OUT VERTEX_INDICES partition2, VERTEX source, VERTEX target, - OPTIONAL EDGE_CAPACITY capacity, OPTIONAL OUT MAXFLOW_STATS stats + OPTIONAL EDGE_CAPACITIES capacity, OPTIONAL OUT MAXFLOW_STATS stats DEPS: |- capacity ON graph, source ON graph, target ON graph, partition1 ON graph, partition2 ON graph, flow ON graph, @@ -2165,30 +2178,29 @@ igraph_maxflow: igraph_maxflow_value: PARAMS: |- GRAPH graph, OUT REAL value, VERTEX source, VERTEX target, - OPTIONAL EDGE_CAPACITY capacity, OPTIONAL OUT MAXFLOW_STATS stats + OPTIONAL EDGE_CAPACITIES capacity, OPTIONAL OUT MAXFLOW_STATS stats DEPS: source ON graph, target ON graph, capacity ON graph igraph_mincut: PARAMS: |- GRAPH graph, OUT REAL value, OUT VERTEX_INDICES partition1, OUT VERTEX_INDICES partition2, OUT EDGE_INDICES cut, - OPTIONAL EDGE_CAPACITY capacity + OPTIONAL EDGE_CAPACITIES capacity DEPS: capacity ON graph, partition1 ON graph, partition2 ON graph, cut ON graph igraph_mincut_value: - PARAMS: GRAPH graph, OUT REAL res, OPTIONAL EDGE_CAPACITY capacity - DEPS: - capacity ON graph + PARAMS: GRAPH graph, OUT REAL res, OPTIONAL EDGE_CAPACITIES capacity + DEPS: capacity ON graph igraph_residual_graph: PARAMS: |- - GRAPH graph, EDGE_CAPACITY capacity, OUT GRAPH residual, - OUT EDGE_CAPACITY residual_capacity, VECTOR flow + GRAPH graph, EDGE_CAPACITIES capacity, OUT GRAPH residual, + OUT EDGE_CAPACITIES residual_capacity, VECTOR flow DEPS: capacity ON graph, flow ON graph, residual_capacity ON residual igraph_reverse_residual_graph: PARAMS: |- - GRAPH graph, EDGE_CAPACITY capacity, OUT GRAPH residual, + GRAPH graph, EDGE_CAPACITIES capacity, OUT GRAPH residual, VECTOR flow DEPS: capacity ON graph, flow ON graph @@ -2197,7 +2209,7 @@ igraph_st_mincut: GRAPH graph, OUT REAL value, OUT EDGE_INDICES cut, OPTIONAL OUT VERTEX_INDICES partition1, OPTIONAL OUT VERTEX_INDICES partition2, - VERTEX source, VERTEX target, OPTIONAL EDGE_CAPACITY capacity + VERTEX source, VERTEX target, OPTIONAL EDGE_CAPACITIES capacity DEPS: |- capacity ON graph, source ON graph, target ON graph, partition1 ON graph, partition2 ON graph, cut ON graph @@ -2205,7 +2217,7 @@ igraph_st_mincut: igraph_st_mincut_value: PARAMS: |- GRAPH graph, OUT REAL res, VERTEX source, VERTEX target, - OPTIONAL EDGE_CAPACITY capacity + OPTIONAL EDGE_CAPACITIES capacity DEPS: source ON graph, target ON graph, capacity ON graph igraph_st_vertex_connectivity: @@ -2251,8 +2263,8 @@ igraph_dominator_tree: igraph_all_st_cuts: PARAMS: |- - GRAPH graph, OPTIONAL OUT EDGESET_LIST cuts, - OPTIONAL OUT VERTEXSET_LIST partition1s, + GRAPH graph, OPTIONAL OUT EDGE_INDICES_LIST cuts, + OPTIONAL OUT VERTEX_INDICES_LIST partition1s, VERTEX source, VERTEX target DEPS: |- source ON graph, target ON graph, cuts ON graph, @@ -2261,15 +2273,15 @@ igraph_all_st_cuts: igraph_all_st_mincuts: PARAMS: |- GRAPH graph, OUT REAL value, - OPTIONAL OUT EDGESET_LIST cuts, - OPTIONAL OUT VERTEXSET_LIST partition1s, - VERTEX source, VERTEX target, OPTIONAL EDGE_CAPACITY capacity + OPTIONAL OUT EDGE_INDICES_LIST cuts, + OPTIONAL OUT VERTEX_INDICES_LIST partition1s, + VERTEX source, VERTEX target, OPTIONAL EDGE_CAPACITIES capacity DEPS: |- capacity ON graph, source ON graph, target ON graph, cuts ON graph, partition1s ON graph igraph_even_tarjan_reduction: - PARAMS: GRAPH graph, OUT GRAPH graphbar, OPTIONAL OUT EDGE_CAPACITY capacity + PARAMS: GRAPH graph, OUT GRAPH graphbar, OPTIONAL OUT EDGE_CAPACITIES capacity DEPS: |- capacity ON graphbar @@ -2282,16 +2294,16 @@ igraph_is_minimal_separator: DEPS: candidate ON graph igraph_all_minimal_st_separators: - PARAMS: GRAPH graph, OUT VERTEXSET_LIST separators + PARAMS: GRAPH graph, OUT VERTEX_INDICES_LIST separators DEPS: separators ON graph igraph_minimum_size_separators: - PARAMS: GRAPH graph, OUT VERTEXSET_LIST separators + PARAMS: GRAPH graph, OUT VERTEX_INDICES_LIST separators DEPS: separators ON graph igraph_cohesive_blocks: PARAMS: |- - GRAPH graph, OUT VERTEXSET_LIST blocks, + GRAPH graph, OUT VERTEX_INDICES_LIST blocks, OUT VECTOR_INT cohesion, OUT INDEX_VECTOR parent, OUT GRAPH blockTree DEPS: blocks ON graph @@ -2313,8 +2325,18 @@ igraph_isoclass: igraph_isomorphic: PARAMS: GRAPH graph1, GRAPH graph2, OUT BOOLEAN iso +igraph_automorphism_group: + PARAMS: |- + GRAPH graph, OPTIONAL VERTEX_COLORS colors, OUT VERTEX_INDICES_LIST generators + DEPS: colors ON graph, generators ON graph + +igraph_count_automorphisms: + PARAMS: |- + GRAPH graph, OPTIONAL VERTEX_COLORS colors, OUT REAL result + DEPS: colors ON graph + igraph_isoclass_subgraph: - PARAMS: GRAPH graph, VECTOR_INT vids, OUT INTEGER isoclass + PARAMS: GRAPH graph, VERTEX_SELECTOR vids, OUT INTEGER isoclass DEPS: vids ON graph igraph_isoclass_create: @@ -2323,10 +2345,10 @@ igraph_isoclass_create: igraph_isomorphic_vf2: PARAMS: |- GRAPH graph1, GRAPH graph2, - OPTIONAL VERTEX_COLOR vertex_color1, - OPTIONAL VERTEX_COLOR vertex_color2, - OPTIONAL EDGE_COLOR edge_color1, - OPTIONAL EDGE_COLOR edge_color2, + OPTIONAL VERTEX_COLORS vertex_color1, + OPTIONAL VERTEX_COLORS vertex_color2, + OPTIONAL EDGE_COLORS edge_color1, + OPTIONAL EDGE_COLORS edge_color2, OUT BOOLEAN iso, OPTIONAL OUT INDEX_VECTOR map12, OPTIONAL OUT INDEX_VECTOR map21, OPTIONAL ISOCOMPAT_FUNC node_compat_fn, @@ -2339,8 +2361,8 @@ igraph_isomorphic_vf2: igraph_get_isomorphisms_vf2_callback: PARAMS: |- GRAPH graph1, GRAPH graph2, - OPTIONAL VERTEX_COLOR vertex_color1, OPTIONAL VERTEX_COLOR vertex_color2, - OPTIONAL EDGE_COLOR edge_color1, OPTIONAL EDGE_COLOR edge_color2, + OPTIONAL VERTEX_COLORS vertex_color1, OPTIONAL VERTEX_COLORS vertex_color2, + OPTIONAL EDGE_COLORS edge_color1, OPTIONAL EDGE_COLORS edge_color2, OPTIONAL OUT INDEX_VECTOR map12, OPTIONAL OUT INDEX_VECTOR map21, ISOMORPHISM_FUNC ishohandler_fn, OPTIONAL ISOCOMPAT_FUNC node_compat_fn, @@ -2353,8 +2375,8 @@ igraph_get_isomorphisms_vf2_callback: igraph_count_isomorphisms_vf2: PARAMS: |- GRAPH graph1, GRAPH graph2, - OPTIONAL VERTEX_COLOR vertex_color1, OPTIONAL VERTEX_COLOR vertex_color2, - OPTIONAL EDGE_COLOR edge_color1, OPTIONAL EDGE_COLOR edge_color2, + OPTIONAL VERTEX_COLORS vertex_color1, OPTIONAL VERTEX_COLORS vertex_color2, + OPTIONAL EDGE_COLORS edge_color1, OPTIONAL EDGE_COLORS edge_color2, OUT INTEGER count, OPTIONAL ISOCOMPAT_FUNC node_compat_fn, OPTIONAL ISOCOMPAT_FUNC edge_compat_fn, @@ -2366,8 +2388,8 @@ igraph_count_isomorphisms_vf2: igraph_get_isomorphisms_vf2: PARAMS: |- GRAPH graph1, GRAPH graph2, - OPTIONAL VERTEX_COLOR vertex_color1, OPTIONAL VERTEX_COLOR vertex_color2, - OPTIONAL EDGE_COLOR edge_color1, OPTIONAL EDGE_COLOR edge_color2, + OPTIONAL VERTEX_COLORS vertex_color1, OPTIONAL VERTEX_COLORS vertex_color2, + OPTIONAL EDGE_COLORS edge_color1, OPTIONAL EDGE_COLORS edge_color2, OUT VECTOR_INT_LIST maps, OPTIONAL ISOCOMPAT_FUNC node_compat_fn, OPTIONAL ISOCOMPAT_FUNC edge_compat_fn, @@ -2382,8 +2404,8 @@ igraph_subisomorphic: igraph_subisomorphic_vf2: PARAMS: |- GRAPH graph1, GRAPH graph2, - OPTIONAL VERTEX_COLOR vertex_color1, OPTIONAL VERTEX_COLOR vertex_color2, - OPTIONAL EDGE_COLOR edge_color1, OPTIONAL EDGE_COLOR edge_color2, + OPTIONAL VERTEX_COLORS vertex_color1, OPTIONAL VERTEX_COLORS vertex_color2, + OPTIONAL EDGE_COLORS edge_color1, OPTIONAL EDGE_COLORS edge_color2, OUT BOOLEAN iso, OPTIONAL OUT INDEX_VECTOR map12, OPTIONAL OUT INDEX_VECTOR map21, OPTIONAL ISOCOMPAT_FUNC node_compat_fn, @@ -2396,8 +2418,8 @@ igraph_subisomorphic_vf2: igraph_get_subisomorphisms_vf2_callback: PARAMS: |- GRAPH graph1, GRAPH graph2, - OPTIONAL VERTEX_COLOR vertex_color1, OPTIONAL VERTEX_COLOR vertex_color2, - OPTIONAL EDGE_COLOR edge_color1, OPTIONAL EDGE_COLOR edge_color2, + OPTIONAL VERTEX_COLORS vertex_color1, OPTIONAL VERTEX_COLORS vertex_color2, + OPTIONAL EDGE_COLORS edge_color1, OPTIONAL EDGE_COLORS edge_color2, OPTIONAL OUT INDEX_VECTOR map12, OPTIONAL OUT INDEX_VECTOR map21, ISOMORPHISM_FUNC ishohandler_fn, OPTIONAL ISOCOMPAT_FUNC node_compat_fn, @@ -2410,8 +2432,8 @@ igraph_get_subisomorphisms_vf2_callback: igraph_count_subisomorphisms_vf2: PARAMS: |- GRAPH graph1, GRAPH graph2, - OPTIONAL VERTEX_COLOR vertex_color1, OPTIONAL VERTEX_COLOR vertex_color2, - OPTIONAL EDGE_COLOR edge_color1, OPTIONAL EDGE_COLOR edge_color2, + OPTIONAL VERTEX_COLORS vertex_color1, OPTIONAL VERTEX_COLORS vertex_color2, + OPTIONAL EDGE_COLORS edge_color1, OPTIONAL EDGE_COLORS edge_color2, OUT INTEGER count, OPTIONAL ISOCOMPAT_FUNC node_compat_fn, OPTIONAL ISOCOMPAT_FUNC edge_compat_fn, @@ -2423,8 +2445,8 @@ igraph_count_subisomorphisms_vf2: igraph_get_subisomorphisms_vf2: PARAMS: |- GRAPH graph1, GRAPH graph2, - OPTIONAL VERTEX_COLOR vertex_color1, OPTIONAL VERTEX_COLOR vertex_color2, - OPTIONAL EDGE_COLOR edge_color1, OPTIONAL EDGE_COLOR edge_color2, + OPTIONAL VERTEX_COLORS vertex_color1, OPTIONAL VERTEX_COLORS vertex_color2, + OPTIONAL EDGE_COLORS edge_color1, OPTIONAL EDGE_COLORS edge_color2, OUT VECTOR_INT_LIST maps, OPTIONAL ISOCOMPAT_FUNC node_compat_fn, OPTIONAL ISOCOMPAT_FUNC edge_compat_fn, @@ -2435,7 +2457,13 @@ igraph_get_subisomorphisms_vf2: igraph_canonical_permutation: PARAMS: |- - GRAPH graph, OPTIONAL VERTEX_COLOR colors, + GRAPH graph, OPTIONAL VERTEX_COLORS colors, + OUT INDEX_VECTOR labeling + DEPS: colors ON graph + +igraph_canonical_permutation_bliss: + PARAMS: |- + GRAPH graph, OPTIONAL VERTEX_COLORS colors, OUT INDEX_VECTOR labeling, BLISSSH sh="fm", OUT BLISSINFO info DEPS: colors ON graph @@ -2445,28 +2473,28 @@ igraph_permute_vertices: igraph_isomorphic_bliss: PARAMS: |- GRAPH graph1, GRAPH graph2, - OPTIONAL VERTEX_COLOR colors1, OPTIONAL VERTEX_COLOR colors2, + OPTIONAL VERTEX_COLORS colors1, OPTIONAL VERTEX_COLORS colors2, OUT BOOLEAN iso, OPTIONAL OUT INDEX_VECTOR map12, OPTIONAL OUT INDEX_VECTOR map21, BLISSSH sh="fm", OPTIONAL OUT BLISSINFO info1, OPTIONAL OUT BLISSINFO info2 DEPS: colors1 ON graph1, colors2 ON graph2 -igraph_count_automorphisms: +igraph_count_automorphisms_bliss: PARAMS: |- - GRAPH graph, OPTIONAL VERTEX_COLOR colors, BLISSSH sh="fm", OUT BLISSINFO info + GRAPH graph, OPTIONAL VERTEX_COLORS colors, BLISSSH sh="fm", OUT BLISSINFO info DEPS: colors ON graph -igraph_automorphism_group: +igraph_automorphism_group_bliss: PARAMS: |- - GRAPH graph, OPTIONAL VERTEX_COLOR colors, PRIMARY OUT VERTEXSET_LIST generators, + GRAPH graph, OPTIONAL VERTEX_COLORS colors, PRIMARY OUT VERTEX_INDICES_LIST generators, BLISSSH sh="fm", OUT BLISSINFO info DEPS: colors ON graph, generators ON graph igraph_subisomorphic_lad: PARAMS: |- - GRAPH pattern, GRAPH target, OPTIONAL VERTEXSET_LIST domains, + GRAPH pattern, GRAPH target, OPTIONAL VERTEX_INDICES_LIST domains, OPTIONAL OUT BOOLEAN iso, OUT INDEX_VECTOR map, - OPTIONAL OUT VECTOR_INT_LIST maps, BOOLEAN induced, INTEGER time_limit + OPTIONAL OUT VECTOR_INT_LIST maps, BOOLEAN induced igraph_simplify_and_colorize: # Despite their names, vertex_color and edge_color are not really colors @@ -2500,7 +2528,7 @@ igraph_maximum_bipartite_matching: OPTIONAL OUT INTEGER matching_size, OPTIONAL OUT REAL matching_weight, OUT INDEX_VECTOR matching, - OPTIONAL EDGEWEIGHTS weights, REAL eps=.Machine$double.eps + OPTIONAL EDGE_WEIGHTS weights, REAL eps=.Machine$double.eps DEPS: types ON graph, weights ON graph ####################################### @@ -2509,20 +2537,20 @@ igraph_maximum_bipartite_matching: igraph_adjacency_spectral_embedding: PARAMS: |- - GRAPH graph, INTEGER no, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, INTEGER no, OPTIONAL EDGE_WEIGHTS weights, EIGENWHICHPOS which=ASE, BOOLEAN scaled=True, OUT MATRIX X, OPTIONAL OUT MATRIX Y, OPTIONAL OUT VECTOR D, VECTOR cvec=AsmDefaultCvec, - INOUT ARPACKOPT options=ARPACK_DEFAULTS + INOUT ARPACK_OPTIONS options=ARPACK_DEFAULTS DEPS: weights ON graph, cvec ON graph igraph_laplacian_spectral_embedding: PARAMS: |- - GRAPH graph, INTEGER no, OPTIONAL EDGEWEIGHTS weights, + GRAPH graph, INTEGER no, OPTIONAL EDGE_WEIGHTS weights, EIGENWHICHPOS which=ASE, LSETYPE type=Default, BOOLEAN scaled=True, OUT MATRIX X, OPTIONAL OUT MATRIX Y, OPTIONAL OUT VECTOR D, - INOUT ARPACKOPT options=ARPACK_DEFAULTS + INOUT ARPACK_OPTIONS options=ARPACK_DEFAULTS DEPS: weights ON graph, type ON graph ####################################### @@ -2533,8 +2561,8 @@ igraph_eigen_adjacency: PARAMS: |- GRAPH graph, EIGENALGO algorithm=ARPACK, EIGENWHICH which=Default, - INOUT ARPACKOPT options=ARPACK_DEFAULTS, - INOUT ARPACKSTORAGE storage, OUT VECTOR values, OUT MATRIX vectors, + INOUT ARPACK_OPTIONS options=ARPACK_DEFAULTS, + INOUT ARPACK_STORAGE storage, OUT VECTOR values, OUT MATRIX vectors, OUT VECTOR_COMPLEX cmplxvalues, OUT MATRIX_COMPLEX cmplxvectors ####################################### @@ -2581,15 +2609,15 @@ igraph_cmp_epsilon: igraph_eigen_matrix: PARAMS: |- - MATRIX A, SPARSEMAT sA, ARPACKFUNC fun, INT n, OPTIONAL EXTRA extra, - EIGENALGO algorithm, EIGENWHICH which, INOUT ARPACKOPT options=ARPACK_DEFAULTS, - INOUT ARPACKSTORAGE storage, OUT VECTOR_COMPLEX values, OUT MATRIX_COMPLEX vectors + MATRIX A, SPARSEMAT sA, ARPACK_FUNC fun, INT n, OPTIONAL EXTRA extra, + EIGENALGO algorithm, EIGENWHICH which, INOUT ARPACK_OPTIONS options=ARPACK_DEFAULTS, + INOUT ARPACK_STORAGE storage, OUT VECTOR_COMPLEX values, OUT MATRIX_COMPLEX vectors igraph_eigen_matrix_symmetric: PARAMS: |- - MATRIX A, SPARSEMAT sA, ARPACKFUNC fun, INT n, OPTIONAL EXTRA extra, - EIGENALGO algorithm, EIGENWHICH which, INOUT ARPACKOPT options=ARPACK_DEFAULTS, - INOUT ARPACKSTORAGE storage, OUT VECTOR values, OUT MATRIX vectors + MATRIX A, SPARSEMAT sA, ARPACK_FUNC fun, INT n, OPTIONAL EXTRA extra, + EIGENALGO algorithm, EIGENWHICH which, INOUT ARPACK_OPTIONS options=ARPACK_DEFAULTS, + INOUT ARPACK_STORAGE storage, OUT VECTOR values, OUT MATRIX vectors igraph_solve_lsap: PARAMS: MATRIX c, INTEGER n, OUT VECTOR_INT p @@ -2607,14 +2635,15 @@ igraph_find_cycle: igraph_simple_cycles: PARAMS: |- GRAPH graph, - OPTIONAL OUT VERTEXSET_LIST vertices, OPTIONAL OUT EDGESET_LIST edges, - NEIMODE mode=OUT, INTEGER min_cycle_length=-1, INTEGER max_cycle_length=-1 + OPTIONAL OUT VERTEX_INDICES_LIST vertices, OPTIONAL OUT EDGE_INDICES_LIST edges, + NEIMODE mode=OUT, INTEGER min_cycle_length=UNLIMITED, INTEGER max_cycle_length=UNLIMITED, + INTEGER max_results=UNLIMITED DEPS: vertices ON graph, edges ON graph igraph_simple_cycles_callback: PARAMS: |- GRAPH graph, - NEIMODE mode=OUT, INTEGER min_cycle_length=-1, INTEGER max_cycle_length=-1, + NEIMODE mode=OUT, INTEGER min_cycle_length=UNLIMITED, INTEGER max_cycle_length=UNLIMITED, CYCLE_FUNC cycle_handler, OPTIONAL EXTRA arg ####################################### @@ -2638,15 +2667,18 @@ igraph_eulerian_cycle: igraph_fundamental_cycles: PARAMS: |- - GRAPH graph, OUT EDGESET_LIST basis, OPTIONAL VERTEX start, - INTEGER bfs_cutoff=-1, OPTIONAL EDGEWEIGHTS weights + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OUT EDGE_INDICES_LIST basis, + OPTIONAL VERTEX start=-1, + REAL bfs_cutoff=UNLIMITED DEPS: weights ON graph, basis ON graph, start ON graph igraph_minimum_cycle_basis: PARAMS: |- - GRAPH graph, OUT EDGESET_LIST basis, INTEGER bfs_cutoff=-1, - BOOLEAN complete=True, BOOLEAN use_cycle_order=True, - OPTIONAL EDGEWEIGHTS weights + GRAPH graph, OPTIONAL EDGE_WEIGHTS weights, + OUT EDGE_INDICES_LIST basis, + REAL bfs_cutoff=UNLIMITED, + BOOLEAN complete=True, BOOLEAN use_cycle_order=True DEPS: weights ON graph, basis ON graph ####################################### @@ -2674,33 +2706,56 @@ igraph_is_complete: PARAMS: GRAPH graph, OUT BOOLEAN res igraph_minimum_spanning_tree: - PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL EDGEWEIGHTS weights + PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL EDGE_WEIGHTS weights, MSTALGORITHM method=AUTOMATIC DEPS: res ON graph, weights ON graph -igraph_minimum_spanning_tree_unweighted: - PARAMS: GRAPH graph, OUT GRAPH mst - -igraph_minimum_spanning_tree_prim: - PARAMS: GRAPH graph, OUT GRAPH mst, EDGEWEIGHTS weights - DEPS: weights ON graph - igraph_random_spanning_tree: - PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL VERTEX vid + PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL VERTEX vid=-1 DEPS: res ON graph, vid ON graph igraph_tree_game: PARAMS: OUT GRAPH graph, INTEGER n, BOOLEAN directed=False, RANDOM_TREE_METHOD method=LERW +####################################### +# Spatial +####################################### + +igraph_nearest_neighbor_graph: + PARAMS: OUT GRAPH graph, MATRIX points, METRIC metric, INTEGER neighbors, REAL cutoff, BOOLEAN directed + +igraph_delaunay_graph: + PARAMS: OUT GRAPH graph, MATRIX points + +igraph_gabriel_graph: + PARAMS: OUT GRAPH graph, MATRIX points + +igraph_relative_neighborhood_graph: + PARAMS: OUT GRAPH graph, MATRIX points + +igraph_lune_beta_skeleton: + PARAMS: OUT GRAPH graph, MATRIX points, REAL beta=1 + +igraph_circle_beta_skeleton: + PARAMS: OUT GRAPH graph, MATRIX points, REAL beta=1 + +igraph_beta_weighted_gabriel_graph: + PARAMS: OUT GRAPH graph, OUT EDGE_WEIGHTS weights, MATRIX points, REAL max_beta=UNLIMITED + DEPS: weights ON graph + +igraph_spatial_edge_lengths: + PARAMS: GRAPH graph, OUT EDGE_LENGTHS lengths, MATRIX points, METRIC METRIC + DEPS: lengths ON graph + ####################################### # Coloring ####################################### igraph_vertex_coloring_greedy: - PARAMS: GRAPH graph, OUT VERTEX_COLOR colors, GREEDY_COLORING_HEURISTIC heuristic=NEIGHBORS + PARAMS: GRAPH graph, OUT VERTEX_COLORS colors, GREEDY_COLORING_HEURISTIC heuristic=NEIGHBORS DEPS: colors ON graph igraph_is_vertex_coloring: - PARAMS: GRAPH graph, VERTEX_COLOR types, OUT BOOLEAN res + PARAMS: GRAPH graph, VERTEX_COLORS types, OUT BOOLEAN res DEPS: types ON graph igraph_is_bipartite_coloring: @@ -2708,37 +2763,9 @@ igraph_is_bipartite_coloring: DEPS: types ON graph igraph_is_edge_coloring: - PARAMS: GRAPH graph, EDGE_COLOR types, OUT BOOLEAN res + PARAMS: GRAPH graph, EDGE_COLORS types, OUT BOOLEAN res DEPS: types ON graph -####################################### -# Microscopic update -####################################### - -igraph_deterministic_optimal_imitation: - PARAMS: |- - GRAPH graph, VERTEX vid, OPTIMALITY optimality=MAXIMUM, ALL_VERTEX_QTY quantities, - INOUT VECTOR_INT strategies, NEIMODE mode=OUT - DEPS: vid ON graph, quantities ON graph, strategies ON graph - -igraph_moran_process: - PARAMS: |- - GRAPH graph, OPTIONAL EDGEWEIGHTS weights, INOUT ALL_VERTEX_QTY quantities, - INOUT VECTOR_INT strategies, NEIMODE mode=OUT - DEPS: weights ON graph, quantities ON graph, strategies ON graph - -igraph_roulette_wheel_imitation: - PARAMS: |- - GRAPH graph, VERTEX vid, BOOLEAN is_local, ALL_VERTEX_QTY quantities, - INOUT VECTOR_INT strategies, NEIMODE mode=OUT - DEPS: vid ON graph, quantities ON graph, strategies ON graph - -igraph_stochastic_imitation: - PARAMS: |- - GRAPH graph, VERTEX vid, IMITATE_ALGORITHM algo, ALL_VERTEX_QTY quantities, - INOUT VECTOR_INT strategies, NEIMODE mode=OUT - DEPS: vid ON graph, quantities ON graph, strategies ON graph - ####################################### # Other, (yet) undocumented functions ####################################### diff --git a/src/vendor/cigraph/interfaces/types.yaml b/src/vendor/cigraph/interfaces/types.yaml index 0a95c14ff19..eda9572ec81 100644 --- a/src/vendor/cigraph/interfaces/types.yaml +++ b/src/vendor/cigraph/interfaces/types.yaml @@ -12,7 +12,7 @@ INTEGER: # An ordinary igraph integer - CTYPE: igraph_integer_t + CTYPE: igraph_int_t REAL: # An ordinary igraph floating-point number @@ -38,10 +38,6 @@ INT: # A C integer CTYPE: int -LONGINT: - # A C long integer - CTYPE: long int - CSTRING: # A null-terminated immutable C string CTYPE: const char* @@ -137,7 +133,7 @@ SPARSEMAT: EDGE: # A single edge index - CTYPE: igraph_integer_t + CTYPE: igraph_int_t EDGE_INDICES: # An integer vector containing edge indices. @@ -150,7 +146,7 @@ EDGE_SELECTOR: VERTEX: # A single vertex index - CTYPE: igraph_integer_t + CTYPE: igraph_int_t VERTEX_INDICES: # An integer vector containing vertex indices. @@ -173,21 +169,16 @@ VERTEX_SELECTOR: BIPARTITE_TYPES: # A vector containing Booleans that define the two partitions of a - # bipartite graph, for a set of vertices - CTYPE: igraph_vector_bool_t - FLAGS: BY_REF - -ALL_BIPARTITE_TYPES: - # Same as BIPARTITE_TYPES, for all vertices of a graph + # bipartite graph CTYPE: igraph_vector_bool_t FLAGS: BY_REF -EDGE_CAPACITY: +EDGE_CAPACITIES: # A vector containing edge capacities (typically for max-flow algorithms) CTYPE: igraph_vector_t FLAGS: BY_REF -EDGE_COLOR: +EDGE_COLORS: # A vector containing edge colors CTYPE: igraph_vector_int_t FLAGS: BY_REF @@ -197,12 +188,12 @@ EDGE_LENGTHS: CTYPE: igraph_vector_t FLAGS: BY_REF -EDGEWEIGHTS: +EDGE_WEIGHTS: # A vector containing edge weights CTYPE: igraph_vector_t FLAGS: BY_REF -EDGESET_LIST: +EDGE_INDICES_LIST: # A list containing vectors of igraph integers where each such # vector represents a sequence of edge indices. CTYPE: igraph_vector_int_list_t @@ -238,18 +229,18 @@ SIR_LIST: CTYPE: igraph_vector_ptr_t FLAGS: BY_REF -VERTEXSET_LIST: +VERTEX_INDICES_LIST: # A list containing vectors of igraph integers where each such # vector represents a sequence of vertex indices. CTYPE: igraph_vector_int_list_t FLAGS: BY_REF -VERTEX_COLOR: +VERTEX_COLORS: # A vector containing vertex colors CTYPE: igraph_vector_int_t FLAGS: BY_REF -VERTEXWEIGHTS: +VERTEX_WEIGHTS: # A vector containing vertex weights CTYPE: igraph_vector_t FLAGS: BY_REF @@ -332,13 +323,6 @@ EIGENWHICHPOS: CTYPE: igraph_eigen_which_position_t FLAGS: ENUM -ERDOS_RENYI_TYPE: - # Enum that says wheter a GNM (n vertices, m edges) or - # GNP (n vertices, every edge exists with probability p) - # graph is created - CTYPE: igraph_erdos_renyi_t - FLAGS: ENUM - FAS_ALGORITHM: # Enum representing feedback arc set algorithms CTYPE: igraph_fas_algorithm_t @@ -365,11 +349,6 @@ GREEDY_COLORING_HEURISTIC: CTYPE: igraph_coloring_greedy_t FLAGS: ENUM -IMITATE_ALGORITHM: - # This enum controls which algorithm to use in stochastic imitation - CTYPE: igraph_imitate_algorithm_t - FLAGS: ENUM - LAPLACIAN_NORMALIZATION: # Enum representing the possible normalization methods of a Laplacian # matrix @@ -383,6 +362,12 @@ LAYOUT_GRID: CTYPE: igraph_layout_grid_t FLAGS: ENUM +LEIDEN_OBJECTIVE: + # The objective function to maximize with the Leiden community detection + # method. + CTYPE: igraph_leiden_objective_t + FLAGS: ENUM + LOOPS: # Enum that describes how loop edges should be handled in undirected graphs # in functions that support it. Possible options are: no loops, loops @@ -396,17 +381,22 @@ LSETYPE: CTYPE: igraph_laplacian_spectral_embedding_type_t FLAGS: ENUM +METRIC: + # Enum that describes the metric to be used for spatial algorithms + CTYPE: igraph_metric_t + FLAGS: ENUM + +MSTALGORITHM: + # Enum that describes the algorithm for computing a minimum spanning tree + CTYPE: igraph_mst_algorithm_t + FLAGS: ENUM + NEIMODE: # Enum that describes how a particular function should take into account # the neighbors of vertices CTYPE: igraph_neimode_t FLAGS: ENUM -OPTIMALITY: - # This enum controls which algorithm to use in deterministic optimal imitation - CTYPE: igraph_optimal_t - FLAGS: ENUM - ORDER: # Whether ordering should be ascending or descending CTYPE: igraph_order_t @@ -439,11 +429,6 @@ RECIP: CTYPE: igraph_reciprocity_t FLAGS: ENUM -REWIRING_MODE: - # Enum for the rewiring modes of igraph_rewire() - CTYPE: igraph_rewiring_t - FLAGS: ENUM - ROOTCHOICE: # Enum for the heuristic of igraph_roots_for_tree_layout() CTYPE: igraph_root_choice_t @@ -514,10 +499,15 @@ VORONOI_TIEBREAKER: FLAGS: ENUM WHEEL_MODE: - # Enum that describes how a star graph should be constructed + # Enum that describes how a wheel graph should be constructed CTYPE: igraph_wheel_mode_t FLAGS: ENUM +LPA_VARIANT: + # Enum that describes the label propagation algorithm variant + CTYPE: igraph_lpa_variant_t + FLAGS: ENUM + ############################################################################### # Switches / flags / bits ############################################################################### @@ -537,7 +527,7 @@ WRITE_GML_SW: # Callbacks ############################################################################### -ARPACKFUNC: +ARPACK_FUNC: # ARPACK matrix multiplication function. CTYPE: igraph_arpack_function_t @@ -571,7 +561,7 @@ ISOMORPHISM_FUNC: # isomorphism is found CTYPE: igraph_isohandler_t -LEVCFUNC: +LEVC_FUNC: # Callback function for igraph_leading_eigenvector_community(). Called # after each eigenvalue / eigenvector calculation. CTYPE: igraph_community_leading_eigenvector_callback_t @@ -580,12 +570,12 @@ LEVCFUNC: # Miscellaneous ############################################################################### -ARPACKOPT: +ARPACK_OPTIONS: # Structure that contains the options of the ARPACK eigensolver. CTYPE: igraph_arpack_options_t FLAGS: BY_REF -ARPACKSTORAGE: +ARPACK_STORAGE: # Pointer to a general-purpose memory block that ARPACK-based algorithms # may use as a working area. CTYPE: igraph_arpack_storage_t @@ -596,10 +586,9 @@ ASTAR_HEURISTIC_FUNC: CTYPE: igraph_astar_heuristic_func_t ATTRIBUTES: - # An opaque data structure that a high-level interface may use to pass - # information about graph/vertex/edge attributes to a low-level igraph - # C function - CTYPE: void + # A data structure specifying graph/vertex/edge attributes to add to a + # graph in a low-level igraph C function + CTYPE: igraph_attribute_record_list_t FLAGS: BY_REF BLISSINFO: @@ -651,6 +640,11 @@ PLFIT: CTYPE: igraph_plfit_result_t FLAGS: BY_REF +REWIRING_STATS: + # Structure storing statistics about degree-preserving edge rewiring + CTYPE: igraph_rewiring_stats_t + FLAGS: BY_REF + VERTEX_ATTRIBUTE_COMBINATION: # Structure specifying how the attributes of vertices should be combined # during graph operations that may merge multiple vertices into a single one diff --git a/src/vendor/cigraph/src/CMakeLists.txt b/src/vendor/cigraph/src/CMakeLists.txt index 56d9dc5bc92..c1b345435a6 100644 --- a/src/vendor/cigraph/src/CMakeLists.txt +++ b/src/vendor/cigraph/src/CMakeLists.txt @@ -39,7 +39,6 @@ add_custom_target(parsersources SOURCES ${PARSER_SOURCES}) # Declare the files needed to compile the igraph library add_library( igraph - core/array.c core/bitset.c core/bitset_list.c core/buckets.c @@ -61,6 +60,7 @@ add_library( core/progress.c core/psumtree.c core/set.c + core/setup.c core/sparsemat.c core/stack.c core/statusbar.c @@ -80,10 +80,12 @@ add_library( linalg/lapack.c random/random.c + random/random_device.cpp random/rng_glibc2.c random/rng_mt19937.c random/rng_pcg32.c random/rng_pcg64.c + random/sampling.c graph/adjlist.c graph/attributes.c @@ -113,7 +115,6 @@ add_library( constructors/regular.c constructors/trees.c - games/barabasi.c games/callaway_traits.c games/chung_lu.c @@ -159,14 +160,12 @@ add_library( community/edge_betweenness.c community/fast_modularity.c community/fluid.c - community/infomap/infomap_FlowGraph.cc - community/infomap/infomap_Greedy.cc - community/infomap/infomap.cc community/label_propagation.c community/leading_eigenvector.c community/leiden.c community/louvain.c community/modularity.c + community/infomap.cpp community/optimal_modularity.c community/spinglass/clustertool.cpp community/spinglass/NetDataTypes.cpp @@ -184,6 +183,9 @@ add_library( connectivity/separators.c connectivity/reachability.c + cycles/cycle_bases.c + cycles/feedback_sets.c + cycles/order_cycle.cpp cycles/simple_cycles.c flow/flow.c @@ -297,29 +299,30 @@ add_library( misc/cocitation.c misc/coloring.c misc/conversion.c - misc/cycle_bases.c misc/degree_sequence.cpp misc/embedding.c - misc/feedback_arc_set.c misc/graphicality.c misc/matching.c - misc/microscopic_update.c misc/mixing.c misc/motifs.c - misc/order_cycle.cpp misc/other.c misc/power_law_fit.c misc/scan.c misc/sir.c misc/spanning_trees.c + spatial/beta_skeleton.cpp + spatial/delaunay.c + spatial/convex_hull.c + spatial/edge_lengths.c + spatial/nearest_neighbor.cpp + internal/glpk_support.c internal/hacks.c internal/lsap.c internal/qsort_r.c internal/qsort.c internal/utils.c - internal/zeroin.c version.c @@ -328,6 +331,7 @@ add_library( $,$,> $,$,> $,$,> + $,$,> $,$,> $,$,> $,$,> @@ -337,8 +341,8 @@ add_library( add_dependencies(igraph parsersources) # Set soname for the library -set_target_properties(igraph PROPERTIES VERSION "3.1.11") -set_target_properties(igraph PROPERTIES SOVERSION 3) +set_target_properties(igraph PROPERTIES VERSION "4.0.0") +set_target_properties(igraph PROPERTIES SOVERSION 4) # Add extra compiler definitions if needed target_compile_definitions( @@ -373,10 +377,12 @@ target_include_directories( # Vendored library include paths "$<$:$>" + "$<$:$>" "$<$:$>" # Include paths for dependencies "$<$:${GLPK_INCLUDE_DIR}>" + "$<$:${INFOMAP_INCLUDE_DIR}>" "$<$:${GMP_INCLUDE_DIR}>" "$<$:${LIBXML2_INCLUDE_DIRS}>" "$<$:${PLFIT_INCLUDE_DIRS}>" @@ -398,6 +404,10 @@ if(GLPK_LIBRARIES) target_link_libraries(igraph PRIVATE ${GLPK_LIBRARIES}) endif() +if(INFOMAP_LIBRARIES) + target_link_libraries(igraph PRIVATE ${INFOMAP_LIBRARIES}) +endif() + if(GMP_LIBRARIES) target_link_libraries(igraph PRIVATE ${GMP_LIBRARIES}) endif() @@ -418,7 +428,7 @@ endif() target_link_libraries( igraph PRIVATE - bliss cliquer cxsparse_vendored pcg prpack + bliss cliquer cxsparse_vendored pcg prpack qhull_vendored ) if (NOT BUILD_SHARED_LIBS) @@ -467,7 +477,7 @@ write_basic_package_version_file( # Define how to install the library install( - TARGETS igraph bliss cliquer cxsparse_vendored pcg prpack + TARGETS igraph bliss cliquer cxsparse_vendored pcg prpack qhull_vendored EXPORT igraph_targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/src/vendor/cigraph/src/centrality/betweenness.c b/src/vendor/cigraph/src/centrality/betweenness.c index 8f7c355ed32..03f7948161b 100644 --- a/src/vendor/cigraph/src/centrality/betweenness.c +++ b/src/vendor/cigraph/src/centrality/betweenness.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2007-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -59,8 +59,8 @@ * \param adjlist the adjacency list of the graph * \param cutoff cutoff length of shortest paths */ -static igraph_error_t igraph_i_sspf( - igraph_integer_t source, +static igraph_error_t sspf( + igraph_int_t source, igraph_vector_t *dist, igraph_real_t *nrgeo, igraph_stack_int_t *stack, @@ -71,7 +71,7 @@ static igraph_error_t igraph_i_sspf( igraph_dqueue_int_t queue; const igraph_vector_int_t *neis; igraph_vector_int_t *v; - igraph_integer_t nlen; + igraph_int_t nlen; IGRAPH_DQUEUE_INT_INIT_FINALLY(&queue, 100); @@ -80,7 +80,7 @@ static igraph_error_t igraph_i_sspf( nrgeo[source] = 1; while (!igraph_dqueue_int_empty(&queue)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&queue); + igraph_int_t actnode = igraph_dqueue_int_pop(&queue); /* Ignore vertices that are more distant than the cutoff */ if (cutoff >= 0 && VECTOR(*dist)[actnode] > cutoff + 1) { @@ -97,8 +97,8 @@ static igraph_error_t igraph_i_sspf( /* Examine the neighbors of this node */ neis = igraph_adjlist_get(adjlist, actnode); nlen = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < nlen; j++) { - igraph_integer_t neighbor = VECTOR(*neis)[j]; + for (igraph_int_t j = 0; j < nlen; j++) { + igraph_int_t neighbor = VECTOR(*neis)[j]; if (VECTOR(*dist)[neighbor] == 0) { /* We have found 'neighbor' for the first time */ @@ -139,9 +139,9 @@ static igraph_error_t igraph_i_sspf( * \param inclist the incidence list of the graph * \param cutoff cutoff length of shortest paths */ -static igraph_error_t igraph_i_sspf_edge( +static igraph_error_t sspf_edge( const igraph_t *graph, - igraph_integer_t source, + igraph_int_t source, igraph_vector_t *dist, igraph_real_t *nrgeo, igraph_stack_int_t *stack, @@ -152,7 +152,7 @@ static igraph_error_t igraph_i_sspf_edge( igraph_dqueue_int_t queue; const igraph_vector_int_t *neis; igraph_vector_int_t *v; - igraph_integer_t nlen; + igraph_int_t nlen; IGRAPH_DQUEUE_INT_INIT_FINALLY(&queue, 100); @@ -161,7 +161,7 @@ static igraph_error_t igraph_i_sspf_edge( nrgeo[source] = 1; while (!igraph_dqueue_int_empty(&queue)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&queue); + igraph_int_t actnode = igraph_dqueue_int_pop(&queue); /* Ignore vertices that are more distant than the cutoff */ if (cutoff >= 0 && VECTOR(*dist)[actnode] > cutoff + 1) { @@ -178,9 +178,9 @@ static igraph_error_t igraph_i_sspf_edge( /* Examine the neighbors of this node */ neis = igraph_inclist_get(inclist, actnode); nlen = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*neis)[j]; - igraph_integer_t neighbor = IGRAPH_OTHER(graph, edge, actnode); + for (igraph_int_t j = 0; j < nlen; j++) { + igraph_int_t edge = VECTOR(*neis)[j]; + igraph_int_t neighbor = IGRAPH_OTHER(graph, edge, actnode); if (VECTOR(*dist)[neighbor] == 0) { /* We have found 'neighbor' for the first time */ @@ -222,9 +222,9 @@ static igraph_error_t igraph_i_sspf_edge( * \param inclist the incidence list of the graph * \param cutoff cutoff length of shortest paths */ -static igraph_error_t igraph_i_sspf_weighted( +static igraph_error_t sspf_weighted( const igraph_t *graph, - igraph_integer_t source, + igraph_int_t source, igraph_vector_t *dist, igraph_real_t *nrgeo, const igraph_vector_t *weights, @@ -239,19 +239,19 @@ static igraph_error_t igraph_i_sspf_weighted( igraph_2wheap_t queue; const igraph_vector_int_t *neis; igraph_vector_int_t *v; - igraph_integer_t nlen; + igraph_int_t nlen; /* TODO: this is an O|V| step here. We could save some time by pre-allocating * the two-way heap in the caller and re-using it here */ IGRAPH_CHECK(igraph_2wheap_init(&queue, igraph_vcount(graph))); IGRAPH_FINALLY(igraph_2wheap_destroy, &queue); - igraph_2wheap_push_with_index(&queue, source, -1.0); + igraph_2wheap_push_with_index(&queue, source, -1.0); /* reserved */ VECTOR(*dist)[source] = 1.0; nrgeo[source] = 1; while (!igraph_2wheap_empty(&queue)) { - igraph_integer_t minnei = igraph_2wheap_max_index(&queue); + igraph_int_t minnei = igraph_2wheap_max_index(&queue); igraph_real_t mindist = -igraph_2wheap_delete_max(&queue); /* Ignore vertices that are more distant than the cutoff */ @@ -269,9 +269,9 @@ static igraph_error_t igraph_i_sspf_weighted( /* Now check all neighbors of 'minnei' for a shorter path */ neis = igraph_inclist_get(inclist, minnei); nlen = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*neis)[j]; - igraph_integer_t to = IGRAPH_OTHER(graph, edge, minnei); + for (igraph_int_t j = 0; j < nlen; j++) { + igraph_int_t edge = VECTOR(*neis)[j]; + igraph_int_t to = IGRAPH_OTHER(graph, edge, minnei); igraph_real_t altdist = mindist + VECTOR(*weights)[edge]; igraph_real_t curdist = VECTOR(*dist)[to]; @@ -331,9 +331,9 @@ static igraph_error_t igraph_i_sspf_weighted( * \param inclist the incidence list of the graph * \param cutoff cutoff length of shortest paths */ -static igraph_error_t igraph_i_sspf_weighted_edge( +static igraph_error_t sspf_weighted_edge( const igraph_t *graph, - igraph_integer_t source, + igraph_int_t source, igraph_vector_t *dist, igraph_real_t *nrgeo, const igraph_vector_t *weights, @@ -348,19 +348,19 @@ static igraph_error_t igraph_i_sspf_weighted_edge( igraph_2wheap_t queue; const igraph_vector_int_t *neis; igraph_vector_int_t *v; - igraph_integer_t nlen; + igraph_int_t nlen; /* TODO: this is an O|V| step here. We could save some time by pre-allocating * the two-way heap in the caller and re-using it here */ IGRAPH_CHECK(igraph_2wheap_init(&queue, igraph_vcount(graph))); IGRAPH_FINALLY(igraph_2wheap_destroy, &queue); - igraph_2wheap_push_with_index(&queue, source, -1.0); + igraph_2wheap_push_with_index(&queue, source, -1.0); /* reserved */ VECTOR(*dist)[source] = 1.0; nrgeo[source] = 1; while (!igraph_2wheap_empty(&queue)) { - igraph_integer_t minnei = igraph_2wheap_max_index(&queue); + igraph_int_t minnei = igraph_2wheap_max_index(&queue); igraph_real_t mindist = -igraph_2wheap_delete_max(&queue); /* Ignore vertices that are more distant than the cutoff */ @@ -378,9 +378,9 @@ static igraph_error_t igraph_i_sspf_weighted_edge( /* Now check all neighbors of 'minnei' for a shorter path */ neis = igraph_inclist_get(inclist, minnei); nlen = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*neis)[j]; - igraph_integer_t to = IGRAPH_OTHER(graph, edge, minnei); + for (igraph_int_t j = 0; j < nlen; j++) { + igraph_int_t edge = VECTOR(*neis)[j]; + igraph_int_t to = IGRAPH_OTHER(graph, edge, minnei); igraph_real_t altdist = mindist + VECTOR(*weights)[edge]; igraph_real_t curdist = VECTOR(*dist)[to]; @@ -422,25 +422,26 @@ static igraph_error_t igraph_i_sspf_weighted_edge( return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_betweenness_check_weights( - const igraph_vector_t* weights, igraph_integer_t no_of_edges +static igraph_error_t betweenness_check_weights( + const igraph_vector_t *weights, igraph_int_t no_of_edges ) { igraph_real_t minweight; if (weights) { if (igraph_vector_size(weights) != no_of_edges) { - IGRAPH_ERROR("Weight vector length must match the number of edges.", IGRAPH_EINVAL); + IGRAPH_ERROR("Edge weight vector length must match the number of edges.", IGRAPH_EINVAL); } if (no_of_edges > 0) { minweight = igraph_vector_min(weights); if (minweight <= 0) { - IGRAPH_ERROR("Weight vector must be positive.", IGRAPH_EINVAL); + IGRAPH_ERROR("Edge weights must be positive for betweenness.", IGRAPH_EINVAL); } else if (isnan(minweight)) { - IGRAPH_ERROR("Weight vector must not contain NaN values.", IGRAPH_EINVAL); + IGRAPH_ERROR("Edge weights must not contain NaN values.", IGRAPH_EINVAL); } else if (minweight <= IGRAPH_SHORTEST_PATH_EPSILON) { - IGRAPH_WARNING( - "Some weights are smaller than epsilon, calculations may " - "suffer from numerical precision issues." + IGRAPH_WARNINGF( + "Some weights are smaller than the path length comparison tolerance (%g), " + "betweenness calculations may suffer from numerical precision issues.", + IGRAPH_SHORTEST_PATH_EPSILON ); } } @@ -456,10 +457,9 @@ static igraph_error_t igraph_i_betweenness_check_weights( * \function igraph_betweenness * \brief Betweenness centrality of some vertices. * - * The betweenness centrality of a vertex is the number of geodesics - * going through it. If there are more than one geodesic between two - * vertices, the value of these geodesics are weighted by one over the - * number of geodesics. + * The betweenness centrality of a vertex \c v is the number of shortest paths + * passing through it. If there is more than one shortest path between two + * vertices, the fraction of these passing through \c v is counted. * * * Reference: @@ -470,20 +470,23 @@ static igraph_error_t igraph_i_betweenness_check_weights( * https://doi.org/10.1080/0022250X.2001.9990249 * * \param graph The graph object. + * \param weights An optional vector containing edge weights for + * calculating weighted betweenness. No edge weight may be NaN. + * Supply a null pointer here for unweighted betweenness. * \param res The result of the computation, a vector containing the * betweenness scores for the specified vertices. - * \param vids The vertices of which the betweenness centrality scores - * will be calculated. + * \param vids The vertices for which the range-limited betweenness centrality + * scores will be returned. This paramerer is for convenience only and + * does not affect performance. Internally, the betewenness of all + * vertices is calculated. * \param directed If true directed paths will be considered * for directed graphs. It is ignored for undirected graphs. - * \param weights An optional vector containing edge weights for - * calculating weighted betweenness. No edge weight may be NaN. - * Supply a null pointer here for unweighted betweenness. + * \param normalized Whether to normalize betweenness scores by the number of + * vertex pairs. In directed graphs, the number of ordered vertex pairs, + * in undirected graphs the number of unordered vertex pairs is used. * \return Error code: - * \c IGRAPH_ENOMEM, not enough memory for - * temporary data. - * \c IGRAPH_EINVVID, invalid vertex ID passed in - * \p vids. + * \c IGRAPH_ENOMEM, not enough memory for temporary data. + * \c IGRAPH_EINVVID, invalid vertex ID passed in \p vids. * * Time complexity: O(|V||E|), * |V| and @@ -492,15 +495,17 @@ static igraph_error_t igraph_i_betweenness_check_weights( * Note that the time complexity is independent of the number of * vertices for which the score is calculated. * - * \sa Other centrality types: \ref igraph_degree(), \ref igraph_closeness(). - * See \ref igraph_edge_betweenness() for calculating the betweenness score - * of the edges in a graph. See \ref igraph_betweenness_cutoff() to - * calculate the range-limited betweenness of the vertices in a graph. + * \sa \ref igraph_edge_betweenness() for calculating the betweenness score + * of the edges in a graph; \ref igraph_betweenness_cutoff() to + * calculate the range-limited betweenness of the vertices in a graph; + * \ref igraph_betweenness_subset() to consider shortest paths only between + * two vertex subsets for calculating betweenness. */ -igraph_error_t igraph_betweenness(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, igraph_bool_t directed, - const igraph_vector_t* weights) { - return igraph_betweenness_cutoff(graph, res, vids, directed, weights, -1); +igraph_error_t igraph_betweenness( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, igraph_vs_t vids, + igraph_bool_t directed, igraph_bool_t normalized) { + return igraph_betweenness_cutoff(graph, weights, res, vids, directed, normalized, -1); } /** @@ -513,23 +518,26 @@ igraph_error_t igraph_betweenness(const igraph_t *graph, igraph_vector_t *res, * then the given cutoff value. * * \param graph The graph object. + * \param weights An optional vector containing edge weights for + * calculating weighted betweenness. No edge weight may be NaN. + * Supply a null pointer here for unweighted betweenness. * \param res The result of the computation, a vector containing the * range-limited betweenness scores for the specified vertices. * \param vids The vertices for which the range-limited betweenness centrality - * scores will be computed. + * scores will be returned. This paramerer is for convenience only and + * does not affect performance. Internally, the betewenness of all + * vertices is calculated. * \param directed If true directed paths will be considered * for directed graphs. It is ignored for undirected graphs. - * \param weights An optional vector containing edge weights for - * calculating weighted betweenness. No edge weight may be NaN. - * Supply a null pointer here for unweighted betweenness. + * \param normalized Whether to normalize betweenness scores by the number of + * vertex pairs. In directed graphs, the number of ordered vertex pairs, + * in undirected graphs the number of unordered vertex pairs is used. * \param cutoff The maximal length of paths that will be considered. - * If negative, the exact betweenness will be calculated, and - * there will be no upper limit on path lengths. + * If negative or \ref IGRAPH_UNLIMITED, the exact betweenness will be + * calculated, and there will be no upper limit on path lengths. * \return Error code: - * \c IGRAPH_ENOMEM, not enough memory for - * temporary data. - * \c IGRAPH_EINVVID, invalid vertex ID passed in - * \p vids. + * \c IGRAPH_ENOMEM, not enough memory for temporary data. + * \c IGRAPH_EINVVID, invalid vertex ID passed in \p vids. * * Time complexity: O(|V||E|), * |V| and @@ -542,17 +550,20 @@ igraph_error_t igraph_betweenness(const igraph_t *graph, igraph_vector_t *res, * \ref igraph_edge_betweenness_cutoff() to calculate the range-limited * edge betweenness. */ -igraph_error_t igraph_betweenness_cutoff(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, igraph_bool_t directed, - const igraph_vector_t *weights, igraph_real_t cutoff) { +igraph_error_t igraph_betweenness_cutoff( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, + igraph_vs_t vids, + igraph_bool_t directed, igraph_bool_t normalized, + igraph_real_t cutoff) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_adjlist_t adjlist, parents; igraph_inclist_t inclist; - igraph_integer_t source, j, neighbor; + igraph_int_t source, j, neighbor; igraph_stack_int_t S; - igraph_neimode_t mode = directed ? IGRAPH_OUT : IGRAPH_ALL; + igraph_neimode_t mode; igraph_vector_t dist; /* Note: nrgeo holds the number of shortest paths, which may be very large in some cases, * e.g. in a grid graph. If using an integer type, this results in overflow. @@ -566,8 +577,14 @@ igraph_error_t igraph_betweenness_cutoff(const igraph_t *graph, igraph_vector_t igraph_real_t *tmpscore; igraph_vector_t v_tmpres, *tmpres = &v_tmpres; igraph_vit_t vit; + igraph_real_t normalization_factor; + + if (!igraph_is_directed(graph)) { + directed = false; + } + mode = directed ? IGRAPH_OUT : IGRAPH_ALL; - IGRAPH_CHECK(igraph_i_betweenness_check_weights(weights, no_of_edges)); + IGRAPH_CHECK(betweenness_check_weights(weights, no_of_edges)); if (weights) { IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, mode, IGRAPH_NO_LOOPS)); @@ -619,17 +636,17 @@ igraph_error_t igraph_betweenness_cutoff(const igraph_t *graph, igraph_vector_t /* Conduct a single-source shortest path search from the source node */ if (weights) { - IGRAPH_CHECK(igraph_i_sspf_weighted(graph, source, &dist, nrgeo, weights, &S, &parents, &inclist, cutoff)); + IGRAPH_CHECK(sspf_weighted(graph, source, &dist, nrgeo, weights, &S, &parents, &inclist, cutoff)); } else { - IGRAPH_CHECK(igraph_i_sspf(source, &dist, nrgeo, &S, &parents, &adjlist, cutoff)); + IGRAPH_CHECK(sspf(source, &dist, nrgeo, &S, &parents, &adjlist, cutoff)); } /* Aggregate betweenness scores for the nodes we have reached in this * traversal */ while (!igraph_stack_int_empty(&S)) { - igraph_integer_t actnode = igraph_stack_int_pop(&S); + igraph_int_t actnode = igraph_stack_int_pop(&S); igraph_vector_int_t *neis = igraph_adjlist_get(&parents, actnode); - igraph_integer_t nneis = igraph_vector_int_size(neis); + igraph_int_t nneis = igraph_vector_int_size(neis); igraph_real_t coeff = (1 + tmpscore[actnode]) / nrgeo[actnode]; for (j = 0; j < nneis; j++) { @@ -660,7 +677,7 @@ igraph_error_t igraph_betweenness_cutoff(const igraph_t *graph, igraph_vector_t for (j = 0, IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), j++) { - igraph_integer_t node = IGRAPH_VIT_GET(vit); + igraph_int_t node = IGRAPH_VIT_GET(vit); VECTOR(*res)[j] = VECTOR(*tmpres)[node]; } @@ -669,10 +686,16 @@ igraph_error_t igraph_betweenness_cutoff(const igraph_t *graph, igraph_vector_t IGRAPH_FINALLY_CLEAN(2); } - if (!directed || !igraph_is_directed(graph)) { - igraph_vector_scale(res, 0.5); + /* The betweenness calculation is always done for all _ordered_ vertex pairs. + * We only need to correct for this in undirected graphs when normalized=false. */ + if (normalized) { + normalization_factor = 1.0 / (no_of_nodes * (no_of_nodes - 1.0)); + } else { + normalization_factor = directed ? 1.0 : 0.5; } + igraph_vector_scale(res, normalization_factor); + IGRAPH_PROGRESS("Betweenness centrality: ", 100.0, 0); IGRAPH_FREE(nrgeo); @@ -698,10 +721,9 @@ igraph_error_t igraph_betweenness_cutoff(const igraph_t *graph, igraph_vector_t * \function igraph_edge_betweenness * \brief Betweenness centrality of the edges. * - * The betweenness centrality of an edge is the number of geodesics - * going through it. If there are more than one geodesics between two - * vertices, the value of these geodesics are weighted by one over the - * number of geodesics. + * The betweenness centrality of an edge \c e is the number of shortest paths + * passing through it. If there is more than one shortest path between two + * vertices, the fraction of these passing through \c e is counted. * * * Reference: @@ -712,13 +734,20 @@ igraph_error_t igraph_betweenness_cutoff(const igraph_t *graph, igraph_vector_t * https://doi.org/10.1080/0022250X.2001.9990249 * * \param graph The graph object. - * \param result The result of the computation, vector containing the - * betweenness scores for the edges. - * \param directed If true directed paths will be considered - * for directed graphs. It is ignored for undirected graphs. * \param weights An optional weight vector for weighted edge * betweenness. No edge weight may be NaN. Supply a null * pointer here for the unweighted version. + * \param res The result of the computation, vector containing the + * betweenness scores for the edges. + * \param eids The edges for which the betweenness centrality will be returned. + * This parameter is for convenience only, and does not affect + * performance. Internally, the betweenness is be calculated for all + * edges. + * \param directed If true directed paths will be considered + * for directed graphs. It is ignored for undirected graphs. + * \param normalized Whether to normalize betweenness scores by the number of + * vertex pairs. In directed graphs, the number of ordered vertex pairs, + * in undirected graphs the number of unordered vertex pairs is used. * \return Error code: * \c IGRAPH_ENOMEM, not enough memory for * temporary data. @@ -728,16 +757,21 @@ igraph_error_t igraph_betweenness_cutoff(const igraph_t *graph, igraph_vector_t * |E| are the number of vertices and * edges in the graph. * - * \sa Other centrality types: \ref igraph_degree(), \ref igraph_closeness(). - * See \ref igraph_edge_betweenness() for calculating the betweenness score - * of the edges in a graph. See \ref igraph_edge_betweenness_cutoff() to - * compute the range-limited betweenness score of the edges in a graph. + * \sa \ref igraph_betweenness() for calculating the betweenness score of the + * vertices in a graph; \ref igraph_edge_betweenness_cutoff() to compute the + * range-limited betweenness score of the edges in a graph; + * \ref igraph_edge_betweenness_subset() to consider shortest paths only between + * two vertex subsets for calculating betweenness. */ -igraph_error_t igraph_edge_betweenness(const igraph_t *graph, igraph_vector_t *result, - igraph_bool_t directed, - const igraph_vector_t *weights) { - return igraph_edge_betweenness_cutoff(graph, result, directed, - weights, -1); +igraph_error_t igraph_edge_betweenness( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, igraph_es_t eids, + igraph_bool_t directed, igraph_bool_t normalized) { + + return igraph_edge_betweenness_cutoff( + graph, weights, + res, eids, + directed, normalized, -1); } /** @@ -750,16 +784,23 @@ igraph_error_t igraph_edge_betweenness(const igraph_t *graph, igraph_vector_t *r * then the given cutoff value. * * \param graph The graph object. - * \param result The result of the computation, vector containing the - * betweenness scores for the edges. - * \param directed If true directed paths will be considered - * for directed graphs. It is ignored for undirected graphs. * \param weights An optional weight vector for weighted * betweenness. No edge weight may be NaN. Supply a null * pointer here for unweighted betweenness. + * \param res The result of the computation, vector containing the + * betweenness scores for the edges. + * \param eids The edges for which the betweenness centrality will be returned. + * This parameter is for convenience only, and does not affect + * performance. Internally, the betweenness is be calculated for all + * edges. + * \param directed If true directed paths will be considered + * for directed graphs. It is ignored for undirected graphs. + * \param normalized Whether to normalize betweenness scores by the number of + * vertex pairs. In directed graphs, the number of ordered vertex pairs, + * in undirected graphs the number of unordered vertex pairs is used. * \param cutoff The maximal length of paths that will be considered. - * If negative, the exact betweenness will be calculated (no - * upper limit on path lengths). + * If negative of \ref IGRAPH_UNLIMITED, the exact betweenness will be + * calculated (no upper limit on path lengths). * \return Error code: * \c IGRAPH_ENOMEM, not enough memory for * temporary data. @@ -772,20 +813,31 @@ igraph_error_t igraph_edge_betweenness(const igraph_t *graph, igraph_vector_t *r * \sa \ref igraph_edge_betweenness() to compute the exact edge betweenness and * \ref igraph_betweenness_cutoff() to compute the range-limited vertex betweenness. */ -igraph_error_t igraph_edge_betweenness_cutoff(const igraph_t *graph, igraph_vector_t *result, - igraph_bool_t directed, - const igraph_vector_t *weights, igraph_real_t cutoff) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); +igraph_error_t igraph_edge_betweenness_cutoff( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, + igraph_es_t eids, + igraph_bool_t directed, igraph_bool_t normalized, + igraph_real_t cutoff) { + + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_inclist_t inclist, parents; - igraph_neimode_t mode = directed ? IGRAPH_OUT : IGRAPH_ALL; + igraph_neimode_t mode; igraph_vector_t dist; + igraph_vector_t v_tmpres, *tmpres = &v_tmpres; igraph_real_t *nrgeo; igraph_real_t *tmpscore; - igraph_integer_t source, j; + igraph_int_t source, j; igraph_stack_int_t S; + igraph_real_t normalization_factor; - IGRAPH_CHECK(igraph_i_betweenness_check_weights(weights, no_of_edges)); + if (!igraph_is_directed(graph)) { + directed = false; + } + mode = directed ? IGRAPH_OUT : IGRAPH_ALL; + + IGRAPH_CHECK(betweenness_check_weights(weights, no_of_edges)); IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, mode, IGRAPH_NO_LOOPS)); IGRAPH_FINALLY(igraph_inclist_destroy, &inclist); @@ -808,8 +860,15 @@ igraph_error_t igraph_edge_betweenness_cutoff(const igraph_t *graph, igraph_vect IGRAPH_CHECK(igraph_stack_int_init(&S, no_of_nodes)); IGRAPH_FINALLY(igraph_stack_int_destroy, &S); - IGRAPH_CHECK(igraph_vector_resize(result, no_of_edges)); - igraph_vector_null(result); + if (!igraph_es_is_all(&eids)) { + /* result needed only for a subset of the vertices */ + IGRAPH_VECTOR_INIT_FINALLY(tmpres, no_of_edges); + } else { + /* result covers all vertices */ + IGRAPH_CHECK(igraph_vector_resize(res, no_of_edges)); + igraph_vector_null(res); + tmpres = res; + } for (source = 0; source < no_of_nodes; source++) { @@ -827,24 +886,24 @@ igraph_error_t igraph_edge_betweenness_cutoff(const igraph_t *graph, igraph_vect /* Conduct a single-source shortest path search from the source node */ if (weights) { - IGRAPH_CHECK(igraph_i_sspf_weighted_edge(graph, source, &dist, nrgeo, weights, &S, &parents, &inclist, cutoff)); + IGRAPH_CHECK(sspf_weighted_edge(graph, source, &dist, nrgeo, weights, &S, &parents, &inclist, cutoff)); } else { - IGRAPH_CHECK(igraph_i_sspf_edge(graph, source, &dist, nrgeo, &S, &parents, &inclist, cutoff)); + IGRAPH_CHECK(sspf_edge(graph, source, &dist, nrgeo, &S, &parents, &inclist, cutoff)); } /* Aggregate betweenness scores for the edges we have reached in this * traversal */ while (!igraph_stack_int_empty(&S)) { - igraph_integer_t actnode = igraph_stack_int_pop(&S); - igraph_vector_int_t *fatv = igraph_inclist_get(&parents, actnode); - igraph_integer_t fatv_len = igraph_vector_int_size(fatv); + igraph_int_t actnode = igraph_stack_int_pop(&S); + igraph_vector_int_t *parentv = igraph_inclist_get(&parents, actnode); + igraph_int_t parentv_len = igraph_vector_int_size(parentv); igraph_real_t coeff = (1 + tmpscore[actnode]) / nrgeo[actnode]; - for (j = 0; j < fatv_len; j++) { - igraph_integer_t fedge = VECTOR(*fatv)[j]; - igraph_integer_t neighbor = IGRAPH_OTHER(graph, fedge, actnode); + for (j = 0; j < parentv_len; j++) { + igraph_int_t fedge = VECTOR(*parentv)[j]; + igraph_int_t neighbor = IGRAPH_OTHER(graph, fedge, actnode); tmpscore[neighbor] += nrgeo[neighbor] * coeff; - VECTOR(*result)[fedge] += nrgeo[neighbor] * coeff; + VECTOR(*tmpres)[fedge] += nrgeo[neighbor] * coeff; } /* Reset variables to ensure that the 'for' loop invariant will @@ -853,14 +912,40 @@ igraph_error_t igraph_edge_betweenness_cutoff(const igraph_t *graph, igraph_vect VECTOR(dist)[actnode] = 0; nrgeo[actnode] = 0; tmpscore[actnode] = 0; - igraph_vector_int_clear(fatv); + igraph_vector_int_clear(parentv); } } /* source < no_of_nodes */ - if (!directed || !igraph_is_directed(graph)) { - igraph_vector_scale(result, 0.5); + /* Keep only the requested edges */ + if (!igraph_es_is_all(&eids)) { + igraph_eit_t eit; + + IGRAPH_CHECK(igraph_eit_create(graph, eids, &eit)); + IGRAPH_FINALLY(igraph_eit_destroy, &eit); + + IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_EIT_SIZE(eit))); + + for (j = 0, IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); + IGRAPH_EIT_NEXT(eit), j++) { + igraph_int_t edge = IGRAPH_EIT_GET(eit); + VECTOR(*res)[j] = VECTOR(*tmpres)[edge]; + } + + igraph_eit_destroy(&eit); + igraph_vector_destroy(tmpres); + IGRAPH_FINALLY_CLEAN(2); } + /* The betweenness calculation is always done for all _ordered_ vertex pairs. + * We only need to correct for this in undirected graphs when normalized=false. */ + if (normalized) { + normalization_factor = 1.0 / (no_of_nodes * (no_of_nodes - 1.0)); + } else { + normalization_factor = directed ? 1.0 : 0.5; + } + + igraph_vector_scale(res, normalization_factor); + IGRAPH_PROGRESS("Edge betweenness centrality: ", 100.0, 0); igraph_stack_int_destroy(&S); @@ -884,19 +969,21 @@ igraph_error_t igraph_edge_betweenness_cutoff(const igraph_t *graph, igraph_vect * source and target subset. * * \param graph The graph object. + * \param weights An optional vector containing edge weights for + * calculating weighted betweenness. No edge weight may be NaN. + * Supply a null pointer here for unweighted betweenness. * \param res The result of the computation, a vector containing the * betweenness score for the subset of vertices. - * \param vids The vertices for which the subset-limited betweenness centrality - * scores will be computed. - * \param directed If true directed paths will be considered - * for directed graphs. It is ignored for undirected graphs. * \param sources A vertex selector for the sources of the shortest paths taken * into considuration in the betweenness calculation. * \param targets A vertex selector for the targets of the shortest paths taken * into considuration in the betweenness calculation. - * \param weights An optional vector containing edge weights for - * calculating weighted betweenness. No edge weight may be NaN. - * Supply a null pointer here for unweighted betweenness. + * \param vids The vertices for which the subset-limited betweenness centrality + * scores will be computed. + * \param directed If true directed paths will be considered + * for directed graphs. It is ignored for undirected graphs. + * \param normalized Whether to normalize betweenness scores. Normalization is + * currently unimplemented, and setting this to \c true raises an error. * \return Error code: * \c IGRAPH_ENOMEM, not enough memory for temporary data. * \c IGRAPH_EINVVID, invalid vertex ID passed in \p vids, @@ -910,29 +997,35 @@ igraph_error_t igraph_edge_betweenness_cutoff(const igraph_t *graph, igraph_vect * \ref igraph_betweenness_cutoff() to calculate the range-limited vertex * betweenness. */ -igraph_error_t igraph_betweenness_subset(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, igraph_bool_t directed, - const igraph_vs_t sources, const igraph_vs_t targets, - const igraph_vector_t *weights) { - - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_sources; - igraph_integer_t no_of_processed_sources; +igraph_error_t igraph_betweenness_subset( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, + igraph_vs_t sources, igraph_vs_t targets, + igraph_vs_t vids, + igraph_bool_t directed, igraph_bool_t normalized) { + + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_sources; + igraph_int_t no_of_processed_sources; igraph_adjlist_t adjlist, parents; igraph_inclist_t inclist; - igraph_integer_t source, j; + igraph_int_t source, j; igraph_stack_int_t S; igraph_vector_t v_tmpres, *tmpres = &v_tmpres; igraph_neimode_t mode = directed ? IGRAPH_OUT : IGRAPH_ALL; - igraph_integer_t father; + igraph_int_t parent; igraph_vector_t dist; igraph_real_t *nrgeo; igraph_real_t *tmpscore; igraph_vit_t vit; bool *is_target; - IGRAPH_CHECK(igraph_i_betweenness_check_weights(weights, no_of_edges)); + if (normalized) { + IGRAPH_ERROR("Normalization is not yet implemented for subset betweenness.", IGRAPH_UNIMPLEMENTED); + } + + IGRAPH_CHECK(betweenness_check_weights(weights, no_of_edges)); IGRAPH_CHECK(igraph_vs_size(graph, &sources, &no_of_sources)); @@ -1016,17 +1109,17 @@ igraph_error_t igraph_betweenness_subset(const igraph_t *graph, igraph_vector_t /* Conduct a single-source shortest path search from the source node */ if (weights) { - IGRAPH_CHECK(igraph_i_sspf_weighted(graph, source, &dist, nrgeo, weights, &S, &parents, &inclist, -1)); + IGRAPH_CHECK(sspf_weighted(graph, source, &dist, nrgeo, weights, &S, &parents, &inclist, -1)); } else { - IGRAPH_CHECK(igraph_i_sspf(source, &dist, nrgeo, &S, &parents, &adjlist, -1)); + IGRAPH_CHECK(sspf(source, &dist, nrgeo, &S, &parents, &adjlist, -1)); } /* Aggregate betweenness scores for the nodes we have reached in this * traversal */ while (!igraph_stack_int_empty(&S)) { - igraph_integer_t actnode = igraph_stack_int_pop(&S); - igraph_vector_int_t *fatv = igraph_adjlist_get(&parents, actnode); - igraph_integer_t fatv_len = igraph_vector_int_size(fatv); + igraph_int_t actnode = igraph_stack_int_pop(&S); + igraph_vector_int_t *parentv = igraph_adjlist_get(&parents, actnode); + igraph_int_t parentv_len = igraph_vector_int_size(parentv); igraph_real_t coeff; if (is_target[actnode]) { @@ -1035,9 +1128,9 @@ igraph_error_t igraph_betweenness_subset(const igraph_t *graph, igraph_vector_t coeff = tmpscore[actnode] / nrgeo[actnode]; } - for (j = 0; j < fatv_len; j++) { - father = VECTOR(*fatv)[j]; - tmpscore[father] += nrgeo[father] * coeff; + for (j = 0; j < parentv_len; j++) { + parent = VECTOR(*parentv)[j]; + tmpscore[parent] += nrgeo[parent] * coeff; } if (actnode != source) { @@ -1050,7 +1143,7 @@ igraph_error_t igraph_betweenness_subset(const igraph_t *graph, igraph_vector_t VECTOR(dist)[actnode] = 0; nrgeo[actnode] = 0; tmpscore[actnode] = 0; - igraph_vector_int_clear(fatv); + igraph_vector_int_clear(parentv); } } @@ -1065,7 +1158,7 @@ igraph_error_t igraph_betweenness_subset(const igraph_t *graph, igraph_vector_t IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_VIT_SIZE(vit))); for (j = 0, IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), j++) { - igraph_integer_t node = IGRAPH_VIT_GET(vit); + igraph_int_t node = IGRAPH_VIT_GET(vit); VECTOR(*res)[j] = VECTOR(*tmpres)[node]; } @@ -1104,19 +1197,22 @@ igraph_error_t igraph_betweenness_subset(const igraph_t *graph, igraph_vector_t * source and target subset. * * \param graph The graph object. + * \param weights An optional weight vector for weighted + * betweenness. No edge weight may be NaN. Supply a null + * pointer here for unweighted betweenness. * \param res The result of the computation, vector containing the * betweenness scores for the edges. - * \param eids The edges for which the subset-limited betweenness centrality - * scores will be computed. - * \param directed If true directed paths will be considered - * for directed graphs. It is ignored for undirected graphs. * \param sources A vertex selector for the sources of the shortest paths taken * into considuration in the betweenness calculation. * \param targets A vertex selector for the targets of the shortest paths taken * into considuration in the betweenness calculation. - * \param weights An optional weight vector for weighted - * betweenness. No edge weight may be NaN. Supply a null - * pointer here for unweighted betweenness. + * \param eids The edges for which the subset-limited betweenness centrality + * scores will be returned. This parameter is for convenience only. + * Internally, the betweenness will be calculated for all edges. + * \param directed If true directed paths will be considered + * for directed graphs. It is ignored for undirected graphs. + * \param normalized Whether to normalize betweenness scores. Normalization is + * currently unimplemented, and setting this to \c true raises an error. * \return Error code: * \c IGRAPH_ENOMEM, not enough memory for temporary data. * \c IGRAPH_EINVVID, invalid vertex ID passed in \p sources or \p targets @@ -1128,14 +1224,17 @@ igraph_error_t igraph_betweenness_subset(const igraph_t *graph, igraph_vector_t * \sa \ref igraph_edge_betweenness() to compute the exact edge betweenness and * \ref igraph_edge_betweenness_cutoff() to compute the range-limited edge betweenness. */ -igraph_error_t igraph_edge_betweenness_subset(const igraph_t *graph, igraph_vector_t *res, - const igraph_es_t eids, igraph_bool_t directed, - const igraph_vs_t sources, const igraph_vs_t targets, - const igraph_vector_t *weights) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_sources; - igraph_integer_t no_of_processed_sources; +igraph_error_t igraph_edge_betweenness_subset( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *res, + igraph_vs_t sources, igraph_vs_t targets, + igraph_es_t eids, + igraph_bool_t directed, igraph_bool_t normalized) { + + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_sources; + igraph_int_t no_of_processed_sources; igraph_inclist_t inclist, parents; igraph_vit_t vit; igraph_eit_t eit; @@ -1144,11 +1243,15 @@ igraph_error_t igraph_edge_betweenness_subset(const igraph_t *graph, igraph_vect igraph_vector_t v_tmpres, *tmpres = &v_tmpres; igraph_real_t *nrgeo; igraph_real_t *tmpscore; - igraph_integer_t source, j; + igraph_int_t source, j; bool *is_target; igraph_stack_int_t S; - IGRAPH_CHECK(igraph_i_betweenness_check_weights(weights, no_of_edges)); + if (normalized) { + IGRAPH_ERROR("Normalization is not yet implemented for subset edge betweenness.", IGRAPH_UNIMPLEMENTED); + } + + IGRAPH_CHECK(betweenness_check_weights(weights, no_of_edges)); IGRAPH_CHECK(igraph_vs_size(graph, &sources, &no_of_sources)); @@ -1226,17 +1329,17 @@ igraph_error_t igraph_edge_betweenness_subset(const igraph_t *graph, igraph_vect /* Conduct a single-source shortest path search from the source node */ if (weights) { - IGRAPH_CHECK(igraph_i_sspf_weighted_edge(graph, source, &dist, nrgeo, weights, &S, &parents, &inclist, -1)); + IGRAPH_CHECK(sspf_weighted_edge(graph, source, &dist, nrgeo, weights, &S, &parents, &inclist, -1)); } else { - IGRAPH_CHECK(igraph_i_sspf_edge(graph, source, &dist, nrgeo, &S, &parents, &inclist, -1)); + IGRAPH_CHECK(sspf_edge(graph, source, &dist, nrgeo, &S, &parents, &inclist, -1)); } /* Aggregate betweenness scores for the nodes we have reached in this * traversal */ while (!igraph_stack_int_empty(&S)) { - igraph_integer_t actnode = igraph_stack_int_pop(&S); - igraph_vector_int_t *fatv = igraph_inclist_get(&parents, actnode); - igraph_integer_t fatv_len = igraph_vector_int_size(fatv); + igraph_int_t actnode = igraph_stack_int_pop(&S); + igraph_vector_int_t *parentv = igraph_inclist_get(&parents, actnode); + igraph_int_t parentv_len = igraph_vector_int_size(parentv); igraph_real_t coeff; if (is_target[actnode]) { @@ -1245,11 +1348,11 @@ igraph_error_t igraph_edge_betweenness_subset(const igraph_t *graph, igraph_vect coeff = tmpscore[actnode] / nrgeo[actnode]; } - for (j = 0; j < fatv_len; j++) { - igraph_integer_t father_edge = VECTOR(*fatv)[j]; - igraph_integer_t neighbor = IGRAPH_OTHER(graph, father_edge, actnode); + for (j = 0; j < parentv_len; j++) { + igraph_int_t parent_edge = VECTOR(*parentv)[j]; + igraph_int_t neighbor = IGRAPH_OTHER(graph, parent_edge, actnode); tmpscore[neighbor] += nrgeo[neighbor] * coeff; - VECTOR(*tmpres)[father_edge] += nrgeo[neighbor] * coeff; + VECTOR(*tmpres)[parent_edge] += nrgeo[neighbor] * coeff; } /* Reset variables to ensure that the 'for' loop invariant will @@ -1258,7 +1361,7 @@ igraph_error_t igraph_edge_betweenness_subset(const igraph_t *graph, igraph_vect VECTOR(dist)[actnode] = 0; nrgeo[actnode] = 0; tmpscore[actnode] = 0; - igraph_vector_int_clear(fatv); + igraph_vector_int_clear(parentv); } } @@ -1274,7 +1377,7 @@ igraph_error_t igraph_edge_betweenness_subset(const igraph_t *graph, igraph_vect for (j = 0, IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit), j++) { - igraph_integer_t edge = IGRAPH_EIT_GET(eit); + igraph_int_t edge = IGRAPH_EIT_GET(eit); VECTOR(*res)[j] = VECTOR(*tmpres)[edge]; } diff --git a/src/vendor/cigraph/src/centrality/centrality_internal.h b/src/vendor/cigraph/src/centrality/centrality_internal.h index 4479a3466ae..10e4bc69d9c 100644 --- a/src/vendor/cigraph/src/centrality/centrality_internal.h +++ b/src/vendor/cigraph/src/centrality/centrality_internal.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -28,10 +27,11 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS igraph_bool_t igraph_i_vector_mostly_negative(const igraph_vector_t *vector); +void igraph_i_vector_scale_by_max_abs(igraph_vector_t *vec); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/centrality/centrality_other.c b/src/vendor/cigraph/src/centrality/centrality_other.c index 6130b253b0c..5865d8b8bf2 100644 --- a/src/vendor/cigraph/src/centrality/centrality_other.c +++ b/src/vendor/cigraph/src/centrality/centrality_other.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -14,8 +12,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "centrality/centrality_internal.h" @@ -31,7 +29,7 @@ igraph_bool_t igraph_i_vector_mostly_negative(const igraph_vector_t *vector) { * the values are relatively large negative numbers, in which case we should * negate the eigenvector. */ - igraph_integer_t n = igraph_vector_size(vector); + igraph_int_t n = igraph_vector_size(vector); igraph_real_t mi, ma; if (n == 0) { @@ -50,3 +48,25 @@ igraph_bool_t igraph_i_vector_mostly_negative(const igraph_vector_t *vector) { /* is the most negative value larger in magnitude than the most positive? */ return (-mi/ma > 1); } + +/* Normalizes a vector of real numbers such that the largest value, as well as + * the largest value by magnitude, are 1.0. This is used by functions that + * produce eigenvector-like centrality values, scaling the largest centrality + * to 1.0. */ +void igraph_i_vector_scale_by_max_abs(igraph_vector_t *vec) { + const igraph_int_t n = igraph_vector_size(vec); + igraph_real_t amax = 0; + igraph_int_t which = 0; + + for (igraph_int_t i = 0; i < n; i++) { + igraph_real_t tmp; + tmp = fabs(VECTOR(*vec)[i]); + if (tmp > amax) { + amax = tmp; + which = i; + } + } + if (amax != 0) { + igraph_vector_scale(vec, 1 / VECTOR(*vec)[which]); + } +} diff --git a/src/vendor/cigraph/src/centrality/centralization.c b/src/vendor/cigraph/src/centrality/centralization.c index d08a95da7a4..976a151a282 100644 --- a/src/vendor/cigraph/src/centrality/centralization.c +++ b/src/vendor/cigraph/src/centrality/centralization.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -14,8 +12,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "igraph_centrality.h" @@ -83,7 +81,7 @@ igraph_real_t igraph_centralization(const igraph_vector_t *scores, igraph_real_t theoretical_max, igraph_bool_t normalized) { - igraph_integer_t no_of_nodes = igraph_vector_size(scores); + igraph_int_t no_of_nodes = igraph_vector_size(scores); igraph_real_t cent; if (no_of_nodes != 0) { @@ -114,8 +112,11 @@ igraph_real_t igraph_centralization(const igraph_vector_t *scores, * \param mode Constant the specifies the type of degree for directed * graphs. Possible values: \c IGRAPH_IN, \c IGRAPH_OUT and \c * IGRAPH_ALL. This argument is ignored for undirected graphs. - * \param loops Boolean, whether to consider loop edges when - * calculating the degree (and the centralization). + * \param loops Specifies how to treat loop edges when calculating the + * degree (and the centralization). \c IGRAPH_NO_LOOPS ignores loop + * edges; \c IGRAPH_LOOPS_ONCE counts each loop edge only once; + * \c IGRAPH_LOOPS_TWICE counts each loop edge twice in undirected + * graphs and once in directed graphs. * \param centralization Pointer to a real number, the centralization * score is placed here. * \param theoretical_max Pointer to real number or a null pointer. If @@ -134,11 +135,11 @@ igraph_real_t igraph_centralization(const igraph_vector_t *scores, * score. */ -igraph_error_t igraph_centralization_degree(const igraph_t *graph, igraph_vector_t *res, - igraph_neimode_t mode, igraph_bool_t loops, - igraph_real_t *centralization, - igraph_real_t *theoretical_max, - igraph_bool_t normalized) { +igraph_error_t igraph_centralization_degree( + const igraph_t *graph, igraph_vector_t *res, igraph_neimode_t mode, + igraph_loops_t loops, igraph_real_t *centralization, + igraph_real_t *theoretical_max, igraph_bool_t normalized +) { igraph_vector_t myscores; igraph_vector_t *scores = res; @@ -200,8 +201,11 @@ igraph_error_t igraph_centralization_degree(const igraph_t *graph, igraph_vector * or total degree (\c IGRAPH_ALL). This is ignored if * the \p graph argument is not a null pointer and the * given graph is undirected. - * \param loops Boolean, whether to consider loop edges in the - * calculation. + * \param loops Specifies how to treat loop edges when calculating the + * degree (and the centralization). \c IGRAPH_NO_LOOPS ignores loop + * edges; \c IGRAPH_LOOPS_ONCE counts each loop edge only once; + * \c IGRAPH_LOOPS_TWICE counts each loop edge twice in undirected + * graphs and once in directed graphs. * \param res Pointer to a real variable, the result is stored here. * \return Error code. * @@ -211,11 +215,10 @@ igraph_error_t igraph_centralization_degree(const igraph_t *graph, igraph_vector * igraph_centralization(). */ -igraph_error_t igraph_centralization_degree_tmax(const igraph_t *graph, - igraph_integer_t nodes, - igraph_neimode_t mode, - igraph_bool_t loops, - igraph_real_t *res) { +igraph_error_t igraph_centralization_degree_tmax( + const igraph_t *graph, igraph_int_t nodes, igraph_neimode_t mode, + igraph_loops_t loops, igraph_real_t *res +) { igraph_bool_t directed = (mode != IGRAPH_ALL); igraph_real_t real_nodes; @@ -240,14 +243,14 @@ igraph_error_t igraph_centralization_degree_tmax(const igraph_t *graph, switch (mode) { case IGRAPH_IN: case IGRAPH_OUT: - if (!loops) { + if (loops == IGRAPH_NO_LOOPS) { *res = (real_nodes - 1) * (real_nodes - 1); } else { *res = (real_nodes - 1) * real_nodes; } break; case IGRAPH_ALL: - if (!loops) { + if (loops == IGRAPH_NO_LOOPS) { *res = 2 * (real_nodes - 1) * (real_nodes - 2); } else { *res = 2 * (real_nodes - 1) * (real_nodes - 1); @@ -255,8 +258,10 @@ igraph_error_t igraph_centralization_degree_tmax(const igraph_t *graph, break; } } else { - if (!loops) { + if (loops == IGRAPH_NO_LOOPS) { *res = (real_nodes - 1) * (real_nodes - 2); + } else if (loops == IGRAPH_LOOPS_ONCE) { + *res = (real_nodes - 1) * (real_nodes - 1); } else { *res = (real_nodes - 1) * real_nodes; } @@ -317,7 +322,7 @@ igraph_error_t igraph_centralization_betweenness(const igraph_t *graph, IGRAPH_VECTOR_INIT_FINALLY(scores, 0); } - IGRAPH_CHECK(igraph_betweenness(graph, scores, igraph_vss_all(), directed, /*weights=*/ 0)); + IGRAPH_CHECK(igraph_betweenness(graph, /*weights=*/ 0, scores, igraph_vss_all(), directed, false)); IGRAPH_CHECK(igraph_centralization_betweenness_tmax(graph, 0, directed, tmax)); @@ -371,7 +376,7 @@ igraph_error_t igraph_centralization_betweenness(const igraph_t *graph, */ igraph_error_t igraph_centralization_betweenness_tmax(const igraph_t *graph, - igraph_integer_t nodes, + igraph_int_t nodes, igraph_bool_t directed, igraph_real_t *res) { igraph_real_t real_nodes; @@ -512,7 +517,7 @@ igraph_error_t igraph_centralization_closeness(const igraph_t *graph, */ igraph_error_t igraph_centralization_closeness_tmax(const igraph_t *graph, - igraph_integer_t nodes, + igraph_int_t nodes, igraph_neimode_t mode, igraph_real_t *res) { igraph_real_t real_nodes; @@ -549,7 +554,7 @@ igraph_error_t igraph_centralization_closeness_tmax(const igraph_t *graph, * \brief Calculate eigenvector centrality scores and graph centralization. * * This function calculates the eigenvector centrality of the vertices - * by passing its arguments to \ref igraph_eigenvector_centrality); + * by passing its arguments to \ref igraph_eigenvector_centrality(); * and it calculates the graph level centralization index based on the * results by calling \ref igraph_centralization(). * @@ -570,10 +575,9 @@ igraph_error_t igraph_centralization_closeness_tmax(const igraph_t *graph, * centrality scores, or a null pointer otherwise. * \param value If not a null pointer, then the leading eigenvalue is * stored here. - * \param directed Boolean scalar, whether to consider edge directions - * in a directed graph. It is ignored for undirected graphs. - * \param scale This parameter is deprecated and ignored since igraph 0.10.14. - * Vertex-level centrality scores are always scaled to have a maximum of one. + * \param mode How to consider edge directions in directed graphs. + * See \ref igraph_eigenvector_centrality() for details. Ignored + * for directed graphs. * \param options Options to ARPACK. See \ref igraph_arpack_options_t * for details. Note that the function overwrites the * n (number of vertices) parameter and @@ -601,8 +605,7 @@ igraph_error_t igraph_centralization_eigenvector_centrality( const igraph_t *graph, igraph_vector_t *vector, igraph_real_t *value, - igraph_bool_t directed, - igraph_bool_t scale, + igraph_neimode_t mode, igraph_arpack_options_t *options, igraph_real_t *centralization, igraph_real_t *theoretical_max, @@ -613,14 +616,6 @@ igraph_error_t igraph_centralization_eigenvector_centrality( igraph_real_t realvalue, *myvalue = value; igraph_real_t *tmax = theoretical_max, mytmax; - if (! scale) { - scale = true; - IGRAPH_WARNING("Computing eigenvector centralization requires normalized " - "eigenvector centrality scores. Normalizing eigenvector centralities " - "by their maximum even though 'scale=false' was requested. The 'scale' " - "parameter will be removed in the future."); - } - if (!tmax) { tmax = &mytmax; } @@ -633,14 +628,12 @@ igraph_error_t igraph_centralization_eigenvector_centrality( myvalue = &realvalue; } - IGRAPH_CHECK(igraph_eigenvector_centrality(graph, scores, myvalue, directed, - scale, /*weights=*/ 0, + IGRAPH_CHECK(igraph_eigenvector_centrality(graph, scores, myvalue, mode, + /*weights=*/ NULL, options)); IGRAPH_CHECK(igraph_centralization_eigenvector_centrality_tmax( - graph, 0, directed, - scale, - tmax)); + graph, 0, mode, tmax)); *centralization = igraph_centralization(scores, *tmax, normalized); @@ -664,45 +657,26 @@ igraph_error_t igraph_centralization_eigenvector_centrality( * graph as the \p graph argument, and then the number of * vertices is taken from this object, and its directedness is * considered as well. The \p nodes argument is ignored in - * this case. The \p directed argument is also ignored if the + * this case. The \p mode argument is also ignored if the * supplied graph is undirected. * * - * The other way is to supply a null pointer as the \p graph - * argument. In this case the \p nodes and \p directed - * arguments are considered. + * The other way is to supply a null pointer as the \p graph. argument. + * In this case the \p nodes and \p mode arguments are considered. * * - * The most centralized directed structure is assumed to bethe in-star. - * The most centralized undirected structure is assumed to be the graph - * with a single edge. igraph continues to implement these choices for - * historical reason. Keep in mind that neither of these two structures - * is connected, which makes their use debatable in the context of - * eigenvector centrality calculations. Eigenvector centrality is not - * uniquely defined for disconnected structures. - * - * - * Note that vertex-level eigenvector centrality scores do not have - * a natural scale. As with any eigenvector, their interpretation is - * invariant to scaling by a constant factor. However, due to how - * graph-level \em centralization is defined, its value depends on the - * specific scale/normalization used for vertex-level scores. Moreover, - * which of two graphs will have a higher eigenvector \em centralization - * also depends on the choice of normalization for centralities. This - * function makes the specific choice of scaling vertex-level centrality - * scores by their maximum (i.e. it uses the ∞-norm). Other normalization - * choices, such as the 1-norm or 2-norm are not currently implemented. + * The most centralized directed structure is the in-star with \p mode + * set to \c IGRAPH_OUT, and the out-star with \p mode set to \c IGRAPH_IN. + * The most centralized undirected structure is the graph with a single edge. * * \param graph A graph object or a null pointer, see the description * above. * \param nodes The number of nodes. This is ignored if the * \p graph argument is not a null pointer. - * \param directed Boolean, whether to consider edge - * directions. This argument is ignored if - * \p graph is not a null pointer and it is undirected. - * \param scale This parameter is deprecated and ignored since igraph 0.10.14. - * Vertex-level centrality scores are always assumed to be scaled to - * have a maximum of one. + * \param mode How to consider edge directions in directed graphs. + * See \ref igraph_eigenvector_centrality() for details. This argument + * is ignored if \p graph is not a null pointer and it is + * undirected. * \param res Pointer to a real variable, the result is stored here. * \return Error code. * @@ -714,23 +688,15 @@ igraph_error_t igraph_centralization_eigenvector_centrality( igraph_error_t igraph_centralization_eigenvector_centrality_tmax( const igraph_t *graph, - igraph_integer_t nodes, - igraph_bool_t directed, - igraph_bool_t scale, + igraph_int_t nodes, + igraph_neimode_t mode, igraph_real_t *res) { - if (! scale) { - scale = true; - IGRAPH_WARNING("Theoretical maximum for eigenvector centralization can " - "only be computed with normalized eigenvector centrality " - "scores. Assuming that eigenvector centralities are normalized " - "by their maximum even though 'scale=false' was passed. The 'scale' " - "parameter will be removed in the future."); - } - if (graph) { nodes = igraph_vcount(graph); - directed = directed && igraph_is_directed(graph); + if (! igraph_is_directed(graph)) { + mode = IGRAPH_ALL; + } } else { if (nodes < 0) { IGRAPH_ERROR("Number of vertices must not be negative.", IGRAPH_EINVAL); @@ -747,14 +713,10 @@ igraph_error_t igraph_centralization_eigenvector_centrality_tmax( return IGRAPH_SUCCESS; } - if (directed) { + if (mode != IGRAPH_ALL) { *res = nodes - 1; } else { - if (scale) { - *res = nodes - 2; - } else { - *res = (nodes - 2.0) / M_SQRT2; - } + *res = nodes - 2; } return IGRAPH_SUCCESS; diff --git a/src/vendor/cigraph/src/centrality/closeness.c b/src/vendor/cigraph/src/centrality/closeness.c index debba1e65cf..96a7b9fb410 100644 --- a/src/vendor/cigraph/src/centrality/closeness.c +++ b/src/vendor/cigraph/src/centrality/closeness.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -14,8 +12,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "igraph_centrality.h" @@ -135,19 +133,19 @@ static igraph_error_t igraph_i_closeness_cutoff_weighted(const igraph_t *graph, /* See igraph_distances_dijkstra() for the implementation details and the dirty tricks. */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_2wheap_t Q; igraph_vit_t vit; - igraph_integer_t nodes_to_calc; + igraph_int_t nodes_to_calc; igraph_lazy_inclist_t inclist; - igraph_integer_t i, j; + igraph_int_t i, j; igraph_vector_t dist; igraph_vector_int_t which; - igraph_integer_t nodes_reached; + igraph_int_t nodes_reached; igraph_real_t mindist = 0; @@ -190,18 +188,18 @@ static igraph_error_t igraph_i_closeness_cutoff_weighted(const igraph_t *graph, for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t source = IGRAPH_VIT_GET(vit); + igraph_int_t source = IGRAPH_VIT_GET(vit); igraph_2wheap_clear(&Q); - igraph_2wheap_push_with_index(&Q, source, -1.0); + igraph_2wheap_push_with_index(&Q, source, -1.0); /* reserved */ VECTOR(which)[source] = i + 1; VECTOR(dist)[source] = 1.0; /* actual distance is zero but we need to store distance + 1 */ nodes_reached = 0; while (!igraph_2wheap_empty(&Q)) { - igraph_integer_t minnei = igraph_2wheap_max_index(&Q); + igraph_int_t minnei = igraph_2wheap_max_index(&Q); /* Now check all neighbors of minnei for a shorter path */ igraph_vector_int_t *neis = igraph_lazy_inclist_get(&inclist, minnei); - igraph_integer_t nlen; + igraph_int_t nlen; IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); @@ -216,8 +214,8 @@ static igraph_error_t igraph_i_closeness_cutoff_weighted(const igraph_t *graph, nodes_reached++; for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*neis)[j]; - igraph_integer_t to = IGRAPH_OTHER(graph, edge, minnei); + igraph_int_t edge = VECTOR(*neis)[j]; + igraph_int_t to = IGRAPH_OTHER(graph, edge, minnei); igraph_real_t altdist = mindist + VECTOR(*weights)[edge]; igraph_real_t curdist = VECTOR(dist)[to]; @@ -302,8 +300,8 @@ static igraph_error_t igraph_i_closeness_cutoff_weighted(const igraph_t *graph, * reachable within the cutoff is returned. If false, the inverse * of the sum of distances is returned. * \param cutoff The maximal length of paths that will be considered. - * If negative, the exact closeness will be calculated (no upper - * limit on path lengths). + * If negative or \ref IGRAPH_UNLIMITED, the exact closeness will be + * calculated (no upper limit on path lengths). * \return Error code: * \clist * \cli IGRAPH_ENOMEM @@ -330,18 +328,18 @@ igraph_error_t igraph_closeness_cutoff(const igraph_t *graph, igraph_vector_t *r igraph_bool_t normalized, igraph_real_t cutoff) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t already_counted; igraph_vector_int_t *neis; - igraph_integer_t i, j; - igraph_integer_t nodes_reached; + igraph_int_t i, j; + igraph_int_t nodes_reached; igraph_adjlist_t allneis; - igraph_integer_t actdist = 0; + igraph_int_t actdist = 0; igraph_dqueue_int_t q; - igraph_integer_t nodes_to_calc; + igraph_int_t nodes_to_calc; igraph_vit_t vit; if (weights) { @@ -389,7 +387,7 @@ igraph_error_t igraph_closeness_cutoff(const igraph_t *graph, igraph_vector_t *r IGRAPH_ALLOW_INTERRUPTION(); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t act = igraph_dqueue_int_pop(&q); + igraph_int_t act = igraph_dqueue_int_pop(&q); actdist = igraph_dqueue_int_pop(&q); if (cutoff >= 0 && actdist > cutoff) { @@ -401,9 +399,9 @@ igraph_error_t igraph_closeness_cutoff(const igraph_t *graph, igraph_vector_t *r /* check the neighbors */ neis = igraph_adjlist_get(&allneis, act); - igraph_integer_t nei_count = igraph_vector_int_size(neis); + igraph_int_t nei_count = igraph_vector_int_size(neis); for (j = 0; j < nei_count; j++) { - igraph_integer_t neighbor = VECTOR(*neis)[j]; + igraph_int_t neighbor = VECTOR(*neis)[j]; if (VECTOR(already_counted)[neighbor] == i + 1) { continue; } @@ -452,17 +450,17 @@ static igraph_error_t igraph_i_harmonic_centrality_unweighted(const igraph_t *gr igraph_bool_t normalized, igraph_real_t cutoff) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t already_counted; igraph_vector_int_t *neis; - igraph_integer_t i, j; + igraph_int_t i, j; igraph_adjlist_t allneis; - igraph_integer_t actdist = 0; + igraph_int_t actdist = 0; igraph_dqueue_int_t q; - igraph_integer_t nodes_to_calc; + igraph_int_t nodes_to_calc; igraph_vit_t vit; IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); @@ -488,7 +486,7 @@ static igraph_error_t igraph_i_harmonic_centrality_unweighted(const igraph_t *gr !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t source = IGRAPH_VIT_GET(vit); + igraph_int_t source = IGRAPH_VIT_GET(vit); igraph_dqueue_int_clear(&q); IGRAPH_CHECK(igraph_dqueue_int_push(&q, source)); @@ -499,7 +497,7 @@ static igraph_error_t igraph_i_harmonic_centrality_unweighted(const igraph_t *gr IGRAPH_ALLOW_INTERRUPTION(); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t act = igraph_dqueue_int_pop(&q); + igraph_int_t act = igraph_dqueue_int_pop(&q); actdist = igraph_dqueue_int_pop(&q); if (cutoff >= 0 && actdist > cutoff) { @@ -513,9 +511,9 @@ static igraph_error_t igraph_i_harmonic_centrality_unweighted(const igraph_t *gr /* check the neighbors */ neis = igraph_adjlist_get(&allneis, act); - igraph_integer_t nei_count = igraph_vector_int_size(neis); + igraph_int_t nei_count = igraph_vector_int_size(neis); for (j = 0; j < nei_count; j++) { - igraph_integer_t neighbor = VECTOR(*neis)[j]; + igraph_int_t neighbor = VECTOR(*neis)[j]; if (VECTOR(already_counted)[neighbor] == i + 1) { continue; } @@ -554,15 +552,15 @@ static igraph_error_t igraph_i_harmonic_centrality_weighted(const igraph_t *grap /* See igraph_distances_dijkstra() for the implementation details and the dirty tricks. */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_2wheap_t Q; igraph_vit_t vit; - igraph_integer_t nodes_to_calc; + igraph_int_t nodes_to_calc; igraph_lazy_inclist_t inclist; - igraph_integer_t i, j; + igraph_int_t i, j; igraph_vector_t dist; igraph_vector_int_t which; @@ -600,17 +598,17 @@ static igraph_error_t igraph_i_harmonic_centrality_weighted(const igraph_t *grap for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t source = IGRAPH_VIT_GET(vit); + igraph_int_t source = IGRAPH_VIT_GET(vit); igraph_2wheap_clear(&Q); - igraph_2wheap_push_with_index(&Q, source, -1.0); + igraph_2wheap_push_with_index(&Q, source, -1.0); /* reserved */ VECTOR(which)[source] = i + 1; VECTOR(dist)[source] = 1.0; /* actual distance is zero but we need to store distance + 1 */ while (!igraph_2wheap_empty(&Q)) { - igraph_integer_t minnei = igraph_2wheap_max_index(&Q); + igraph_int_t minnei = igraph_2wheap_max_index(&Q); /* Now check all neighbors of minnei for a shorter path */ igraph_vector_int_t *neis = igraph_lazy_inclist_get(&inclist, minnei); - igraph_integer_t nlen; + igraph_int_t nlen; IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); @@ -627,8 +625,8 @@ static igraph_error_t igraph_i_harmonic_centrality_weighted(const igraph_t *grap } for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*neis)[j]; - igraph_integer_t to = IGRAPH_OTHER(graph, edge, minnei); + igraph_int_t edge = VECTOR(*neis)[j]; + igraph_int_t to = IGRAPH_OTHER(graph, edge, minnei); igraph_real_t altdist = mindist + VECTOR(*weights)[edge]; igraph_real_t curdist = VECTOR(dist)[to]; diff --git a/src/vendor/cigraph/src/centrality/coreness.c b/src/vendor/cigraph/src/centrality/coreness.c index e48d18f15be..9c383d8bb1a 100644 --- a/src/vendor/cigraph/src/centrality/coreness.c +++ b/src/vendor/cigraph/src/centrality/coreness.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -56,9 +55,9 @@ igraph_error_t igraph_coreness(const igraph_t *graph, igraph_vector_int_t *cores, igraph_neimode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t *bin, *vert, *pos; - igraph_integer_t maxdeg; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t *bin, *vert, *pos; + igraph_int_t maxdeg; igraph_vector_int_t neis; igraph_neimode_t omode; @@ -76,62 +75,64 @@ igraph_error_t igraph_coreness(const igraph_t *graph, return IGRAPH_SUCCESS; } - vert = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + vert = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(vert, "Insufficient memory for k-cores."); IGRAPH_FINALLY(igraph_free, vert); - pos = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + pos = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(pos, "Insufficient memory for k-cores."); IGRAPH_FINALLY(igraph_free, pos); /* maximum degree + degree of vertices */ - IGRAPH_CHECK(igraph_degree(graph, cores, igraph_vss_all(), mode, /* loops= */ true)); + IGRAPH_CHECK(igraph_degree(graph, cores, igraph_vss_all(), mode, IGRAPH_LOOPS)); /* null graph was already handled earlier, 'cores' is not empty */ maxdeg = igraph_vector_int_max(cores); - bin = IGRAPH_CALLOC(maxdeg + 1, igraph_integer_t); + bin = IGRAPH_CALLOC(maxdeg + 1, igraph_int_t); IGRAPH_CHECK_OOM(bin, "Insufficient memory for k-cores."); IGRAPH_FINALLY(igraph_free, bin); /* degree histogram */ - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { bin[ VECTOR(*cores)[i] ] += 1; } /* start pointers */ - for (igraph_integer_t d = 0, start = 0; d <= maxdeg; d++) { - igraph_integer_t k = bin[d]; + for (igraph_int_t d = 0, start = 0; d <= maxdeg; d++) { + igraph_int_t k = bin[d]; bin[d] = start; start += k; } /* sort in vert (and corrupt bin) */ - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { pos[i] = bin[VECTOR(*cores)[i]]; vert[pos[i]] = i; bin[VECTOR(*cores)[i]] += 1; } /* correct bin */ - for (igraph_integer_t d = maxdeg; d > 0; d--) { + for (igraph_int_t d = maxdeg; d > 0; d--) { bin[d] = bin[d - 1]; } bin[0] = 0; /* this is the main algorithm */ IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, maxdeg); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t v = vert[i]; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, omode)); - igraph_integer_t nei_count = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < nei_count; j++) { - igraph_integer_t u = VECTOR(neis)[j]; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t v = vert[i]; + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, v, omode, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); + igraph_int_t nei_count = igraph_vector_int_size(&neis); + for (igraph_int_t j = 0; j < nei_count; j++) { + igraph_int_t u = VECTOR(neis)[j]; if (VECTOR(*cores)[u] > VECTOR(*cores)[v]) { - igraph_integer_t du = VECTOR(*cores)[u]; - igraph_integer_t pu = pos[u]; - igraph_integer_t pw = bin[du]; - igraph_integer_t w = vert[pw]; + igraph_int_t du = VECTOR(*cores)[u]; + igraph_int_t pu = pos[u]; + igraph_int_t pw = bin[du]; + igraph_int_t w = vert[pw]; if (u != w) { pos[u] = pw; pos[w] = pu; diff --git a/src/vendor/cigraph/src/centrality/eigenvector.c b/src/vendor/cigraph/src/centrality/eigenvector.c index e9d017e261d..0cafd771df1 100644 --- a/src/vendor/cigraph/src/centrality/eigenvector.c +++ b/src/vendor/cigraph/src/centrality/eigenvector.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -14,35 +12,37 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "igraph_centrality.h" #include "igraph_adjlist.h" +#include "igraph_cycles.h" #include "igraph_interface.h" #include "igraph_random.h" #include "igraph_structural.h" -#include "igraph_topology.h" #include "centrality/centrality_internal.h" +#include #include +#include /* Multiplies vector 'from' by the unweighted adjacency matrix and stores the result in 'to'. */ static igraph_error_t adjmat_mul_unweighted(igraph_real_t *to, const igraph_real_t *from, int n, void *extra) { igraph_adjlist_t *adjlist = extra; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; for (i = 0; i < n; i++) { neis = igraph_adjlist_get(adjlist, i); nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; to[i] += from[nei]; } } @@ -65,15 +65,15 @@ static igraph_error_t adjmat_mul_weighted(igraph_real_t *to, const igraph_real_t const igraph_inclist_t *inclist = data->inclist; const igraph_vector_t *weights = data->weights; igraph_vector_int_t *edges; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; for (i = 0; i < n; i++) { edges = igraph_inclist_get(inclist, i); nlen = igraph_vector_int_size(edges); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*edges)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, i); + igraph_int_t edge = VECTOR(*edges)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, i); igraph_real_t w = VECTOR(*weights)[edge]; to[i] += w * from[nei]; } @@ -82,23 +82,48 @@ static igraph_error_t adjmat_mul_weighted(igraph_real_t *to, const igraph_real_t return IGRAPH_SUCCESS; } +/* Checks if any eigenvector centrality values are zero. If they are, it indicates that the + * graph is not (strongly) connected. Eigenvector centrality is not meaningful for such graphs. + * To account for numerical inaccuracies, a threshold of 'eps' is used when testing for zero. + * This function is intended to be used with eigenvector centrality values scaled such that + * the maximum is 1. 'eps' is chosen accordinly. + */ +static void warn_zero_entries(const igraph_vector_t *evcent) { + /* This is a conservative tolerance that will still catch most values + * which should be zero without being triggered by small yet truly + * nonzero values. + * See https://github.com/igraph/igraph/pull/2592 */ + const igraph_real_t tol = 10 * DBL_EPSILON; + const igraph_int_t n = igraph_vector_size(evcent); + + for (igraph_int_t i=0; i < n; i++) { + igraph_real_t x = VECTOR(*evcent)[i]; + if (-tol < x && x < tol) { + IGRAPH_WARNING("Some eigenvector centralities are nearly zero, indicating that the graph may not be (strongly) connected. " + "Eigenvector centrality is not meaningful for disconnected graphs."); + return; + } + } +} + static igraph_error_t igraph_i_eigenvector_centrality_undirected(const igraph_t *graph, igraph_vector_t *vector, - igraph_real_t *value, igraph_bool_t scale, + igraph_real_t *value, const igraph_vector_t *weights, igraph_arpack_options_t *options) { igraph_vector_t values; igraph_matrix_t vectors; igraph_vector_t degree; - igraph_integer_t i; - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t negative_weights = false; if (no_of_nodes > INT_MAX) { IGRAPH_ERROR("Graph has too many vertices for ARPACK.", IGRAPH_EOVERFLOW); } - if (igraph_ecount(graph) == 0) { + if (no_of_edges == 0) { /* special case: empty graph */ if (value) { *value = 0; @@ -107,16 +132,20 @@ static igraph_error_t igraph_i_eigenvector_centrality_undirected(const igraph_t IGRAPH_CHECK(igraph_vector_resize(vector, igraph_vcount(graph))); igraph_vector_fill(vector, 1); } + if (no_of_nodes > 1) { + IGRAPH_WARNING("The graph has no edges and is disconnected. " + "Eigenvector centrality is not meaningful for disconnected graphs."); + } return IGRAPH_SUCCESS; } if (weights) { igraph_real_t min, max; - if (igraph_vector_size(weights) != igraph_ecount(graph)) { + if (igraph_vector_size(weights) != no_of_edges) { IGRAPH_ERRORF("Weights vector length (%" IGRAPH_PRId ") not equal to " "number of edges (%" IGRAPH_PRId ").", IGRAPH_EINVAL, - igraph_vector_size(weights), igraph_ecount(graph)); + igraph_vector_size(weights), no_of_edges); } /* Safe to call minmax, ecount == 0 case was caught earlier */ igraph_vector_minmax(weights, &min, &max); @@ -129,6 +158,10 @@ static igraph_error_t igraph_i_eigenvector_centrality_undirected(const igraph_t IGRAPH_CHECK(igraph_vector_resize(vector, igraph_vcount(graph))); igraph_vector_fill(vector, 1); } + if (no_of_nodes > 1) { + IGRAPH_WARNING("All edge weights are zero, making the graph effectively disconnected. " + "Eigenvector centrality is not meaningful for disconnected graphs."); + } return IGRAPH_SUCCESS; } @@ -148,16 +181,24 @@ static igraph_error_t igraph_i_eigenvector_centrality_undirected(const igraph_t IGRAPH_VECTOR_INIT_FINALLY(°ree, no_of_nodes); IGRAPH_CHECK(igraph_strength(graph, °ree, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS, weights)); - RNG_BEGIN(); + for (i = 0; i < no_of_nodes; i++) { if (VECTOR(degree)[i]) { /* Note: Keep random perturbation non-negative. */ MATRIX(vectors, i, 0) = VECTOR(degree)[i] + RNG_UNIF(0, 1e-4); + } else if (! negative_weights) { + /* The eigenvector centrality of zero degree vertices is also zero. */ + MATRIX(vectors, i, 0) = 0.0; } else { - MATRIX(vectors, i, 0) = 0.01; + /* When negative weights are present, a zero strength may occur even + * if the degree is not zero, and some edges have non-zero weight. */ + igraph_int_t deg; + IGRAPH_CHECK(igraph_degree_1(graph, °, i, IGRAPH_ALL, IGRAPH_LOOPS)); + MATRIX(vectors, i, 0) = deg == 0 ? 0.0 : 1.0; } + } - RNG_END(); + igraph_vector_destroy(°ree); IGRAPH_FINALLY_CLEAN(1); @@ -200,41 +241,28 @@ static igraph_error_t igraph_i_eigenvector_centrality_undirected(const igraph_t } if (vector) { - igraph_real_t amax = 0; - igraph_integer_t which = 0; IGRAPH_CHECK(igraph_vector_resize(vector, no_of_nodes)); - if (!negative_weights && VECTOR(values)[0] <= 0) { - /* Pathological case: largest eigenvalue is zero, therefore all the - * scores can also be zeros, this will be a valid eigenvector. - * This usually happens with graphs that have lots of sinks and - * sources only. */ - igraph_vector_fill(vector, 0); - VECTOR(values)[0] = 0; - } else { + /* Note: With non-negative weights, a zero eigenvalue should only occur + * when there are no edges, or all edge have zero weight. This case is + * caught earlier. Thus we do not handle the case of zero eigenvalues here .*/ + + for (i = 0; i < no_of_nodes; i++) { + VECTOR(*vector)[i] = MATRIX(vectors, i, 0); + } + + /* Scale result so that the largest value is 1.0. */ + igraph_i_vector_scale_by_max_abs(vector); + + /* Correction for numeric inaccuracies (eliminating -0.0) */ + if (! negative_weights) { for (i = 0; i < no_of_nodes; i++) { - igraph_real_t tmp; - VECTOR(*vector)[i] = MATRIX(vectors, i, 0); - tmp = fabs(VECTOR(*vector)[i]); - if (tmp > amax) { - amax = tmp; - which = i; + if (VECTOR(*vector)[i] < 0) { + VECTOR(*vector)[i] = 0; } } - if (scale && amax != 0) { - igraph_vector_scale(vector, 1 / VECTOR(*vector)[which]); - } else if (igraph_i_vector_mostly_negative(vector)) { - igraph_vector_scale(vector, -1.0); - } - /* Correction for numeric inaccuracies (eliminating -0.0) */ - if (! negative_weights) { - for (i = 0; i < no_of_nodes; i++) { - if (VECTOR(*vector)[i] < 0) { - VECTOR(*vector)[i] = 0; - } - } - } + warn_zero_entries(vector); } } @@ -254,7 +282,8 @@ static igraph_error_t igraph_i_eigenvector_centrality_undirected(const igraph_t } static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *graph, igraph_vector_t *vector, - igraph_real_t *value, igraph_bool_t scale, + igraph_real_t *value, + igraph_neimode_t mode, const igraph_vector_t *weights, igraph_arpack_options_t *options) { @@ -262,11 +291,13 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g igraph_matrix_t vectors; igraph_vector_t indegree; igraph_bool_t dag; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t i; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t negative_weights = false; - if (igraph_ecount(graph) == 0) { + mode = IGRAPH_REVERSE_MODE(mode); + + if (no_of_edges == 0) { /* special case: empty graph */ if (value) { *value = 0; @@ -275,16 +306,20 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g IGRAPH_CHECK(igraph_vector_resize(vector, igraph_vcount(graph))); igraph_vector_fill(vector, 1); } + if (no_of_nodes > 1) { + IGRAPH_WARNING("The graph has no edges and is disconnected. " + "Eigenvector centrality is not meaningful for disconnected graphs."); + } return IGRAPH_SUCCESS; } if (weights) { igraph_real_t min, max; - if (igraph_vector_size(weights) != igraph_ecount(graph)) { + if (igraph_vector_size(weights) != no_of_edges) { IGRAPH_ERRORF("Weights vector length (%" IGRAPH_PRId ") not equal to " "number of edges (%" IGRAPH_PRId ").", IGRAPH_EINVAL, - igraph_vector_size(weights), igraph_ecount(graph)); + igraph_vector_size(weights), no_of_edges); } /* Safe to call minmax, ecount == 0 case was caught earlier */ @@ -305,6 +340,10 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g IGRAPH_CHECK(igraph_vector_resize(vector, igraph_vcount(graph))); igraph_vector_fill(vector, 1); } + if (no_of_nodes > 1) { + IGRAPH_WARNING("All edge weights are zero, making the graph effectively disconnected. " + "Eigenvector centrality is not meaningful for disconnected graphs."); + } return IGRAPH_SUCCESS; } } @@ -339,8 +378,11 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g *value = 0; } if (vector) { - IGRAPH_CHECK(igraph_strength(graph, vector, igraph_vss_all(), IGRAPH_OUT, true, weights)); - for (i=0; i < no_of_nodes; i++) { + IGRAPH_CHECK(igraph_strength( + graph, vector, igraph_vss_all(), IGRAPH_REVERSE_MODE(mode), + IGRAPH_LOOPS, weights + )); + for (igraph_int_t i=0; i < no_of_nodes; i++) { if (VECTOR(*vector)[i] == 0) { VECTOR(*vector)[i] = 1; } else { @@ -372,24 +414,31 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes); IGRAPH_CHECK(igraph_strength(graph, &indegree, igraph_vss_all(), - IGRAPH_IN, IGRAPH_LOOPS, weights)); - RNG_BEGIN(); - for (i = 0; i < no_of_nodes; i++) { + mode, IGRAPH_LOOPS, weights)); + + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(indegree)[i]) { /* Note: Keep random perturbation non-negative. */ MATRIX(vectors, i, 0) = VECTOR(indegree)[i] + RNG_UNIF(0, 1e-4); + } else if (! negative_weights) { + /* The eigenvector centrality of zero in-degree vertices is also zero. */ + MATRIX(vectors, i, 0) = 0.0; } else { - MATRIX(vectors, i, 0) = 0.01; + /* When negative weights are present, a zero in-strength may occur even + * if the in-degree is not zero, and some in-edges have non-zero weight. */ + igraph_int_t deg; + IGRAPH_CHECK(igraph_degree_1(graph, °, i, mode, IGRAPH_LOOPS)); + MATRIX(vectors, i, 0) = deg == 0 ? 0.0 : 1.0; } } - RNG_END(); + igraph_vector_destroy(&indegree); IGRAPH_FINALLY_CLEAN(1); if (!weights) { igraph_adjlist_t adjlist; - IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_IN, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE)); + IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, mode, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); IGRAPH_CHECK(igraph_arpack_rnsolve(adjmat_mul_unweighted, @@ -406,7 +455,7 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g data.inclist = &inclist; data.weights = weights; - IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_IN, IGRAPH_LOOPS_ONCE)); + IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, mode, IGRAPH_LOOPS_ONCE)); IGRAPH_FINALLY(igraph_inclist_destroy, &inclist); IGRAPH_CHECK(igraph_arpack_rnsolve(adjmat_mul_weighted, @@ -417,9 +466,6 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g } if (vector) { - igraph_real_t amax = 0; - igraph_integer_t which = 0; - IGRAPH_CHECK(igraph_vector_resize(vector, options->n)); if (!negative_weights && MATRIX(values, 0, 0) <= 0) { @@ -430,29 +476,23 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g igraph_vector_fill(vector, 0); MATRIX(values, 0, 0) = 0; } else { - for (i = 0; i < no_of_nodes; i++) { - igraph_real_t tmp; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { VECTOR(*vector)[i] = MATRIX(vectors, i, 0); - tmp = fabs(VECTOR(*vector)[i]); - if (tmp > amax) { - amax = tmp; - which = i; - } - } - if (scale && amax != 0) { - igraph_vector_scale(vector, 1 / VECTOR(*vector)[which]); - } else if (igraph_i_vector_mostly_negative(vector)) { - igraph_vector_scale(vector, -1.0); } + + /* Scale result so that the largest value is 1.0. */ + igraph_i_vector_scale_by_max_abs(vector); } /* Correction for numeric inaccuracies (eliminating -0.0) */ if (! negative_weights) { - for (i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(*vector)[i] < 0) { VECTOR(*vector)[i] = 0; } } + + warn_zero_entries(vector); } } @@ -483,7 +523,13 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g * vertex is proportional to the sum of eigenvector centralities of its * neighbors. In practice, the centralities are determined by calculating the * eigenvector corresponding to the largest positive eigenvalue of the - * adjacency matrix. In the undirected case, this function considers + * adjacency matrix. This is motivated by the fact that the principal + * eigenvector is guaranteed to be non-negative, assuming that edge weights + * are also non-negative. In fact, in connected undirected graphs, this is + * the \em only non-negative eigenvector. + * + * + * In the undirected case, this function considers * the diagonal entries of the adjacency matrix to be \em twice the number of * self-loops on the corresponding vertex. * @@ -495,35 +541,35 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g * are added up. * * - * The centrality scores returned by igraph can be normalized - * (using the \p scale parameter) such that the largest eigenvector centrality - * score is 1 (with one exception, see below). - * - * - * In the directed case, the left eigenvector of the adjacency matrix is - * calculated. In other words, the centrality of a vertex is proportional - * to the sum of centralities of vertices pointing to it. + * The centrality scores returned by igraph are normalized such that the largest + * eigenvector centrality score is 1, unless all scores are zeros. * * * Eigenvector centrality is meaningful only for (strongly) connected graphs. * Undirected graphs that are not connected should be decomposed into connected * components, and the eigenvector centrality calculated for each separately. - * The scores between components will not be comparable. - * This function does not verify that the graph is connected. If it is not, - * in the undirected case the scores of all but one component will be zeros. + * This function does not directly verify that the graph is connected. If it is + * not, in the undirected case the scores of all but one component will typically + * be zeros. When zeros are detected, a warning is issued. * * * Also note that the adjacency matrix of a directed acyclic graph or the * adjacency matrix of an empty graph does not possess positive eigenvalues, * therefore the eigenvector centrality is not meaningful for these graphs. * igraph will return an eigenvalue of zero in such cases. The returned - * eigenvector centralities will all be equal for vertices with zero out-degree, + * eigenvector centralities will all be equal for vertices with zero out-degree + * or zero in-degrees (depending on whether \p mode is \c IGRAPH_OUT or \c IGRAPH_IN) * and zeros for other vertices. Such pathological cases can be detected * by asking igraph to calculate the eigenvalue as well (using the \p value * parameter, see below) and checking whether the eigenvalue is very close * to zero. * * + * Eigenvector centrality was developed for networks with non-negative edge + * weights. While igraph does not refuse to carry out the calculation with + * negative weights, it will issue a warning. + * + * * When working with directed graphs, consider using hub and authority * scores instead, see \ref igraph_hub_and_authority_scores(). * @@ -533,10 +579,22 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g * be a null pointer, then it is ignored. * \param value If not a null pointer, then the eigenvalue * corresponding to the found eigenvector is stored here. - * \param directed Boolean scalar, whether to consider edge directions - * in a directed graph. It is ignored for undirected graphs. - * \param scale If not zero then the result will be scaled such that - * the absolute value of the maximum centrality is one. + * \param mode How to consider edge directions in directed graphs. + * It is ignored for undirected graphs. Possible values: + * \clist + * \cli IGRAPH_OUT + * the left eigenvector of the adjacency matrix is calculated, + * i.e. the centrality of a vertex is proportional to the sum + * of centralities of vertices pointing to it. This is the standard + * eigenvector centrality. + * \cli IGRAPH_IN + * the right eigenvector of the adjacency matrix is calculated, + * i.e. the centrality of a vertex is proportional to the sum + * of centralities of vertices it points to. + * \cli IGRAPH_ALL + * edge directions are ignored, and the unweighted eigenvector + * centrality is calculated. + * \endclist * \param weights A null pointer (indicating no edge weights), or a vector * giving the weights of the edges. Weights should be positive to guarantee * a meaningful result. The algorithm might produce complex numbers when some @@ -562,7 +620,7 @@ static igraph_error_t igraph_i_eigenvector_centrality_directed(const igraph_t *g igraph_error_t igraph_eigenvector_centrality(const igraph_t *graph, igraph_vector_t *vector, igraph_real_t *value, - igraph_bool_t directed, igraph_bool_t scale, + igraph_neimode_t mode, const igraph_vector_t *weights, igraph_arpack_options_t *options) { @@ -570,11 +628,19 @@ igraph_error_t igraph_eigenvector_centrality(const igraph_t *graph, options = igraph_arpack_options_get_default(); } - if (directed && igraph_is_directed(graph)) { - return igraph_i_eigenvector_centrality_directed(graph, vector, value, - scale, weights, options); - } else { + if (mode != IGRAPH_ALL && mode != IGRAPH_OUT && mode != IGRAPH_IN) { + IGRAPH_ERROR("Invalid mode for eigenvector centrality.", IGRAPH_EINVAL); + } + + if (! igraph_is_directed(graph)) { + mode = IGRAPH_ALL; + } + + if (mode == IGRAPH_ALL) { return igraph_i_eigenvector_centrality_undirected(graph, vector, value, - scale, weights, options); + weights, options); + } else { + return igraph_i_eigenvector_centrality_directed(graph, vector, value, + mode, weights, options); } } diff --git a/src/vendor/cigraph/src/centrality/hub_authority.c b/src/vendor/cigraph/src/centrality/hub_authority.c index a034c926a38..f74da43ecf0 100644 --- a/src/vendor/cigraph/src/centrality/hub_authority.c +++ b/src/vendor/cigraph/src/centrality/hub_authority.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -14,20 +12,20 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "igraph_centrality.h" #include "igraph_adjlist.h" -#include "igraph_blas.h" #include "igraph_interface.h" -#include "igraph_random.h" #include "igraph_structural.h" +#include "igraph_random.h" #include "centrality/centrality_internal.h" +#include #include /* struct for the unweighted variant of the HITS algorithm */ @@ -46,18 +44,59 @@ typedef struct igraph_i_kleinberg_data2_t { const igraph_vector_t *weights; } igraph_i_kleinberg_data2_t; +/* Checks if at least a certain fraction of HITS centrality scores are zero. + * Any zero value indicates that the graphs corresponding to A A^T and A^T A are + * not connected, and therefore the solution is not unique. However, this situation + * is fairly common, and difficult to control. Thefore we only warn if the number + * of zero values exceeds a certain fraction. + * + * To account for numerical inaccuracies, a threshold of 'eps' is used when testing for zero. + * This function is intended to be used with centrality values scaled such that + * the maximum is 1. 'eps' is chosen accordinly. + * + * See the analogous function used in igraph_eigenvector_centrality() for details + * on the choice of 'eps'. + */ +static void warn_zero_entries(const igraph_vector_t *cent) { + const igraph_real_t tol = 10 * DBL_EPSILON; + const igraph_real_t frac = 0.3; /* warn if at least this fraction of centralities is zero */ + const igraph_int_t n = igraph_vector_size(cent); + + /* Skip check for small graphs */ + if (n < 10) { + return; + } + + const igraph_int_t max_zero_cnt = ((igraph_int_t) (frac*n)); + igraph_int_t zero_cnt = 0; + + for (igraph_int_t i=0; i < n; i++) { + igraph_real_t x = VECTOR(*cent)[i]; + if (-tol < x && x < tol) { + if (++zero_cnt > max_zero_cnt) { + IGRAPH_WARNINGF( + "More than %d%% of hub or authority scores are zeros. The presence of zero values " + "indicates that the solution is not unique, thus the returned result may not be meaningful.", + (int) (frac * 100) + ); + return; + } + } + } +} + static igraph_error_t igraph_i_kleinberg_unweighted_hub_to_auth( - igraph_integer_t n, igraph_vector_t *to, const igraph_real_t *from, + igraph_int_t n, igraph_vector_t *to, const igraph_real_t *from, igraph_adjlist_t *in) { igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; for (i = 0; i < n; i++) { neis = igraph_adjlist_get(in, i); nlen = igraph_vector_int_size(neis); VECTOR(*to)[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; VECTOR(*to)[i] += from[nei]; } } @@ -72,7 +111,7 @@ static igraph_error_t igraph_i_kleinberg_unweighted(igraph_real_t *to, igraph_adjlist_t *out = data->out; igraph_vector_t *tmp = data->tmp; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; igraph_i_kleinberg_unweighted_hub_to_auth(n, tmp, from, data->in); @@ -81,7 +120,7 @@ static igraph_error_t igraph_i_kleinberg_unweighted(igraph_real_t *to, nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; to[i] += VECTOR(*tmp)[nei]; } } @@ -89,18 +128,18 @@ static igraph_error_t igraph_i_kleinberg_unweighted(igraph_real_t *to, return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_kleinberg_weighted_hub_to_auth(igraph_integer_t n, +static igraph_error_t igraph_i_kleinberg_weighted_hub_to_auth(igraph_int_t n, igraph_vector_t *to, const igraph_real_t *from, igraph_inclist_t *in, const igraph_t *g, const igraph_vector_t *weights) { igraph_vector_int_t *neis; - igraph_integer_t nlen, i, j; + igraph_int_t nlen, i, j; for (i = 0; i < n; i++) { neis = igraph_inclist_get(in, i); nlen = igraph_vector_int_size(neis); VECTOR(*to)[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei_edge = VECTOR(*neis)[j]; - igraph_integer_t nei = IGRAPH_OTHER(g, nei_edge, i); + igraph_int_t nei_edge = VECTOR(*neis)[j]; + igraph_int_t nei = IGRAPH_OTHER(g, nei_edge, i); VECTOR(*to)[i] += from[nei] * VECTOR(*weights)[nei_edge]; } } @@ -118,7 +157,7 @@ static igraph_error_t igraph_i_kleinberg_weighted(igraph_real_t *to, const igraph_vector_t *weights = data->weights; const igraph_t *g = data->graph; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; igraph_i_kleinberg_weighted_hub_to_auth(n, tmp, from, data->in, g, weights); @@ -127,8 +166,8 @@ static igraph_error_t igraph_i_kleinberg_weighted(igraph_real_t *to, nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei_edge = VECTOR(*neis)[j]; - igraph_integer_t nei = IGRAPH_OTHER(g, nei_edge, i); + igraph_int_t nei_edge = VECTOR(*neis)[j]; + igraph_int_t nei = IGRAPH_OTHER(g, nei_edge, i); to[i] += VECTOR(*tmp)[nei] * VECTOR(*weights)[nei_edge]; } } @@ -151,48 +190,64 @@ static igraph_error_t igraph_i_kleinberg_weighted(igraph_real_t *to, * The hub and authority scores of the vertices are defined as the principal * eigenvectors of A A^T and A^T A, respectively, * where A is the adjacency matrix of the graph and A^T - * is its transposed. + * is its transpose. The motivation for choosing the principal eigenvector + * is that it is guaranteed to be non-negative when edge weights are also + * non-negative. * * - * If vector \c h and \c a contain hub and authority scores, then the two - * scores are related by h = Aa and a = A^T h. + * If vectors \c h and \c a contain hub and authority scores, then the two + * scores are related by h = A a and a = A^T h. * When the principal eigenvalue of A A^T is degenerate, there * is no unique solution to the hub- and authority-score problem. * igraph guarantees that the scores that are returned are matching, i.e. are * related by these formulas, even in this situation. * * + * Note that hub and authority scores are not well behaved in extremely sparse + * graphs where no single connected component dominates the undirected graphs + * corresponding to A A^T and A^T A. In these cases, + * there are many different non-negative eigenvectors, all reasonable solutions + * to the HITS equations. The symptom of such a situation is that a large + * fraction of the scores are zeros. igraph issues a warning when this is + * detected. + * + * + * Results are scaled so that the largest hub and authority scores are both 1. + * + * * The concept of hub and authority scores were developed for \em directed graphs. * In undirected graphs, both the hub and authority scores are equal to the * eigenvector centrality, which can be computed using * \ref igraph_eigenvector_centrality(). * * + * HITS scores were developed for networks with non-negative edge weights. + * While igraph does not refuse to carry out the calculation with negative + * weights, it will issue a warning. + * + * * See the following reference on the meaning of this score: * J. Kleinberg. Authoritative sources in a hyperlinked * environment. \emb Proc. 9th ACM-SIAM Symposium on Discrete * Algorithms, \eme 1998. Extended version in \emb Journal of the - * ACM \eme 46(1999). + * ACM \eme 46 (1999). * https://doi.org/10.1145/324133.324140 - * Also appears as IBM Research Report RJ 10076, May - * 1997. + * Also appears as IBM Research Report RJ 10076, May 1997. * * \param graph The input graph. Can be directed and undirected. * \param hub_vector Pointer to an initialized vector, the hub scores are * stored here. If a null pointer then it is ignored. - * \param authority_vector Pointer to an initialized vector, the authority scores are - * stored here. If a null pointer then it is ignored. + * \param authority_vector Pointer to an initialized vector, the authority + * scores are stored here. If a null pointer then it is ignored. * \param value If not a null pointer then the eigenvalue * corresponding to the calculated eigenvectors is stored here. - * \param scale If not zero then the result will be scaled such that - * the absolute value of the maximum centrality is one. * \param weights A null pointer (meaning no edge weights), or a vector * giving the weights of the edges. * \param options Options to ARPACK. See \ref igraph_arpack_options_t - * for details. Supply \c NULL here to use the defaults. Note that the function - * overwrites the n (number of vertices) parameter and - * it always starts the calculation from a vector calculated based - * on the degree of the vertices. + * for details. Supply \c NULL here to use the defaults. Note that the + * function overwrites the n (number of vertices) parameter + * and it always starts the calculation from a vector calculated based on + * the degree of the vertices. * \return Error code. * * Time complexity: depends on the input graph, usually it is O(|V|), @@ -204,7 +259,7 @@ static igraph_error_t igraph_i_kleinberg_weighted(igraph_real_t *to, */ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, igraph_vector_t *hub_vector, igraph_vector_t *authority_vector, - igraph_real_t *value, igraph_bool_t scale, + igraph_real_t *value, const igraph_vector_t *weights, igraph_arpack_options_t *options) { /* The current implementation computes hub scores, i.e the principal @@ -213,7 +268,7 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, igraph_adjlist_t inadjlist, outadjlist; igraph_inclist_t ininclist, outinclist; - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_t tmp; igraph_vector_t values; igraph_matrix_t vectors; @@ -223,10 +278,43 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, igraph_vector_t my_hub_vector; igraph_bool_t negative_weights = false; + if (! igraph_is_directed(graph)) { + /* In undirected graphs, hub and authority scores are the same as eigenvector + * centralities. We issue a warning to avoid user confusion. + * If Ax = lambda x then A^2 x = lambda^2 x. Therefore the principal + * eigenvector of A is also a principal eigenvector of A^2. However, + * if both lambda and -lambda are eigenvalues of A, then the lambda^2 + * eigenvalue of A^2 will be degenerate. This happens for example in + * an even cycle graph where 2 and -2 are the largest eigenvalues in magnitude, + * therefore 4 is a degenerate eigenvalue of A^2, with eigenspace spanned by + * (0, 1, 0, 1, ...) and (1, 0, 1, ...). The vector (1, 1, ...), which + * would be expected by users based on symmetry considerations, may not be + * returned. We avoid such issues by falling back to igraph_eigenvector_centrality() */ + + IGRAPH_WARNING("Hub and authority scores requested for undirected graph. " + "These are the same as eigenvector centralities."); + if (! hub_vector) { + IGRAPH_VECTOR_INIT_FINALLY(&my_hub_vector, no_of_nodes); + my_hub_vector_p = &my_hub_vector; + } else { + my_hub_vector_p = hub_vector; + } + IGRAPH_CHECK(igraph_eigenvector_centrality(graph, my_hub_vector_p, value, IGRAPH_ALL, weights, options)); + *value = (*value) * (*value); /* adjust the eigenvalue, see comment at top */ + if (authority_vector) { + IGRAPH_CHECK(igraph_vector_update(authority_vector, my_hub_vector_p)); + } + if (! hub_vector) { + igraph_vector_destroy(&my_hub_vector); + IGRAPH_FINALLY_CLEAN(1); + } + return IGRAPH_SUCCESS; + } + if (igraph_ecount(graph) == 0) { /* special case: empty graph */ if (value) { - *value = igraph_ecount(graph) ? 1.0 : IGRAPH_NAN; + *value = 0; } if (hub_vector) { IGRAPH_CHECK(igraph_vector_resize(hub_vector, no_of_nodes)); @@ -236,6 +324,9 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_resize(authority_vector, no_of_nodes)); igraph_vector_fill(authority_vector, 1.0); } + if (no_of_nodes > 1) { + IGRAPH_WARNING("The graph has no edges. Hub and authority scores are not meaningful."); + } return IGRAPH_SUCCESS; } @@ -267,7 +358,7 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, if (min == 0 && max == 0) { /* special case: all weights are zeros */ if (value) { - *value = IGRAPH_NAN; + *value = 0; } if (hub_vector) { IGRAPH_CHECK(igraph_vector_resize(hub_vector, no_of_nodes)); @@ -277,12 +368,13 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_resize(authority_vector, no_of_nodes)); igraph_vector_fill(authority_vector, 1); } + IGRAPH_WARNING("All edge weights are zero. Hub and authority scores are not meaningful."); return IGRAPH_SUCCESS; } } if (no_of_nodes > INT_MAX) { - IGRAPH_ERROR("Graph has too many vertices for ARPACK", IGRAPH_EOVERFLOW); + IGRAPH_ERROR("Graph has too many vertices for ARPACK.", IGRAPH_EOVERFLOW); } if (!options) { @@ -308,17 +400,25 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, IGRAPH_FINALLY(igraph_inclist_destroy, &outinclist); } + /* We calculate hub scores, which correlate with out-degrees / out-strengths. + * Thus we use out-strengths as starting values. */ IGRAPH_CHECK(igraph_strength(graph, &tmp, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS, weights)); - RNG_BEGIN(); - for (igraph_integer_t i = 0; i < options->n; i++) { + + for (igraph_int_t i = 0; i < options->n; i++) { if (VECTOR(tmp)[i] != 0) { /* Note: Keep random perturbation non-negative. */ MATRIX(vectors, i, 0) = VECTOR(tmp)[i] + RNG_UNIF(0, 1e-4); + } else if (! negative_weights) { + /* The hub score of zero out-degree vertices is also zero. */ + MATRIX(vectors, i, 0) = 0.0; } else { - MATRIX(vectors, i, 0) = 0.01; + /* When negative weights are present, a zero out-strength may occur even + * if the out-degree is not zero, and some out-edges have non-zero weight. */ + igraph_int_t deg; + IGRAPH_CHECK(igraph_degree_1(graph, °, i, IGRAPH_OUT, /* loops */ true)); + MATRIX(vectors, i, 0) = deg == 0 ? 0.0 : 1.0; } } - RNG_END(); extra.in = &inadjlist; extra.out = &outadjlist; extra.tmp = &tmp; extra2.in = &ininclist; extra2.out = &outinclist; extra2.tmp = &tmp; @@ -336,7 +436,6 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, options, 0, &values, &vectors)); } - if (value) { *value = VECTOR(values)[0]; } @@ -348,33 +447,24 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, } else { my_hub_vector_p = hub_vector; } - igraph_real_t amax = 0; - igraph_integer_t which = 0; IGRAPH_CHECK(igraph_vector_resize(my_hub_vector_p, options->n)); - for (igraph_integer_t i = 0; i < options->n; i++) { - igraph_real_t tmp; + for (igraph_int_t i = 0; i < options->n; i++) { VECTOR(*my_hub_vector_p)[i] = MATRIX(vectors, i, 0); - tmp = fabs(VECTOR(*my_hub_vector_p)[i]); - if (tmp > amax) { - amax = tmp; - which = i; - } - } - if (scale && amax != 0) { - igraph_vector_scale(my_hub_vector_p, 1 / VECTOR(*my_hub_vector_p)[which]); - } else if (igraph_i_vector_mostly_negative(my_hub_vector_p)) { - igraph_vector_scale(my_hub_vector_p, -1.0); } + igraph_i_vector_scale_by_max_abs(my_hub_vector_p); + /* Correction for numeric inaccuracies (eliminating -0.0) */ if (! negative_weights) { - for (igraph_integer_t i = 0; i < options->n; i++) { + for (igraph_int_t i = 0; i < options->n; i++) { if (VECTOR(*my_hub_vector_p)[i] < 0) { VECTOR(*my_hub_vector_p)[i] = 0; } } } + + warn_zero_entries(my_hub_vector_p); } if (options->info) { @@ -385,7 +475,6 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, IGRAPH_FINALLY_CLEAN(2); if (authority_vector) { - igraph_real_t norm; IGRAPH_CHECK(igraph_vector_resize(authority_vector, no_of_nodes)); igraph_vector_null(authority_vector); if (weights == NULL) { @@ -393,12 +482,7 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, } else { igraph_i_kleinberg_weighted_hub_to_auth(no_of_nodes, authority_vector, &VECTOR(*my_hub_vector_p)[0], &ininclist, graph, weights); } - if (!scale) { - norm = 1.0 / igraph_blas_dnrm2(authority_vector); - } else { - norm = 1.0 / igraph_vector_max(authority_vector); - } - igraph_vector_scale(authority_vector, norm); + igraph_i_vector_scale_by_max_abs(authority_vector); } if (!hub_vector && authority_vector) { @@ -419,105 +503,3 @@ igraph_error_t igraph_hub_and_authority_scores(const igraph_t *graph, return IGRAPH_SUCCESS; } - -/** - * \function igraph_hub_score - * \brief Kleinberg's hub scores. - * - * \deprecated-by igraph_hub_and_authority_scores 0.10.5 - * - * The hub scores of the vertices are defined as the principal - * eigenvector of A A^T, where A is the adjacency - * matrix of the graph, A^T is its transposed. - * - * - * See the following reference on the meaning of this score: - * J. Kleinberg. Authoritative sources in a hyperlinked - * environment. \emb Proc. 9th ACM-SIAM Symposium on Discrete - * Algorithms, \eme 1998. Extended version in \emb Journal of the - * ACM \eme 46(1999). Also appears as IBM Research Report RJ 10076, May - * 1997. - * - * \param graph The input graph. Can be directed and undirected. - * \param vector Pointer to an initialized vector, the result is - * stored here. If a null pointer then it is ignored. - * \param value If not a null pointer then the eigenvalue - * corresponding to the calculated eigenvector is stored here. - * \param scale If not zero then the result will be scaled such that - * the absolute value of the maximum centrality is one. - * \param weights A null pointer (=no edge weights), or a vector - * giving the weights of the edges. - * \param options Options to ARPACK. See \ref igraph_arpack_options_t - * for details. Note that the function overwrites the - * n (number of vertices) parameter and - * it always starts the calculation from a non-random vector - * calculated based on the degree of the vertices. - * \return Error code. - * - * Time complexity: depends on the input graph, usually it is O(|V|), - * the number of vertices. - * - * \sa \ref igraph_hub_and_authority_scores() to compute - * hub and authrotity scores efficiently at the same time, - * \ref igraph_authority_score() for the companion measure, - * \ref igraph_pagerank(), \ref igraph_personalized_pagerank(), - * \ref igraph_eigenvector_centrality() for similar measures. - */ - -igraph_error_t igraph_hub_score(const igraph_t *graph, igraph_vector_t *vector, - igraph_real_t *value, igraph_bool_t scale, - const igraph_vector_t *weights, - igraph_arpack_options_t *options) { - return igraph_hub_and_authority_scores(graph, vector, NULL, value, scale, weights, options); -} - -/** - * \function igraph_authority_score - * \brief Kleinberg's authority scores. - * - * \deprecated-by igraph_hub_and_authority_scores 0.10.5 - * - * The authority scores of the vertices are defined as the principal - * eigenvector of A^T A, where A is the adjacency - * matrix of the graph, A^T is its transposed. - * - * - * See the following reference on the meaning of this score: - * J. Kleinberg. Authoritative sources in a hyperlinked - * environment. \emb Proc. 9th ACM-SIAM Symposium on Discrete - * Algorithms, \eme 1998. Extended version in \emb Journal of the - * ACM \eme 46(1999). Also appears as IBM Research Report RJ 10076, May - * 1997. - * - * \param graph The input graph. Can be directed and undirected. - * \param vector Pointer to an initialized vector, the result is - * stored here. If a null pointer then it is ignored. - * \param value If not a null pointer then the eigenvalue - * corresponding to the calculated eigenvector is stored here. - * \param scale If not zero then the result will be scaled such that - * the absolute value of the maximum centrality is one. - * \param weights A null pointer (=no edge weights), or a vector - * giving the weights of the edges. - * \param options Options to ARPACK. See \ref igraph_arpack_options_t - * for details. Note that the function overwrites the - * n (number of vertices) parameter and - * it always starts the calculation from a non-random vector - * calculated based on the degree of the vertices. - * \return Error code. - * - * Time complexity: depends on the input graph, usually it is O(|V|), - * the number of vertices. - * - * \sa \ref igraph_hub_and_authority_scores() to compute - * hub and authrotity scores efficiently at the same time, - * \ref igraph_hub_score() for the companion measure, - * \ref igraph_pagerank(), \ref igraph_personalized_pagerank(), - * \ref igraph_eigenvector_centrality() for similar measures. - */ - -igraph_error_t igraph_authority_score(const igraph_t *graph, igraph_vector_t *vector, - igraph_real_t *value, igraph_bool_t scale, - const igraph_vector_t *weights, - igraph_arpack_options_t *options) { - return igraph_hub_and_authority_scores(graph, NULL, vector, value, scale, weights, options); -} diff --git a/src/vendor/cigraph/src/centrality/pagerank.c b/src/vendor/cigraph/src/centrality/pagerank.c index 04115c21fe5..d216c582dde 100644 --- a/src/vendor/cigraph/src/centrality/pagerank.c +++ b/src/vendor/cigraph/src/centrality/pagerank.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -14,8 +12,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "igraph_centrality.h" @@ -68,7 +66,7 @@ static igraph_error_t pagerank_operator_unweighted(igraph_real_t *to, const igra igraph_vector_t *tmp = data->tmp; igraph_vector_t *reset = data->reset; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; igraph_real_t sumfrom = 0.0; igraph_real_t fact = 1 - data->damping; @@ -94,7 +92,7 @@ static igraph_error_t pagerank_operator_unweighted(igraph_real_t *to, const igra nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; to[i] += VECTOR(*tmp)[nei]; } to[i] *= data->damping; @@ -131,7 +129,7 @@ static igraph_error_t pagerank_operator_weighted(igraph_real_t *to, const igraph igraph_vector_t *outdegree = data->outdegree; igraph_vector_t *tmp = data->tmp; igraph_vector_t *reset = data->reset; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; igraph_real_t sumfrom = 0.0; igraph_vector_int_t *neis; igraph_real_t fact = 1 - data->damping; @@ -161,8 +159,8 @@ static igraph_error_t pagerank_operator_weighted(igraph_real_t *to, const igraph nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*neis)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, i); + igraph_int_t edge = VECTOR(*neis)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, i); to[i] += VECTOR(*weights)[edge] * VECTOR(*tmp)[nei]; } to[i] *= data->damping; @@ -237,8 +235,9 @@ static igraph_error_t pagerank_operator_weighted(igraph_real_t *to, const igraph * https://doi.org/10.1016/S0169-7552(98)00110-X * * \param graph The graph object. - * \param algo The PageRank implementation to use. Possible values: - * \c IGRAPH_PAGERANK_ALGO_ARPACK, \c IGRAPH_PAGERANK_ALGO_PRPACK. + * \param weights Optional edge weights. May be a \c NULL pointer, + * meaning unweighted edges, or a vector of non-negative values + * of the same length as the number of edges. * \param vector Pointer to an initialized vector, the result is * stored here. It is resized as needed. * \param value Pointer to a real variable. When using \c IGRAPH_PAGERANK_ALGO_ARPACK, @@ -246,16 +245,15 @@ static igraph_error_t pagerank_operator_weighted(igraph_real_t *to, const igraph * expected to be exactly one. Checking this value can be used to diagnose cases * when ARPACK failed to converge to the leading eigenvector. * When using \c IGRAPH_PAGERANK_ALGO_PRPACK, this is always set to 1.0. + * \param damping The damping factor ("d" in the original paper). + * Must be a probability in the range [0, 1]. A commonly used value is 0.85. + * \param directed Boolean, whether to consider the directedness of + * the edges. This is ignored for undirected graphs. * \param vids The vertex IDs for which the PageRank is returned. This parameter * is only for convenience. Computing PageRank for fewer than all vertices will * not speed up the calculation. - * \param directed Boolean, whether to consider the directedness of - * the edges. This is ignored for undirected graphs. - * \param damping The damping factor ("d" in the original paper). - * Must be a probability in the range [0, 1]. A commonly used value is 0.85. - * \param weights Optional edge weights. May be a \c NULL pointer, - * meaning unweighted edges, or a vector of non-negative values - * of the same length as the number of edges. + * \param algo The PageRank implementation to use. Possible values: + * \c IGRAPH_PAGERANK_ALGO_ARPACK, \c IGRAPH_PAGERANK_ALGO_PRPACK. * \param options Options for the ARPACK method. See \ref igraph_arpack_options_t * for details. Supply \c NULL here to use the defaults. Note that the function * overwrites the n (number of vertices), nev (1), @@ -276,15 +274,21 @@ static igraph_error_t pagerank_operator_weighted(igraph_real_t *to, const igraph * * \example examples/simple/igraph_pagerank.c */ - -igraph_error_t igraph_pagerank(const igraph_t *graph, igraph_pagerank_algo_t algo, - igraph_vector_t *vector, - igraph_real_t *value, const igraph_vs_t vids, - igraph_bool_t directed, igraph_real_t damping, - const igraph_vector_t *weights, igraph_arpack_options_t *options) { - return igraph_personalized_pagerank(graph, algo, vector, value, vids, - directed, damping, NULL, weights, - options); +igraph_error_t igraph_pagerank( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *vector, igraph_real_t *value, + igraph_real_t damping, igraph_bool_t directed, + igraph_vs_t vids, + igraph_pagerank_algo_t algo, + igraph_arpack_options_t *options) { + return igraph_personalized_pagerank( + graph, weights, + vector, value, + NULL, + damping, directed, + vids, + algo, + options); } /** @@ -313,8 +317,9 @@ igraph_error_t igraph_pagerank(const igraph_t *graph, igraph_pagerank_algo_t alg * does not result in any performance increase at all. * * \param graph The graph object. - * \param algo The PageRank implementation to use. Possible values: - * \c IGRAPH_PAGERANK_ALGO_ARPACK, \c IGRAPH_PAGERANK_ALGO_PRPACK. + * \param weights Optional edge weights, it is either a null pointer, + * then the edges are not weighted, or a vector of the same length + * as the number of edges. * \param vector Pointer to an initialized vector, the result is * stored here. It is resized as needed. * \param value Pointer to a real variable. When using \c IGRAPH_PAGERANK_ALGO_ARPACK, @@ -322,19 +327,18 @@ igraph_error_t igraph_pagerank(const igraph_t *graph, igraph_pagerank_algo_t alg * expected to be exactly one. Checking this value can be used to diagnose cases * when ARPACK failed to converge to the leading eigenvector. * When using \c IGRAPH_PAGERANK_ALGO_PRPACK, this is always set to 1.0. - * \param vids The vertex IDs for which the PageRank is returned. This parameter - * is only for convenience. Computing PageRank for fewer than all vertices will - * not speed up the calculation. - * \param directed Boolean, whether to consider the directedness of - * the edges. This is ignored for undirected graphs. - * \param damping The damping factor ("d" in the original paper). - * Must be a probability in the range [0, 1]. A commonly used value is 0.85. * \param reset_vids IDs of the vertices used when resetting the random walk. * The walk will be restarted from a vertex in this set, chosen uniformly at * random. Duplicate vertices are allowed. - * \param weights Optional edge weights, it is either a null pointer, - * then the edges are not weighted, or a vector of the same length - * as the number of edges. + * \param damping The damping factor ("d" in the original paper). + * Must be a probability in the range [0, 1]. A commonly used value is 0.85. + * \param directed Boolean, whether to consider the directedness of + * the edges. This is ignored for undirected graphs. + * \param vids The vertex IDs for which the PageRank is returned. This parameter + * is only for convenience. Computing PageRank for fewer than all vertices will + * not speed up the calculation. + * \param algo The PageRank implementation to use. Possible values: + * \c IGRAPH_PAGERANK_ALGO_ARPACK, \c IGRAPH_PAGERANK_ALGO_PRPACK. * \param options Options for the ARPACK method. See \ref igraph_arpack_options_t * for details. Supply \c NULL here to use the defaults. Note that the function * overwrites the n (number of vertices), nev (1), @@ -353,14 +357,15 @@ igraph_error_t igraph_pagerank(const igraph_t *graph, igraph_pagerank_algo_t alg * * \sa \ref igraph_pagerank() for the non-personalized implementation. */ +igraph_error_t igraph_personalized_pagerank_vs( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *vector, igraph_real_t *value, + igraph_vs_t reset_vids, + igraph_real_t damping, igraph_bool_t directed, + igraph_vs_t vids, + igraph_pagerank_algo_t algo, + igraph_arpack_options_t *options) { -igraph_error_t igraph_personalized_pagerank_vs(const igraph_t *graph, - igraph_pagerank_algo_t algo, igraph_vector_t *vector, - igraph_real_t *value, const igraph_vs_t vids, - igraph_bool_t directed, igraph_real_t damping, - igraph_vs_t reset_vids, - const igraph_vector_t *weights, - igraph_arpack_options_t *options) { igraph_vector_t reset; igraph_vit_t vit; @@ -377,9 +382,9 @@ igraph_error_t igraph_personalized_pagerank_vs(const igraph_t *graph, IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(igraph_personalized_pagerank( - graph, algo, vector, - value, vids, directed, - damping, &reset, weights, + graph, weights, vector, + value, &reset, + damping, directed, vids, algo, options)); igraph_vector_destroy(&reset); @@ -408,8 +413,9 @@ igraph_error_t igraph_personalized_pagerank_vs(const igraph_t *graph, * does not result in any performance increase at all. * * \param graph The graph object. - * \param algo The PageRank implementation to use. Possible values: - * \c IGRAPH_PAGERANK_ALGO_ARPACK, \c IGRAPH_PAGERANK_ALGO_PRPACK. + * \param weights Optional edge weights. May be a \c NULL pointer, + * meaning unweighted edges, or a vector of non-negative values + * of the same length as the number of edges. * \param vector Pointer to an initialized vector, the result is * stored here. It is resized as needed. * \param value Pointer to a real variable. When using \c IGRAPH_PAGERANK_ALGO_ARPACK, @@ -417,20 +423,19 @@ igraph_error_t igraph_personalized_pagerank_vs(const igraph_t *graph, * expected to be exactly one. Checking this value can be used to diagnose cases * when ARPACK failed to converge to the leading eigenvector. * When using \c IGRAPH_PAGERANK_ALGO_PRPACK, this is always set to 1.0. - * \param vids The vertex IDs for which the PageRank is returned. This parameter - * is only for convenience. Computing PageRank for fewer than all vertices will - * not speed up the calculation. - * \param directed Boolean, whether to consider the directedness of - * the edges. This is ignored for undirected graphs. - * \param damping The damping factor ("d" in the original paper). - * Must be a probability in the range [0, 1]. A commonly used value is 0.85. * \param reset The probability distribution over the vertices used when * resetting the random walk. It is either a \c NULL pointer (denoting * a uniform choice that results in the original PageRank measure) * or a vector of the same length as the number of vertices. - * \param weights Optional edge weights. May be a \c NULL pointer, - * meaning unweighted edges, or a vector of non-negative values - * of the same length as the number of edges. + * \param damping The damping factor ("d" in the original paper). + * Must be a probability in the range [0, 1]. A commonly used value is 0.85. + * \param directed Boolean, whether to consider the directedness of + * the edges. This is ignored for undirected graphs. + * \param vids The vertex IDs for which the PageRank is returned. This parameter + * is only for convenience. Computing PageRank for fewer than all vertices will + * not speed up the calculation. + * \param algo The PageRank implementation to use. Possible values: + * \c IGRAPH_PAGERANK_ALGO_ARPACK, \c IGRAPH_PAGERANK_ALGO_PRPACK. * \param options Options for the ARPACK method. See \ref igraph_arpack_options_t * for details. Supply \c NULL here to use the defaults. Note that the function * overwrites the n (number of vertices), nev (1), @@ -450,13 +455,14 @@ igraph_error_t igraph_personalized_pagerank_vs(const igraph_t *graph, * \ref igraph_personalized_pagerank_vs() for a personalized implementation * with resetting to specific vertices. */ -igraph_error_t igraph_personalized_pagerank(const igraph_t *graph, - igraph_pagerank_algo_t algo, igraph_vector_t *vector, - igraph_real_t *value, const igraph_vs_t vids, - igraph_bool_t directed, igraph_real_t damping, - const igraph_vector_t *reset, - const igraph_vector_t *weights, - igraph_arpack_options_t *options) { +igraph_error_t igraph_personalized_pagerank( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_t *vector, igraph_real_t *value, + const igraph_vector_t *reset, + igraph_real_t damping, igraph_bool_t directed, + igraph_vs_t vids, + igraph_pagerank_algo_t algo, + igraph_arpack_options_t *options) { if (damping < 0.0 || damping > 1.0) { IGRAPH_ERROR("The PageRank damping factor must be in the range [0,1].", IGRAPH_EINVAL); @@ -495,9 +501,9 @@ static igraph_error_t igraph_i_personalized_pagerank_arpack(const igraph_t *grap igraph_vector_t tmp; igraph_vector_t normalized_reset; - igraph_integer_t i; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t i; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_real_t reset_sum; /* used only when reset != NULL */ @@ -597,8 +603,6 @@ static igraph_error_t igraph_i_personalized_pagerank_arpack(const igraph_t *grap IGRAPH_VECTOR_INIT_FINALLY(&outdegree, options->n); IGRAPH_VECTOR_INIT_FINALLY(&tmp, options->n); - RNG_BEGIN(); - if (reset) { /* Normalize reset vector so the sum is 1 */ IGRAPH_CHECK(igraph_vector_init_copy(&normalized_reset, reset)); @@ -612,8 +616,8 @@ static igraph_error_t igraph_i_personalized_pagerank_arpack(const igraph_t *grap IGRAPH_CHECK(igraph_strength(graph, &indegree, igraph_vss_all(), directed ? IGRAPH_IN : IGRAPH_ALL, IGRAPH_LOOPS, weights)); - /* Set up an appropriate starting vector. We start from the (possibly weight) in-degrees - * plus some small random noise to avoid convergence problems. */ + /* Set up an appropriate starting vector. We start from the (possibly weighted) + * in-degrees plus some small random noise to avoid convergence problems. */ for (i = 0; i < no_of_nodes; i++) { if (VECTOR(indegree)[i] > 0) { /* Note: Keep random perturbation non-negative. */ @@ -667,8 +671,6 @@ static igraph_error_t igraph_i_personalized_pagerank_arpack(const igraph_t *grap IGRAPH_FINALLY_CLEAN(1); } - RNG_END(); - if (reset) { igraph_vector_destroy(&normalized_reset); IGRAPH_FINALLY_CLEAN(1); @@ -685,7 +687,7 @@ static igraph_error_t igraph_i_personalized_pagerank_arpack(const igraph_t *grap if (vector) { igraph_vit_t vit; - igraph_integer_t nodes_to_calc; + igraph_int_t nodes_to_calc; igraph_real_t sum = 0; for (i = 0; i < no_of_nodes; i++) { diff --git a/src/vendor/cigraph/src/centrality/prpack.cpp b/src/vendor/cigraph/src/centrality/prpack.cpp index ad3c73a284a..1391b28908f 100644 --- a/src/vendor/cigraph/src/centrality/prpack.cpp +++ b/src/vendor/cigraph/src/centrality/prpack.cpp @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -41,7 +40,7 @@ igraph_error_t igraph_i_personalized_pagerank_prpack(const igraph_t *graph, igra const igraph_vector_t *weights) { IGRAPH_HANDLE_EXCEPTIONS_BEGIN; - igraph_integer_t i, no_of_nodes = igraph_vcount(graph); + igraph_int_t i, no_of_nodes = igraph_vcount(graph); double *u = nullptr; std::unique_ptr v; @@ -113,7 +112,7 @@ igraph_error_t igraph_i_personalized_pagerank_prpack(const igraph_t *graph, igra igraph_vit_t vit; IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); - igraph_integer_t nodes_to_calc = IGRAPH_VIT_SIZE(vit); + igraph_int_t nodes_to_calc = IGRAPH_VIT_SIZE(vit); IGRAPH_CHECK(igraph_vector_resize(vector, nodes_to_calc)); for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { diff --git a/src/vendor/cigraph/src/centrality/prpack/prpack_igraph_graph.cpp b/src/vendor/cigraph/src/centrality/prpack/prpack_igraph_graph.cpp index fa84057660d..35cd85a7006 100644 --- a/src/vendor/cigraph/src/centrality/prpack/prpack_igraph_graph.cpp +++ b/src/vendor/cigraph/src/centrality/prpack/prpack_igraph_graph.cpp @@ -14,8 +14,8 @@ igraph_error_t prpack_igraph_graph::convert_from_igraph( const igraph_t *g, const igraph_vector_t *weights, bool directed) { const bool treat_as_directed = igraph_is_directed(g) && directed; - const igraph_integer_t vcount = igraph_vcount(g); - const igraph_integer_t ecount = igraph_ecount(g); + const igraph_int_t vcount = igraph_vcount(g); + const igraph_int_t ecount = igraph_ecount(g); double *p_weight; int *p_head; @@ -62,7 +62,7 @@ igraph_error_t prpack_igraph_graph::convert_from_igraph( IGRAPH_CHECK(igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_TO), &eit)); IGRAPH_FINALLY(igraph_eit_destroy, &eit); while (!IGRAPH_EIT_END(eit)) { - igraph_integer_t eid = IGRAPH_EIT_GET(eit); + igraph_int_t eid = IGRAPH_EIT_GET(eit); IGRAPH_EIT_NEXT(eit); // Handle the weight @@ -103,7 +103,7 @@ igraph_error_t prpack_igraph_graph::convert_from_igraph( IGRAPH_FINALLY(igraph_vector_int_destroy, &neis); for (int i = 0; i < num_vs; i++) { - IGRAPH_CHECK(igraph_incident(g, &neis, i, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(g, &neis, i, IGRAPH_ALL, IGRAPH_LOOPS)); int temp = igraph_vector_int_size(&neis); diff --git a/src/vendor/cigraph/src/centrality/prpack_internal.h b/src/vendor/cigraph/src/centrality/prpack_internal.h index 938a41e63ed..28b4b52296f 100644 --- a/src/vendor/cigraph/src/centrality/prpack_internal.h +++ b/src/vendor/cigraph/src/centrality/prpack_internal.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -31,7 +30,7 @@ #include "igraph_interface.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS igraph_error_t igraph_i_personalized_pagerank_prpack(const igraph_t *graph, igraph_vector_t *vector, igraph_real_t *value, const igraph_vs_t vids, @@ -39,6 +38,6 @@ igraph_error_t igraph_i_personalized_pagerank_prpack(const igraph_t *graph, igra const igraph_vector_t *reset, const igraph_vector_t *weights); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/centrality/truss.cpp b/src/vendor/cigraph/src/centrality/truss.cpp index 76e96478c32..13e1024a71e 100644 --- a/src/vendor/cigraph/src/centrality/truss.cpp +++ b/src/vendor/cigraph/src/centrality/truss.cpp @@ -47,11 +47,11 @@ using std::unordered_set; // So, instead of the triangle specified as vertices [1, 2, 3], return the // edges as [1, 2, 1, 3, 2, 3] so that the support can be computed. static igraph_error_t igraph_truss_i_unpack(const igraph_vector_int_t *tri, igraph_vector_int_t *unpacked_tri) { - igraph_integer_t num_triangles = igraph_vector_int_size(tri); + igraph_int_t num_triangles = igraph_vector_int_size(tri); IGRAPH_CHECK(igraph_vector_int_resize(unpacked_tri, 2 * num_triangles)); - for (igraph_integer_t i = 0, j = 0; i < num_triangles; i += 3, j += 6) { + for (igraph_int_t i = 0, j = 0; i < num_triangles; i += 3, j += 6) { VECTOR(*unpacked_tri)[j] = VECTOR(*unpacked_tri)[j+2] = VECTOR(*tri)[i]; VECTOR(*unpacked_tri)[j+1] = VECTOR(*unpacked_tri)[j+4] = VECTOR(*tri)[i+1]; VECTOR(*unpacked_tri)[j+3] = VECTOR(*unpacked_tri)[j+5] = VECTOR(*tri)[i+2]; @@ -64,8 +64,8 @@ static igraph_error_t igraph_truss_i_unpack(const igraph_vector_int_t *tri, igra // Compute the edge support, i.e. number of triangles each edge occurs in. // Time complexity: O(m), where m is the number of edges listed in eid. static void igraph_truss_i_compute_support(const igraph_vector_int_t *eid, igraph_vector_int_t *support) { - igraph_integer_t m = igraph_vector_int_size(eid); - for (igraph_integer_t i = 0; i < m; ++i) { + igraph_int_t m = igraph_vector_int_size(eid); + for (igraph_int_t i = 0; i < m; ++i) { VECTOR(*support)[VECTOR(*eid)[i]] += 1; } } @@ -81,10 +81,10 @@ static igraph_error_t igraph_i_trussness(const igraph_t *graph, igraph_vector_in igraph_vector_bool_t completed; // C++ data structures - vector< unordered_set > vec; + vector< unordered_set > vec; // Allocate memory for result - igraph_integer_t no_of_edges = igraph_vector_int_size(support); + igraph_int_t no_of_edges = igraph_vector_int_size(support); IGRAPH_CHECK(igraph_vector_int_resize(trussness, no_of_edges)); if (no_of_edges == 0) { return IGRAPH_SUCCESS; @@ -92,7 +92,7 @@ static igraph_error_t igraph_i_trussness(const igraph_t *graph, igraph_vector_in // Get max possible value = max entry in support. // This cannot be computed if there are no edges, hence the above check - igraph_integer_t max = igraph_vector_int_max(support); + igraph_int_t max = igraph_vector_int_max(support); // Initialize completed edges. IGRAPH_VECTOR_BOOL_INIT_FINALLY(&completed, no_of_edges); @@ -102,7 +102,7 @@ static igraph_error_t igraph_i_trussness(const igraph_t *graph, igraph_vector_in vec.resize(max + 1); // Add each edge to its appropriate level of support. - for (igraph_integer_t i = 0; i < no_of_edges; ++i) { + for (igraph_int_t i = 0; i < no_of_edges; ++i) { vec[VECTOR(*support)[i]].insert(i); // insert edge i into its support level } @@ -119,18 +119,18 @@ static igraph_error_t igraph_i_trussness(const igraph_t *graph, igraph_vector_in IGRAPH_VECTOR_INT_INIT_FINALLY(&commonNeighbors, 0); // Move through the levels, one level at a time, starting at first level. - for (igraph_integer_t level = 1; level <= max; ++level) { + for (igraph_int_t level = 1; level <= max; ++level) { /* Track down edges one at a time */ while (!vec[level].empty()) { IGRAPH_ALLOW_INTERRUPTION(); - igraph_integer_t seed = *vec[level].begin(); // pull out the first edge + igraph_int_t seed = *vec[level].begin(); // pull out the first edge vec[level].erase(seed); // remove the first element /* Find the vertices of this edge */ - igraph_integer_t fromVertex = IGRAPH_FROM(graph, seed); - igraph_integer_t toVertex = IGRAPH_TO(graph, seed); + igraph_int_t fromVertex = IGRAPH_FROM(graph, seed); + igraph_int_t toVertex = IGRAPH_TO(graph, seed); /* Find neighbors of both vertices. If they run into each other, * there is a triangle. We rely on the neighbor lists being sorted, @@ -150,10 +150,10 @@ static igraph_error_t igraph_i_trussness(const igraph_t *graph, igraph_vector_in IGRAPH_CHECK(igraph_vector_int_intersect_sorted(q1, q2, &commonNeighbors)); /* Go over the overlapping neighbors and check each */ - igraph_integer_t ncommon = igraph_vector_int_size(&commonNeighbors); - for (igraph_integer_t j = 0; j < ncommon; j++) { - igraph_integer_t n = VECTOR(commonNeighbors)[j]; // the common neighbor - igraph_integer_t e1, e2; + igraph_int_t ncommon = igraph_vector_int_size(&commonNeighbors); + for (igraph_int_t j = 0; j < ncommon; j++) { + igraph_int_t n = VECTOR(commonNeighbors)[j]; // the common neighbor + igraph_int_t e1, e2; IGRAPH_CHECK(igraph_get_eid(graph, &e1, fromVertex, n, IGRAPH_UNDIRECTED, /* error= */ true)); IGRAPH_CHECK(igraph_get_eid(graph, &e2, toVertex, n, IGRAPH_UNDIRECTED, /* error= */ true)); @@ -161,7 +161,7 @@ static igraph_error_t igraph_i_trussness(const igraph_t *graph, igraph_vector_in bool e2_complete = VECTOR(completed)[e2]; if (!e1_complete && !e2_complete) { - igraph_integer_t newLevel; + igraph_int_t newLevel; // Demote this edge, if higher than current level. if (VECTOR(*support)[e1] > level) { diff --git a/src/vendor/cigraph/src/cliques/cliquer_internal.h b/src/vendor/cigraph/src/cliques/cliquer_internal.h index 93e9897978e..009f24eb761 100644 --- a/src/vendor/cigraph/src/cliques/cliquer_internal.h +++ b/src/vendor/cigraph/src/cliques/cliquer_internal.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2016-2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -22,21 +22,23 @@ #include "igraph_decls.h" #include "igraph_cliques.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS igraph_error_t igraph_i_cliquer_cliques(const igraph_t *graph, igraph_vector_int_list_t *res, - igraph_integer_t min_size, igraph_integer_t max_size); + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); igraph_error_t igraph_i_cliquer_histogram(const igraph_t *graph, igraph_vector_t *hist, - igraph_integer_t min_size, igraph_integer_t max_size); + igraph_int_t min_size, igraph_int_t max_size); igraph_error_t igraph_i_cliquer_callback(const igraph_t *graph, - igraph_integer_t min_size, igraph_integer_t max_size, + igraph_int_t min_size, igraph_int_t max_size, igraph_clique_handler_t *cliquehandler_fn, void *arg); igraph_error_t igraph_i_weighted_cliques(const igraph_t *graph, const igraph_vector_t *vertex_weights, igraph_vector_int_list_t *res, - igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal); + igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal, + igraph_int_t max_results); igraph_error_t igraph_i_largest_weighted_cliques(const igraph_t *graph, const igraph_vector_t *vertex_weights, igraph_vector_int_list_t *res); @@ -44,6 +46,6 @@ igraph_error_t igraph_i_largest_weighted_cliques(const igraph_t *graph, igraph_error_t igraph_i_weighted_clique_number(const igraph_t *graph, const igraph_vector_t *vertex_weights, igraph_real_t *res); -__END_DECLS +IGRAPH_END_C_DECLS #endif // IGRAPH_CLIQUER_H diff --git a/src/vendor/cigraph/src/cliques/cliquer_wrapper.c b/src/vendor/cigraph/src/cliques/cliquer_wrapper.c index 25002f2ecaa..e01370db38f 100644 --- a/src/vendor/cigraph/src/cliques/cliquer_wrapper.c +++ b/src/vendor/cigraph/src/cliques/cliquer_wrapper.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2016-2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -35,8 +35,8 @@ static IGRAPH_THREAD_LOCAL clique_options igraph_cliquer_opt = { /* Convert an igraph graph to a Cliquer graph */ static igraph_error_t igraph_to_cliquer(const igraph_t *ig, graph_t **cg) { - igraph_integer_t vcount, ecount; - igraph_integer_t i; + igraph_int_t vcount, ecount; + igraph_int_t i; if (igraph_is_directed(ig)) { IGRAPH_WARNING("Edge directions are ignored for clique calculations."); @@ -52,7 +52,7 @@ static igraph_error_t igraph_to_cliquer(const igraph_t *ig, graph_t **cg) { *cg = graph_new((int) vcount); for (i = 0; i < ecount; ++i) { - igraph_integer_t s, t; + igraph_int_t s, t; s = IGRAPH_FROM(ig, i); t = IGRAPH_TO(ig, i); if (s != t) { @@ -66,7 +66,7 @@ static igraph_error_t igraph_to_cliquer(const igraph_t *ig, graph_t **cg) { /* Copy weights to a Cliquer graph */ static igraph_error_t set_weights(const igraph_vector_t *vertex_weights, graph_t *g) { - igraph_integer_t i; + igraph_int_t i; IGRAPH_ASSERT(vertex_weights != NULL); @@ -93,6 +93,7 @@ static igraph_error_t set_weights(const igraph_vector_t *vertex_weights, graph_t typedef struct { igraph_vector_int_t clique; igraph_vector_int_list_t* result; + igraph_int_t max_results; } igraph_i_cliquer_cliques_user_data_t; static igraph_error_t igraph_i_cliquer_cliques_user_data_init( @@ -100,6 +101,7 @@ static igraph_error_t igraph_i_cliquer_cliques_user_data_init( igraph_vector_int_list_t* result ) { data->result = result; + data->max_results = IGRAPH_UNLIMITED; igraph_vector_int_list_clear(result); return igraph_vector_int_init(&data->clique, 0); } @@ -113,7 +115,7 @@ static void igraph_i_cliquer_cliques_user_data_destroy( static igraph_error_t collect_cliques_callback(set_t s, graph_t *g, clique_options *opt) { int i; - igraph_integer_t j; + igraph_int_t j; igraph_i_cliquer_cliques_user_data_t* data = (igraph_i_cliquer_cliques_user_data_t *) opt->user_data; IGRAPH_UNUSED(g); @@ -129,16 +131,23 @@ static igraph_error_t collect_cliques_callback(set_t s, graph_t *g, clique_optio IGRAPH_CHECK(igraph_vector_int_list_push_back_copy(data->result, &data->clique)); - return IGRAPH_SUCCESS; + if (data->max_results > 0 && igraph_vector_int_list_size(data->result) == data->max_results) { + return IGRAPH_STOP; + } else { + return IGRAPH_SUCCESS; + } } -igraph_error_t igraph_i_cliquer_cliques(const igraph_t *graph, igraph_vector_int_list_t *res, - igraph_integer_t min_size, igraph_integer_t max_size) { +igraph_error_t igraph_i_cliquer_cliques( + const igraph_t *graph, igraph_vector_int_list_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results) { + graph_t *g; - igraph_integer_t vcount = igraph_vcount(graph); + igraph_int_t vcount = igraph_vcount(graph); igraph_i_cliquer_cliques_user_data_t data; - if (vcount == 0) { + if (vcount == 0 || max_results == 0) { igraph_vector_int_list_clear(res); return IGRAPH_SUCCESS; } @@ -162,6 +171,8 @@ igraph_error_t igraph_i_cliquer_cliques(const igraph_t *graph, igraph_vector_int IGRAPH_CHECK(igraph_i_cliquer_cliques_user_data_init(&data, res)); IGRAPH_FINALLY(igraph_i_cliquer_cliques_user_data_destroy, &data); + data.max_results = max_results; + IGRAPH_CHECK(igraph_to_cliquer(graph, &g)); IGRAPH_FINALLY(graph_free, g); @@ -194,10 +205,10 @@ static igraph_error_t count_cliques_callback(set_t s, graph_t *g, clique_options } igraph_error_t igraph_i_cliquer_histogram(const igraph_t *graph, igraph_vector_t *hist, - igraph_integer_t min_size, igraph_integer_t max_size) { + igraph_int_t min_size, igraph_int_t max_size) { graph_t *g; - igraph_integer_t i; - igraph_integer_t vcount = igraph_vcount(graph); + igraph_int_t i; + igraph_int_t vcount = igraph_vcount(graph); if (vcount == 0) { igraph_vector_clear(hist); @@ -257,7 +268,7 @@ struct callback_data { static igraph_error_t callback_callback(set_t s, graph_t *g, clique_options *opt) { struct callback_data *cd; int i; - igraph_integer_t j; + igraph_int_t j; igraph_error_t retval; IGRAPH_UNUSED(g); @@ -279,12 +290,12 @@ static igraph_error_t callback_callback(set_t s, graph_t *g, clique_options *opt } igraph_error_t igraph_i_cliquer_callback(const igraph_t *graph, - igraph_integer_t min_size, igraph_integer_t max_size, + igraph_int_t min_size, igraph_int_t max_size, igraph_clique_handler_t *cliquehandler_fn, void *arg) { graph_t *g; igraph_vector_int_t current_clique; struct callback_data cd; - igraph_integer_t vcount = igraph_vcount(graph); + igraph_int_t vcount = igraph_vcount(graph); if (vcount == 0) { return IGRAPH_SUCCESS; @@ -331,12 +342,13 @@ igraph_error_t igraph_i_cliquer_callback(const igraph_t *graph, igraph_error_t igraph_i_weighted_cliques(const igraph_t *graph, const igraph_vector_t *vertex_weights, igraph_vector_int_list_t *res, - igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal) { + igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal, + igraph_int_t max_results) { graph_t *g; - igraph_integer_t vcount = igraph_vcount(graph); + igraph_int_t vcount = igraph_vcount(graph); igraph_i_cliquer_cliques_user_data_t data; - if (vcount == 0) { + if (vcount == 0 || max_results == 0) { igraph_vector_int_list_clear(res); return IGRAPH_SUCCESS; } @@ -365,6 +377,7 @@ igraph_error_t igraph_i_weighted_cliques(const igraph_t *graph, IGRAPH_CHECK(igraph_i_cliquer_cliques_user_data_init(&data, res)); IGRAPH_FINALLY(igraph_i_cliquer_cliques_user_data_destroy, &data); + data.max_results = max_results; IGRAPH_CHECK(igraph_to_cliquer(graph, &g)); IGRAPH_FINALLY(graph_free, g); @@ -389,7 +402,7 @@ igraph_error_t igraph_i_weighted_cliques(const igraph_t *graph, igraph_error_t igraph_i_largest_weighted_cliques(const igraph_t *graph, const igraph_vector_t *vertex_weights, igraph_vector_int_list_t *res) { graph_t *g; - igraph_integer_t vcount = igraph_vcount(graph); + igraph_int_t vcount = igraph_vcount(graph); igraph_i_cliquer_cliques_user_data_t data; if (vcount == 0) { @@ -429,7 +442,7 @@ static igraph_error_t check_interruption_callback(set_t s, graph_t *g, clique_op igraph_error_t igraph_i_weighted_clique_number(const igraph_t *graph, const igraph_vector_t *vertex_weights, igraph_real_t *res) { graph_t *g; - igraph_integer_t vcount = igraph_vcount(graph); + igraph_int_t vcount = igraph_vcount(graph); int res_int; if (vcount == 0) { @@ -444,7 +457,7 @@ igraph_error_t igraph_i_weighted_clique_number(const igraph_t *graph, IGRAPH_CHECK(set_weights(vertex_weights, g)); - igraph_cliquer_opt.user_function = check_interruption_callback; + igraph_cliquer_opt.user_function = &check_interruption_callback; IGRAPH_CHECK(clique_max_weight(g, &igraph_cliquer_opt, &res_int)); diff --git a/src/vendor/cigraph/src/cliques/cliques.c b/src/vendor/cigraph/src/cliques/cliques.c index 63606b18e2f..83c29418465 100644 --- a/src/vendor/cigraph/src/cliques/cliques.c +++ b/src/vendor/cigraph/src/cliques/cliques.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -29,23 +28,23 @@ #include "core/set.h" static igraph_error_t igraph_i_find_k_indsets( - igraph_integer_t size, - const igraph_integer_t *member_storage, - igraph_integer_t **new_member_storage, - igraph_integer_t old_count, - igraph_integer_t *new_count, + igraph_int_t size, + const igraph_int_t *member_storage, + igraph_int_t **new_member_storage, + igraph_int_t old_count, + igraph_int_t *new_count, igraph_lazy_adjlist_t *al) { - igraph_integer_t l, m, n, new_member_storage_size; - const igraph_integer_t *c1, *c2; + igraph_int_t l, m, n, new_member_storage_size; + const igraph_int_t *c1, *c2; const igraph_vector_int_t *neis; - igraph_integer_t v1, v2; + igraph_int_t v1, v2; igraph_bool_t ok; /* Allocate the storage */ *new_member_storage = IGRAPH_REALLOC(*new_member_storage, (size_t) (size * old_count), - igraph_integer_t); + igraph_int_t); IGRAPH_CHECK_OOM(*new_member_storage, "Insufficient memory for independent vertex sets."); new_member_storage_size = size * old_count; @@ -54,8 +53,8 @@ static igraph_error_t igraph_i_find_k_indsets( m = n = 0; /* Now consider all pairs of i-1-indsets and see if they can be merged */ - for (igraph_integer_t j = 0; j < old_count; j++) { - for (igraph_integer_t k = j + 1; k < old_count; k++) { + for (igraph_int_t j = 0; j < old_count; j++) { + for (igraph_int_t k = j + 1; k < old_count; k++) { IGRAPH_ALLOW_INTERRUPTION(); /* Since indsets are represented by their vertex indices in increasing @@ -138,7 +137,7 @@ static igraph_error_t igraph_i_find_k_indsets( IGRAPH_FINALLY_CLEAN(1); *new_member_storage = IGRAPH_REALLOC(*new_member_storage, (size_t) new_member_storage_size * 2, - igraph_integer_t); + igraph_int_t); IGRAPH_CHECK_OOM(*new_member_storage, "Insufficient memory to find independent vertex sets."); new_member_storage_size *= 2; IGRAPH_FINALLY(igraph_free, *new_member_storage); @@ -175,6 +174,8 @@ static igraph_error_t igraph_i_find_k_indsets( * returned. If negative or zero, no lower bound will be used. * \param max_size Integer specifying the maximum size of the cliques to be * returned. If negative or zero, no upper bound will be used. + * \param max_results At most this many cliques will be recorded. If + * negative, or \ref IGRAPH_UNLIMITED, no limit is applied. * \return Error code. * * \sa \ref igraph_largest_cliques() and \ref igraph_clique_number(). @@ -183,9 +184,11 @@ static igraph_error_t igraph_i_find_k_indsets( * * \example examples/simple/igraph_cliques.c */ -igraph_error_t igraph_cliques(const igraph_t *graph, igraph_vector_int_list_t *res, - igraph_integer_t min_size, igraph_integer_t max_size) { - return igraph_i_cliquer_cliques(graph, res, min_size, max_size); +igraph_error_t igraph_cliques( + const igraph_t *graph, igraph_vector_int_list_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results) { + return igraph_i_cliquer_cliques(graph, res, min_size, max_size, max_results); } @@ -217,7 +220,7 @@ igraph_error_t igraph_cliques(const igraph_t *graph, igraph_vector_int_list_t *r * */ igraph_error_t igraph_clique_size_hist(const igraph_t *graph, igraph_vector_t *hist, - igraph_integer_t min_size, igraph_integer_t max_size) { + igraph_int_t min_size, igraph_int_t max_size) { return igraph_i_cliquer_histogram(graph, hist, min_size, max_size); } @@ -254,7 +257,7 @@ igraph_error_t igraph_clique_size_hist(const igraph_t *graph, igraph_vector_t *h * */ igraph_error_t igraph_cliques_callback(const igraph_t *graph, - igraph_integer_t min_size, igraph_integer_t max_size, + igraph_int_t min_size, igraph_int_t max_size, igraph_clique_handler_t *cliquehandler_fn, void *arg) { return igraph_i_cliquer_callback(graph, min_size, max_size, cliquehandler_fn, arg); } @@ -283,11 +286,13 @@ igraph_error_t igraph_cliques_callback(const igraph_t *graph, * here to make each vertex have a weight of 1. * \param res Pointer to an initialized list of integer vectors. The cliques * will be stored here as vectors of vertex IDs. + * \param maximal If true, only maximal cliques will be returned * \param min_weight Integer specifying the minimum weight of the cliques to be * returned. If negative or zero, no lower bound will be used. * \param max_weight Integer specifying the maximum weight of the cliques to be * returned. If negative or zero, no upper bound will be used. - * \param maximal If true, only maximal cliques will be returned + * \param max_results At most this many cliques will be recorded. If + * negative, or \ref IGRAPH_UNLIMITED, no limit is applied. * \return Error code. * * \sa \ref igraph_cliques(), \ref igraph_maximal_cliques() @@ -295,15 +300,19 @@ igraph_error_t igraph_cliques_callback(const igraph_t *graph, * Time complexity: Exponential * */ -igraph_error_t igraph_weighted_cliques(const igraph_t *graph, - const igraph_vector_t *vertex_weights, igraph_vector_int_list_t *res, - igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal) { +igraph_error_t igraph_weighted_cliques( + const igraph_t *graph, const igraph_vector_t *vertex_weights, + igraph_vector_int_list_t *res, + igraph_bool_t maximal, + igraph_real_t min_weight, igraph_real_t max_weight, + igraph_int_t max_results) { + if (vertex_weights) { - return igraph_i_weighted_cliques(graph, vertex_weights, res, min_weight, max_weight, maximal); + return igraph_i_weighted_cliques(graph, vertex_weights, res, min_weight, max_weight, maximal, max_results); } else if (maximal) { - return igraph_maximal_cliques(graph, res, min_weight, max_weight); + return igraph_maximal_cliques(graph, res, min_weight, max_weight, max_results); } else { - return igraph_cliques(graph, res, min_weight, max_weight); + return igraph_cliques(graph, res, min_weight, max_weight, max_results); } } @@ -378,7 +387,7 @@ igraph_error_t igraph_weighted_clique_number(const igraph_t *graph, if (vertex_weights) { return igraph_i_weighted_clique_number(graph, vertex_weights, res); } else { - igraph_integer_t res_int; + igraph_int_t res_int; IGRAPH_CHECK(igraph_clique_number(graph, &res_int)); if (res) { *res = res_int; @@ -390,7 +399,7 @@ igraph_error_t igraph_weighted_clique_number(const igraph_t *graph, static igraph_error_t igraph_i_maximal_or_largest_cliques_or_indsets( const igraph_t *graph, igraph_vector_int_list_t *res, - igraph_integer_t *clique_number, + igraph_int_t *clique_number, igraph_bool_t keep_only_largest, igraph_bool_t complementer); @@ -420,6 +429,8 @@ static igraph_error_t igraph_i_maximal_or_largest_cliques_or_indsets( * returned. If negative or zero, no lower bound will be used. * \param max_size Integer specifying the maximum size of the sets to be * returned. If negative or zero, no upper bound will be used. + * \param max_results At most this many independent vertex sets will be recorded. + * If negative, or \ref IGRAPH_UNLIMITED, no limit is applied. * \return Error code. * * \sa \ref igraph_largest_independent_vertex_sets(), @@ -429,15 +440,16 @@ static igraph_error_t igraph_i_maximal_or_largest_cliques_or_indsets( * * \example examples/simple/igraph_independent_sets.c */ -igraph_error_t igraph_independent_vertex_sets(const igraph_t *graph, - igraph_vector_int_list_t *res, - igraph_integer_t min_size, - igraph_integer_t max_size) { - igraph_integer_t no_of_nodes; +igraph_error_t igraph_independent_vertex_sets( + const igraph_t *graph, + igraph_vector_int_list_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results) { + + igraph_int_t no_of_nodes; igraph_vector_int_t *indset; - igraph_integer_t *member_storage, *new_member_storage, *c1; - igraph_vector_int_t new_member_storage_view; - igraph_integer_t indset_count, old_indset_count; + igraph_int_t *member_storage, *new_member_storage, *c1; + igraph_int_t indset_count, old_indset_count; igraph_lazy_adjlist_t al; if (igraph_is_directed(graph)) { @@ -452,38 +464,48 @@ igraph_error_t igraph_independent_vertex_sets(const igraph_t *graph, if (max_size > no_of_nodes || max_size <= 0) { max_size = no_of_nodes; } + if (max_results < 0) { + max_results = IGRAPH_INTEGER_MAX; + } igraph_vector_int_list_clear(res); + /* Add size-1 indsets if requested */ + if (min_size <= 1) { + igraph_int_t max_singletons_to_add = + (max_results > no_of_nodes) ? no_of_nodes : max_results; + IGRAPH_CHECK(igraph_vector_int_list_resize(res, max_singletons_to_add)); + for (igraph_int_t i = 0; i < max_singletons_to_add; i++) { + indset = igraph_vector_int_list_get_ptr(res, i); + IGRAPH_CHECK(igraph_vector_int_push_back(indset, i)); + --max_results; + } + } + + if (max_results == 0) { + return IGRAPH_SUCCESS; + } + IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &al, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &al); /* Will be resized later, if needed. */ - member_storage = IGRAPH_CALLOC(1, igraph_integer_t); + member_storage = IGRAPH_CALLOC(1, igraph_int_t); IGRAPH_CHECK_OOM(member_storage, "Insufficient memory for independent vertex set calculation."); IGRAPH_FINALLY(igraph_free, member_storage); /* Find all 1-cliques: every vertex will be a clique */ - new_member_storage = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + new_member_storage = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(new_member_storage, "Insufficient memory for independent vertex set calculation."); IGRAPH_FINALLY(igraph_free, new_member_storage); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { new_member_storage[i] = i; } indset_count = no_of_nodes; old_indset_count = 0; - /* Add size 1 indsets if requested */ - if (min_size <= 1) { - IGRAPH_CHECK(igraph_vector_int_list_resize(res, no_of_nodes)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - indset = igraph_vector_int_list_get_ptr(res, i); - IGRAPH_CHECK(igraph_vector_int_push_back(indset, i)); - } - } - - for (igraph_integer_t i = 2; i <= max_size && indset_count > 1; i++) { + for (igraph_int_t i = 2; i <= max_size && indset_count > 1; i++) { /* Here new_member_storage contains the independent vertex sets found in the previous iteration. Save this into member_storage, might be needed later */ @@ -508,14 +530,20 @@ igraph_error_t igraph_independent_vertex_sets(const igraph_t *graph, /* Add the cliques just found to the result if requested */ if (i >= min_size && i <= max_size) { - for (igraph_integer_t j = 0, k = 0; j < indset_count; j++, k += i) { - igraph_vector_int_view(&new_member_storage_view, new_member_storage + k, i); + for (igraph_int_t j = 0, k = 0; j < indset_count; j++, k += i) { + const igraph_vector_int_t new_member_storage_view = + igraph_vector_int_view(new_member_storage + k, i); + IGRAPH_CHECK(igraph_vector_int_list_push_back_copy(res, &new_member_storage_view)); + if (--max_results == 0) { + goto done; + } } } } /* i <= max_size && clique_count != 0 */ +done: IGRAPH_FREE(new_member_storage); IGRAPH_FREE(member_storage); igraph_lazy_adjlist_destroy(&al); @@ -556,31 +584,37 @@ igraph_error_t igraph_largest_independent_vertex_sets(const igraph_t *graph, } typedef struct igraph_i_max_ind_vsets_data_t { - igraph_integer_t matrix_size; + igraph_int_t matrix_size; igraph_adjlist_t adj_list; /* Adjacency list of the graph */ igraph_vector_int_t deg; /* Degrees of individual nodes */ igraph_set_t* buckets; /* Bucket array */ /* The IS value for each node. Still to be explained :) */ - igraph_integer_t* IS; - igraph_integer_t largest_set_size; /* Size of the largest set encountered */ + igraph_int_t* IS; + igraph_int_t largest_set_size; /* Size of the largest set encountered */ igraph_bool_t keep_only_largest; /* True if we keep only the largest sets */ + igraph_int_t min_size, max_size; + igraph_int_t max_results; } igraph_i_max_ind_vsets_data_t; static igraph_error_t igraph_i_maximal_independent_vertex_sets_backtrack( const igraph_t *graph, igraph_vector_int_list_t *res, igraph_i_max_ind_vsets_data_t *clqdata, - igraph_integer_t level) { + igraph_int_t level) { - igraph_integer_t v1, v2, v3, c, j, k; + igraph_int_t v1, v2, v3, c, j, k; igraph_vector_int_t *neis1, *neis2; igraph_bool_t f; - igraph_integer_t it_state; + igraph_int_t it_state; + + if (clqdata->max_results == 0) { + return IGRAPH_SUCCESS; + } IGRAPH_ALLOW_INTERRUPTION(); if (level >= clqdata->matrix_size - 1) { - igraph_integer_t size = 0; + igraph_int_t size = 0; if (res) { igraph_vector_int_t vec, *newvec; @@ -598,8 +632,11 @@ static igraph_error_t igraph_i_maximal_independent_vertex_sets_backtrack( * Instead of copying the vector contents, we add an empty vector to * the list, then swap it with the vector to-be-added in O(1) time. */ if (!clqdata->keep_only_largest) { - IGRAPH_CHECK(igraph_vector_int_list_push_back_new(res, &newvec)); - igraph_vector_int_swap(newvec, &vec); + if (clqdata->min_size <= size && size <= clqdata->max_size) { + IGRAPH_CHECK(igraph_vector_int_list_push_back_new(res, &newvec)); + igraph_vector_int_swap(newvec, &vec); + if (clqdata->max_results >= 0) --(clqdata->max_results); + } } else { if (size > clqdata->largest_set_size) { /* We are keeping only the largest sets, and we've found one that's @@ -722,7 +759,7 @@ static igraph_error_t igraph_i_maximal_independent_vertex_sets_backtrack( * Should probably be replaced with a proper igraph_vector_ptr_t. */ static void free_set_array_incomplete(igraph_set_t *array) { - igraph_integer_t i = 0; + igraph_int_t i = 0; while (igraph_set_inited(array + i)) { igraph_set_destroy(array + i); i++; @@ -730,8 +767,8 @@ static void free_set_array_incomplete(igraph_set_t *array) { IGRAPH_FREE(array); } -static void free_set_array(igraph_set_t *array, igraph_integer_t n) { - for (igraph_integer_t i=0; i < n; i++) { +static void free_set_array(igraph_set_t *array, igraph_int_t n) { + for (igraph_int_t i=0; i < n; i++) { igraph_set_destroy(&array[i]); } IGRAPH_FREE(array); @@ -763,6 +800,12 @@ static void free_set_array(igraph_set_t *array, igraph_integer_t n) { * \param graph The input graph. * \param res Pointer to an initialized list of integer vectors. The cliques * will be stored here as vectors of vertex IDs. + * \param min_size Integer specifying the minimum size of the sets to be + * returned. If negative or zero, no lower bound will be used. + * \param max_size Integer specifying the maximum size of the sets to be + * returned. If negative or zero, no upper bound will be used. + * \param max_results At most this many independent vertex sets will be recorded. + * If negative, or \ref IGRAPH_UNLIMITED, no limit is applied. * \return Error code. * * \sa \ref igraph_maximal_cliques(), \ref @@ -770,10 +813,14 @@ static void free_set_array(igraph_set_t *array, igraph_integer_t n) { * * Time complexity: TODO. */ -igraph_error_t igraph_maximal_independent_vertex_sets(const igraph_t *graph, - igraph_vector_int_list_t *res) { +igraph_error_t igraph_maximal_independent_vertex_sets( + const igraph_t *graph, + igraph_vector_int_list_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results) { + igraph_i_max_ind_vsets_data_t clqdata; - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (igraph_is_directed(graph)) { IGRAPH_WARNING("Edge directions are ignored during independent vertex set calculations."); @@ -782,17 +829,29 @@ igraph_error_t igraph_maximal_independent_vertex_sets(const igraph_t *graph, clqdata.matrix_size = no_of_nodes; clqdata.keep_only_largest = false; + if (max_size <= 0) { + max_size = IGRAPH_INTEGER_MAX; + } + + if (max_results < 0) { + max_results = IGRAPH_INTEGER_MAX; + } + + clqdata.min_size = min_size; + clqdata.max_size = max_size; + clqdata.max_results = max_results; + IGRAPH_CHECK(igraph_adjlist_init( graph, &clqdata.adj_list, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE )); IGRAPH_FINALLY(igraph_adjlist_destroy, &clqdata.adj_list); - clqdata.IS = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + clqdata.IS = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(clqdata.IS, "Insufficient memory for maximal independent vertex sets."); IGRAPH_FINALLY(igraph_free, clqdata.IS); IGRAPH_VECTOR_INT_INIT_FINALLY(&clqdata.deg, no_of_nodes); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { VECTOR(clqdata.deg)[i] = igraph_vector_int_size(igraph_adjlist_get(&clqdata.adj_list, i)); } @@ -800,7 +859,7 @@ igraph_error_t igraph_maximal_independent_vertex_sets(const igraph_t *graph, IGRAPH_CHECK_OOM(clqdata.buckets, "Insufficient memory for maximal independent vertex sets."); IGRAPH_FINALLY(free_set_array_incomplete, clqdata.buckets); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { IGRAPH_CHECK(igraph_set_init(&clqdata.buckets[i], 0)); } @@ -837,16 +896,16 @@ igraph_error_t igraph_maximal_independent_vertex_sets(const igraph_t *graph, * * \param graph The input graph. * \param no The independence number will be returned to the \c - * igraph_integer_t pointed by this variable. + * igraph_int_t pointed by this variable. * \return Error code. * * \sa \ref igraph_independent_vertex_sets(). * * Time complexity: TODO. */ -igraph_error_t igraph_independence_number(const igraph_t *graph, igraph_integer_t *no) { +igraph_error_t igraph_independence_number(const igraph_t *graph, igraph_int_t *no) { igraph_i_max_ind_vsets_data_t clqdata; - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (igraph_is_directed(graph)) { IGRAPH_WARNING("Edge directions are ignored during independence number calculations."); @@ -854,18 +913,19 @@ igraph_error_t igraph_independence_number(const igraph_t *graph, igraph_integer_ clqdata.matrix_size = no_of_nodes; clqdata.keep_only_largest = false; + clqdata.max_results = IGRAPH_INTEGER_MAX; IGRAPH_CHECK(igraph_adjlist_init( graph, &clqdata.adj_list, IGRAPH_ALL, IGRAPH_LOOPS_TWICE, IGRAPH_MULTIPLE )); IGRAPH_FINALLY(igraph_adjlist_destroy, &clqdata.adj_list); - clqdata.IS = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + clqdata.IS = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(clqdata.IS, "Insufficient memory for independence number calculation."); IGRAPH_FINALLY(igraph_free, clqdata.IS); IGRAPH_VECTOR_INT_INIT_FINALLY(&clqdata.deg, no_of_nodes); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { VECTOR(clqdata.deg)[i] = igraph_vector_int_size(igraph_adjlist_get(&clqdata.adj_list, i)); } @@ -873,7 +933,7 @@ igraph_error_t igraph_independence_number(const igraph_t *graph, igraph_integer_ IGRAPH_CHECK_OOM(clqdata.buckets, "Insufficient memory for independence number calculation."); IGRAPH_FINALLY(free_set_array_incomplete, clqdata.buckets); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { IGRAPH_CHECK(igraph_set_init(&clqdata.buckets[i], 0)); } @@ -897,7 +957,7 @@ igraph_error_t igraph_independence_number(const igraph_t *graph, igraph_integer_ /*************************************************************************/ static igraph_error_t igraph_i_maximal_cliques_store_max_size(const igraph_vector_int_t* clique, void* data) { - igraph_integer_t* result = (igraph_integer_t*)data; + igraph_int_t* result = (igraph_int_t*)data; if (*result < igraph_vector_int_size(clique)) { *result = igraph_vector_int_size(clique); } @@ -906,7 +966,7 @@ static igraph_error_t igraph_i_maximal_cliques_store_max_size(const igraph_vecto static igraph_error_t igraph_i_largest_cliques_store(const igraph_vector_int_t* clique, void* data) { igraph_vector_int_list_t* result = (igraph_vector_int_list_t*)data; - igraph_integer_t n; + igraph_int_t n; /* Is the current clique at least as large as the others that we have found? */ if (!igraph_vector_int_list_empty(result)) { @@ -962,7 +1022,7 @@ static igraph_error_t igraph_i_largest_cliques_store(const igraph_vector_int_t* igraph_error_t igraph_largest_cliques(const igraph_t *graph, igraph_vector_int_list_t *res) { igraph_vector_int_list_clear(res); - IGRAPH_CHECK(igraph_maximal_cliques_callback(graph, &igraph_i_largest_cliques_store, (void*)res, 0, 0)); + IGRAPH_CHECK(igraph_maximal_cliques_callback(graph, 0, 0, &igraph_i_largest_cliques_store, (void *) res)); return IGRAPH_SUCCESS; } @@ -978,7 +1038,7 @@ igraph_error_t igraph_largest_cliques(const igraph_t *graph, igraph_vector_int_l * track of the size of the largest clique that was found. * * \param graph The input graph. - * \param no The clique number will be returned to the \c igraph_integer_t + * \param no The clique number will be returned to the \c igraph_int_t * pointed by this variable. * \return Error code. * @@ -986,19 +1046,19 @@ igraph_error_t igraph_largest_cliques(const igraph_t *graph, igraph_vector_int_l * * Time complexity: O(3^(|V|/3)) worst case. */ -igraph_error_t igraph_clique_number(const igraph_t *graph, igraph_integer_t *no) { +igraph_error_t igraph_clique_number(const igraph_t *graph, igraph_int_t *no) { *no = 0; - return igraph_maximal_cliques_callback(graph, &igraph_i_maximal_cliques_store_max_size, (void*)no, 0, 0); + return igraph_maximal_cliques_callback(graph, 0, 0, &igraph_i_maximal_cliques_store_max_size, (void *) no); } static igraph_error_t igraph_i_maximal_or_largest_cliques_or_indsets(const igraph_t *graph, igraph_vector_int_list_t *res, - igraph_integer_t *clique_number, + igraph_int_t *clique_number, igraph_bool_t keep_only_largest, igraph_bool_t complementer) { igraph_i_max_ind_vsets_data_t clqdata; - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (igraph_is_directed(graph)) { IGRAPH_WARNING("Edge directions are ignored for largest independent vertex set or clique calculations."); @@ -1006,9 +1066,12 @@ static igraph_error_t igraph_i_maximal_or_largest_cliques_or_indsets(const igrap clqdata.matrix_size = no_of_nodes; clqdata.keep_only_largest = keep_only_largest; + clqdata.min_size = 0; + clqdata.max_size = IGRAPH_INTEGER_MAX; + clqdata.max_results = IGRAPH_INTEGER_MAX; if (complementer) { - IGRAPH_CHECK(igraph_adjlist_init_complementer(graph, &clqdata.adj_list, IGRAPH_ALL, 0)); + IGRAPH_CHECK(igraph_adjlist_init_complementer(graph, &clqdata.adj_list, IGRAPH_ALL, IGRAPH_NO_LOOPS)); } else { IGRAPH_CHECK(igraph_adjlist_init( graph, &clqdata.adj_list, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE @@ -1016,12 +1079,12 @@ static igraph_error_t igraph_i_maximal_or_largest_cliques_or_indsets(const igrap } IGRAPH_FINALLY(igraph_adjlist_destroy, &clqdata.adj_list); - clqdata.IS = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + clqdata.IS = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(clqdata.IS, "Insufficient memory for largest independent sets or cliques."); IGRAPH_FINALLY(igraph_free, clqdata.IS); IGRAPH_VECTOR_INT_INIT_FINALLY(&clqdata.deg, no_of_nodes); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { VECTOR(clqdata.deg)[i] = igraph_vector_int_size(igraph_adjlist_get(&clqdata.adj_list, i)); } @@ -1029,7 +1092,7 @@ static igraph_error_t igraph_i_maximal_or_largest_cliques_or_indsets(const igrap IGRAPH_CHECK_OOM(clqdata.buckets, "Insufficient memory for largest independent sets or cliques."); IGRAPH_FINALLY(free_set_array_incomplete, clqdata.buckets); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { IGRAPH_CHECK(igraph_set_init(&clqdata.buckets[i], 0)); } diff --git a/src/vendor/cigraph/src/cliques/glet.c b/src/vendor/cigraph/src/cliques/glet.c index d400e51d241..3e9092aff29 100644 --- a/src/vendor/cigraph/src/cliques/glet.c +++ b/src/vendor/cigraph/src/cliques/glet.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2013 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -75,12 +74,12 @@ typedef struct { igraph_vector_int_t *resultids; igraph_t *result; igraph_vector_t *resultweights; - igraph_integer_t nc; + igraph_int_t nc; } igraph_i_subclique_next_free_t; static void igraph_i_subclique_next_free(void *ptr) { igraph_i_subclique_next_free_t *data = ptr; - igraph_integer_t i; + igraph_int_t i; if (data->resultids) { for (i = 0; i < data->nc; i++) { igraph_vector_int_destroy(&data->resultids[i]); @@ -137,9 +136,9 @@ static igraph_error_t igraph_i_subclique_next(const igraph_t *graph, igraph_vector_int_t mark, map; igraph_vector_int_t edges; igraph_vector_int_t neis, newedges; - igraph_integer_t c, nc = igraph_vector_int_list_size(cliques); - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t c, nc = igraph_vector_int_list_size(cliques); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_i_subclique_next_free_t freedata = { NULL, NULL, NULL, nc }; if (igraph_vector_size(weights) != no_of_edges) { @@ -183,8 +182,8 @@ static igraph_error_t igraph_i_subclique_next(const igraph_t *graph, for (c = 0; c < nc; c++) { igraph_vector_int_t *clique = igraph_vector_int_list_get_ptr(cliques, c); igraph_real_t minweight = IGRAPH_INFINITY, nextweight = IGRAPH_INFINITY; - igraph_integer_t e, v, clsize = igraph_vector_int_size(clique); - igraph_integer_t noe, nov = 0; + igraph_int_t e, v, clsize = igraph_vector_int_size(clique); + igraph_int_t noe, nov = 0; igraph_vector_int_t *newids = (*resultids) + c; igraph_vector_t *neww = (*resultweights) + c; igraph_t *newgraph = (*result) + c; @@ -200,13 +199,13 @@ static igraph_error_t igraph_i_subclique_next(const igraph_t *graph, the clique and the next edge weight if any. */ for (v = 0; v < clsize; v++) { - igraph_integer_t i, neilen, node = VECTOR(*clique)[v]; - IGRAPH_CHECK(igraph_incident(graph, &neis, node, IGRAPH_ALL)); + igraph_int_t i, neilen, node = VECTOR(*clique)[v]; + IGRAPH_CHECK(igraph_incident(graph, &neis, node, IGRAPH_ALL, IGRAPH_LOOPS)); neilen = igraph_vector_int_size(&neis); VECTOR(mark)[node] = c + 1; for (i = 0; i < neilen; i++) { - igraph_integer_t edge = VECTOR(neis)[i]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, node); + igraph_int_t edge = VECTOR(neis)[i]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, node); if (VECTOR(mark)[nei] == c + 1) { igraph_real_t w = VECTOR(*weights)[edge]; IGRAPH_CHECK(igraph_vector_int_push_back(&edges, edge)); @@ -247,8 +246,8 @@ static igraph_error_t igraph_i_subclique_next(const igraph_t *graph, noe = igraph_vector_int_size(&edges); for (e = 0; e < noe; e++) { - igraph_integer_t edge = VECTOR(edges)[e]; - igraph_integer_t from, to; + igraph_int_t edge = VECTOR(edges)[e]; + igraph_int_t from, to; igraph_real_t w = VECTOR(*weights)[edge]; IGRAPH_CHECK(igraph_edge(graph, edge, &from, &to)); if (w >= nextweight) { @@ -285,7 +284,7 @@ static igraph_error_t igraph_i_subclique_next(const igraph_t *graph, } static void igraph_i_graphlets_destroy_clique_list(igraph_vector_ptr_t *vl) { - igraph_integer_t i, n = igraph_vector_ptr_size(vl); + igraph_int_t i, n = igraph_vector_ptr_size(vl); for (i = 0; i < n; i++) { igraph_vector_int_t *v = (igraph_vector_int_t*) VECTOR(*vl)[i]; if (v) { @@ -309,7 +308,7 @@ static igraph_error_t igraph_i_graphlets(const igraph_t *graph, 'startthr' */ igraph_vector_int_list_t mycliques; - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_int_t subv; igraph_t subg; igraph_t *newgraphs = NULL; @@ -322,19 +321,19 @@ static igraph_error_t igraph_i_graphlets(const igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&subv, 0); /* We start by finding cliques at the lowest threshold */ - for (igraph_integer_t i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { if (VECTOR(*weights)[i] >= startthr) { IGRAPH_CHECK(igraph_vector_int_push_back(&subv, i)); } } IGRAPH_CHECK(igraph_subgraph_from_edges(graph, &subg, igraph_ess_vector(&subv), /*delete_vertices=*/ 0)); IGRAPH_FINALLY(igraph_destroy, &subg); - IGRAPH_CHECK(igraph_maximal_cliques(&subg, &mycliques, /*min_size=*/ 0, /*max_size=*/ 0)); + IGRAPH_CHECK(igraph_maximal_cliques(&subg, &mycliques, /*min_size=*/ 0, /*max_size=*/ 0, IGRAPH_UNLIMITED)); igraph_destroy(&subg); igraph_vector_int_destroy(&subv); IGRAPH_FINALLY_CLEAN(2); - const igraph_integer_t nocliques = igraph_vector_int_list_size(&mycliques); + const igraph_int_t nocliques = igraph_vector_int_list_size(&mycliques); /* Get the next cliques and thresholds */ IGRAPH_VECTOR_INIT_FINALLY(&next_thr, 0); @@ -359,7 +358,7 @@ static igraph_error_t igraph_i_graphlets(const igraph_t *graph, IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(igraph_vector_ptr_resize(cliques, igraph_vector_ptr_size(cliques) + nocliques)); - for (igraph_integer_t i = 0, j = igraph_vector_ptr_size(cliques) - 1; i < nocliques; i++, j--) { + for (igraph_int_t i = 0, j = igraph_vector_ptr_size(cliques) - 1; i < nocliques; i++, j--) { igraph_vector_int_t *cl = IGRAPH_CALLOC(1, igraph_vector_int_t); IGRAPH_CHECK_OOM(cl, "Cannot find graphlets."); IGRAPH_FINALLY(igraph_free, cl); @@ -371,9 +370,9 @@ static igraph_error_t igraph_i_graphlets(const igraph_t *graph, VECTOR(*cliques)[j] = cl; IGRAPH_FINALLY_CLEAN(1); - const igraph_integer_t n = igraph_vector_int_size(cl); - for (igraph_integer_t k = 0; k < n; k++) { - igraph_integer_t node = VECTOR(*cl)[k]; + const igraph_int_t n = igraph_vector_int_size(cl); + for (igraph_int_t k = 0; k < n; k++) { + igraph_int_t node = VECTOR(*cl)[k]; VECTOR(*cl)[k] = VECTOR(*ids)[node]; } igraph_vector_int_sort(cl); @@ -383,7 +382,7 @@ static igraph_error_t igraph_i_graphlets(const igraph_t *graph, IGRAPH_FINALLY_CLEAN(1); /* Recursive calls for cliques found */ - for (igraph_integer_t i = 0; i < nocliques; i++) { + for (igraph_int_t i = 0; i < nocliques; i++) { igraph_t *g = newgraphs + i; if (igraph_vcount(g) > 1) { igraph_vector_t *w_sub = newweights + i; @@ -406,12 +405,12 @@ typedef struct { static int igraph_i_graphlets_filter_cmp(void *data, const void *a, const void *b) { igraph_i_graphlets_filter_t *ddata = (igraph_i_graphlets_filter_t *) data; - igraph_integer_t *aa = (igraph_integer_t*) a; - igraph_integer_t *bb = (igraph_integer_t*) b; + igraph_int_t *aa = (igraph_int_t*) a; + igraph_int_t *bb = (igraph_int_t*) b; igraph_real_t t_a = VECTOR(*ddata->thresholds)[*aa]; igraph_real_t t_b = VECTOR(*ddata->thresholds)[*bb]; igraph_vector_int_t *v_a, *v_b; - igraph_integer_t s_a, s_b; + igraph_int_t s_a, s_b; if (t_a < t_b) { return -1; @@ -444,7 +443,7 @@ static igraph_error_t igraph_i_graphlets_filter(igraph_vector_ptr_t *cliques, superset, we only need to check the cliques next in the list, until their threshold is different. */ - igraph_integer_t i, iptr, nocliques = igraph_vector_ptr_size(cliques); + igraph_int_t i, iptr, nocliques = igraph_vector_ptr_size(cliques); igraph_vector_int_t order; igraph_i_graphlets_filter_t sortdata = { cliques, thresholds }; @@ -455,16 +454,16 @@ static igraph_error_t igraph_i_graphlets_filter(igraph_vector_ptr_t *cliques, igraph_i_graphlets_filter_cmp); for (i = 0; i < nocliques - 1; i++) { - igraph_integer_t ri = VECTOR(order)[i]; + igraph_int_t ri = VECTOR(order)[i]; igraph_vector_int_t *needle = VECTOR(*cliques)[ri]; igraph_real_t thr_i = VECTOR(*thresholds)[ri]; - igraph_integer_t n_i = igraph_vector_int_size(needle); + igraph_int_t n_i = igraph_vector_int_size(needle); - for (igraph_integer_t j = i + 1; j < nocliques; j++) { - igraph_integer_t rj = VECTOR(order)[j]; + for (igraph_int_t j = i + 1; j < nocliques; j++) { + igraph_int_t rj = VECTOR(order)[j]; igraph_real_t thr_j = VECTOR(*thresholds)[rj]; igraph_vector_int_t *hay; - igraph_integer_t n_j, pi = 0, pj = 0; + igraph_int_t n_j, pi = 0, pj = 0; /* Done, not found */ if (thr_j != thr_i) { @@ -480,8 +479,8 @@ static igraph_error_t igraph_i_graphlets_filter(igraph_vector_ptr_t *cliques, /* Check if hay is a superset */ while (pi < n_i && pj < n_j && n_i - pi <= n_j - pj) { - igraph_integer_t ei = VECTOR(*needle)[pi]; - igraph_integer_t ej = VECTOR(*hay)[pj]; + igraph_int_t ei = VECTOR(*needle)[pi]; + igraph_int_t ej = VECTOR(*hay)[pj]; if (ei < ej) { break; } else if (ei > ej) { @@ -541,12 +540,12 @@ igraph_error_t igraph_graphlets_candidate_basis(const igraph_t *graph, igraph_vector_int_list_t *cliques, igraph_vector_t *thresholds) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_real_t minthr; igraph_vector_int_t ids; igraph_bool_t simple; - igraph_integer_t i, no_of_cliques; + igraph_int_t i, no_of_cliques; igraph_vector_ptr_t mycliques; /* Some checks */ @@ -558,19 +557,10 @@ igraph_error_t igraph_graphlets_candidate_basis(const igraph_t *graph, IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_is_simple(graph, &simple)); + IGRAPH_CHECK(igraph_is_simple(graph, &simple, IGRAPH_UNDIRECTED)); if (!simple) { IGRAPH_ERROR("Graphlets work on simple graphs only", IGRAPH_EINVAL); } - if (igraph_is_directed(graph)) { - /* When the graph is directed, mutual edges are effectively multi-edges as we - * are ignoring edge directions. */ - igraph_bool_t has_mutual; - IGRAPH_CHECK(igraph_has_mutual(graph, &has_mutual, false)); - if (has_mutual) { - IGRAPH_ERROR("Graphlets work on simple graphs only", IGRAPH_EINVAL); - } - } /* Internally, we will still use igraph_vector_ptr_t instead of * igraph_vector_int_list_t to manage the list of cliques; this is because @@ -616,16 +606,16 @@ igraph_error_t igraph_graphlets_candidate_basis(const igraph_t *graph, igraph_error_t igraph_i_graphlets_project( const igraph_t *graph, const igraph_vector_t *weights, const igraph_vector_int_list_t *cliques, igraph_vector_t *Mu, igraph_bool_t startMu, - igraph_integer_t niter, igraph_integer_t vid1 + igraph_int_t niter, igraph_int_t vid1 ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_cliques = igraph_vector_int_list_size(cliques); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_cliques = igraph_vector_int_list_size(cliques); igraph_vector_int_t vcl, vclidx, ecl, eclidx, cel, celidx; igraph_vector_int_t edgelist; igraph_vector_t newweights, normfact; - igraph_integer_t i, total_vertices, e, ptr, total_edges; + igraph_int_t i, total_vertices, e, ptr, total_edges; igraph_bool_t simple; /* Check arguments */ @@ -641,19 +631,10 @@ igraph_error_t igraph_i_graphlets_project( if (niter < 0) { IGRAPH_ERROR("Number of iterations must be non-negative", IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_is_simple(graph, &simple)); + IGRAPH_CHECK(igraph_is_simple(graph, &simple, IGRAPH_UNDIRECTED)); if (!simple) { IGRAPH_ERROR("Graphlets work on simple graphs only", IGRAPH_EINVAL); } - if (igraph_is_directed(graph)) { - /* When the graph is directed, mutual edges are effectively multi-edges as we - * are ignoring edge directions. */ - igraph_bool_t has_mutual; - IGRAPH_CHECK(igraph_has_mutual(graph, &has_mutual, false)); - if (has_mutual) { - IGRAPH_ERROR("Graphlets work on simple graphs only", IGRAPH_EINVAL); - } - } if (!startMu) { IGRAPH_CHECK(igraph_vector_resize(Mu, no_cliques)); @@ -666,12 +647,12 @@ igraph_error_t igraph_i_graphlets_project( IGRAPH_VECTOR_INT_INIT_FINALLY(&celidx, no_cliques + 3); for (i = 0, total_vertices = 0, total_edges = 0; i < no_cliques; i++) { igraph_vector_int_t *v = igraph_vector_int_list_get_ptr(cliques, i); - igraph_integer_t j, n = igraph_vector_int_size(v); + igraph_int_t j, n = igraph_vector_int_size(v); total_vertices += n; total_edges += n * (n - 1) / 2; VECTOR(celidx)[i + 2] = total_edges; for (j = 0; j < n; j++) { - igraph_integer_t vv = VECTOR(*v)[j] - vid1; + igraph_int_t vv = VECTOR(*v)[j] - vid1; VECTOR(vclidx)[vv + 2] += 1; } } @@ -686,10 +667,10 @@ igraph_error_t igraph_i_graphlets_project( IGRAPH_VECTOR_INT_INIT_FINALLY(&vcl, total_vertices); for (i = 0; i < no_cliques; i++) { igraph_vector_int_t *v = igraph_vector_int_list_get_ptr(cliques, i); - igraph_integer_t j, n = igraph_vector_int_size(v); + igraph_int_t j, n = igraph_vector_int_size(v); for (j = 0; j < n; j++) { - igraph_integer_t vv = VECTOR(*v)[j] - vid1; - igraph_integer_t p = VECTOR(vclidx)[vv + 1]; + igraph_int_t vv = VECTOR(*v)[j] - vid1; + igraph_int_t p = VECTOR(vclidx)[vv + 1]; VECTOR(vcl)[p] = i; VECTOR(vclidx)[vv + 1] += 1; } @@ -701,16 +682,16 @@ igraph_error_t igraph_i_graphlets_project( IGRAPH_VECTOR_INT_INIT_FINALLY(&edgelist, no_of_edges * 2); IGRAPH_CHECK(igraph_get_edgelist(graph, &edgelist, /*by_col=*/ 0)); for (i = 0, e = 0, ptr = 0; e < no_of_edges; e++) { - igraph_integer_t from = VECTOR(edgelist)[i++]; - igraph_integer_t to = VECTOR(edgelist)[i++]; - igraph_integer_t from_s = VECTOR(vclidx)[from]; - igraph_integer_t from_e = VECTOR(vclidx)[from + 1]; - igraph_integer_t to_s = VECTOR(vclidx)[to]; - igraph_integer_t to_e = VECTOR(vclidx)[to + 1]; + igraph_int_t from = VECTOR(edgelist)[i++]; + igraph_int_t to = VECTOR(edgelist)[i++]; + igraph_int_t from_s = VECTOR(vclidx)[from]; + igraph_int_t from_e = VECTOR(vclidx)[from + 1]; + igraph_int_t to_s = VECTOR(vclidx)[to]; + igraph_int_t to_e = VECTOR(vclidx)[to + 1]; VECTOR(eclidx)[e] = ptr; while (from_s < from_e && to_s < to_e) { - igraph_integer_t from_v = VECTOR(vcl)[from_s]; - igraph_integer_t to_v = VECTOR(vcl)[to_s]; + igraph_int_t from_v = VECTOR(vcl)[from_s]; + igraph_int_t to_v = VECTOR(vcl)[to_s]; if (from_v == to_v) { VECTOR(ecl)[ptr++] = from_v; from_s++; to_s++; @@ -729,10 +710,10 @@ igraph_error_t igraph_i_graphlets_project( /* Convert the edge-clique list to a clique-edge list */ IGRAPH_VECTOR_INT_INIT_FINALLY(&cel, total_edges); for (i = 0; i < no_of_edges; i++) { - igraph_integer_t ecl_s = VECTOR(eclidx)[i], ecl_e = VECTOR(eclidx)[i + 1], j; + igraph_int_t ecl_s = VECTOR(eclidx)[i], ecl_e = VECTOR(eclidx)[i + 1], j; for (j = ecl_s; j < ecl_e; j++) { - igraph_integer_t cl = VECTOR(ecl)[j]; - igraph_integer_t epos = VECTOR(celidx)[cl + 1]; + igraph_int_t cl = VECTOR(ecl)[j]; + igraph_int_t epos = VECTOR(celidx)[cl + 1]; VECTOR(cel)[epos] = i; VECTOR(celidx)[cl + 1] += 1; } @@ -742,7 +723,7 @@ igraph_error_t igraph_i_graphlets_project( IGRAPH_VECTOR_INIT_FINALLY(&normfact, no_cliques); for (i = 0; i < no_cliques; i++) { igraph_vector_int_t *v = igraph_vector_int_list_get_ptr(cliques, i); - igraph_integer_t n = igraph_vector_int_size(v); + igraph_int_t n = igraph_vector_int_size(v); VECTOR(normfact)[i] = n * (n + 1) / 2; } @@ -750,20 +731,20 @@ igraph_error_t igraph_i_graphlets_project( IGRAPH_VECTOR_INIT_FINALLY(&newweights, no_of_edges); for (i = 0; i < niter; i++) { for (e = 0; e < no_of_edges; e++) { - igraph_integer_t start = VECTOR(eclidx)[e]; - igraph_integer_t end = VECTOR(eclidx)[e + 1]; + igraph_int_t start = VECTOR(eclidx)[e]; + igraph_int_t end = VECTOR(eclidx)[e + 1]; VECTOR(newweights)[e] = 0.0001; while (start < end) { - igraph_integer_t clique = VECTOR(ecl)[start++]; + igraph_int_t clique = VECTOR(ecl)[start++]; VECTOR(newweights)[e] += VECTOR(*Mu)[clique]; } } for (e = 0; e < no_cliques; e++) { igraph_real_t sumratio = 0; - igraph_integer_t start = VECTOR(celidx)[e]; - igraph_integer_t end = VECTOR(celidx)[e + 1]; + igraph_int_t start = VECTOR(celidx)[e]; + igraph_int_t end = VECTOR(celidx)[e + 1]; while (start < end) { - igraph_integer_t edge = VECTOR(cel)[start++]; + igraph_int_t edge = VECTOR(cel)[start++]; sumratio += VECTOR(*weights)[edge] / VECTOR(newweights)[edge]; } VECTOR(*Mu)[e] *= sumratio / VECTOR(normfact)[e]; @@ -816,7 +797,7 @@ igraph_error_t igraph_graphlets_project(const igraph_t *graph, const igraph_vector_t *weights, const igraph_vector_int_list_t *cliques, igraph_vector_t *Mu, igraph_bool_t startMu, - igraph_integer_t niter) { + igraph_int_t niter) { return igraph_i_graphlets_project(graph, weights, cliques, Mu, startMu, niter, /*vid1=*/ 0); @@ -829,8 +810,8 @@ typedef struct igraph_i_graphlets_order_t { static int igraph_i_graphlets_order_cmp(void *data, const void *a, const void *b) { igraph_i_graphlets_order_t *ddata = (igraph_i_graphlets_order_t*) data; - igraph_integer_t *aa = (igraph_integer_t*) a; - igraph_integer_t *bb = (igraph_integer_t*) b; + igraph_int_t *aa = (igraph_int_t*) a; + igraph_int_t *bb = (igraph_int_t*) b; igraph_real_t Mu_a = VECTOR(*ddata->Mu)[*aa]; igraph_real_t Mu_b = VECTOR(*ddata->Mu)[*bb]; @@ -869,9 +850,9 @@ static int igraph_i_graphlets_order_cmp(void *data, const void *a, const void *b igraph_error_t igraph_graphlets(const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_int_list_t *cliques, - igraph_vector_t *Mu, igraph_integer_t niter) { + igraph_vector_t *Mu, igraph_int_t niter) { - igraph_integer_t nocliques; + igraph_int_t nocliques; igraph_vector_t thresholds; igraph_vector_int_t order; igraph_i_graphlets_order_t sortdata = { cliques, Mu }; @@ -891,7 +872,7 @@ igraph_error_t igraph_graphlets(const igraph_t *graph, igraph_i_graphlets_order_cmp); IGRAPH_CHECK(igraph_vector_int_list_permute(cliques, &order)); - IGRAPH_CHECK(igraph_vector_index_int(Mu, &order)); + IGRAPH_CHECK(igraph_vector_index_in_place(Mu, &order)); igraph_vector_int_destroy(&order); IGRAPH_FINALLY_CLEAN(1); diff --git a/src/vendor/cigraph/src/cliques/maximal_cliques.c b/src/vendor/cigraph/src/cliques/maximal_cliques.c index f676fe5b245..c841cde924c 100644 --- a/src/vendor/cigraph/src/cliques/maximal_cliques.c +++ b/src/vendor/cigraph/src/cliques/maximal_cliques.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2013 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -38,42 +37,42 @@ static igraph_error_t igraph_i_maximal_cliques_reorder_adjlists( const igraph_vector_int_t *PX, - igraph_integer_t PS, igraph_integer_t PE, igraph_integer_t XS, igraph_integer_t XE, + igraph_int_t PS, igraph_int_t PE, igraph_int_t XS, igraph_int_t XE, const igraph_vector_int_t *pos, igraph_adjlist_t *adjlist); static igraph_error_t igraph_i_maximal_cliques_select_pivot( const igraph_vector_int_t *PX, - igraph_integer_t PS, igraph_integer_t PE, igraph_integer_t XS, igraph_integer_t XE, + igraph_int_t PS, igraph_int_t PE, igraph_int_t XS, igraph_int_t XE, const igraph_vector_int_t *pos, const igraph_adjlist_t *adjlist, - igraph_integer_t *pivot, + igraph_int_t *pivot, igraph_vector_int_t *nextv, - igraph_integer_t oldPS, igraph_integer_t oldXE); + igraph_int_t oldPS, igraph_int_t oldXE); static igraph_error_t igraph_i_maximal_cliques_down( igraph_vector_int_t *PX, - igraph_integer_t PS, igraph_integer_t PE, igraph_integer_t XS, igraph_integer_t XE, + igraph_int_t PS, igraph_int_t PE, igraph_int_t XS, igraph_int_t XE, igraph_vector_int_t *pos, - igraph_adjlist_t *adjlist, igraph_integer_t mynextv, + igraph_adjlist_t *adjlist, igraph_int_t mynextv, igraph_vector_int_t *R, - igraph_integer_t *newPS, igraph_integer_t *newXE); + igraph_int_t *newPS, igraph_int_t *newXE); static igraph_error_t igraph_i_maximal_cliques_PX( - igraph_vector_int_t *PX, igraph_integer_t PS, igraph_integer_t *PE, - igraph_integer_t *XS, igraph_integer_t XE, igraph_vector_int_t *pos, - igraph_adjlist_t *adjlist, igraph_integer_t v, + igraph_vector_int_t *PX, igraph_int_t PS, igraph_int_t *PE, + igraph_int_t *XS, igraph_int_t XE, igraph_vector_int_t *pos, + igraph_adjlist_t *adjlist, igraph_int_t v, igraph_vector_int_t *H); static igraph_error_t igraph_i_maximal_cliques_up( - igraph_vector_int_t *PX, igraph_integer_t PS, igraph_integer_t PE, - igraph_integer_t XS, igraph_integer_t XE, igraph_vector_int_t *pos, + igraph_vector_int_t *PX, igraph_int_t PS, igraph_int_t PE, + igraph_int_t XS, igraph_int_t XE, igraph_vector_int_t *pos, igraph_adjlist_t *adjlist, igraph_vector_int_t *R, igraph_vector_int_t *H); #define PRINT_PX do { \ - igraph_integer_t j; \ + igraph_int_t j; \ printf("PX="); \ for (j=0; j= sPS && avneipos <= sPE) { if (pp != avnei) { - igraph_integer_t tmp = *avnei; + igraph_int_t tmp = *avnei; *avnei = *pp; *pp = tmp; } @@ -151,37 +150,37 @@ static igraph_error_t igraph_i_maximal_cliques_reorder_adjlists( static igraph_error_t igraph_i_maximal_cliques_select_pivot( const igraph_vector_int_t *PX, - igraph_integer_t PS, igraph_integer_t PE, - igraph_integer_t XS, igraph_integer_t XE, + igraph_int_t PS, igraph_int_t PE, + igraph_int_t XS, igraph_int_t XE, const igraph_vector_int_t *pos, const igraph_adjlist_t *adjlist, - igraph_integer_t *pivot, + igraph_int_t *pivot, igraph_vector_int_t *nextv, - igraph_integer_t oldPS, igraph_integer_t oldXE) { + igraph_int_t oldPS, igraph_int_t oldXE) { igraph_vector_int_t *pivotvectneis; - igraph_integer_t j, pivotvectlen; - igraph_integer_t i, usize = -1; - igraph_integer_t soldPS = oldPS + 1, soldXE = oldXE + 1, sPS = PS + 1, sPE = PE + 1; + igraph_int_t j, pivotvectlen; + igraph_int_t i, usize = -1; + igraph_int_t soldPS = oldPS + 1, soldXE = oldXE + 1, sPS = PS + 1, sPE = PE + 1; IGRAPH_UNUSED(XS); /* Choose a pivotvect, and bring up P vertices at the same time */ for (i = PS; i <= XE; i++) { - igraph_integer_t av = VECTOR(*PX)[i]; + igraph_int_t av = VECTOR(*PX)[i]; igraph_vector_int_t *avneis = igraph_adjlist_get(adjlist, av); - igraph_integer_t *avp = VECTOR(*avneis); - igraph_integer_t avlen = igraph_vector_int_size(avneis); - igraph_integer_t *ave = avp + avlen; - igraph_integer_t *avnei = avp, *pp = avp; + igraph_int_t *avp = VECTOR(*avneis); + igraph_int_t avlen = igraph_vector_int_size(avneis); + igraph_int_t *ave = avp + avlen; + igraph_int_t *avnei = avp, *pp = avp; for (; avnei < ave; avnei++) { - igraph_integer_t avneipos = VECTOR(*pos)[(*avnei)]; + igraph_int_t avneipos = VECTOR(*pos)[(*avnei)]; if (avneipos < soldPS || avneipos > soldXE) { break; } if (avneipos >= sPS && avneipos <= sPE) { if (pp != avnei) { - igraph_integer_t tmp = *avnei; + igraph_int_t tmp = *avnei; *avnei = *pp; *pp = tmp; } @@ -199,12 +198,12 @@ static igraph_error_t igraph_i_maximal_cliques_select_pivot( pivotvectlen = igraph_vector_int_size(pivotvectneis); for (j = PS; j <= PE; j++) { - igraph_integer_t vcand = VECTOR(*PX)[j]; + igraph_int_t vcand = VECTOR(*PX)[j]; igraph_bool_t nei = false; - igraph_integer_t k = 0; + igraph_int_t k = 0; for (k = 0; k < pivotvectlen; k++) { - igraph_integer_t unv = VECTOR(*pivotvectneis)[k]; - igraph_integer_t unvpos = VECTOR(*pos)[unv]; + igraph_int_t unv = VECTOR(*pivotvectneis)[k]; + igraph_int_t unvpos = VECTOR(*pos)[unv]; if (unvpos < sPS || unvpos > sPE) { break; } @@ -222,8 +221,8 @@ static igraph_error_t igraph_i_maximal_cliques_select_pivot( } #define SWAP(p1,p2) do { \ - igraph_integer_t v1=VECTOR(*PX)[p1]; \ - igraph_integer_t v2=VECTOR(*PX)[p2]; \ + igraph_int_t v1=VECTOR(*PX)[p1]; \ + igraph_int_t v2=VECTOR(*PX)[p2]; \ VECTOR(*PX)[p1] = v2; \ VECTOR(*PX)[p2] = v1; \ VECTOR(*pos)[v1] = (p2)+1; \ @@ -231,21 +230,21 @@ static igraph_error_t igraph_i_maximal_cliques_select_pivot( } while (0) static igraph_error_t igraph_i_maximal_cliques_down(igraph_vector_int_t *PX, - igraph_integer_t PS, igraph_integer_t PE, - igraph_integer_t XS, igraph_integer_t XE, + igraph_int_t PS, igraph_int_t PE, + igraph_int_t XS, igraph_int_t XE, igraph_vector_int_t *pos, - igraph_adjlist_t *adjlist, igraph_integer_t mynextv, + igraph_adjlist_t *adjlist, igraph_int_t mynextv, igraph_vector_int_t *R, - igraph_integer_t *newPS, igraph_integer_t *newXE) { + igraph_int_t *newPS, igraph_int_t *newXE) { igraph_vector_int_t *vneis = igraph_adjlist_get(adjlist, mynextv); - igraph_integer_t j, vneislen = igraph_vector_int_size(vneis); - igraph_integer_t sPS = PS + 1, sPE = PE + 1, sXS = XS + 1, sXE = XE + 1; + igraph_int_t j, vneislen = igraph_vector_int_size(vneis); + igraph_int_t sPS = PS + 1, sPE = PE + 1, sXS = XS + 1, sXE = XE + 1; *newPS = PE + 1; *newXE = XS - 1; for (j = 0; j < vneislen; j++) { - igraph_integer_t vnei = VECTOR(*vneis)[j]; - igraph_integer_t vneipos = VECTOR(*pos)[vnei]; + igraph_int_t vnei = VECTOR(*vneis)[j]; + igraph_int_t vneipos = VECTOR(*pos)[vnei]; if (vneipos >= sPS && vneipos <= sPE) { (*newPS)--; SWAP(vneipos - 1, *newPS); @@ -263,13 +262,13 @@ static igraph_error_t igraph_i_maximal_cliques_down(igraph_vector_int_t *PX, #undef SWAP static igraph_error_t igraph_i_maximal_cliques_PX(igraph_vector_int_t *PX, - igraph_integer_t PS, igraph_integer_t *PE, igraph_integer_t *XS, igraph_integer_t XE, - igraph_vector_int_t *pos, igraph_adjlist_t *adjlist, igraph_integer_t v, + igraph_int_t PS, igraph_int_t *PE, igraph_int_t *XS, igraph_int_t XE, + igraph_vector_int_t *pos, igraph_adjlist_t *adjlist, igraph_int_t v, igraph_vector_int_t *H ) { - igraph_integer_t vpos = VECTOR(*pos)[v] - 1; - igraph_integer_t tmp = VECTOR(*PX)[*PE]; + igraph_int_t vpos = VECTOR(*pos)[v] - 1; + igraph_int_t tmp = VECTOR(*PX)[*PE]; IGRAPH_UNUSED(PS); IGRAPH_UNUSED(XE); @@ -286,13 +285,13 @@ static igraph_error_t igraph_i_maximal_cliques_PX(igraph_vector_int_t *PX, } static igraph_error_t igraph_i_maximal_cliques_up( - igraph_vector_int_t *PX, igraph_integer_t PS, igraph_integer_t PE, - igraph_integer_t XS, igraph_integer_t XE, igraph_vector_int_t *pos, + igraph_vector_int_t *PX, igraph_int_t PS, igraph_int_t PE, + igraph_int_t XS, igraph_int_t XE, igraph_vector_int_t *pos, igraph_adjlist_t *adjlist, igraph_vector_int_t *R, igraph_vector_int_t *H ) { - igraph_integer_t vv; + igraph_int_t vv; IGRAPH_UNUSED(PS); IGRAPH_UNUSED(PE); @@ -302,8 +301,8 @@ static igraph_error_t igraph_i_maximal_cliques_up( igraph_vector_int_pop_back(R); while ((vv = igraph_vector_int_pop_back(H)) != -1) { - igraph_integer_t vvpos = VECTOR(*pos)[vv]; - igraph_integer_t tmp = VECTOR(*PX)[XS]; + igraph_int_t vvpos = VECTOR(*pos)[vv]; + igraph_int_t tmp = VECTOR(*PX)[XS]; VECTOR(*PX)[XS] = vv; VECTOR(*PX)[vvpos - 1] = tmp; VECTOR(*pos)[vv] = XS + 1; @@ -314,6 +313,19 @@ static igraph_error_t igraph_i_maximal_cliques_up( return IGRAPH_SUCCESS; } + +/* igraph_maximal_cliques */ + +igraph_error_t igraph_i_maximal_cliques( + const igraph_t *graph, + igraph_vector_int_list_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +#define IGRAPH_MC_ORIG +#include "maximal_cliques_template.h" +#undef IGRAPH_MC_ORIG + /** * \function igraph_maximal_cliques * \brief Finds all maximal cliques in a graph. @@ -349,6 +361,8 @@ static igraph_error_t igraph_i_maximal_cliques_up( * returned. If negative or zero, no lower bound will be used. * \param max_size Integer giving the maximum size of the cliques to be * returned. If negative or zero, no upper bound will be used. + * \param max_results At most this many cliques will be recorded. If + * negative, or \ref IGRAPH_UNLIMITED, no limit is applied. * \return Error code. * * \sa \ref igraph_maximal_independent_vertex_sets() to find maximal @@ -363,13 +377,25 @@ static igraph_error_t igraph_i_maximal_cliques_up( */ igraph_error_t igraph_maximal_cliques( - const igraph_t *graph, igraph_vector_int_list_t *res, - igraph_integer_t min_size, igraph_integer_t max_size -); + const igraph_t *graph, + igraph_vector_int_list_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results) { + return igraph_i_maximal_cliques(graph, res, min_size, max_size, max_results); +} -#define IGRAPH_MC_ORIG + +/* igraph_maximal_cliques_count */ + +igraph_error_t igraph_i_maximal_cliques_count( + const igraph_t *graph, + igraph_int_t *res, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +#define IGRAPH_MC_COUNT #include "maximal_cliques_template.h" -#undef IGRAPH_MC_ORIG +#undef IGRAPH_MC_COUNT /** * \function igraph_maximal_cliques_count @@ -378,7 +404,7 @@ igraph_error_t igraph_maximal_cliques( * See \ref igraph_maximal_cliques() for details. * * \param graph The input graph. Edge directions are ignored. - * \param res Pointer to an \c igraph_integer_t; the number of maximal + * \param res Pointer to an \c igraph_int_t; the number of maximal * cliques will be stored here. * \param min_size Integer giving the minimum size of the cliques to be * returned. If negative or zero, no lower bound will be used. @@ -394,14 +420,24 @@ igraph_error_t igraph_maximal_cliques( * \example examples/simple/igraph_maximal_cliques.c */ -igraph_error_t igraph_maximal_cliques_count(const igraph_t *graph, - igraph_integer_t *res, - igraph_integer_t min_size, - igraph_integer_t max_size); +igraph_error_t igraph_maximal_cliques_count( + const igraph_t *graph, + igraph_int_t *res, + igraph_int_t min_size, igraph_int_t max_size) { + return igraph_i_maximal_cliques_count(graph, res, min_size, max_size, IGRAPH_UNLIMITED); +} + +/* igraph_maximal_cliques_file */ -#define IGRAPH_MC_COUNT +igraph_error_t igraph_i_maximal_cliques_file( + const igraph_t *graph, + FILE *outfile, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +#define IGRAPH_MC_FILE #include "maximal_cliques_template.h" -#undef IGRAPH_MC_COUNT +#undef IGRAPH_MC_FILE /** * \function igraph_maximal_cliques_file @@ -417,6 +453,8 @@ igraph_error_t igraph_maximal_cliques_count(const igraph_t *graph, * returned. If negative or zero, no lower bound will be used. * \param max_size Integer giving the maximum size of the cliques to be * returned. If negative or zero, no upper bound will be used. + * \param max_results At most this many cliques will be output. If + * negative, or \ref IGRAPH_UNLIMITED, no limit is applied. * \return Error code. * * \sa \ref igraph_maximal_cliques(). @@ -426,14 +464,26 @@ igraph_error_t igraph_maximal_cliques_count(const igraph_t *graph, * */ -igraph_error_t igraph_maximal_cliques_file(const igraph_t *graph, - FILE *outfile, - igraph_integer_t min_size, - igraph_integer_t max_size); +igraph_error_t igraph_maximal_cliques_file( + const igraph_t *graph, + FILE *outfile, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results) { + return igraph_i_maximal_cliques_file(graph, outfile, min_size, max_size, max_results); +} -#define IGRAPH_MC_FILE + +/* igraph_maximal_cliques_subset */ + +igraph_error_t igraph_i_maximal_cliques_subset( + const igraph_t *graph, const igraph_vector_int_t *subset, + igraph_vector_int_list_t *res, igraph_int_t *no, + FILE *outfile, igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +#define IGRAPH_MC_FULL #include "maximal_cliques_template.h" -#undef IGRAPH_MC_FILE +#undef IGRAPH_MC_FULL /** * \function igraph_maximal_cliques_subset @@ -448,7 +498,7 @@ igraph_error_t igraph_maximal_cliques_file(const igraph_t *graph, * subset of initial vertices. * \param res Pointer to a list of integer vectors; the cliques will be * stored here. - * \param no Pointer to an \c igraph_integer_t; the number of maximal + * \param no Pointer to an \c igraph_int_t; the number of maximal * cliques will be stored here. * \param outfile Pointer to an output file or \c NULL. * When not \c NULL, the file should be writable. @@ -456,6 +506,8 @@ igraph_error_t igraph_maximal_cliques_file(const igraph_t *graph, * returned. If negative or zero, no lower bound will be used. * \param max_size Integer giving the maximum size of the cliques to be * returned. If negative or zero, no upper bound will be used. + * \param max_results At most this many cliques will be recorded. If + * negative, or \ref IGRAPH_UNLIMITED, no limit is applied. * \return Error code. * * \sa \ref igraph_maximal_cliques(). @@ -466,15 +518,25 @@ igraph_error_t igraph_maximal_cliques_file(const igraph_t *graph, */ igraph_error_t igraph_maximal_cliques_subset( - const igraph_t *graph, const igraph_vector_int_t *subset, - igraph_vector_int_list_t *res, igraph_integer_t *no, - FILE *outfile, igraph_integer_t min_size, igraph_integer_t max_size -); + const igraph_t *graph, const igraph_vector_int_t *subset, + igraph_vector_int_list_t *res, igraph_int_t *no, FILE *outfile, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results) { + return igraph_i_maximal_cliques_subset(graph, subset, res, no, outfile, min_size, max_size, max_results); +} -#define IGRAPH_MC_FULL -#include "maximal_cliques_template.h" -#undef IGRAPH_MC_FULL +/* igraph_maximal_cliques_callback */ + +igraph_error_t igraph_i_maximal_cliques_callback( + const igraph_t *graph, + igraph_clique_handler_t *cliquehandler_fn, void *arg, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +#define IGRAPH_MC_CALLBACK +#include "maximal_cliques_template.h" +#undef IGRAPH_MC_CALLBACK /** * \function igraph_maximal_cliques_callback @@ -504,14 +566,25 @@ igraph_error_t igraph_maximal_cliques_subset( * */ -igraph_error_t igraph_maximal_cliques_callback(const igraph_t *graph, - igraph_clique_handler_t *cliquehandler_fn, void *arg, - igraph_integer_t min_size, igraph_integer_t max_size); +igraph_error_t igraph_maximal_cliques_callback( + const igraph_t *graph, + igraph_int_t min_size, igraph_int_t max_size, + igraph_clique_handler_t *cliquehandler_fn, void *arg) { + return igraph_i_maximal_cliques_callback(graph, cliquehandler_fn, arg, min_size, max_size, IGRAPH_UNLIMITED); +} + -#define IGRAPH_MC_CALLBACK -#include "maximal_cliques_template.h" -#undef IGRAPH_MC_CALLBACK +/* igraph_maximal_cliques_hist */ +igraph_error_t igraph_i_maximal_cliques_hist( + const igraph_t *graph, + igraph_vector_t *hist, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results); + +#define IGRAPH_MC_HIST +#include "maximal_cliques_template.h" +#undef IGRAPH_MC_HIST /** * \function igraph_maximal_cliques_hist @@ -538,11 +611,9 @@ igraph_error_t igraph_maximal_cliques_callback(const igraph_t *graph, * */ -igraph_error_t igraph_maximal_cliques_hist(const igraph_t *graph, - igraph_vector_t *hist, - igraph_integer_t min_size, - igraph_integer_t max_size); - -#define IGRAPH_MC_HIST -#include "maximal_cliques_template.h" -#undef IGRAPH_MC_HIST +igraph_error_t igraph_maximal_cliques_hist( + const igraph_t *graph, + igraph_vector_t *hist, + igraph_int_t min_size, igraph_int_t max_size) { + return igraph_i_maximal_cliques_hist(graph, hist, min_size, max_size, IGRAPH_UNLIMITED); +} diff --git a/src/vendor/cigraph/src/cliques/maximal_cliques_template.h b/src/vendor/cigraph/src/cliques/maximal_cliques_template.h index 699b0317b1c..cfc5cb83d98 100644 --- a/src/vendor/cigraph/src/cliques/maximal_cliques_template.h +++ b/src/vendor/cigraph/src/cliques/maximal_cliques_template.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2013 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -37,7 +36,7 @@ #endif #ifdef IGRAPH_MC_COUNT - #define RESTYPE igraph_integer_t *res + #define RESTYPE igraph_int_t *res #define RESNAME res #define SUFFIX _count #define RECORD (*res)++ @@ -62,7 +61,7 @@ #define RESTYPE \ const igraph_vector_int_t *subset, \ igraph_vector_int_list_t *res, \ - igraph_integer_t *no, \ + igraph_int_t *no, \ FILE *outfile #define RESNAME subset, res, no, outfile #define SUFFIX _subset @@ -114,10 +113,10 @@ #define RESNAME hist #define SUFFIX _hist #define RECORD do { \ - igraph_integer_t hsize = igraph_vector_size(hist); \ + igraph_int_t hsize = igraph_vector_size(hist); \ if (clsize > hsize) { \ - igraph_integer_t hcapacity = igraph_vector_capacity(hist); \ - igraph_integer_t j; \ + igraph_int_t hcapacity = igraph_vector_capacity(hist); \ + igraph_int_t j; \ igraph_error_t err; \ if (hcapacity < clsize && clsize < 2*hcapacity) \ err = igraph_vector_reserve(hist, 2*hcapacity); \ @@ -138,15 +137,16 @@ #endif static igraph_error_t FUNCTION(igraph_i_maximal_cliques_bk, SUFFIX)( - igraph_vector_int_t *PX, igraph_integer_t PS, igraph_integer_t PE, - igraph_integer_t XS, igraph_integer_t XE, igraph_integer_t oldPS, igraph_integer_t oldXE, - igraph_vector_int_t *R, - igraph_vector_int_t *pos, - igraph_adjlist_t *adjlist, - RESTYPE, - igraph_vector_int_t *nextv, - igraph_vector_int_t *H, - igraph_integer_t min_size, igraph_integer_t max_size) { + igraph_vector_int_t *PX, igraph_int_t PS, igraph_int_t PE, + igraph_int_t XS, igraph_int_t XE, igraph_int_t oldPS, igraph_int_t oldXE, + igraph_vector_int_t *R, + igraph_vector_int_t *pos, + igraph_adjlist_t *adjlist, + RESTYPE, + igraph_vector_int_t *nextv, + igraph_vector_int_t *H, + igraph_int_t min_size, igraph_int_t max_size, + igraph_int_t max_results, igraph_int_t *result_count) { igraph_error_t err; @@ -154,18 +154,22 @@ static igraph_error_t FUNCTION(igraph_i_maximal_cliques_bk, SUFFIX)( if (PS > PE && XS > XE) { /* Found a maximum clique, report it */ - igraph_integer_t clsize = igraph_vector_int_size(R); + igraph_int_t clsize = igraph_vector_int_size(R); if (min_size <= clsize && (clsize <= max_size || max_size <= 0)) { RECORD; + *result_count += 1; + if (max_results >= 0 && *result_count == max_results) { + return IGRAPH_STOP; + } } } else if (PS <= PE) { /* Select a pivot element */ - igraph_integer_t pivot, mynextv; + igraph_int_t pivot, mynextv; IGRAPH_CHECK(igraph_i_maximal_cliques_select_pivot( PX, PS, PE, XS, XE, pos, adjlist, &pivot, nextv, oldPS, oldXE )); while ((mynextv = igraph_vector_int_pop_back(nextv)) != -1) { - igraph_integer_t newPS, newXE; + igraph_int_t newPS, newXE; /* Going down, prepare */ IGRAPH_CHECK(igraph_i_maximal_cliques_down( @@ -175,7 +179,8 @@ static igraph_error_t FUNCTION(igraph_i_maximal_cliques_bk, SUFFIX)( err = FUNCTION(igraph_i_maximal_cliques_bk, SUFFIX)( PX, newPS, PE, XS, newXE, PS, XE, R, pos, adjlist, RESNAME, nextv, H, - min_size, max_size); + min_size, max_size, + max_results, result_count); if (err == IGRAPH_STOP) { return err; @@ -197,21 +202,23 @@ static igraph_error_t FUNCTION(igraph_i_maximal_cliques_bk, SUFFIX)( return IGRAPH_SUCCESS; } -igraph_error_t FUNCTION(igraph_maximal_cliques, SUFFIX)( +igraph_error_t FUNCTION(igraph_i_maximal_cliques, SUFFIX)( const igraph_t *graph, RESTYPE, - igraph_integer_t min_size, - igraph_integer_t max_size) { + igraph_int_t min_size, + igraph_int_t max_size, + igraph_int_t max_results) { /* Implementation details. TODO */ - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t PX, R, H, pos, nextv; igraph_vector_int_t coreness; igraph_vector_int_t order; igraph_vector_int_t rank; /* TODO: this is not needed */ - igraph_integer_t i, ii, nn; + igraph_int_t i, ii, nn; igraph_adjlist_t adjlist, fulladjlist; + igraph_int_t result_count = 0; igraph_real_t pgreset = round(no_of_nodes / 100.0), pg = pgreset, pgc = 0; igraph_error_t err; @@ -221,13 +228,19 @@ igraph_error_t FUNCTION(igraph_maximal_cliques, SUFFIX)( IGRAPH_WARNING("Edge directions are ignored for maximal clique calculations."); } + PREPARE; + + if (max_results == 0) { + return IGRAPH_SUCCESS; + } + IGRAPH_VECTOR_INT_INIT_FINALLY(&order, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&rank, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&coreness, no_of_nodes); IGRAPH_CHECK(igraph_coreness(graph, &coreness, /*mode=*/ IGRAPH_ALL)); IGRAPH_CHECK(igraph_vector_int_sort_ind(&coreness, &order, IGRAPH_ASCENDING)); for (ii = 0; ii < no_of_nodes; ii++) { - igraph_integer_t v = VECTOR(order)[ii]; + igraph_int_t v = VECTOR(order)[ii]; VECTOR(rank)[v] = ii; } @@ -246,15 +259,13 @@ igraph_error_t FUNCTION(igraph_maximal_cliques, SUFFIX)( IGRAPH_VECTOR_INT_INIT_FINALLY(&pos, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&nextv, 100); - PREPARE; - FOR_LOOP_OVER_VERTICES { - igraph_integer_t v; - igraph_integer_t vrank; + igraph_int_t v; + igraph_int_t vrank; igraph_vector_int_t *vneis; - igraph_integer_t vdeg; - igraph_integer_t Pptr, Xptr, PS, PE, XS, XE; - igraph_integer_t j; + igraph_int_t vdeg; + igraph_int_t Pptr, Xptr, PS, PE, XS, XE; + igraph_int_t j; FOR_LOOP_OVER_VERTICES_PREPARE; @@ -287,7 +298,7 @@ igraph_error_t FUNCTION(igraph_maximal_cliques, SUFFIX)( VECTOR(R)[0] = v; for (j = 0; j < vdeg; j++) { - igraph_integer_t vx = VECTOR(*vneis)[j]; + igraph_int_t vx = VECTOR(*vneis)[j]; if (VECTOR(rank)[vx] > vrank) { VECTOR(PX)[Pptr] = vx; VECTOR(pos)[vx] = Pptr + 1; @@ -309,14 +320,14 @@ igraph_error_t FUNCTION(igraph_maximal_cliques, SUFFIX)( igraph_adjlist_get(&fulladjlist, v) )); for (j = 0; j <= vdeg - 1; j++) { - igraph_integer_t vv = VECTOR(PX)[j]; + igraph_int_t vv = VECTOR(PX)[j]; igraph_vector_int_t *fadj = igraph_adjlist_get(&fulladjlist, vv); igraph_vector_int_t *radj = igraph_adjlist_get(&adjlist, vv); - igraph_integer_t k, fn = igraph_vector_int_size(fadj); + igraph_int_t k, fn = igraph_vector_int_size(fadj); igraph_vector_int_clear(radj); for (k = 0; k < fn; k++) { - igraph_integer_t nei = VECTOR(*fadj)[k]; - igraph_integer_t neipos = VECTOR(pos)[nei] - 1; + igraph_int_t nei = VECTOR(*fadj)[k]; + igraph_int_t neipos = VECTOR(pos)[nei] - 1; if (neipos >= PS && neipos <= XE) { IGRAPH_CHECK(igraph_vector_int_push_back(radj, nei)); } @@ -330,8 +341,8 @@ igraph_error_t FUNCTION(igraph_maximal_cliques, SUFFIX)( err = FUNCTION(igraph_i_maximal_cliques_bk, SUFFIX)( &PX, PS, PE, XS, XE, PS, XE, &R, &pos, - &adjlist, RESNAME, &nextv, &H, min_size, - max_size); + &adjlist, RESNAME, &nextv, &H, + min_size, max_size, max_results, &result_count); if (err == IGRAPH_STOP) { break; } else { diff --git a/src/vendor/cigraph/src/community/community_internal.h b/src/vendor/cigraph/src/community/community_internal.h index 052e866c7bc..4282547f674 100644 --- a/src/vendor/cigraph/src/community/community_internal.h +++ b/src/vendor/cigraph/src/community/community_internal.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2025 The igraph development team This program is free software; you can redistribute it and/or modify @@ -22,13 +22,13 @@ #include "igraph_decls.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS igraph_error_t igraph_i_reindex_membership_large( igraph_vector_int_t *membership, igraph_vector_int_t *new_to_old, - igraph_integer_t *nb_clusters); + igraph_int_t *nb_clusters); -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_COMMUNITY_INTERNAL_H */ diff --git a/src/vendor/cigraph/src/community/community_misc.c b/src/vendor/cigraph/src/community/community_misc.c index 93b3e7291b9..6072da658a9 100644 --- a/src/vendor/cigraph/src/community/community_misc.c +++ b/src/vendor/cigraph/src/community/community_misc.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2007-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -103,14 +103,14 @@ * Time complexity: O(|V|), the number of vertices in the graph. */ igraph_error_t igraph_community_to_membership(const igraph_matrix_int_t *merges, - igraph_integer_t nodes, - igraph_integer_t steps, + igraph_int_t nodes, + igraph_int_t steps, igraph_vector_int_t *membership, igraph_vector_int_t *csize) { - const igraph_integer_t no_of_nodes = nodes; - const igraph_integer_t components = no_of_nodes - steps; - igraph_integer_t found = 0; + const igraph_int_t no_of_nodes = nodes; + const igraph_int_t components = no_of_nodes - steps; + igraph_int_t found = 0; igraph_vector_int_t tmp; igraph_vector_bool_t already_merged; igraph_vector_int_t own_membership; @@ -149,9 +149,9 @@ igraph_error_t igraph_community_to_membership(const igraph_matrix_int_t *merges, IGRAPH_VECTOR_BOOL_INIT_FINALLY(&already_merged, steps + no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, steps); - for (igraph_integer_t i = steps - 1; i >= 0; i--) { - const igraph_integer_t c1 = MATRIX(*merges, i, 0); - const igraph_integer_t c2 = MATRIX(*merges, i, 1); + for (igraph_int_t i = steps - 1; i >= 0; i--) { + const igraph_int_t c1 = MATRIX(*merges, i, 0); + const igraph_int_t c2 = MATRIX(*merges, i, 1); if (VECTOR(already_merged)[c1] == 0) { VECTOR(already_merged)[c1] = true; @@ -171,7 +171,7 @@ igraph_error_t igraph_community_to_membership(const igraph_matrix_int_t *merges, } if (c1 < no_of_nodes) { - const igraph_integer_t cid = VECTOR(tmp)[i] - 1; + const igraph_int_t cid = VECTOR(tmp)[i] - 1; if (membership) { VECTOR(*membership)[c1] = cid + 1; } @@ -183,7 +183,7 @@ igraph_error_t igraph_community_to_membership(const igraph_matrix_int_t *merges, } if (c2 < no_of_nodes) { - const igraph_integer_t cid = VECTOR(tmp)[i] - 1; + const igraph_int_t cid = VECTOR(tmp)[i] - 1; if (membership) { VECTOR(*membership)[c2] = cid + 1; } @@ -197,21 +197,18 @@ igraph_error_t igraph_community_to_membership(const igraph_matrix_int_t *merges, } if (membership || csize) { - /* it can never happen that csize != NULL and membership == NULL; we have - * handled that case above */ - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - const igraph_integer_t c = VECTOR(*membership)[i]; + /* It can never happen that csize != NULL and membership == NULL; we have + * handled that case above. Thus we skip if (membership) checks, which + * would confuse static analysers in this context. */ + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + const igraph_int_t c = VECTOR(*membership)[i]; if (c != 0) { - if (membership) { - VECTOR(*membership)[i] = c - 1; - } + VECTOR(*membership)[i] = c - 1; } else { if (csize) { VECTOR(*csize)[found] += 1; } - if (membership) { - VECTOR(*membership)[i] = found; - } + VECTOR(*membership)[i] = found; found++; } } @@ -245,9 +242,9 @@ igraph_error_t igraph_community_to_membership(const igraph_matrix_int_t *merges, igraph_error_t igraph_i_reindex_membership_large( igraph_vector_int_t *membership, igraph_vector_int_t *new_to_old, - igraph_integer_t *nb_clusters) { + igraph_int_t *nb_clusters) { - const igraph_integer_t vcount = igraph_vector_int_size(membership); + const igraph_int_t vcount = igraph_vector_int_size(membership); igraph_vector_int_t permutation; /* The vcount == 0 case requires special handling because the main @@ -270,16 +267,16 @@ igraph_error_t igraph_i_reindex_membership_large( igraph_vector_int_clear(new_to_old); } - igraph_integer_t j = VECTOR(permutation)[0]; - igraph_integer_t c_old = VECTOR(*membership)[j]; - igraph_integer_t c_old_prev = c_old; - igraph_integer_t c_new = 0; + igraph_int_t j = VECTOR(permutation)[0]; + igraph_int_t c_old = VECTOR(*membership)[j]; + igraph_int_t c_old_prev = c_old; + igraph_int_t c_new = 0; if (new_to_old) { IGRAPH_CHECK(igraph_vector_int_push_back(new_to_old, c_old)); } VECTOR(*membership)[j] = c_new; - for (igraph_integer_t i=1; i < vcount; i++) { + for (igraph_int_t i=1; i < vcount; i++) { j = VECTOR(permutation)[i]; c_old = VECTOR(*membership)[j]; if (c_old != c_old_prev) { @@ -329,11 +326,11 @@ igraph_error_t igraph_i_reindex_membership_large( igraph_error_t igraph_reindex_membership( igraph_vector_int_t *membership, igraph_vector_int_t *new_to_old, - igraph_integer_t *nb_clusters) { + igraph_int_t *nb_clusters) { - const igraph_integer_t vcount = igraph_vector_int_size(membership); + const igraph_int_t vcount = igraph_vector_int_size(membership); igraph_vector_int_t new_cluster; - igraph_integer_t i_nb_clusters; + igraph_int_t i_nb_clusters; /* First, we assume cluster indices in the range 0..vcount-1, * and attempt to use a performant implementation. If indices @@ -348,8 +345,8 @@ igraph_error_t igraph_reindex_membership( /* Clean clusters. We will store the new cluster + 1 so that membership == 0 * indicates that no cluster was assigned yet. */ i_nb_clusters = 1; - for (igraph_integer_t i = 0; i < vcount; i++) { - igraph_integer_t c = VECTOR(*membership)[i]; + for (igraph_int_t i = 0; i < vcount; i++) { + igraph_int_t c = VECTOR(*membership)[i]; if (c < 0 || c >= vcount) { /* Found cluster indices out of the 0..vcount-1 range. @@ -369,8 +366,8 @@ igraph_error_t igraph_reindex_membership( } /* Assign new membership */ - for (igraph_integer_t i = 0; i < vcount; i++) { - igraph_integer_t c = VECTOR(*membership)[i]; + for (igraph_int_t i = 0; i < vcount; i++) { + igraph_int_t c = VECTOR(*membership)[i]; VECTOR(*membership)[i] = VECTOR(new_cluster)[c] - 1; } @@ -392,8 +389,8 @@ static igraph_error_t igraph_i_compare_communities_nmi(const igraph_vector_int_t static igraph_error_t igraph_i_compare_communities_rand(const igraph_vector_int_t *v1, const igraph_vector_int_t *v2, igraph_real_t* result, igraph_bool_t adjust); static igraph_error_t igraph_i_split_join_distance(const igraph_vector_int_t *v1, - const igraph_vector_int_t *v2, igraph_integer_t* distance12, - igraph_integer_t* distance21); + const igraph_vector_int_t *v2, igraph_int_t* distance12, + igraph_int_t* distance21); /** * \ingroup communities @@ -549,7 +546,7 @@ igraph_error_t igraph_compare_communities(const igraph_vector_int_t *comm1, break; case IGRAPH_COMMCMP_SPLIT_JOIN: { - igraph_integer_t d12, d21; + igraph_int_t d12, d21; IGRAPH_CHECK(igraph_i_split_join_distance(&c1, &c2, &d12, &d21)); *result = d12 + d21; } @@ -609,10 +606,10 @@ igraph_error_t igraph_compare_communities(const igraph_vector_int_t *comm1, * * \param comm1 the membership vector of the first community structure * \param comm2 the membership vector of the second community structure - * \param distance12 pointer to an \c igraph_integer_t, the projection distance + * \param distance12 pointer to an \c igraph_int_t, the projection distance * of the first community structure from the second one will be * returned here. - * \param distance21 pointer to an \c igraph_integer_t, the projection distance + * \param distance21 pointer to an \c igraph_int_t, the projection distance * of the second community structure from the first one will be * returned here. * \return Error code. @@ -624,8 +621,8 @@ igraph_error_t igraph_compare_communities(const igraph_vector_int_t *comm1, * Time complexity: O(n log(n)). */ igraph_error_t igraph_split_join_distance(const igraph_vector_int_t *comm1, - const igraph_vector_int_t *comm2, igraph_integer_t *distance12, - igraph_integer_t *distance21) { + const igraph_vector_int_t *comm2, igraph_int_t *distance12, + igraph_int_t *distance21) { igraph_vector_int_t c1, c2; if (igraph_vector_int_size(comm1) != igraph_vector_int_size(comm2)) { @@ -660,9 +657,9 @@ igraph_error_t igraph_split_join_distance(const igraph_vector_int_t *comm1, */ static igraph_error_t igraph_i_entropy_and_mutual_information(const igraph_vector_int_t* v1, const igraph_vector_int_t* v2, double* h1, double* h2, double* mut_inf) { - igraph_integer_t i, n; - igraph_integer_t k1; - igraph_integer_t k2; + igraph_int_t i, n; + igraph_int_t k1; + igraph_int_t k2; igraph_real_t *p1, *p2; igraph_sparsemat_t m; igraph_sparsemat_t mu; /* uncompressed */ @@ -811,7 +808,7 @@ static igraph_error_t igraph_i_compare_communities_vi(const igraph_vector_int_t */ static igraph_error_t igraph_i_confusion_matrix(const igraph_vector_int_t *v1, const igraph_vector_int_t *v2, igraph_sparsemat_t *m) { - igraph_integer_t k1, k2, i, n; + igraph_int_t k1, k2, i, n; n = igraph_vector_int_size(v1); if (n == 0) { @@ -848,8 +845,8 @@ static igraph_error_t igraph_i_confusion_matrix(const igraph_vector_int_t *v1, c * and k2 are the number of clusters in each of the clusterings. */ static igraph_error_t igraph_i_split_join_distance(const igraph_vector_int_t *v1, const igraph_vector_int_t *v2, - igraph_integer_t* distance12, igraph_integer_t* distance21) { - igraph_integer_t n = igraph_vector_int_size(v1); + igraph_int_t* distance12, igraph_int_t* distance21) { + igraph_int_t n = igraph_vector_int_size(v1); igraph_vector_t rowmax, colmax; igraph_sparsemat_t m; igraph_sparsemat_t mu; /* uncompressed */ @@ -876,8 +873,8 @@ static igraph_error_t igraph_i_split_join_distance(const igraph_vector_int_t *v1 IGRAPH_CHECK(igraph_sparsemat_iterator_init(&mit, &m)); while (!igraph_sparsemat_iterator_end(&mit)) { igraph_real_t value = igraph_sparsemat_iterator_get(&mit); - igraph_integer_t row = igraph_sparsemat_iterator_row(&mit); - igraph_integer_t col = igraph_sparsemat_iterator_col(&mit); + igraph_int_t row = igraph_sparsemat_iterator_row(&mit); + igraph_int_t col = igraph_sparsemat_iterator_col(&mit); if (value > VECTOR(rowmax)[row]) { VECTOR(rowmax)[row] = value; } @@ -888,8 +885,8 @@ static igraph_error_t igraph_i_split_join_distance(const igraph_vector_int_t *v1 } /* Calculate the distances */ - *distance12 = (igraph_integer_t) (n - igraph_vector_sum(&rowmax)); - *distance21 = (igraph_integer_t) (n - igraph_vector_sum(&colmax)); + *distance12 = (igraph_int_t) (n - igraph_vector_sum(&rowmax)); + *distance21 = (igraph_int_t) (n - igraph_vector_sum(&colmax)); igraph_vector_destroy(&rowmax); igraph_vector_destroy(&colmax); @@ -929,7 +926,7 @@ static igraph_error_t igraph_i_compare_communities_rand( igraph_sparsemat_t mu; /* uncompressed */ igraph_sparsemat_iterator_t mit; igraph_vector_t rowsums, colsums; - igraph_integer_t i, nrow, ncol; + igraph_int_t i, nrow, ncol; igraph_real_t rand, n; igraph_real_t frac_pairs_in_1, frac_pairs_in_2; diff --git a/src/vendor/cigraph/src/community/edge_betweenness.c b/src/vendor/cigraph/src/community/edge_betweenness.c index d916f6361b9..d5982b3f4ad 100644 --- a/src/vendor/cigraph/src/community/edge_betweenness.c +++ b/src/vendor/cigraph/src/community/edge_betweenness.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -24,6 +22,7 @@ #include "igraph_community.h" #include "igraph_adjlist.h" +#include "igraph_bitset.h" #include "igraph_components.h" #include "igraph_dqueue.h" #include "igraph_interface.h" @@ -38,14 +37,14 @@ #include static igraph_error_t igraph_i_rewrite_membership_vector(igraph_vector_int_t *membership) { - const igraph_integer_t no = igraph_vector_int_max(membership) + 1; + const igraph_int_t no = igraph_vector_int_max(membership) + 1; igraph_vector_int_t idx; - igraph_integer_t realno = 0; - const igraph_integer_t len = igraph_vector_int_size(membership); + igraph_int_t realno = 0; + const igraph_int_t len = igraph_vector_int_size(membership); IGRAPH_VECTOR_INT_INIT_FINALLY(&idx, no); - for (igraph_integer_t i = 0; i < len; i++) { - const igraph_integer_t t = VECTOR(*membership)[i]; + for (igraph_int_t i = 0; i < len; i++) { + const igraph_int_t t = VECTOR(*membership)[i]; if (VECTOR(idx)[t]) { VECTOR(*membership)[i] = VECTOR(idx)[t] - 1; } else { @@ -69,12 +68,12 @@ static igraph_error_t igraph_i_community_eb_get_merges2(const igraph_t *graph, igraph_vector_int_t *membership) { igraph_vector_int_t mymembership; - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_real_t maxmod = -1; - igraph_integer_t midx = 0; - igraph_integer_t no_comps; + igraph_int_t midx = 0; + igraph_int_t no_comps; const igraph_bool_t use_directed = directed && igraph_is_directed(graph); - igraph_integer_t max_merges; + igraph_int_t max_merges; if (membership) { IGRAPH_CHECK(igraph_vector_int_resize(membership, no_of_nodes)); @@ -110,12 +109,12 @@ static igraph_error_t igraph_i_community_eb_get_merges2(const igraph_t *graph, VECTOR(*modularity)[0] = maxmod; } - for (igraph_integer_t i = igraph_vector_int_size(edges) - 1; i >= 0; i--) { - igraph_integer_t edge = VECTOR(*edges)[i]; - igraph_integer_t from = IGRAPH_FROM(graph, edge); - igraph_integer_t to = IGRAPH_TO(graph, edge); - igraph_integer_t c1 = VECTOR(mymembership)[from]; - igraph_integer_t c2 = VECTOR(mymembership)[to]; + for (igraph_int_t i = igraph_vector_int_size(edges) - 1; i >= 0; i--) { + igraph_int_t edge = VECTOR(*edges)[i]; + igraph_int_t from = IGRAPH_FROM(graph, edge); + igraph_int_t to = IGRAPH_TO(graph, edge); + igraph_int_t c1 = VECTOR(mymembership)[from]; + igraph_int_t c2 = VECTOR(mymembership)[to]; igraph_real_t actmod; if (c1 != c2) { /* this is a merge */ @@ -128,7 +127,7 @@ static igraph_error_t igraph_i_community_eb_get_merges2(const igraph_t *graph, } /* The new cluster has id no_of_nodes+midx+1 */ - for (igraph_integer_t j = 0; j < no_of_nodes; j++) { + for (igraph_int_t j = 0; j < no_of_nodes; j++) { if (VECTOR(mymembership)[j] == c1 || VECTOR(mymembership)[j] == c2) { VECTOR(mymembership)[j] = no_of_nodes + midx; @@ -225,16 +224,19 @@ igraph_error_t igraph_community_eb_get_merges(const igraph_t *graph, igraph_vector_t *modularity, igraph_vector_int_t *membership) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_int_t ptr; - igraph_integer_t midx = 0; - igraph_integer_t no_comps; - const igraph_integer_t no_removed_edges = igraph_vector_int_size(edges); - igraph_integer_t max_merges; + igraph_int_t midx = 0; + igraph_int_t no_comps; + const igraph_int_t no_removed_edges = igraph_vector_int_size(edges); + igraph_int_t max_merges; if (! igraph_vector_int_isininterval(edges, 0, no_of_edges-1)) { - IGRAPH_ERROR("Invalid edge ID.", IGRAPH_EINVAL); + IGRAPH_ERROR( + "Cannot calculate merges of edge betweenness community detection.", + IGRAPH_EINVEID + ); } if (no_removed_edges < no_of_edges) { IGRAPH_ERRORF("Number of removed edges (%" IGRAPH_PRId ") should be equal to " @@ -278,9 +280,9 @@ igraph_error_t igraph_community_eb_get_merges(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_resize(bridges, max_merges)); } - for (igraph_integer_t i = igraph_vector_int_size(edges) - 1; i >= 0; i--) { - igraph_integer_t edge = VECTOR(*edges)[i]; - igraph_integer_t from, to, c1, c2, idx; + for (igraph_int_t i = igraph_vector_int_size(edges) - 1; i >= 0; i--) { + igraph_int_t edge = VECTOR(*edges)[i]; + igraph_int_t from, to, c1, c2, idx; IGRAPH_CHECK(igraph_edge(graph, edge, &from, &to)); idx = from + 1; while (VECTOR(ptr)[idx - 1] != 0) { @@ -316,19 +318,24 @@ igraph_error_t igraph_community_eb_get_merges(const igraph_t *graph, return IGRAPH_SUCCESS; } -/* Find the smallest active element in the vector */ -static igraph_integer_t igraph_i_vector_which_max_not_null(const igraph_vector_t *v, - const bool *passive) { - igraph_integer_t which, i = 0, size = igraph_vector_size(v); - igraph_real_t max; - while (passive[i]) { - i++; - } - which = i; - max = VECTOR(*v)[which]; - for (i++; i < size; i++) { - igraph_real_t elem = VECTOR(*v)[i]; - if (!passive[i] && elem > max) { +/* Find the index i for which v[i] / w[i] is the largest + * and the corresponding element is active (i.e. !passive[i]). + * If w is a null pointer then all w[i] are assumed to be 1, + * and the ranking is done solely based on v. + * + * This function requires that at least one element is active. */ +static igraph_int_t igraph_i_which_max_active_ratio( + const igraph_vector_t *v, + const igraph_vector_t *w, + igraph_bitset_t *passive) { + + const igraph_int_t size = igraph_vector_size(v); + igraph_int_t which = igraph_bitset_countr_one(passive); /* start with first active element */ + igraph_real_t max = VECTOR(*v)[which] / (w ? VECTOR(*w)[which] : 1.0); + + for (igraph_int_t i = which+1; i < size; i++) { + igraph_real_t elem = VECTOR(*v)[i] / (w ? VECTOR(*w)[i] : 1.0); + if (! IGRAPH_BIT_TEST(*passive, i) && elem > max) { max = elem; which = i; } @@ -342,18 +349,18 @@ static igraph_integer_t igraph_i_vector_which_max_not_null(const igraph_vector_t * \brief Community finding based on edge betweenness. * * Community structure detection based on the betweenness of the edges - * in the network, known as the Grivan-Newman algorithm. + * in the network. This method is also known as the Girvan-Newman + * algorithm. * * - * The idea is that the betweenness of the edges connecting two - * communities is typically high, as many of the shortest paths - * between nodes in separate communities go through them. So we - * gradually remove the edge with highest betweenness from the - * network, and recalculate edge betweenness after every removal. - * This way sooner or later the network splits into two components, - * then after a while one of these components splits again into two smaller - * components, and so on until all edges are removed. This is a divisive - * hierarchical approach, the result of which is a dendrogram. + * The idea behind this method is that the betweenness of the edges connecting + * two communities is typically high, as many of the shortest paths between + * vertices in separate communities pass through them. The algorithm + * successively removes edges with the highest betweenness, recalculating + * betweenness values after each removal. This way eventually the network splits + * into two components, then one of these components splits again, and so on, + * until all edges are removed. The resulting hierarhical partitioning of the + * vertices can be encoded as a dendrogram. * * * In directed graphs, when \p directed is set to true, the directed version @@ -361,22 +368,46 @@ static igraph_integer_t igraph_i_vector_which_max_not_null(const igraph_vector_t * \em weakly connected components are detected. * * - * Reference: + * When edge weights are given, the ratio of betweenness and weight values + * is used to choose which edges to remove first, as described in + * M. E. J. Newman: Analysis of Weighted Networks (2004), Section C. + * Thus, edges with large weights are treated as strong connections, + * and will be removed later than weak connections having similar betweenness. + * Weights are also used for calculating modularity. + * + * + * If lengths are given, they will be considered for shortest path length + * calculations while computing betweenness values. + * + * + * Note: In igraph 0.10, this function interpreted weights in a different, + * erroneous way, and issued a warning when weights were used. Please + * see https://github.com/igraph/igraph/issues/2229 for additional details. * * - * M. Girvan and M. E. J. Newman: - * Community structure in social and biological networks. - * Proc. Nat. Acad. Sci. USA 99, 7821-7826 (2002). + * References: + * + * + * M. Girvan and M. E. J. Newman, + * Community Structure in Social and Biological Networks, PNAS 99, 7821 (2002). * https://doi.org/10.1073/pnas.122653799 * + * + * M. E. J. Newman, + * Analysis of Weighted Networks, Phys. Rev. E 70, 9 (2004). + * https://doi.org/10.1103/PhysRevE.70.056131 + * * \param graph The input graph. - * \param removed_edges Pointer to an initialized vector, the result will be - * stored here, the IDs of the removed edges in the order of their - * removal. It will be resized as needed. It may be \c NULL if + * \param removed_edges Pointer to an initialized integer vector, which will + * be resized as needed. The IDs of the removed edges in the order of their + * removal will be stored here. This vector is suitable as input to + * \ref igraph_community_eb_get_merges(). This parameter may be \c NULL if * the edge IDs are not needed by the caller. * \param edge_betweenness Pointer to an initialized vector or * \c NULL. In the former case the edge betweenness of the removed - * edge is stored here. The vector will be resized as needed. + * edges is stored here. The vector will be resized as needed. + * Note that the betweenness values stored here are \em not divided + * by weights. * \param merges Pointer to an initialized matrix or \c NULL. If not \c NULL * then merges performed by the algorithm are stored here. Even if * this is a divisive algorithm, we can replay it backwards and @@ -397,10 +428,12 @@ static igraph_integer_t igraph_i_vector_which_max_not_null(const igraph_vector_t * betweenness (i.e. directed paths) for directed graphs, and whether * to use the directed version of modularity. It is ignored for undirected * graphs. - * \param weights An optional vector containing edge weights. If null, - * the unweighted edge betweenness scores will be calculated and - * used. If not null, the weighted edge betweenness scores will be - * calculated and used. + * \param weights An optional vector containing edge weights. If not \c NULL, + * the weights will be used to divide the edge betweenness scores, + * as well as for the calculation of modularity. + * \param lengths An optional vector containing edge lengths. If not \c NULL, + * path lengths used in the betweenness calculation will take these + * lengths into account. * \return Error code. * * \sa \ref igraph_community_eb_get_merges(), \ref @@ -419,25 +452,25 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, igraph_vector_t *modularity, igraph_vector_int_t *membership, igraph_bool_t directed, - const igraph_vector_t *weights) { + const igraph_vector_t *weights, + const igraph_vector_t *lengths) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); double *distance, *tmpscore; double *nrgeo; igraph_inclist_t elist_out, elist_in, parents; igraph_inclist_t *elist_out_p, *elist_in_p; igraph_vector_int_t *neip; - igraph_integer_t neino; + igraph_int_t neino; igraph_vector_t eb; - igraph_integer_t maxedge, pos; - igraph_integer_t from, to; + igraph_int_t maxedge, pos; + igraph_int_t from, to; igraph_bool_t result_owned = false; igraph_stack_int_t stack; igraph_real_t steps, steps_done; - - bool *passive; + igraph_bitset_t passive; /* Needed only for the unweighted case */ igraph_dqueue_int_t q; @@ -480,9 +513,7 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, IGRAPH_CHECK_OOM(tmpscore, "Insufficient memory for edge betweenness-based community detection."); IGRAPH_FINALLY(igraph_free, tmpscore); - if (weights == NULL) { - IGRAPH_DQUEUE_INT_INIT_FINALLY(&q, 100); - } else { + if (weights) { if (igraph_vector_size(weights) != no_of_edges) { IGRAPH_ERROR("Weight vector length must agree with number of edges.", IGRAPH_EINVAL); } @@ -498,17 +529,25 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, IGRAPH_ERROR("Weights must not be NaN.", IGRAPH_EINVAL); } } + } - if (membership != NULL) { - IGRAPH_WARNING("Membership vector will be selected based on the highest " - "modularity score."); + if (lengths == NULL) { + IGRAPH_DQUEUE_INT_INIT_FINALLY(&q, 100); + } else { + if (igraph_vector_size(lengths) != no_of_edges) { + IGRAPH_ERROR("Edge length vector size must agree with number of edges.", IGRAPH_EINVAL); } - if (modularity != NULL || membership != NULL) { - IGRAPH_WARNING("Modularity calculation with weighted edge betweenness " - "community detection might not make sense -- modularity treats edge " - "weights as similarities while edge betwenness treats them as " - "distances."); + if (no_of_edges > 0) { + /* Must not call vector_min on empty vector */ + igraph_real_t minlength = igraph_vector_min(lengths); + if (minlength <= 0) { + IGRAPH_ERROR("Edge lengths must be strictly positive.", IGRAPH_EINVAL); + } + + if (isnan(minlength)) { + IGRAPH_ERROR("Edge lengths must not be NaN.", IGRAPH_EINVAL); + } } IGRAPH_CHECK(igraph_2wheap_init(&heap, no_of_nodes)); @@ -528,10 +567,7 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, } IGRAPH_VECTOR_INIT_FINALLY(&eb, no_of_edges); - - passive = IGRAPH_CALLOC(no_of_edges, bool); - IGRAPH_CHECK_OOM(passive, "Insufficient memory for edge betweenness-based community detection."); - IGRAPH_FINALLY(igraph_free, passive); + IGRAPH_BITSET_INIT_FINALLY(&passive, no_of_edges); /* Estimate the number of steps to be taken. * It is assumed that one iteration is O(|E||V|), but |V| is constant @@ -542,18 +578,18 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, steps = no_of_edges / 2.0 * (no_of_edges + 1); steps_done = 0; - for (igraph_integer_t e = 0; e < no_of_edges; steps_done += no_of_edges - e, e++) { + for (igraph_int_t e = 0; e < no_of_edges; steps_done += no_of_edges - e, e++) { IGRAPH_PROGRESS("Edge betweenness community detection: ", 100.0 * steps_done / steps, NULL); igraph_vector_null(&eb); - if (weights == NULL) { + if (lengths == NULL) { /* Unweighted variant follows */ /* The following for loop is copied almost intact from * igraph_edge_betweenness_cutoff */ - for (igraph_integer_t source = 0; source < no_of_nodes; source++) { + for (igraph_int_t source = 0; source < no_of_nodes; source++) { IGRAPH_ALLOW_INTERRUPTION(); @@ -568,13 +604,13 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, distance[source] = 0; while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); neip = igraph_inclist_get(elist_out_p, actnode); neino = igraph_vector_int_size(neip); - for (igraph_integer_t i = 0; i < neino; i++) { - igraph_integer_t edge = VECTOR(*neip)[i]; - igraph_integer_t neighbor = IGRAPH_OTHER(graph, edge, actnode); + for (igraph_int_t i = 0; i < neino; i++) { + igraph_int_t edge = VECTOR(*neip)[i]; + igraph_int_t neighbor = IGRAPH_OTHER(graph, edge, actnode); if (nrgeo[neighbor] != 0) { /* we've already seen this node, another shortest path? */ if (distance[neighbor] == distance[actnode] + 1) { @@ -594,7 +630,7 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, shortest paths to them. Now we do an inverse search, starting with the farthest nodes. */ while (!igraph_stack_int_empty(&stack)) { - igraph_integer_t actnode = igraph_stack_int_pop(&stack); + igraph_int_t actnode = igraph_stack_int_pop(&stack); if (distance[actnode] < 1) { continue; /* skip source node */ } @@ -602,9 +638,9 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, /* set the temporary score of the friends */ neip = igraph_inclist_get(elist_in_p, actnode); neino = igraph_vector_int_size(neip); - for (igraph_integer_t i = 0; i < neino; i++) { - igraph_integer_t edge = VECTOR(*neip)[i]; - igraph_integer_t neighbor = IGRAPH_OTHER(graph, edge, actnode); + for (igraph_int_t i = 0; i < neino; i++) { + igraph_int_t edge = VECTOR(*neip)[i]; + igraph_int_t neighbor = IGRAPH_OTHER(graph, edge, actnode); if (distance[neighbor] == distance[actnode] - 1 && nrgeo[neighbor] != 0) { tmpscore[neighbor] += @@ -624,7 +660,7 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, /* The following for loop is copied almost intact from * igraph_i_edge_betweenness_cutoff_weighted */ - for (igraph_integer_t source = 0; source < no_of_nodes; source++) { + for (igraph_int_t source = 0; source < no_of_nodes; source++) { /* This will contain the edge betweenness in the current step */ IGRAPH_ALLOW_INTERRUPTION(); @@ -637,7 +673,7 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, nrgeo[source] = 1; while (!igraph_2wheap_empty(&heap)) { - igraph_integer_t minnei = igraph_2wheap_max_index(&heap); + igraph_int_t minnei = igraph_2wheap_max_index(&heap); igraph_real_t mindist = -igraph_2wheap_delete_max(&heap); IGRAPH_CHECK(igraph_stack_int_push(&stack, minnei)); @@ -645,10 +681,10 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, neip = igraph_inclist_get(elist_out_p, minnei); neino = igraph_vector_int_size(neip); - for (igraph_integer_t i = 0; i < neino; i++) { - igraph_integer_t edge = VECTOR(*neip)[i]; - igraph_integer_t to = IGRAPH_OTHER(graph, edge, minnei); - igraph_real_t altdist = mindist + VECTOR(*weights)[edge]; + for (igraph_int_t i = 0; i < neino; i++) { + igraph_int_t edge = VECTOR(*neip)[i]; + igraph_int_t to = IGRAPH_OTHER(graph, edge, minnei); + igraph_real_t altdist = mindist + VECTOR(*lengths)[edge]; igraph_real_t curdist = distance[to]; igraph_vector_int_t *v; @@ -683,13 +719,13 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, } /* igraph_2wheap_empty(&Q) */ while (!igraph_stack_int_empty(&stack)) { - igraph_integer_t w = igraph_stack_int_pop(&stack); + igraph_int_t w = igraph_stack_int_pop(&stack); igraph_vector_int_t *parv = igraph_inclist_get(&parents, w); - igraph_integer_t parv_len = igraph_vector_int_size(parv); + igraph_int_t parv_len = igraph_vector_int_size(parv); - for (igraph_integer_t i = 0; i < parv_len; i++) { - igraph_integer_t fedge = VECTOR(*parv)[i]; - igraph_integer_t neighbor = IGRAPH_OTHER(graph, fedge, w); + for (igraph_int_t i = 0; i < parv_len; i++) { + igraph_int_t fedge = VECTOR(*parv)[i]; + igraph_int_t neighbor = IGRAPH_OTHER(graph, fedge, w); tmpscore[neighbor] += (tmpscore[w] + 1) * nrgeo[neighbor] / nrgeo[w]; VECTOR(eb)[fedge] += (tmpscore[w] + 1) * nrgeo[neighbor] / nrgeo[w]; } @@ -704,7 +740,7 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, /* Now look for the smallest edge betweenness */ /* and eliminate that edge from the network */ - maxedge = igraph_i_vector_which_max_not_null(&eb, passive); + maxedge = igraph_i_which_max_active_ratio(&eb, weights, &passive); VECTOR(*removed_edges)[e] = maxedge; if (edge_betweenness) { VECTOR(*edge_betweenness)[e] = VECTOR(eb)[maxedge]; @@ -712,7 +748,7 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, VECTOR(*edge_betweenness)[e] /= 2.0; } } - passive[maxedge] = true; + IGRAPH_BIT_SET(passive, maxedge); IGRAPH_CHECK(igraph_edge(graph, maxedge, &from, &to)); neip = igraph_inclist_get(elist_in_p, to); @@ -730,12 +766,12 @@ igraph_error_t igraph_community_edge_betweenness(const igraph_t *graph, IGRAPH_PROGRESS("Edge betweenness community detection: ", 100.0, NULL); - IGRAPH_FREE(passive); + igraph_bitset_destroy(&passive); igraph_vector_destroy(&eb); igraph_stack_int_destroy(&stack); IGRAPH_FINALLY_CLEAN(3); - if (weights == NULL) { + if (lengths == NULL) { igraph_dqueue_int_destroy(&q); IGRAPH_FINALLY_CLEAN(1); } else { diff --git a/src/vendor/cigraph/src/community/fast_modularity.c b/src/vendor/cigraph/src/community/fast_modularity.c index 2315d69c0ad..0b4c8a970ee 100644 --- a/src/vendor/cigraph/src/community/fast_modularity.c +++ b/src/vendor/cigraph/src/community/fast_modularity.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -34,24 +33,11 @@ /* #define IGRAPH_FASTCOMM_DEBUG */ -#ifdef _MSC_VER -/* MSVC does not support variadic macros */ -#include -void debug(const char *fmt, ...) { - va_list args; - va_start(args, fmt); -#ifdef IGRAPH_FASTCOMM_DEBUG - vfprintf(stderr, fmt, args); -#endif - va_end(args); -} -#else #ifdef IGRAPH_FASTCOMM_DEBUG #define debug(...) fprintf(stderr, __VA_ARGS__) #else #define debug(...) #endif -#endif /* * Implementation of the community structure algorithm originally published @@ -84,8 +70,8 @@ void debug(const char *fmt, ...) { /* Structure storing a pair of communities along with their dQ values */ typedef struct s_igraph_i_fastgreedy_commpair { - igraph_integer_t first; /* first member of the community pair */ - igraph_integer_t second; /* second member of the community pair */ + igraph_int_t first; /* first member of the community pair */ + igraph_int_t second; /* second member of the community pair */ igraph_real_t *dq; /* pointer to a member of the dq vector storing the */ /* increase in modularity achieved when joining */ struct s_igraph_i_fastgreedy_commpair *opposite; @@ -93,25 +79,25 @@ typedef struct s_igraph_i_fastgreedy_commpair { /* Structure storing a community */ typedef struct { - igraph_integer_t id; /* Identifier of the community (for merges matrix) */ - igraph_integer_t size; /* Size of the community */ + igraph_int_t id; /* Identifier of the community (for merges matrix) */ + igraph_int_t size; /* Size of the community */ igraph_vector_ptr_t neis; /* references to neighboring communities */ igraph_i_fastgreedy_commpair *maxdq; /* community pair with maximal dq */ } igraph_i_fastgreedy_community; /* Global community list structure */ typedef struct { - igraph_integer_t no_of_communities, n; /* number of communities, number of vertices */ + igraph_int_t no_of_communities, n; /* number of communities, number of vertices */ igraph_i_fastgreedy_community *e; /* list of communities */ igraph_i_fastgreedy_community **heap; /* heap of communities */ - igraph_integer_t *heapindex; /* heap index to speed up lookup by community idx */ + igraph_int_t *heapindex; /* heap index to speed up lookup by community idx */ } igraph_i_fastgreedy_community_list; /* Scans the community neighborhood list for the new maximal dq value. * Returns true if the maximum is different from the previous one, * false otherwise. */ static igraph_bool_t igraph_i_fastgreedy_community_rescan_max(igraph_i_fastgreedy_community *comm) { - igraph_integer_t i, n; + igraph_int_t i, n; igraph_i_fastgreedy_commpair *p, *best; igraph_real_t bestdq, currdq; @@ -143,7 +129,7 @@ static igraph_bool_t igraph_i_fastgreedy_community_rescan_max(igraph_i_fastgreed /* Destroys the global community list object */ static void igraph_i_fastgreedy_community_list_destroy( igraph_i_fastgreedy_community_list *list) { - igraph_integer_t i; + igraph_int_t i; for (i = 0; i < list->n; i++) { igraph_vector_ptr_destroy(&list->e[i].neis); } @@ -158,12 +144,12 @@ static void igraph_i_fastgreedy_community_list_destroy( /* Community list heap maintenance: sift down */ static void igraph_i_fastgreedy_community_list_sift_down( - igraph_i_fastgreedy_community_list *list, igraph_integer_t idx) { - igraph_integer_t root, child, c1, c2; + igraph_i_fastgreedy_community_list *list, igraph_int_t idx) { + igraph_int_t root, child, c1, c2; igraph_i_fastgreedy_community *dummy; - igraph_integer_t dummy2; + igraph_int_t dummy2; igraph_i_fastgreedy_community** heap = list->heap; - igraph_integer_t *heapindex = list->heapindex; + igraph_int_t *heapindex = list->heapindex; root = idx; while (root * 2 + 1 < list->no_of_communities) { @@ -193,12 +179,12 @@ static void igraph_i_fastgreedy_community_list_sift_down( /* Community list heap maintenance: sift up */ static void igraph_i_fastgreedy_community_list_sift_up( - igraph_i_fastgreedy_community_list *list, igraph_integer_t idx) { - igraph_integer_t root, parent, c1, c2; + igraph_i_fastgreedy_community_list *list, igraph_int_t idx) { + igraph_int_t root, parent, c1, c2; igraph_i_fastgreedy_community *dummy; - igraph_integer_t dummy2; + igraph_int_t dummy2; igraph_i_fastgreedy_community** heap = list->heap; - igraph_integer_t *heapindex = list->heapindex; + igraph_int_t *heapindex = list->heapindex; root = idx; while (root > 0) { @@ -225,7 +211,7 @@ static void igraph_i_fastgreedy_community_list_sift_up( /* Builds the community heap for the first time */ static void igraph_i_fastgreedy_community_list_build_heap( igraph_i_fastgreedy_community_list *list) { - igraph_integer_t i; + igraph_int_t i; for (i = list->no_of_communities / 2 - 1; i >= 0; i--) { igraph_i_fastgreedy_community_list_sift_down(list, i); } @@ -239,7 +225,7 @@ static void igraph_i_fastgreedy_community_list_build_heap( /* static void igraph_i_fastgreedy_community_list_dump_heap( igraph_i_fastgreedy_community_list *list) { - igraph_integer_t i; + igraph_int_t i; debug("Heap:\n"); for (i = 0; i < list->no_of_communities; i++) { debug("(%ld, %p, %p)", i, list->heap[i], @@ -263,7 +249,7 @@ static void igraph_i_fastgreedy_community_list_dump_heap( /* static void igraph_i_fastgreedy_community_list_check_heap( igraph_i_fastgreedy_community_list *list) { - igraph_integer_t i; + igraph_int_t i; for (i = 0; i < list->no_of_communities / 2; i++) { if ((2 * i + 1 < list->no_of_communities && *list->heap[i]->maxdq->dq < *list->heap[2 * i + 1]->maxdq->dq) || (2 * i + 2 < list->no_of_communities && *list->heap[i]->maxdq->dq < *list->heap[2 * i + 2]->maxdq->dq)) { @@ -277,9 +263,9 @@ static void igraph_i_fastgreedy_community_list_check_heap( /* Removes a given element from the heap */ static void igraph_i_fastgreedy_community_list_remove( - igraph_i_fastgreedy_community_list *list, igraph_integer_t idx) { + igraph_i_fastgreedy_community_list *list, igraph_int_t idx) { igraph_real_t old; - igraph_integer_t commidx; + igraph_int_t commidx; /* First adjust the index */ commidx = list->heap[list->no_of_communities - 1]->maxdq->first; @@ -303,8 +289,8 @@ static void igraph_i_fastgreedy_community_list_remove( /* Removes a given element from the heap when there are no more neighbors * for it (comm->maxdq is NULL) */ static void igraph_i_fastgreedy_community_list_remove2( - igraph_i_fastgreedy_community_list *list, igraph_integer_t idx, igraph_integer_t comm) { - igraph_integer_t i; + igraph_i_fastgreedy_community_list *list, igraph_int_t idx, igraph_int_t comm) { + igraph_int_t i; if (idx == list->no_of_communities - 1) { /* We removed the rightmost element on the bottom level, no problem, @@ -332,8 +318,8 @@ static void igraph_i_fastgreedy_community_list_remove2( /* Removes the pair belonging to community k from the neighborhood list * of community c (that is, clist[c]) and recalculates maxdq */ static void igraph_i_fastgreedy_community_remove_nei( - igraph_i_fastgreedy_community_list *list, igraph_integer_t c, igraph_integer_t k) { - igraph_integer_t i, n; + igraph_i_fastgreedy_community_list *list, igraph_int_t c, igraph_int_t k) { + igraph_int_t i, n; igraph_bool_t rescan = false; igraph_i_fastgreedy_commpair *p; igraph_i_fastgreedy_community *comm; @@ -377,7 +363,7 @@ static void igraph_i_fastgreedy_community_remove_nei( * `second` field */ static int igraph_i_fastgreedy_commpair_cmp(const void *p1, const void *p2) { igraph_i_fastgreedy_commpair *cp1, *cp2; - igraph_integer_t diff; + igraph_int_t diff; cp1 = *(igraph_i_fastgreedy_commpair**)p1; cp2 = *(igraph_i_fastgreedy_commpair**)p2; diff = cp1->second - cp2->second; @@ -388,10 +374,10 @@ static int igraph_i_fastgreedy_commpair_cmp(const void *p1, const void *p2) { * optimizing the process if we know that the list is nearly sorted and only * a given pair is in the wrong place. */ static void igraph_i_fastgreedy_community_sort_neighbors_of( - igraph_i_fastgreedy_community_list *list, igraph_integer_t index, + igraph_i_fastgreedy_community_list *list, igraph_int_t index, igraph_i_fastgreedy_commpair *changed_pair) { igraph_vector_ptr_t *vec; - igraph_integer_t i, n; + igraph_int_t i, n; igraph_bool_t can_skip_sort = false; igraph_i_fastgreedy_commpair *other_pair; @@ -458,7 +444,7 @@ static igraph_bool_t igraph_i_fastgreedy_community_update_dq( igraph_i_fastgreedy_community_list *list, igraph_i_fastgreedy_commpair *p, igraph_real_t newdq) { - igraph_integer_t i, j, to, from; + igraph_int_t i, j, to, from; igraph_real_t olddq; igraph_i_fastgreedy_community *comm_to, *comm_from; to = p->first; from = p->second; @@ -620,8 +606,8 @@ igraph_error_t igraph_community_fastgreedy(const igraph_t *graph, igraph_matrix_int_t *merges, igraph_vector_t *modularity, igraph_vector_int_t *membership) { - igraph_integer_t no_of_edges, no_of_nodes, no_of_joins, total_joins; - igraph_integer_t i, j, k, n, m, from, to, dummy, best_no_of_joins; + igraph_int_t no_of_edges, no_of_nodes, no_of_joins, total_joins; + igraph_int_t i, j, k, n, m, from, to, dummy, best_no_of_joins; igraph_eit_t edgeit; igraph_i_fastgreedy_commpair *pairs, *p1, *p2; igraph_i_fastgreedy_community_list communities; @@ -631,8 +617,8 @@ igraph_error_t igraph_community_fastgreedy(const igraph_t *graph, igraph_bool_t has_multiple; igraph_matrix_int_t merges_local; - /*igraph_integer_t join_order[] = { 16,5, 5,6, 6,0, 4,0, 10,0, 26,29, 29,33, 23,33, 27,33, 25,24, 24,31, 12,3, 21,1, 30,8, 8,32, 9,2, 17,1, 11,0, 7,3, 3,2, 13,2, 1,2, 28,31, 31,33, 22,32, 18,32, 20,32, 32,33, 15,33, 14,33, 0,19, 19,2, -1,-1 };*/ - /*igraph_integer_t join_order[] = { 43,42, 42,41, 44,41, 41,36, 35,36, 37,36, 36,29, 38,29, 34,29, 39,29, 33,29, 40,29, 32,29, 14,29, 30,29, 31,29, 6,18, 18,4, 23,4, 21,4, 19,4, 27,4, 20,4, 22,4, 26,4, 25,4, 24,4, 17,4, 0,13, 13,2, 1,2, 11,2, 8,2, 5,2, 3,2, 10,2, 9,2, 7,2, 2,28, 28,15, 12,15, 29,16, 4,15, -1,-1 };*/ + /*igraph_int_t join_order[] = { 16,5, 5,6, 6,0, 4,0, 10,0, 26,29, 29,33, 23,33, 27,33, 25,24, 24,31, 12,3, 21,1, 30,8, 8,32, 9,2, 17,1, 11,0, 7,3, 3,2, 13,2, 1,2, 28,31, 31,33, 22,32, 18,32, 20,32, 32,33, 15,33, 14,33, 0,19, 19,2, -1,-1 };*/ + /*igraph_int_t join_order[] = { 43,42, 42,41, 44,41, 41,36, 35,36, 37,36, 36,29, 38,29, 34,29, 39,29, 33,29, 40,29, 32,29, 14,29, 30,29, 31,29, 6,18, 18,4, 23,4, 21,4, 19,4, 27,4, 20,4, 22,4, 26,4, 25,4, 24,4, 17,4, 0,13, 13,2, 1,2, 11,2, 8,2, 5,2, 3,2, 10,2, 9,2, 7,2, 2,28, 28,15, 12,15, 29,16, 4,15, -1,-1 };*/ no_of_nodes = igraph_vcount(graph); no_of_edges = igraph_ecount(graph); @@ -694,7 +680,7 @@ igraph_error_t igraph_community_fastgreedy(const igraph_t *graph, } else { debug("Calculating degrees\n"); IGRAPH_VECTOR_INT_INIT_FINALLY(°rees, no_of_nodes); - IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), IGRAPH_ALL, true)); + IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS)); for (i = 0; i < no_of_nodes; i++) { VECTOR(a)[i] = VECTOR(degrees)[i]; } @@ -714,7 +700,7 @@ igraph_error_t igraph_community_fastgreedy(const igraph_t *graph, IGRAPH_CHECK_OOM(communities.heap, "Insufficient memory for fast greedy community detection."); IGRAPH_FINALLY(igraph_free, communities.heap); - communities.heapindex = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + communities.heapindex = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(communities.heapindex, "Insufficient memory for fast greedy community detection."); IGRAPH_FINALLY_CLEAN(2); @@ -741,7 +727,7 @@ igraph_error_t igraph_community_fastgreedy(const igraph_t *graph, loop_weight_sum = 0; for (i = 0, j = 0; !IGRAPH_EIT_END(edgeit); i += 2, j++, IGRAPH_EIT_NEXT(edgeit)) { - igraph_integer_t eidx = IGRAPH_EIT_GET(edgeit); + igraph_int_t eidx = IGRAPH_EIT_GET(edgeit); /* Create the pairs themselves */ from = IGRAPH_FROM(graph, eidx); to = IGRAPH_TO(graph, eidx); @@ -1026,10 +1012,10 @@ igraph_error_t igraph_community_fastgreedy(const igraph_t *graph, * the excess rows from the merge matrix */ if (merges != NULL) { if (no_of_joins < total_joins) { - igraph_integer_t *ivec; - igraph_integer_t merges_nrow = igraph_matrix_int_nrow(merges); + igraph_int_t *ivec; + igraph_int_t merges_nrow = igraph_matrix_int_nrow(merges); - ivec = IGRAPH_CALLOC(merges_nrow, igraph_integer_t); + ivec = IGRAPH_CALLOC(merges_nrow, igraph_int_t); IGRAPH_CHECK_OOM(ivec, "Insufficient memory for fast greedy community detection."); IGRAPH_FINALLY(igraph_free, ivec); @@ -1070,7 +1056,7 @@ igraph_error_t igraph_community_fastgreedy(const igraph_t *graph, no_of_nodes, /*steps=*/ best_no_of_joins, membership, - /*csize=*/ 0)); + /*csize=*/ NULL)); } if (merges == &merges_local) { diff --git a/src/vendor/cigraph/src/community/fluid.c b/src/vendor/cigraph/src/community/fluid.c index 70d13ef68ca..25bbee53c85 100644 --- a/src/vendor/cigraph/src/community/fluid.c +++ b/src/vendor/cigraph/src/community/fluid.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -57,21 +55,30 @@ * * Time complexity: O(|E|) */ -igraph_error_t igraph_community_fluid_communities(const igraph_t *graph, - igraph_integer_t no_of_communities, - igraph_vector_int_t *membership) { - /* Declaration of variables */ - igraph_integer_t no_of_nodes, i, j, k, kv1; +igraph_error_t igraph_community_fluid_communities( + const igraph_t *graph, + igraph_int_t no_of_communities, + igraph_vector_int_t *membership) { + + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i, j, k, kv1; igraph_adjlist_t al; igraph_real_t max_density; igraph_bool_t is_simple, is_connected, running; igraph_vector_t density, label_counters; igraph_vector_int_t dominant_labels, node_order, com_to_numvertices; - /* Initialization of variables needed for initial checking */ - no_of_nodes = igraph_vcount(graph); - /* Checking input values */ + if (igraph_is_directed(graph)) { + IGRAPH_WARNING("Edge directions are ignored by fluid community detection."); + } + IGRAPH_CHECK(igraph_is_simple(graph, &is_simple, IGRAPH_UNDIRECTED)); + if (!is_simple) { + IGRAPH_ERROR("Fluid community detection supports only simple graphs.", IGRAPH_EINVAL); + } + + /* This must come before the connectedness check so we can support the null + * graph (considered disconnected) for purposes of convenience. */ if (no_of_nodes < 2) { if (membership) { IGRAPH_CHECK(igraph_vector_int_resize(membership, no_of_nodes)); @@ -79,33 +86,20 @@ igraph_error_t igraph_community_fluid_communities(const igraph_t *graph, } return IGRAPH_SUCCESS; } + if (no_of_communities < 1) { - IGRAPH_ERROR("Number of requested communities must be greater than zero.", IGRAPH_EINVAL); + IGRAPH_ERROR("Number of requested communities must be positive.", IGRAPH_EINVAL); } + if (no_of_communities > no_of_nodes) { IGRAPH_ERROR("Number of requested communities must not be greater than the number of nodes.", IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_is_simple(graph, &is_simple)); - if (!is_simple) { - IGRAPH_ERROR("Fluid community detection supports only simple graphs.", IGRAPH_EINVAL); - } - if (igraph_is_directed(graph)) { - /* When the graph is directed, mutual edges are effectively multi-edges as we - * are ignoring edge directions. */ - igraph_bool_t has_mutual; - IGRAPH_CHECK(igraph_has_mutual(graph, &has_mutual, false)); - if (has_mutual) { - IGRAPH_ERROR("Fluid community detection supports only simple graphs.", IGRAPH_EINVAL); - } - } + IGRAPH_CHECK(igraph_is_connected(graph, &is_connected, IGRAPH_WEAK)); if (!is_connected) { IGRAPH_ERROR("Fluid community detection supports only connected graphs.", IGRAPH_EINVAL); } - if (igraph_is_directed(graph)) { - IGRAPH_WARNING("Edge directions are ignored by fluid community detection."); - } /* Internal variables initialization */ max_density = 1.0; @@ -129,7 +123,7 @@ igraph_error_t igraph_community_fluid_communities(const igraph_t *graph, igraph_vector_fill(&density, max_density); /* Initialize com_to_numvertices and initialize communities into membership vector */ - IGRAPH_CHECK(igraph_vector_int_shuffle(&node_order)); + igraph_vector_int_shuffle(&node_order); for (i = 0; i < no_of_communities; i++) { /* Initialize membership at initial nodes for each community * where 0 refers to have no label*/ @@ -148,13 +142,11 @@ igraph_error_t igraph_community_fluid_communities(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_init(&label_counters, no_of_communities)); IGRAPH_FINALLY(igraph_vector_destroy, &label_counters); - RNG_BEGIN(); - /* running is the convergence boolean variable */ running = true; while (running) { /* Declarations of variables used inside main loop */ - igraph_integer_t v1, size, rand_idx; + igraph_int_t v1, size, rand_idx; igraph_real_t max_count, label_counter_diff; igraph_vector_int_t *neis; igraph_bool_t same_label_in_dominant; @@ -162,7 +154,7 @@ igraph_error_t igraph_community_fluid_communities(const igraph_t *graph, running = false; /* Shuffle the node ordering vector */ - IGRAPH_CHECK(igraph_vector_int_shuffle(&node_order)); + igraph_vector_int_shuffle(&node_order); /* In the prescribed order, loop over the vertices and reassign labels */ for (i = 0; i < no_of_nodes; i++) { /* Clear dominant_labels and nonzero_labels vectors */ @@ -236,8 +228,6 @@ igraph_error_t igraph_community_fluid_communities(const igraph_t *graph, } } - RNG_END(); - /* Shift back the membership vector */ /* There must be no 0 labels in membership vector at this point */ for (i = 0; i < no_of_nodes; i++) { @@ -246,14 +236,12 @@ igraph_error_t igraph_community_fluid_communities(const igraph_t *graph, } igraph_adjlist_destroy(&al); - IGRAPH_FINALLY_CLEAN(1); - igraph_vector_int_destroy(&node_order); igraph_vector_destroy(&density); igraph_vector_int_destroy(&com_to_numvertices); igraph_vector_destroy(&label_counters); igraph_vector_int_destroy(&dominant_labels); - IGRAPH_FINALLY_CLEAN(5); + IGRAPH_FINALLY_CLEAN(6); return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/community/infomap.cpp b/src/vendor/cigraph/src/community/infomap.cpp new file mode 100644 index 00000000000..4ae90e9cd72 --- /dev/null +++ b/src/vendor/cigraph/src/community/infomap.cpp @@ -0,0 +1,275 @@ +/* + igraph library. + Copyright (C) 2011-2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "igraph_community.h" + +#include "config.h" + +#ifdef HAVE_INFOMAP + +#include "igraph_interface.h" +#include "igraph_interrupt.h" + +#include "core/exceptions.h" + +#include +#include + +#include "Infomap.h" + +static igraph_error_t infomap_get_membership(infomap::InfomapBase &infomap, igraph_vector_int_t *membership) { + igraph_int_t n = infomap.numLeafNodes(); + + IGRAPH_CHECK(igraph_vector_int_resize(membership, n)); + + for (auto it(infomap.iterTreePhysical(1)); !it.isEnd(); ++it) { + infomap::InfoNode &node = *it; + if (node.isLeaf()) { + // Note: We must use moduleIndex() and not moduleId(), as the latter + // may be >= vcount, which causes igraph_reindex_membership() to fail. + VECTOR(*membership)[node.physicalId] = it.moduleIndex(); + } + } + + // Re-index membership + IGRAPH_CHECK(igraph_reindex_membership(membership, NULL, NULL)); + + return IGRAPH_SUCCESS; +} + +static igraph_error_t convert_igraph_to_infomap(const igraph_t *graph, + const igraph_vector_t *edge_weights, + const igraph_vector_t *vertex_weights, + infomap::Network &network) { + + igraph_int_t vcount = igraph_vcount(graph); + igraph_int_t ecount = igraph_ecount(graph); + + if (vcount > UINT_MAX) { + IGRAPH_ERROR("Graph has too many vertices for Infomap.", IGRAPH_EINVAL); + } + + for (igraph_int_t v = 0; v < vcount; v++) { + if (vertex_weights) { + double weight = VECTOR(*vertex_weights)[v]; + if (weight < 0) { + IGRAPH_ERRORF("Vertex weights must not be negative, got %g.", + IGRAPH_EINVAL, weight); + } + if (! std::isfinite(weight)) { + IGRAPH_ERRORF("Vertex weights must not be infinite or NaN, got %g.", + IGRAPH_EINVAL, weight); + } + network.addNode(v, weight); + } else { + network.addNode(v); + } + } + + for (igraph_int_t e = 0; e < ecount; e++) { + igraph_int_t v1 = IGRAPH_FROM(graph, e); + igraph_int_t v2 = IGRAPH_TO(graph, e); + + if (edge_weights) { + double weight = VECTOR(*edge_weights)[e]; + if (weight < 0) { + IGRAPH_ERRORF("Edge weights must not be negative, got %g.", + IGRAPH_EINVAL, weight); + } + if (! std::isfinite(weight)) { + IGRAPH_ERRORF("Edge weights must not be infinite or NaN, got %g.", + IGRAPH_EINVAL, weight); + } + network.addLink(v1, v2, weight); + } else { + network.addLink(v1, v2); + } + } + + return IGRAPH_SUCCESS; +} + +// Needed in case C++'s bool is not compatible with igraph's igraph_bool_t +// which may happen in some configurations on some platforms, notable with R/igraph. +static bool infomap_allow_interruption() { + return igraph_allow_interruption(); +} +#endif // HAVE_INFOMAP + +/** + * \function igraph_community_infomap + * \brief Community structure that minimizes the expected description length of a random walker trajectory. + * + * Implementation of the Infomap community detection algorithm of + * Martin Rosvall and Carl T. Bergstrom. This algorithm takes edge directions + * into account. For more details, see the visualization of the math and the + * map generator at https://www.mapequation.org. + * + * + * Infomap is based on a random walker model similar to PageRank: the walker + * either chooses out-edges to follow with probabilities proportional to edge + * weights, or teleports to a random vertex with probability 0.15. Vertex weights + * can be given to control the probability of choosing different vertices as + * the target of the teleportation. In addition, Infomap can be regularized to + * account for potential missing links. + * + * + * As of igraph 1.0, the Infomap library written by Daniel Edler, Anton Holmgren + * and Martin Rosvall is used. See https://github.com/mapequation/infomap/. + * + * + * If you want to specify a random seed (as in the original + * implementation) you can use \ref igraph_rng_seed(). + * + * + * References: + * + * + * M. Rosvall and C. T. Bergstrom: + * Maps of information flow reveal community structure in complex networks, + * PNAS 105, 1118 (2008). + * https://dx.doi.org/10.1073/pnas.0706851105, https://arxiv.org/abs/0707.0609 + * + * + * M. Rosvall, D. Axelsson, and C. T. Bergstrom: + * The map equation, + * Eur. Phys. J. Special Topics 178, 13 (2009). + * https://dx.doi.org/10.1140/epjst/e2010-01179-1, https://arxiv.org/abs/0906.1405 + * + * + * Smiljanić, Jelena, Daniel Edler, and Martin Rosvall: Mapping Flows on + * Sparse Networks with Missing Links. Phys Rev E 102 (1–1): 012302 (2020). + * https://doi.org/10.1103/PhysRevE.102.012302, https://arxiv.org/abs/2106.14798 + * + * \param graph The input graph. Edge directions are taken into account. + * \param edge_weights Numeric vector giving the weights of the edges. + * The random walker will favour edges with high weights over + * edges with low weights; the probability of picking a particular + * outbound edge from a node is directly proportional to its weight. + * If it is \c NULL then all edges will have equal + * weights. The weights are expected to be non-negative. + * \param vertex_weights Numeric vector giving the weights of the vertices. + * Vertices with higher weights are favoured by the random walker + * when it teleports to a new vertex. The probability of picking a vertex + * when the random walker teleports is directly proportional to the weight + * of the vertex. If this argument is \c NULL then all vertices will have + * equal weights. Weights are expected to be positive. + * \param nb_trials The number of attempts to partition the network + * (can be any integer value equal to or larger than 1). + * \param is_regularized If true, adds a fully connected Bayesian prior network + * to avoid overfitting due to missing links. + * \param regularization_strength Adjust relative strength of the Bayesian prior + * network used for regularization. This multiplies the default strength, a + * parameter of 1 hence uses the default regularization strength. Ignored + * when \p is_regularized is set to \c false. + * \param membership Pointer to a vector. The membership vector is + * stored here. \c NULL means that the caller is not interested in the + * membership vector. + * \param codelength Pointer to a real. If not \c NULL the code length of the + * partition is stored here. + * \return Error code. + * When Infomap is not available, \c IGRAPH_UNIMPLEMENTED is returned. + * + * \sa \ref igraph_community_spinglass(), \ref + * igraph_community_edge_betweenness(), \ref igraph_community_walktrap(). + * + * Time complexity: TODO. + */ + +igraph_error_t igraph_community_infomap( + const igraph_t *graph, + const igraph_vector_t *edge_weights, + const igraph_vector_t *vertex_weights, + igraph_int_t nb_trials, + igraph_bool_t is_regularized, + igraph_real_t regularization_strength, + igraph_vector_int_t *membership, + igraph_real_t *codelength) { + +#ifndef HAVE_INFOMAP + IGRAPH_ERROR("Infomap is not available.", IGRAPH_UNIMPLEMENTED); +#else + + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); + + if (edge_weights) { + if (igraph_vector_size(edge_weights) != ecount) { + IGRAPH_ERROR("Length of edge weight vector does not match edge count.", + IGRAPH_EINVAL); + } + } + + if (vertex_weights) { + if (igraph_vector_size(vertex_weights) != vcount) { + IGRAPH_ERROR("Length of vertex weight vector does not match edge count.", + IGRAPH_EINVAL); + } + } + + if (nb_trials < 1) { + IGRAPH_ERRORF("Number of trials must be at least 1, got %" IGRAPH_PRId ".", + IGRAPH_EINVAL, + nb_trials); + } + + // Handle null graph + if (vcount == 0) { + if (membership) { + IGRAPH_CHECK(igraph_vector_int_resize(membership, 0)); + } + + if (codelength) { + *codelength = IGRAPH_NAN; + } + + return IGRAPH_SUCCESS; + } + + IGRAPH_HANDLE_EXCEPTIONS_BEGIN; + + // Configure infomap + infomap::Config conf; + conf.twoLevel = true; + conf.numTrials = nb_trials; + conf.silent = true; + conf.directed = igraph_is_directed(graph); + conf.interruptionHandler = &infomap_allow_interruption; + conf.regularized = is_regularized; + conf.regularizationStrength = regularization_strength; + + infomap::InfomapBase infomap(conf); + + IGRAPH_CHECK(convert_igraph_to_infomap(graph, edge_weights, vertex_weights, infomap.network())); + + infomap.run(); + + if (membership) { + IGRAPH_CHECK(infomap_get_membership(infomap, membership)); + } + + if (codelength) { + *codelength = infomap.codelength(); + } + + IGRAPH_HANDLE_EXCEPTIONS_END; + + return IGRAPH_SUCCESS; + +#endif +} diff --git a/src/vendor/cigraph/src/community/infomap/infomap.cc b/src/vendor/cigraph/src/community/infomap/infomap.cc deleted file mode 100644 index 88bb2ac2ca7..00000000000 --- a/src/vendor/cigraph/src/community/infomap/infomap.cc +++ /dev/null @@ -1,323 +0,0 @@ -/* -*- mode: C -*- */ -/* - IGraph library. - Copyright (C) 2011-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - - ---- - The original version of this file was written by Martin Rosvall - email: martin.rosvall@physics.umu.se - homePage: http://www.tp.umu.se/~rosvall/ - - It was integrated in igraph by Emmanuel Navarro - email: navarro@irit.fr - homePage: http://www.irit.fr/~Emmanuel.Navarro/ -*/ - -#include "igraph_community.h" - -#include "core/exceptions.h" -#include "core/interruption.h" - -#include "infomap_Node.h" -#include "infomap_FlowGraph.h" -#include "infomap_Greedy.h" - -#include -#include - -// This is necessary for GCC 5 and earlier, where including -// makes isnan() unusable without the std:: prefix, even if -// was included as well. -using std::isnan; - -/****************************************************************************/ -static igraph_error_t infomap_partition(FlowGraph &fgraph, bool rcall) { - - // save the original graph - FlowGraph cpy_fgraph(fgraph); - - igraph_integer_t Nnode = cpy_fgraph.Nnode; - // "real" number of vertex, ie. number of vertex of the graph - - igraph_integer_t iteration = 0; - double outer_oldCodeLength, newCodeLength; - - std::vector initial_move; - bool initial_move_done = true; - - // re-use vector in loop for better performance - std::vector subMoveTo; - - do { // Main loop - outer_oldCodeLength = fgraph.codeLength; - - if (iteration > 0) { - /**********************************************************************/ - // FIRST PART: re-split the network (if need) - // =========================================== - - // intial_move indicate current clustering - initial_move.resize(Nnode); - // new_cluster_id --> old_cluster_id (save curent clustering state) - - initial_move_done = false; - - subMoveTo.clear(); // enventual new partitionment of original graph - - if ((iteration % 2 == 0) && (fgraph.Nnode > 1)) { - // 0/ Submodule movements : partition each module of the - // current partition (rec. call) - - subMoveTo.resize(Nnode); - // vid_cpy_fgraph --> new_cluster_id (new partition) - - igraph_integer_t subModIndex = 0; - - for (igraph_integer_t i = 0 ; i < fgraph.Nnode ; i++) { - // partition each non trivial module - size_t sub_Nnode = fgraph.node[i].members.size(); - if (sub_Nnode > 1) { // If the module is not trivial - const std::vector &sub_members = fgraph.node[i].members; - - // extraction of the subgraph - FlowGraph sub_fgraph(cpy_fgraph, sub_members); - sub_fgraph.initiate(); - - // recursif call of partitionment on the subgraph - infomap_partition(sub_fgraph, true); - - // Record membership changes - for (igraph_integer_t j = 0; j < sub_fgraph.Nnode; j++) { - for (const auto &v : sub_fgraph.node[j].members) { - subMoveTo[sub_members[v]] = subModIndex; - } - initial_move[subModIndex] = i; - subModIndex++; - } - } else { - subMoveTo[fgraph.node[i].members[0]] = subModIndex; - initial_move[subModIndex] = i; - subModIndex++; - } - } - } else { - // 1/ Single-node movements : allows each node to move (again) - // save current modules - for (igraph_integer_t i = 0; i < fgraph.Nnode; i++) { // for each module - for (const auto &v : fgraph.node[i].members) { // for each vertex (of the module) - initial_move[v] = i; - } - } - } - - fgraph.back_to(cpy_fgraph); - if (! subMoveTo.empty()) { - Greedy cpy_greedy(&fgraph); - - cpy_greedy.setMove(subMoveTo); - cpy_greedy.apply(false); - } - } - /**********************************************************************/ - // SECOND PART: greedy optimizing it self - // =========================================== - double oldCodeLength; - - do { - // greedy optimizing object creation - Greedy greedy(&fgraph); - - // Initial move to apply ? - if (!initial_move_done && ! initial_move.empty()) { - initial_move_done = true; - greedy.setMove(initial_move); - } - - oldCodeLength = greedy.codeLength; - bool moved = true; - double inner_oldCodeLength = 1000; - - while (moved) { // main greedy optimizing loop - inner_oldCodeLength = greedy.codeLength; - moved = greedy.optimize(); - - if (fabs(greedy.codeLength - inner_oldCodeLength) < 1.0e-10) - // if the move does'n reduce the codelenght -> exit ! - { - moved = false; - } - } - - // transform the network to network of modules: - greedy.apply(true); - newCodeLength = greedy.codeLength; - } while (oldCodeLength - newCodeLength > 1.0e-10); - // while there is some improvement - - iteration++; - if (!rcall) { - IGRAPH_ALLOW_INTERRUPTION(); - } - } while (outer_oldCodeLength - newCodeLength > 1.0e-10); - - return IGRAPH_SUCCESS; -} - - -/** - * \function igraph_community_infomap - * \brief Find community structure that minimizes the expected description length of a random walker trajectory. - * - * Implementation of the Infomap community detection algorithm of - * Martin Rosvall and Carl T. Bergstrom. This algorithm takes edge directions - * into account. - * - * - * For more details, see the visualization of the math and the map generator - * at https://www.mapequation.org . The original paper describing the algorithm - * is: M. Rosvall and C. T. Bergstrom, Maps of information flow reveal community - * structure in complex networks, PNAS 105, 1118 (2008) - * (https://dx.doi.org/10.1073/pnas.0706851105, https://arxiv.org/abs/0707.0609). - * A more detailed paper about the algorithm is: M. Rosvall, D. Axelsson, and - * C. T. Bergstrom, The map equation, Eur. Phys. J. Special Topics 178, 13 (2009). - * (https://dx.doi.org/10.1140/epjst/e2010-01179-1, https://arxiv.org/abs/0906.1405) - - * - * The original C++ implementation of Martin Rosvall is used, - * see http://www.tp.umu.se/~rosvall/downloads/infomap_undir.tgz . - * Integration in igraph was done by Emmanuel Navarro (who is grateful to - * Martin Rosvall and Carl T. Bergstrom for providing this source code). - * - * - * Note that the graph must not contain isolated vertices. - * - * - * If you want to specify a random seed (as in the original - * implementation) you can use \ref igraph_rng_seed(). - * - * \param graph The input graph. Edge directions are taken into account. - * \param e_weights Numeric vector giving the weights of the edges. - * The random walker will favour edges with high weights over - * edges with low weights; the probability of picking a particular - * outbound edge from a node is directly proportional to its weight. - * If it is \c NULL then all edges will have equal - * weights. The weights are expected to be non-negative. - * \param v_weights Numeric vector giving the weights of the vertices. - * Vertices with higher weights are favoured by the random walker - * when it needs to "teleport" to a new node after getting stuck in - * a sink node (i.e. a node with no outbound edges). The probability - * of picking a vertex when the random walker teleports is directly - * proportional to the weight of the vertex. If this argument is \c NULL - * then all vertices will have equal weights. Weights are expected - * to be positive. - * \param nb_trials The number of attempts to partition the network - * (can be any integer value equal or larger than 1). - * \param membership Pointer to a vector. The membership vector is - * stored here. - * \param codelength Pointer to a real. If not NULL the code length of the - * partition is stored here. - * \return Error code. - * - * \sa \ref igraph_community_spinglass(), \ref - * igraph_community_edge_betweenness(), \ref igraph_community_walktrap(). - * - * Time complexity: TODO. - */ -igraph_error_t igraph_community_infomap(const igraph_t * graph, - const igraph_vector_t *e_weights, - const igraph_vector_t *v_weights, - igraph_integer_t nb_trials, - igraph_vector_int_t *membership, - igraph_real_t *codelength) { - - IGRAPH_HANDLE_EXCEPTIONS_BEGIN; - - if (e_weights) { - const igraph_integer_t ecount = igraph_ecount(graph); - if (igraph_vector_size(e_weights) != ecount) { - IGRAPH_ERROR("Invalid edge weight vector length.", IGRAPH_EINVAL); - } - if (ecount > 0) { - /* Allow both positive and zero weights. - * The conversion to Infomap format will simply skip zero-weight edges/ */ - igraph_real_t minweight = igraph_vector_min(e_weights); - if (minweight < 0) { - IGRAPH_ERROR("Edge weights must not be negative.", IGRAPH_EINVAL); - } else if (isnan(minweight)) { - IGRAPH_ERROR("Edge weights must not be NaN values.", IGRAPH_EINVAL); - } - } - } - - if (v_weights) { - const igraph_integer_t vcount = igraph_vcount(graph); - if (igraph_vector_size(v_weights) != vcount) { - IGRAPH_ERROR("Invalid vertex weight vector length.", IGRAPH_EINVAL); - } - if (vcount > 0) { - /* TODO: Currently we require strictly positive. Can this be - * relaxed to non-negative values? */ - igraph_real_t minweight = igraph_vector_min(v_weights); - if (minweight <= 0) { - IGRAPH_ERROR("Vertex weights must be positive.", IGRAPH_EINVAL); - } else if (isnan(minweight)) { - IGRAPH_ERROR("Vertex weights must not be NaN values.", IGRAPH_EINVAL); - } - } - } - - FlowGraph fgraph(graph, e_weights, v_weights); - - // compute stationary distribution - fgraph.initiate(); - - double shortestCodeLength = 1000.0; - - // create membership vector - igraph_integer_t Nnode = fgraph.Nnode; - IGRAPH_CHECK(igraph_vector_int_resize(membership, Nnode)); - - for (igraph_integer_t trial = 0; trial < nb_trials; trial++) { - FlowGraph cpy_fgraph(fgraph); - - //partition the network - IGRAPH_CHECK(infomap_partition(cpy_fgraph, false)); - - // if better than the better... - if (cpy_fgraph.codeLength < shortestCodeLength) { - shortestCodeLength = cpy_fgraph.codeLength; - // ... store the partition - for (igraph_integer_t i = 0 ; i < cpy_fgraph.Nnode ; i++) { - size_t Nmembers = cpy_fgraph.node[i].members.size(); - for (size_t k = 0; k < Nmembers; k++) { - //cluster[ cpy_fgraph->node[i].members[k] ] = i; - VECTOR(*membership)[cpy_fgraph.node[i].members[k]] = i; - } - } - } - } - - *codelength = shortestCodeLength / log(2.0); - - IGRAPH_CHECK(igraph_reindex_membership(membership, NULL, NULL)); - - return IGRAPH_SUCCESS; - - IGRAPH_HANDLE_EXCEPTIONS_END; -} diff --git a/src/vendor/cigraph/src/community/infomap/infomap_FlowGraph.cc b/src/vendor/cigraph/src/community/infomap/infomap_FlowGraph.cc deleted file mode 100644 index 405dc6a1da0..00000000000 --- a/src/vendor/cigraph/src/community/infomap/infomap_FlowGraph.cc +++ /dev/null @@ -1,382 +0,0 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - IGraph library. - Copyright (C) 2011-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - -*/ - -#include "infomap_FlowGraph.h" - -using namespace std; - -void FlowGraph::init(igraph_integer_t n, const igraph_vector_t *v_weights) { - alpha = 0.15; - beta = 1.0 - alpha; - Nnode = n; - node.reserve(Nnode); - if (v_weights) { - for (igraph_integer_t i = 0; i < Nnode; i++) { - node.emplace_back(i, VECTOR(*v_weights)[i]); - } - } else { - for (igraph_integer_t i = 0; i < Nnode; i++) { - node.emplace_back(i, 1.0); - } - } -} - -FlowGraph::FlowGraph(igraph_integer_t n) { - init(n, nullptr); -} - -/* Build the graph from igraph_t object */ -FlowGraph::FlowGraph(const igraph_t *graph, - const igraph_vector_t *e_weights, - const igraph_vector_t *v_weights) { - - igraph_integer_t n = igraph_vcount(graph); - init(n, v_weights); - - bool directed = igraph_is_directed(graph); - - double linkWeight = 1.0; - igraph_integer_t from, to; - - igraph_integer_t Nlinks = igraph_ecount(graph); - if (!directed) { - Nlinks = Nlinks * 2 ; - } - for (igraph_integer_t i = 0; i < Nlinks; i++) { - if (!directed) { // not directed - if (i % 2 == 0) { - linkWeight = e_weights ? VECTOR(*e_weights)[i / 2] : 1.0; - igraph_edge(graph, i / 2, &from, &to); - } else { - igraph_edge(graph, (i - 1) / 2, &to, &from); - } - } else { // directed - linkWeight = e_weights ? VECTOR(*e_weights)[i] : 1.0; - igraph_edge(graph, i, &from, &to); - } - - // Populate node from igraph_graph - // Negative edge weights were checked for already. - // We skip adding zero-weight edges. - if (linkWeight > 0.0) { - if (from != to) { - node[from].outLinks.emplace_back(to, linkWeight); - node[to].inLinks.emplace_back(from, linkWeight); - } - } - } -} - -FlowGraph::FlowGraph(const FlowGraph &fgraph) { - igraph_integer_t n = fgraph.Nnode; - init(n, nullptr); - for (igraph_integer_t i = 0; i < n; i++) { - node[i] = fgraph.node[i]; - } - - //XXX: quid de danglings et Ndanglings? - - alpha = fgraph.alpha ; - beta = fgraph.beta ; - - exit = fgraph.exit; - exitFlow = fgraph.exitFlow; - exit_log_exit = fgraph.exit_log_exit; - size_log_size = fgraph.size_log_size ; - nodeSize_log_nodeSize = fgraph.nodeSize_log_nodeSize; - - codeLength = fgraph.codeLength; -} - -/** construct a graph by extracting a subgraph from the given graph - */ -FlowGraph::FlowGraph(const FlowGraph &fgraph, const vector &sub_members) { - igraph_integer_t sub_Nnode = sub_members.size(); - - init(sub_Nnode, nullptr); - - //XXX: use set of integer to ensure that elements are sorted - set sub_mem(sub_members.begin(), sub_members.end()); - - auto it_mem = sub_mem.begin(); - - vector sub_renumber(fgraph.Nnode, -1); - // id --> sub_id - - for (igraph_integer_t j = 0; j < sub_Nnode; j++) { - igraph_integer_t orig_nr = (*it_mem); - - node[j].teleportWeight = fgraph.node[orig_nr].teleportWeight; - node[j].selfLink = fgraph.node[orig_nr].selfLink; - // Take care of self-link - - size_t orig_NoutLinks = fgraph.node[orig_nr].outLinks.size(); - size_t orig_NinLinks = fgraph.node[orig_nr].inLinks.size(); - - sub_renumber[orig_nr] = j; - - for (size_t k = 0; k < orig_NoutLinks; k++) { - igraph_integer_t to = fgraph.node[orig_nr].outLinks[k].first; - igraph_integer_t to_newnr = sub_renumber[to]; - double link_weight = fgraph.node[orig_nr].outLinks[k].second; - - if (to < orig_nr) { - // we add links if the destination (to) has already be seen - // (ie. smaller than current id) => orig - - if (sub_mem.find(to) != sub_mem.end()) { - // printf("%2d | %4d to %4d\n", j, orig_nr, to); - // printf("from %4d (%4d:%1.5f) to %4d (%4d)\n", j, orig_nr, - // node[j].selfLink, to_newnr, to); - node[j].outLinks.emplace_back(to_newnr, link_weight); - node[to_newnr].inLinks.emplace_back(j, link_weight); - } - } - } - - for (size_t k = 0; k < orig_NinLinks; k++) { - igraph_integer_t to = fgraph.node[orig_nr].inLinks[k].first; - igraph_integer_t to_newnr = sub_renumber[to]; - double link_weight = fgraph.node[orig_nr].inLinks[k].second; - if (to < orig_nr) { - if (sub_mem.find(to) != sub_mem.end()) { - node[j].inLinks.emplace_back(to_newnr, link_weight); - node[to_newnr].outLinks.emplace_back(j, link_weight); - } - } - } - it_mem++; - } -} - - -/** Swap the graph with the one given - the graph is "re" calibrate - but NOT the given one. - */ -void FlowGraph::swap(FlowGraph &fgraph) noexcept { - node.swap(fgraph.node); - - igraph_integer_t Nnode_tmp = fgraph.Nnode; - fgraph.Nnode = Nnode; - Nnode = Nnode_tmp; - - calibrate(); -} - -/** Initialisation of the graph, compute the flow inside the graph - * - count danglings nodes - * - normalized edge weights - * - Call eigenvector() to compute steady state distribution - * - call calibrate to compute codelenght - */ -void FlowGraph::initiate() { - // Take care of dangling nodes, normalize outLinks, and calculate - // total teleport weight - Ndanglings = 0; - double totTeleportWeight = 0.0; - for (igraph_integer_t i = 0; i < Nnode; i++) { - totTeleportWeight += node[i].teleportWeight; - } - - for (igraph_integer_t i = 0; i < Nnode; i++) { - node[i].teleportWeight /= totTeleportWeight; - // normalize teleportation weight - - if (node[i].outLinks.empty() && (node[i].selfLink <= 0.0)) { - danglings.push_back(i); - Ndanglings++; - } else { // Normalize the weights - size_t NoutLinks = node[i].outLinks.size(); - double sum = node[i].selfLink; // Take care of self-links - for (size_t j = 0; j < NoutLinks; j++) { - sum += node[i].outLinks[j].second; - } - node[i].selfLink /= sum; - for (size_t j = 0; j < NoutLinks; j++) { - node[i].outLinks[j].second /= sum; - } - } - } - - // Calculate steady state matrix - eigenvector(); - - // Update links to represent flow - for (igraph_integer_t i = 0; i < Nnode; i++) { - node[i].selfLink = beta * node[i].size * node[i].selfLink; - // (1 - \tau) * \pi_i * P_{ii} - - if (!node[i].outLinks.empty()) { - size_t NoutLinks = node[i].outLinks.size(); - for (size_t j = 0; j < NoutLinks; j++) { - node[i].outLinks[j].second = beta * node[i].size * - node[i].outLinks[j].second; - // (1 - \tau) * \pi_i * P_{ij} - } - - // Update values for corresponding inlink - for (size_t j = 0; j < NoutLinks; j++) { - size_t NinLinks = node[node[i].outLinks[j].first].inLinks.size(); - for (size_t k = 0; k < NinLinks; k++) { - if (node[node[i].outLinks[j].first].inLinks[k].first == i) { - node[node[i].outLinks[j].first].inLinks[k].second = - node[i].outLinks[j].second; - k = NinLinks; - } - } - } - } - } - - // To be able to handle dangling nodes efficiently - for (igraph_integer_t i = 0; i < Nnode; i++) - if (node[i].outLinks.empty() && (node[i].selfLink <= 0.0)) { - node[i].danglingSize = node[i].size; - } else { - node[i].danglingSize = 0.0; - } - - nodeSize_log_nodeSize = 0.0 ; - // The exit flow from each node at initiation - for (igraph_integer_t i = 0; i < Nnode; i++) { - node[i].exit = node[i].size // Proba to be on i - - (alpha * node[i].size + beta * node[i].danglingSize) * - node[i].teleportWeight // Proba teleport back to i - - node[i].selfLink; // Proba stay on i - - // node[i].exit == q_{i\exit} - nodeSize_log_nodeSize += plogp(node[i].size); - } - - calibrate(); -} - - -/* Compute steady state distribution (ie. PageRank) over the network - * (for all i update node[i].size) - */ -void FlowGraph::eigenvector() { - vector size_tmp(Nnode, 1.0 / Nnode); - - int Niterations = 0; - double danglingSize; - - double sqdiff = 1.0; - double sqdiff_old; - double sum; - do { - // Calculate dangling size - danglingSize = 0.0; - for (igraph_integer_t i = 0; i < Ndanglings; i++) { - danglingSize += size_tmp[danglings[i]]; - } - - // Flow from teleportation - for (igraph_integer_t i = 0; i < Nnode; i++) { - node[i].size = (alpha + beta * danglingSize) * node[i].teleportWeight; - } - - // Flow from network steps - for (igraph_integer_t i = 0; i < Nnode; i++) { - node[i].size += beta * node[i].selfLink * size_tmp[i]; - size_t Nlinks = node[i].outLinks.size(); - for (size_t j = 0; j < Nlinks; j++) - node[node[i].outLinks[j].first].size += beta * - node[i].outLinks[j].second * size_tmp[i]; - } - - // Normalize - sum = 0.0; - for (igraph_integer_t i = 0; i < Nnode; i++) { - sum += node[i].size; - } - sqdiff_old = sqdiff; - sqdiff = 0.0; - for (igraph_integer_t i = 0; i < Nnode; i++) { - node[i].size /= sum; - sqdiff += fabs(node[i].size - size_tmp[i]); - size_tmp[i] = node[i].size; - } - Niterations++; - - if (sqdiff == sqdiff_old) { - alpha += 1.0e-10; - beta = 1.0 - alpha; - } - - } while ((Niterations < 200) && (sqdiff > 1.0e-15 || Niterations < 50)); - - danglingSize = 0.0; - for (igraph_integer_t i = 0; i < Ndanglings; i++) { - danglingSize += size_tmp[danglings[i]]; - } - // cout << "done! (the error is " << sqdiff << " after " << Niterations - // << " iterations)" << endl; -} - - -/* Compute the codeLength of the given network - * note: (in **node, one node == one module) - */ -void FlowGraph::calibrate() noexcept { - exit_log_exit = 0.0; - exitFlow = 0.0; - size_log_size = 0.0; - - for (igraph_integer_t i = 0; i < Nnode; i++) { // For each module - // own node/module codebook - size_log_size += plogp(node[i].exit + node[i].size); - - // use of index codebook - exitFlow += node[i].exit; - exit_log_exit += plogp(node[i].exit); - } - - exit = plogp(exitFlow); - - codeLength = exit - 2.0 * exit_log_exit + size_log_size - - nodeSize_log_nodeSize; -} - - -/* Restore the data from the given FlowGraph object - */ -void FlowGraph::back_to(const FlowGraph &fgraph) { - // delete current nodes and copy original ones - Nnode = fgraph.Nnode; - node = fgraph.node; - - // restore atributs - alpha = fgraph.alpha ; - beta = fgraph.beta ; - - exit = fgraph.exit; - exitFlow = fgraph.exitFlow; - exit_log_exit = fgraph.exit_log_exit; - size_log_size = fgraph.size_log_size ; - nodeSize_log_nodeSize = fgraph.nodeSize_log_nodeSize; - - codeLength = fgraph.codeLength; -} diff --git a/src/vendor/cigraph/src/community/infomap/infomap_FlowGraph.h b/src/vendor/cigraph/src/community/infomap/infomap_FlowGraph.h deleted file mode 100644 index 6364d5d0ce6..00000000000 --- a/src/vendor/cigraph/src/community/infomap/infomap_FlowGraph.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - IGraph library. - Copyright (C) 2011-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - -*/ - -#ifndef INFOMAP_FLOWGRAPH_H -#define INFOMAP_FLOWGRAPH_H - -#include "infomap_Node.h" - -#include "igraph_datatype.h" -#include "igraph_types.h" -#include "igraph_vector.h" - -#include -#include -#include - -inline double plogp(double x) { - return x > 0.0 ? x*std::log(x) : 0.0; -} - -class FlowGraph { -private: - void init(igraph_integer_t n, const igraph_vector_t *nodeWeights); - -public: - explicit FlowGraph(igraph_integer_t n); - - FlowGraph(const FlowGraph &fgraph); - FlowGraph(const FlowGraph &fgraph, const std::vector &sub_members); - - FlowGraph(const igraph_t *graph, const igraph_vector_t *e_weights, - const igraph_vector_t *v_weights); - - void swap(FlowGraph &fgraph) noexcept; - - void initiate(); - void eigenvector(); - void calibrate() noexcept; - - void back_to(const FlowGraph &fgraph); - - /*************************************************************************/ - std::vector node; - igraph_integer_t Nnode; - - double alpha, beta; - - igraph_integer_t Ndanglings; - std::vector danglings; // id of dangling nodes - - double exit; // - double exitFlow; // - double exit_log_exit; // - double size_log_size; // - double nodeSize_log_nodeSize; // \sum_{v in V} p log(p) - - double codeLength; -}; - -#endif // INFOMAP_FLOWGRAPH_H diff --git a/src/vendor/cigraph/src/community/infomap/infomap_Greedy.cc b/src/vendor/cigraph/src/community/infomap/infomap_Greedy.cc deleted file mode 100644 index 954e9169717..00000000000 --- a/src/vendor/cigraph/src/community/infomap/infomap_Greedy.cc +++ /dev/null @@ -1,522 +0,0 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - IGraph library. - Copyright (C) 2011-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - -*/ - -#include "infomap_Greedy.h" - -#include -#include -#include - -using namespace std; - -Greedy::Greedy(FlowGraph *fgraph) : - graph(fgraph), - Nnode(graph->Nnode), - alpha(graph->alpha), // teleportation probability - beta(1.0 - alpha), // probability to take normal step - - node_index(Nnode), - - mod_empty(Nnode), - mod_exit(Nnode), - mod_size(Nnode), - mod_danglingSize(Nnode), - mod_teleportWeight(Nnode), - mod_members(Nnode) -{ - nodeSize_log_nodeSize = graph->nodeSize_log_nodeSize; - exit_log_exit = graph->exit_log_exit; - size_log_size = graph->size_log_size; - exitFlow = graph->exitFlow; - - const std::vector &node = graph->node; - for (igraph_integer_t i = 0; i < Nnode; i++) { // For each module - node_index[i] = i; - mod_exit[i] = node[i].exit; - mod_size[i] = node[i].size; - - mod_danglingSize[i] = node[i].danglingSize; - mod_teleportWeight[i] = node[i].teleportWeight; - mod_members[i] = node[i].members.size(); - } - - exit = plogp(exitFlow); - - codeLength = exit - 2.0 * exit_log_exit + size_log_size - nodeSize_log_nodeSize; -} - - -/** Greedy optimizing (as in Blodel and Al.) : - * for each vertex (selected in a random order) compute the best possible move within neighborhood - */ -bool Greedy::optimize() { - bool moved = false; - const std::vector &node = graph->node; - - RNG_BEGIN(); - - // Generate random enumeration of nodes - vector randomOrder(Nnode); - for (igraph_integer_t i = 0; i < Nnode; i++) { - randomOrder[i] = i; - } - - for (igraph_integer_t i = 0; i < Nnode - 1; i++) { - igraph_integer_t randPos = RNG_INTEGER(i, Nnode - 1); - // swap i & randPos - igraph_integer_t tmp = randomOrder[i]; - randomOrder[i] = randomOrder[randPos]; - randomOrder[randPos] = tmp; - } - - igraph_uint_t offset = 1; - vector redirect(Nnode, 0); - vector > > flowNtoM(Nnode); - - for (igraph_integer_t k = 0; k < Nnode; k++) { - - // Pick nodes in random order - igraph_integer_t flip = randomOrder[k]; - igraph_integer_t oldM = node_index[flip]; - - // Reset offset when igraph_integer_t overflows - if (offset > IGRAPH_INTEGER_MAX) { - for (igraph_integer_t j = 0; j < Nnode; j++) { - redirect[j] = 0; - } - offset = 1; - } - // Size of vector with module links - igraph_integer_t NmodLinks = 0; - // For all outLinks - size_t NoutLinks = node[flip].outLinks.size(); - if (NoutLinks == 0) { //dangling node, add node to calculate flow below - redirect[oldM] = offset + NmodLinks; - flowNtoM[NmodLinks].first = oldM; - flowNtoM[NmodLinks].second.first = 0.0; - flowNtoM[NmodLinks].second.second = 0.0; - NmodLinks++; - } else { - for (size_t j = 0; j < NoutLinks; j++) { - igraph_integer_t nb_M = node_index[node[flip].outLinks[j].first]; - // index destination du lien - double nb_flow = node[flip].outLinks[j].second; - // wgt du lien - if (redirect[nb_M] >= offset) { - flowNtoM[redirect[nb_M] - offset].second.first += nb_flow; - } else { - redirect[nb_M] = offset + NmodLinks; - flowNtoM[NmodLinks].first = nb_M; - flowNtoM[NmodLinks].second.first = nb_flow; - flowNtoM[NmodLinks].second.second = 0.0; - NmodLinks++; - } - } - } - // For all inLinks - size_t NinLinks = node[flip].inLinks.size(); - for (size_t j = 0; j < NinLinks; j++) { - igraph_integer_t nb_M = node_index[node[flip].inLinks[j].first]; - double nb_flow = node[flip].inLinks[j].second; - - if (redirect[nb_M] >= offset) { - flowNtoM[redirect[nb_M] - offset].second.second += nb_flow; - } else { - redirect[nb_M] = offset + NmodLinks; - flowNtoM[NmodLinks].first = nb_M; - flowNtoM[NmodLinks].second.first = 0.0; - flowNtoM[NmodLinks].second.second = nb_flow; - NmodLinks++; - } - } - - // For teleportation and dangling nodes - for (igraph_integer_t j = 0; j < NmodLinks; j++) { - igraph_integer_t newM = flowNtoM[j].first; - if (newM == oldM) { - flowNtoM[j].second.first += - (alpha * node[flip].size + beta * node[flip].danglingSize) * - (mod_teleportWeight[oldM] - node[flip].teleportWeight); - flowNtoM[j].second.second += - (alpha * (mod_size[oldM] - node[flip].size) + - beta * (mod_danglingSize[oldM] - node[flip].danglingSize)) * - node[flip].teleportWeight; - } else { - flowNtoM[j].second.first += - (alpha * node[flip].size + beta * node[flip].danglingSize) * - mod_teleportWeight[newM]; - flowNtoM[j].second.second += - (alpha * mod_size[newM] + beta * mod_danglingSize[newM] ) * - node[flip].teleportWeight; - } - } - - // Calculate flow to/from own module (default value if no link to - // own module) - double outFlowOldM = - (alpha * node[flip].size + beta * node[flip].danglingSize) * - (mod_teleportWeight[oldM] - node[flip].teleportWeight) ; - double inFlowOldM = - (alpha * (mod_size[oldM] - node[flip].size) + - beta * (mod_danglingSize[oldM] - node[flip].danglingSize)) * - node[flip].teleportWeight; - if (redirect[oldM] >= offset) { - outFlowOldM = flowNtoM[redirect[oldM] - offset].second.first; - inFlowOldM = flowNtoM[redirect[oldM] - offset].second.second; - } - - // Option to move to empty module (if node not already alone) - if (mod_members[oldM] > node[flip].members.size()) { - if (Nempty > 0) { - flowNtoM[NmodLinks].first = mod_empty[Nempty - 1]; - flowNtoM[NmodLinks].second.first = 0.0; - flowNtoM[NmodLinks].second.second = 0.0; - NmodLinks++; - } - } - - // Randomize link order for optimized search - for (igraph_integer_t j = 0; j < NmodLinks - 1; j++) { - igraph_integer_t randPos = RNG_INTEGER(j, NmodLinks - 1); - igraph_integer_t tmp_M = flowNtoM[j].first; - double tmp_outFlow = flowNtoM[j].second.first; - double tmp_inFlow = flowNtoM[j].second.second; - flowNtoM[j].first = flowNtoM[randPos].first; - flowNtoM[j].second.first = flowNtoM[randPos].second.first; - flowNtoM[j].second.second = flowNtoM[randPos].second.second; - flowNtoM[randPos].first = tmp_M; - flowNtoM[randPos].second.first = tmp_outFlow; - flowNtoM[randPos].second.second = tmp_inFlow; - } - - igraph_integer_t bestM = oldM; - double best_outFlow = 0.0; - double best_inFlow = 0.0; - double best_delta = 0.0; - - // Find the move that minimizes the description length - for (igraph_integer_t j = 0; j < NmodLinks; j++) { - - igraph_integer_t newM = flowNtoM[j].first; - double outFlowNewM = flowNtoM[j].second.first; - double inFlowNewM = flowNtoM[j].second.second; - - if (newM != oldM) { - - double delta_exit = plogp(exitFlow + outFlowOldM + inFlowOldM - - outFlowNewM - inFlowNewM) - exit; - - double delta_exit_log_exit = - plogp(mod_exit[oldM]) - - plogp(mod_exit[newM]) + - plogp(mod_exit[oldM] - node[flip].exit + outFlowOldM + inFlowOldM) - + plogp(mod_exit[newM] + node[flip].exit - outFlowNewM - - inFlowNewM); - - double delta_size_log_size = - plogp(mod_exit[oldM] + mod_size[oldM]) - - plogp(mod_exit[newM] + mod_size[newM]) - + plogp(mod_exit[oldM] + mod_size[oldM] - node[flip].exit - - node[flip].size + outFlowOldM + inFlowOldM) - + plogp(mod_exit[newM] + mod_size[newM] + node[flip].exit + - node[flip].size - outFlowNewM - inFlowNewM); - - double deltaL = delta_exit - 2.0 * delta_exit_log_exit + - delta_size_log_size; - - if (deltaL - best_delta < -1e-10) { - bestM = newM; - best_outFlow = outFlowNewM; - best_inFlow = inFlowNewM; - best_delta = deltaL; - } - } - } - - // Make best possible move - if (bestM != oldM) { - //Update empty module vector - if (mod_members[bestM] == 0) { - Nempty--; - } - if (mod_members[oldM] == node[flip].members.size()) { - mod_empty[Nempty] = oldM; - Nempty++; - } - - exitFlow -= mod_exit[oldM] + mod_exit[bestM]; - - exit_log_exit -= plogp(mod_exit[oldM]) + plogp(mod_exit[bestM]); - size_log_size -= plogp(mod_exit[oldM] + mod_size[oldM]) + - plogp(mod_exit[bestM] + mod_size[bestM]); - - mod_exit[oldM] -= node[flip].exit - outFlowOldM - - inFlowOldM; - mod_size[oldM] -= node[flip].size; - mod_danglingSize[oldM] -= node[flip].danglingSize; - mod_teleportWeight[oldM] -= node[flip].teleportWeight; - mod_members[oldM] -= node[flip].members.size(); - - mod_exit[bestM] += node[flip].exit - best_outFlow - - best_inFlow; - mod_size[bestM] += node[flip].size; - mod_danglingSize[bestM] += node[flip].danglingSize; - mod_teleportWeight[bestM] += node[flip].teleportWeight; - mod_members[bestM] += node[flip].members.size(); - - exitFlow += mod_exit[oldM] + mod_exit[bestM]; - - // Update terms in map equation - - exit_log_exit += plogp(mod_exit[oldM]) + plogp(mod_exit[bestM]); - size_log_size += plogp(mod_exit[oldM] + mod_size[oldM]) + - plogp(mod_exit[bestM] + mod_size[bestM]); - exit = plogp(exitFlow); - - // Update code length - - codeLength = exit - 2.0 * exit_log_exit + size_log_size - - nodeSize_log_nodeSize; - - node_index[flip] = bestM; - moved = true; - } - offset += Nnode; - } - - RNG_END(); - - return moved; -} - -/** Apply the move to the given network - */ -void Greedy::apply(bool sort) { - - //old fct prepare(sort) - vector modSnode; // will give IDs of no-empty modules (nodes) - modSnode.reserve(Nnode); - - igraph_integer_t Nmod = 0; - for (igraph_integer_t i = 0; i < Nnode; i++) { - if (mod_members[i] > 0) { - Nmod++; - modSnode.push_back(i); - } - } - - if (sort) { - // sort by mod_size - std::sort(modSnode.begin(), modSnode.end(), - [&](size_t a, size_t b) { return mod_size[a] > mod_size[b]; } ); - } - - // Create the new graph - FlowGraph tmp_fgraph(Nmod); - vector &node_tmp = tmp_fgraph.node ; - - const vector &node = graph->node; - - vector nodeInMod(Nnode); - - // creation of new nodes - for (igraph_integer_t i = 0; i < Nmod; i++) { - node_tmp[i].members.clear(); // clear membership - node_tmp[i].exit = mod_exit[modSnode[i]]; - node_tmp[i].size = mod_size[modSnode[i]]; - node_tmp[i].danglingSize = mod_danglingSize[modSnode[i]]; - node_tmp[i].teleportWeight = mod_teleportWeight[modSnode[i]]; - - nodeInMod[modSnode[i]] = i; - } - - // Calculate outflow of links to different modules - vector > outFlowNtoM(Nmod); - - for (igraph_integer_t i = 0; i < Nnode; i++) { - igraph_integer_t i_M = nodeInMod[node_index[i]]; //final id of the module of the node i - // add node members to the module - copy( node[i].members.begin(), node[i].members.end(), - back_inserter( node_tmp[i_M].members ) ); - - for (const auto &link : node[i].outLinks) { - igraph_integer_t nb = link.first; - igraph_integer_t nb_M = nodeInMod[node_index[nb]]; - double nb_flow = link.second; - if (nb != i) { - // inserts key nb_M if it does not exist - outFlowNtoM[i_M][nb_M] += nb_flow; - } - } - } - - // Create outLinks at new level - for (igraph_integer_t i = 0; i < Nmod; i++) { - for (const auto &item : outFlowNtoM[i]) { - if (item.first != i) { - node_tmp[i].outLinks.emplace_back(item); - } - } - } - - // Calculate inflow of links from different modules - vector > inFlowNtoM(Nmod); - - for (igraph_integer_t i = 0; i < Nnode; i++) { - igraph_integer_t i_M = nodeInMod[node_index[i]]; - for (const auto &inLink : node[i].inLinks) { - igraph_integer_t nb = inLink.first; - igraph_integer_t nb_M = nodeInMod[node_index[nb]]; - double nb_flow = inLink.second; - if (nb != i) { - // inserts key nb_M if it does not exist - inFlowNtoM[i_M][nb_M] += nb_flow; - } - } - } - - // Create inLinks at new level - for (igraph_integer_t i = 0; i < Nmod; i++) { - for (const auto &item : inFlowNtoM[i]) { - if (item.first != i) { - node_tmp[i].inLinks.emplace_back(item); - } - } - } - - // Option to move to empty module - mod_empty.clear(); - Nempty = 0; - - //swap node between tmp_graph and graph, then destroy tmp_fgraph - graph->swap(tmp_fgraph); - Nnode = Nmod; -} - - -/** - * RAZ et recalcul : - * - mod_exit - * - mod_size - * - mod_danglingSize - * - mod_teleportWeight - * - mod_members - * and - * - exit_log_exit - * - size_log_size - * - exitFlow - * - exit - * - codeLength - * according to **node / node[i]->index - */ - - -/* Compute the new CodeSize if modules are merged as indicated by moveTo - */ -void Greedy::setMove(const std::vector &moveTo) { - const std::vector &node = graph->node; - for (igraph_integer_t i = 0 ; i < Nnode ; i++) { // pour chaque module - igraph_integer_t oldM = i; - igraph_integer_t newM = moveTo[i]; - //printf("old -> new : %d -> %d \n", oldM, newM); - if (newM != oldM) { - - // Si je comprend bien : - // outFlow... : c'est le "flow" de i-> autre sommet du meme module - // inFlow... : c'est le "flow" depuis un autre sommet du meme module --> i - double outFlowOldM = (alpha * node[i].size + beta * node[i].danglingSize) * - (mod_teleportWeight[oldM] - node[i].teleportWeight); - double inFlowOldM = (alpha * (mod_size[oldM] - node[i].size) + - beta * (mod_danglingSize[oldM] - - node[i].danglingSize)) * - node[i].teleportWeight; - double outFlowNewM = (alpha * node[i].size + beta * node[i].danglingSize) - * mod_teleportWeight[newM]; - double inFlowNewM = (alpha * mod_size[newM] + - beta * mod_danglingSize[newM]) * - node[i].teleportWeight; - - // For all outLinks - for (const auto &outLink : node[i].outLinks) { - igraph_integer_t nb_M = node_index[outLink.first]; - double nb_flow = outLink.second; - if (nb_M == oldM) { - outFlowOldM += nb_flow; - } else if (nb_M == newM) { - outFlowNewM += nb_flow; - } - } - - // For all inLinks - for (const auto &inLink : node[i].inLinks) { - igraph_integer_t nb_M = node_index[inLink.first]; - double nb_flow = inLink.second; - if (nb_M == oldM) { - inFlowOldM += nb_flow; - } else if (nb_M == newM) { - inFlowNewM += nb_flow; - } - } - - // Update empty module vector - // RAZ de mod_empty et Nempty ds calibrate() - if (mod_members[newM] == 0) { - // si le nouveau etait vide, on a un vide de moins... - Nempty--; - } - if (mod_members[oldM] == node[i].members.size()) { - // si l'ancien avait la taille de celui qui bouge, un vide de plus - mod_empty[Nempty] = oldM; - Nempty++; - } - - exitFlow -= mod_exit[oldM] + mod_exit[newM]; - exit_log_exit -= plogp(mod_exit[oldM]) + plogp(mod_exit[newM]); - size_log_size -= plogp(mod_exit[oldM] + mod_size[oldM]) + - plogp(mod_exit[newM] + mod_size[newM]); - - mod_exit[oldM] -= node[i].exit - outFlowOldM - inFlowOldM; - mod_size[oldM] -= node[i].size; - mod_danglingSize[oldM] -= node[i].danglingSize; - mod_teleportWeight[oldM] -= node[i].teleportWeight; - mod_members[oldM] -= node[i].members.size(); - mod_exit[newM] += node[i].exit - outFlowNewM - inFlowNewM; - mod_size[newM] += node[i].size; - mod_danglingSize[newM] += node[i].danglingSize; - mod_teleportWeight[newM] += node[i].teleportWeight; - mod_members[newM] += node[i].members.size(); - - exitFlow += mod_exit[oldM] + mod_exit[newM]; - exit_log_exit += plogp(mod_exit[oldM]) + plogp(mod_exit[newM]); - size_log_size += plogp(mod_exit[oldM] + mod_size[oldM]) + - plogp(mod_exit[newM] + mod_size[newM]); - exit = plogp(exitFlow); - - codeLength = exit - 2.0 * exit_log_exit + size_log_size - - nodeSize_log_nodeSize; - - node_index[i] = newM; - - } - - } -} diff --git a/src/vendor/cigraph/src/community/infomap/infomap_Greedy.h b/src/vendor/cigraph/src/community/infomap/infomap_Greedy.h deleted file mode 100644 index 87bf0b53cc9..00000000000 --- a/src/vendor/cigraph/src/community/infomap/infomap_Greedy.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - IGraph library. - Copyright (C) 2011-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - -*/ - -#ifndef INFOMAP_GREEDY_H -#define INFOMAP_GREEDY_H - -#include "infomap_Node.h" -#include "infomap_FlowGraph.h" - -#include "igraph_random.h" - -#include - -class Greedy { -public: - explicit Greedy(FlowGraph *fgraph); - // initialise les attributs par rapport au graph - - void setMove(const std::vector &moveTo); - bool optimize(); - void apply(bool sort); - - /**************************************************************************/ - -public: - double codeLength; - -private: - FlowGraph * graph; - igraph_integer_t Nnode; - - double exit; - double exitFlow; - double exit_log_exit; - double size_log_size; - double nodeSize_log_nodeSize; - - double alpha, beta; - // local copy of fgraph alpha, beta (=alpha - Nnode = graph->Nnode;1) - - std::vector node_index; // module number of each node - - igraph_integer_t Nempty = 0; - std::vector mod_empty; - - std::vector mod_exit; // version tmp de node - std::vector mod_size; - std::vector mod_danglingSize; - std::vector mod_teleportWeight; - std::vector mod_members; -}; - -#endif // INFOMAP_GREEDY_H diff --git a/src/vendor/cigraph/src/community/infomap/infomap_Node.h b/src/vendor/cigraph/src/community/infomap/infomap_Node.h deleted file mode 100644 index c3ef8c685ef..00000000000 --- a/src/vendor/cigraph/src/community/infomap/infomap_Node.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - IGraph library. - Copyright (C) 2011-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - -*/ - -#ifndef INFOMAP_NODE_H -#define INFOMAP_NODE_H - -#include "igraph_interface.h" - -#include - -struct Node { - - Node() = default; - Node(igraph_integer_t modulenr, double tpweight) : - teleportWeight(tpweight) - { - members.push_back(modulenr); // members = [nodenr] - } - - std::vector members; - std::vector< std::pair > inLinks; - std::vector< std::pair > outLinks; - double selfLink = 0.0; - - double teleportWeight = 0.0; - double danglingSize = 0.0; - double exit = 0.0; - double size = 0.0; -}; - -#endif // INFOMAP_NODE_H diff --git a/src/vendor/cigraph/src/community/label_propagation.c b/src/vendor/cigraph/src/community/label_propagation.c index 1fc537ad4ef..a82984421e8 100644 --- a/src/vendor/cigraph/src/community/label_propagation.c +++ b/src/vendor/cigraph/src/community/label_propagation.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -28,15 +26,437 @@ #include "core/interruption.h" +static igraph_error_t community_label_propagation( + const igraph_t *graph, + igraph_vector_int_t *membership, + igraph_neimode_t mode, + const igraph_vector_t *weights, + const igraph_vector_bool_t *fixed, + igraph_bool_t retention) { + + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_not_fixed_nodes = 0; + igraph_int_t i, j, k; + igraph_adjlist_t al; + igraph_inclist_t il; + igraph_bool_t running, control_iteration; + + igraph_vector_t label_weights; + igraph_vector_int_t dominant_labels, nonzero_labels, node_order; + igraph_neimode_t reverse_mode; + int iter = 0; /* interruption counter */ + + reverse_mode = IGRAPH_REVERSE_MODE(mode); + + /* Create an adjacency/incidence list representation for efficiency. + * For the unweighted case, the adjacency list is enough. For the + * weighted case, we need the incidence list */ + if (weights) { + IGRAPH_CHECK(igraph_inclist_init(graph, &il, reverse_mode, IGRAPH_LOOPS_ONCE)); + IGRAPH_FINALLY(igraph_inclist_destroy, &il); + } else { + IGRAPH_CHECK(igraph_adjlist_init(graph, &al, reverse_mode, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE)); + IGRAPH_FINALLY(igraph_adjlist_destroy, &al); + } + + /* Create storage space for counting distinct labels and dominant ones */ + IGRAPH_VECTOR_INIT_FINALLY(&label_weights, no_of_nodes); + IGRAPH_VECTOR_INT_INIT_FINALLY(&dominant_labels, 0); + IGRAPH_VECTOR_INT_INIT_FINALLY(&nonzero_labels, 0); + IGRAPH_CHECK(igraph_vector_int_reserve(&dominant_labels, 2)); + + /* Initialize node ordering vector with only the not fixed nodes */ + if (fixed) { + IGRAPH_VECTOR_INT_INIT_FINALLY(&node_order, no_of_nodes); + for (i = 0; i < no_of_nodes; i++) { + if (!VECTOR(*fixed)[i]) { + VECTOR(node_order)[no_of_not_fixed_nodes] = i; + no_of_not_fixed_nodes++; + } + } + IGRAPH_CHECK(igraph_vector_int_resize(&node_order, no_of_not_fixed_nodes)); + } else { + IGRAPH_CHECK(igraph_vector_int_init_range(&node_order, 0, no_of_nodes)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &node_order); + no_of_not_fixed_nodes = no_of_nodes; + } + + /* There are two modes of operation in this implementation: retention or + * dominance. When using retention, we prefer to keep the current label of a node. + * Only if the current label is not among the dominant labels will we + * update the label. If a label changes, we will continue to iterate + * over all nodes. + * + * When not using retention we check for dominance after each iteration. This + * is implemented as two alternating types of iterations, one for changing + * labels and the other one for checking the end condition - every vertex in the + * graph has a label to which the maximum number of its neighbors belongs. If + * control_iteration is true, we are just checking the end condition and not + * relabeling nodes. + */ + + control_iteration = true; + running = true; + while (running) { + igraph_int_t v1, num_neis; + igraph_real_t max_count; + igraph_vector_int_t *neis; + igraph_vector_int_t *ineis; + igraph_bool_t was_zero; + + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 8); + + if (retention) { + /* We stop in this iteration by default, unless a label changes */ + running = false; + /* Shuffle the node ordering vector */ + igraph_vector_int_shuffle(&node_order); + } else { + if (control_iteration) { + /* If we are in the control iteration, we expect in the beginning of + the iteration that all vertices meet the end condition, so 'running' is false. + If some of them does not, 'running' is set to true later in the code. */ + running = false; + } else { + /* Shuffle the node ordering vector if we are in the label updating iteration */ + igraph_vector_int_shuffle(&node_order); + } + } + + /* In the prescribed order, loop over the vertices and reassign labels */ + for (i = 0; i < no_of_not_fixed_nodes; i++) { + v1 = VECTOR(node_order)[i]; + + /* Count the weights corresponding to different labels */ + igraph_vector_int_clear(&dominant_labels); + igraph_vector_int_clear(&nonzero_labels); + max_count = 0.0; + if (weights) { + + ineis = igraph_inclist_get(&il, v1); + num_neis = igraph_vector_int_size(ineis); + + for (j = 0; j < num_neis; j++) { + k = VECTOR(*membership)[IGRAPH_OTHER(graph, VECTOR(*ineis)[j], v1)]; + if (k < 0) { + continue; /* skip if it has no label yet */ + } + was_zero = (VECTOR(label_weights)[k] == 0); + VECTOR(label_weights)[k] += VECTOR(*weights)[VECTOR(*ineis)[j]]; + + if (was_zero && VECTOR(label_weights)[k] != 0) { + /* weights just became nonzero */ + IGRAPH_CHECK(igraph_vector_int_push_back(&nonzero_labels, k)); + } + + if (max_count < VECTOR(label_weights)[k]) { + max_count = VECTOR(label_weights)[k]; + IGRAPH_CHECK(igraph_vector_int_resize(&dominant_labels, 1)); + VECTOR(dominant_labels)[0] = k; + } else if (max_count == VECTOR(label_weights)[k]) { + IGRAPH_CHECK(igraph_vector_int_push_back(&dominant_labels, k)); + } + } + } else { + + neis = igraph_adjlist_get(&al, v1); + num_neis = igraph_vector_int_size(neis); + + for (j = 0; j < num_neis; j++) { + + k = VECTOR(*membership)[VECTOR(*neis)[j]]; + if (k < 0) { + continue; /* skip if it has no label yet */ + } + VECTOR(label_weights)[k]++; + + if (VECTOR(label_weights)[k] == 1) { + /* weights just became nonzero */ + IGRAPH_CHECK(igraph_vector_int_push_back(&nonzero_labels, k)); + } + + if (max_count < VECTOR(label_weights)[k]) { + max_count = VECTOR(label_weights)[k]; + IGRAPH_CHECK(igraph_vector_int_resize(&dominant_labels, 1)); + VECTOR(dominant_labels)[0] = k; + } else if (max_count == VECTOR(label_weights)[k]) { + IGRAPH_CHECK(igraph_vector_int_push_back(&dominant_labels, k)); + } + } + } + + if (igraph_vector_int_size(&dominant_labels) > 0) { + if (retention) { + /* If we are using retention, we first check if the current label + is among the maximum label. */ + j = (long)VECTOR(*membership)[v1]; + if (j < 0 || /* Doesn't have a label yet */ + VECTOR(label_weights)[j] == 0 || /* Label not present in neighbors */ + VECTOR(label_weights)[j] < max_count /* Label not dominant */) { + /* Select randomly from the dominant labels */ + k = RNG_INTEGER(0, igraph_vector_int_size(&dominant_labels) - 1); + k = VECTOR(dominant_labels)[(long int)k]; + /* If label changes, we will continue running */ + if (k != j) { + running = true; + } + /* Actually change label */ + VECTOR(*membership)[v1] = k; + } + } else { + /* We are not using retention, so check if we should do a control iteration + or an update iteration. */ + if (control_iteration) { + /* Check if the _current_ label of the node is also dominant */ + k = VECTOR(*membership)[v1]; + if (k < 0 || /* No label assigned yet or */ + VECTOR(label_weights)[k] < max_count /* Label is not maximum */ + ) { + /* Nope, we need at least one more iteration */ + running = true; + } + } else { + /* Select randomly from the dominant labels */ + k = RNG_INTEGER(0, igraph_vector_int_size(&dominant_labels) - 1); + VECTOR(*membership)[v1] = VECTOR(dominant_labels)[k]; + } + } + } + + /* Clear the nonzero elements in label_weights */ + num_neis = igraph_vector_int_size(&nonzero_labels); + for (j = 0; j < num_neis; j++) { + VECTOR(label_weights)[VECTOR(nonzero_labels)[j]] = 0; + } + } + + /* Alternating between control iterations and label updating iterations */ + if (!retention) { + control_iteration = !control_iteration; + } + } + + if (weights) { + igraph_inclist_destroy(&il); + } else { + igraph_adjlist_destroy(&al); + } + IGRAPH_FINALLY_CLEAN(1); + + igraph_vector_int_destroy(&node_order); + igraph_vector_int_destroy(&nonzero_labels); + igraph_vector_int_destroy(&dominant_labels); + igraph_vector_destroy(&label_weights); + IGRAPH_FINALLY_CLEAN(4); + + return IGRAPH_SUCCESS; +} + +static igraph_error_t community_fast_label_propagation( + const igraph_t *graph, + igraph_vector_int_t *membership, + igraph_neimode_t mode, + const igraph_vector_t *weights, + const igraph_vector_bool_t *fixed) { + + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_not_fixed_nodes = 0; + igraph_int_t i, j, k; + igraph_inclist_t il; + igraph_adjlist_t al; + + igraph_vector_t label_weights; + igraph_vector_int_t dominant_labels, nonzero_labels, node_order; + igraph_dqueue_int_t queue; + igraph_vector_bool_t in_queue; + igraph_neimode_t reverse_mode; + int iter = 0; /* interruption counter */ + + reverse_mode = IGRAPH_REVERSE_MODE(mode); + + if (weights) { + IGRAPH_CHECK(igraph_inclist_init(graph, &il, reverse_mode, IGRAPH_LOOPS_ONCE)); + IGRAPH_FINALLY(igraph_inclist_destroy, &il); + } else { + IGRAPH_CHECK(igraph_adjlist_init(graph, &al, reverse_mode, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE)); + IGRAPH_FINALLY(igraph_adjlist_destroy, &al); + } + + /* Create storage space for counting distinct labels and dominant ones */ + IGRAPH_VECTOR_INIT_FINALLY(&label_weights, no_of_nodes); + IGRAPH_VECTOR_INT_INIT_FINALLY(&dominant_labels, 0); + IGRAPH_VECTOR_INT_INIT_FINALLY(&nonzero_labels, 0); + IGRAPH_CHECK(igraph_vector_int_reserve(&dominant_labels, 2)); + + /* Initialize node ordering vector with only the not fixed nodes */ + IGRAPH_DQUEUE_INT_INIT_FINALLY(&queue, no_of_nodes); + IGRAPH_VECTOR_BOOL_INIT_FINALLY(&in_queue, no_of_nodes); + + /* Initialize node ordering vector with only the not fixed nodes */ + if (fixed) { + IGRAPH_VECTOR_INT_INIT_FINALLY(&node_order, no_of_nodes); + for (i = 0; i < no_of_nodes; i++) { + if (!VECTOR(*fixed)[i]) { + VECTOR(node_order)[no_of_not_fixed_nodes] = i; + no_of_not_fixed_nodes++; + } + } + IGRAPH_CHECK(igraph_vector_int_resize(&node_order, no_of_not_fixed_nodes)); + } else { + IGRAPH_CHECK(igraph_vector_int_init_range(&node_order, 0, no_of_nodes)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &node_order); + no_of_not_fixed_nodes = no_of_nodes; + } + + for (i = 0; i < no_of_not_fixed_nodes; i++) { + IGRAPH_CHECK(igraph_dqueue_int_push(&queue, VECTOR(node_order)[i])); + VECTOR(in_queue)[VECTOR(node_order)[i]] = true; + } + igraph_vector_int_destroy(&node_order); + IGRAPH_FINALLY_CLEAN(1); + + while (!igraph_dqueue_int_empty(&queue)) { + igraph_int_t v1, v2, e = -1, num_neis; + igraph_real_t max_count; + igraph_vector_int_t *neis; + igraph_bool_t was_zero; + + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 8); + + v1 = igraph_dqueue_int_pop(&queue); + VECTOR(in_queue)[v1] = false; + + /* Count the weights corresponding to different labels */ + igraph_vector_int_clear(&dominant_labels); + igraph_vector_int_clear(&nonzero_labels); + max_count = 0.0; + if (weights) { + neis = igraph_inclist_get(&il, v1); + } else { + neis = igraph_adjlist_get(&al, v1); + } + + num_neis = igraph_vector_int_size(neis); + for (j = 0; j < num_neis; j++) { + if (weights) { + e = VECTOR(*neis)[j]; + v2 = IGRAPH_OTHER(graph, e, v1); + } else { + v2 = VECTOR(*neis)[j]; + } + k = VECTOR(*membership)[v2]; + if (k < 0) { + continue; /* skip if it has no label yet */ + } + was_zero = (VECTOR(label_weights)[k] == 0); + VECTOR(label_weights)[k] += (weights ? VECTOR(*weights)[e] : 1); + + if (was_zero && VECTOR(label_weights)[k] >= 0) { + /* counter just became non-negative */ + IGRAPH_CHECK(igraph_vector_int_push_back(&nonzero_labels, k)); + } + + if (max_count < VECTOR(label_weights)[k]) { + max_count = VECTOR(label_weights)[k]; + IGRAPH_CHECK(igraph_vector_int_resize(&dominant_labels, 1)); + VECTOR(dominant_labels)[0] = k; + } else if (max_count == VECTOR(label_weights)[k]) { + IGRAPH_CHECK(igraph_vector_int_push_back(&dominant_labels, k)); + } + } + + if (igraph_vector_int_size(&dominant_labels) > 0) { + igraph_int_t current_label = VECTOR(*membership)[v1]; + + /* Select randomly from the dominant labels */ + k = RNG_INTEGER(0, igraph_vector_int_size(&dominant_labels) - 1); + igraph_int_t new_label = VECTOR(dominant_labels)[k]; /* a dominant label */ + + /* Check if the _current_ label of the node is not the same */ + if (new_label != current_label) { + /* We still need to consider its neighbors not in the new community */ + for (j = 0; j < num_neis; j++) { + if (weights) { + e = VECTOR(*neis)[j]; + v2 = IGRAPH_OTHER(graph, e, v1); + } else { + v2 = VECTOR(*neis)[j]; + } + if (!VECTOR(in_queue)[v2]) { + igraph_int_t neigh_label = VECTOR(*membership)[v2]; /* neighbor community */ + if (neigh_label != new_label && /* not in new community */ + (fixed == NULL || !VECTOR(*fixed)[v2]) ) { /* not fixed */ + IGRAPH_CHECK(igraph_dqueue_int_push(&queue, v2)); + VECTOR(in_queue)[v2] = true; + } + } + } + } + VECTOR(*membership)[v1] = new_label; + } + + /* Clear the nonzero elements in label_weights */ + num_neis = igraph_vector_int_size(&nonzero_labels); + for (j = 0; j < num_neis; j++) { + VECTOR(label_weights)[VECTOR(nonzero_labels)[j]] = 0; + } + } + + if (weights) { + igraph_inclist_destroy(&il); + } else { + igraph_adjlist_destroy(&al); + } + IGRAPH_FINALLY_CLEAN(1); + + igraph_vector_bool_destroy(&in_queue); + igraph_dqueue_int_destroy(&queue); + igraph_vector_destroy(&label_weights); + igraph_vector_int_destroy(&dominant_labels); + igraph_vector_int_destroy(&nonzero_labels); + IGRAPH_FINALLY_CLEAN(5); + + return IGRAPH_SUCCESS; +} + /** * \ingroup communities * \function igraph_community_label_propagation * \brief Community detection based on label propagation. * * This function implements the label propagation-based community detection - * algorithm described by Raghavan, Albert and Kumara. This version extends + * algorithm described by Raghavan, Albert and Kumara (2007). This version extends * the original method by the ability to take edge weights into consideration - * and also by allowing some labels to be fixed. + * and also by allowing some labels to be fixed. In addition, it implements + * the fast label propagation alternative introduced by Traag and Šubelj (2023). + * + * + * The algorithm works by iterating over nodes and updating the label of a node + * based on the labels of its neighbors. The labels that are most frequent among + * the neighbors are said to be dominant labels. The label of a node is always + * updated to a dominant label. The algorithm guarantees that the label for each + * is dominant when it terminates. + * + * + * There are several variants implemented, which work slightly differently with + * the dominance of labels. Nodes with a dominant label might no longer have a + * dominant label if one of their neighbors change label. In \c + * IGRAPH_LPA_DOMINANCE an additional iteration over all nodes is made after + * updating all labels to double check whether all nodes indeed have a dominant + * label. When updating the label of a node, labels are always sampled from + * among all dominant labels. The algorithm stops when all nodes have dominant + * labels. In \c IGRAPH_LPA_RETENTION instead labels are only updated when they + * are not dominant. That is, they retain their current label whenever the + * current label is already dominant. The algorithm does not make an additional + * iteration to check for dominance. Instead, it simply keeps track whether a + * label has been updated, and terminates if no updates have been made. In \c + * IGRAPH_LPA_FAST labels are sampled from among all dominant labels, similar to + * \c IGRAPH_LPA_DOMINANCE. Instead of iterating over all nodes, it keeps track + * of a queue of nodes that should be considered. Nodes are popped from the + * queue when they are considered for update. When the label of a node is + * updated, the node's neighbors are added to the queue again (if they weren't + * already in the queue). The algorithm terminates when the queue is empty. All + * variants guarantee that the labels for all nodes are dominant. * * * Weights are taken into account as follows: when the new label of node @@ -57,10 +477,9 @@ * References: * * - * Raghavan, U.N. and Albert, R. and Kumara, S.: - * Near linear time algorithm to detect community structures in large-scale networks. - * Phys Rev E 76, 036106 (2007). - * https://doi.org/10.1103/PhysRevE.76.036106 + * Raghavan, U.N. and Albert, R. and Kumara, S.: Near linear time algorithm to + * detect community structures in large-scale networks. Phys Rev E 76, 036106 + * (2007). https://doi.org/10.1103/PhysRevE.76.036106 * * * Šubelj, L.: Label propagation for clustering. Chapter in "Advances in @@ -69,7 +488,13 @@ * https://doi.org/10.1002/9781119483298.ch5 * https://arxiv.org/abs/1709.05634 * - * \param graph The input graph. Note that the algorithm wsa originally + * + * Traag, V. A., and Šubelj, L.: Large network community detection by fast + * label propagation. Scientific Reports, 13:1, (2023). + * https://doi.org/10.1038/s41598-023-29610-z + * https://arxiv.org/abs/2209.13338 + * + * \param graph The input graph. Note that the algorithm was originally * defined for undirected graphs. You are advised to set \p mode to * \c IGRAPH_ALL if you pass a directed graph here to treat it as * undirected. @@ -105,6 +530,15 @@ * and igraph may renumber labels. However, co-membership constraints * will be respected: two vertices can be fixed to be in the same or in * different communities. + * \param lpa_variant Which variant of the label propagation algorithm to run. + * \clist + * \cli IGRAPH_LPA_DOMINANCE + * check for dominance of all nodes after each iteration. + * \cli IGRAPH_LPA_RETENTION + * keep current label if among dominant labels, only check if labels changed. + * \cli IGRAPH_LPA_FAST + * sample from dominant labels, only check neighbors. + * \endclist * \return Error code. * * Time complexity: O(m+n) @@ -112,35 +546,26 @@ * \example examples/simple/igraph_community_label_propagation.c */ igraph_error_t igraph_community_label_propagation(const igraph_t *graph, - igraph_vector_int_t *membership, - igraph_neimode_t mode, - const igraph_vector_t *weights, - const igraph_vector_int_t *initial, - const igraph_vector_bool_t *fixed) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_not_fixed_nodes = no_of_nodes; - igraph_integer_t i, j, k; - igraph_adjlist_t al; - igraph_inclist_t il; - igraph_bool_t running, control_iteration; + igraph_vector_int_t *membership, + igraph_neimode_t mode, + const igraph_vector_t *weights, + const igraph_vector_int_t *initial, + const igraph_vector_bool_t *fixed, + igraph_lpa_variant_t lpa_variant) { + + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_not_fixed_nodes = no_of_nodes; + igraph_int_t i, j, k; igraph_bool_t unlabelled_left; - igraph_neimode_t reversed_mode; - int iter = 0; /* interruption counter */ - - igraph_vector_t label_counters; /* real type, stores weight sums */ - igraph_vector_int_t dominant_labels, nonzero_labels, node_order; /* We make a copy of 'fixed' as a pointer into 'fixed_copy' after casting * away the constness, and promise ourselves that we will make a proper * copy of 'fixed' into 'fixed_copy' as soon as we start mutating it */ igraph_vector_bool_t *fixed_copy = (igraph_vector_bool_t *) fixed; - /* The implementation uses a trick to avoid negative array indexing: - * elements of the membership vector are increased by 1 at the start - * of the algorithm; this to allow us to denote unlabeled vertices - * (if any) by zeroes. The membership vector is shifted back in the end - */ + /* Unlabelled nodes are represented with -1. */ +#define IS_UNLABELLED(x) (VECTOR(*membership)[x] < 0) /* Do some initial checks */ if (fixed && igraph_vector_bool_size(fixed) != no_of_nodes) { @@ -173,25 +598,22 @@ igraph_error_t igraph_community_label_propagation(const igraph_t *graph, /* Check if the labels used are valid, initialize membership vector */ for (i = 0; i < no_of_nodes; i++) { if (VECTOR(*initial)[i] < 0) { - VECTOR(*membership)[i] = 0; + VECTOR(*membership)[i] = -1; } else { - VECTOR(*membership)[i] = VECTOR(*initial)[i] + 1; + VECTOR(*membership)[i] = VECTOR(*initial)[i]; } } if (fixed) { for (i = 0; i < no_of_nodes; i++) { if (VECTOR(*fixed)[i]) { - if (VECTOR(*membership)[i] == 0) { + if (IS_UNLABELLED(i)) { IGRAPH_WARNING("Fixed nodes cannot be unlabeled, ignoring them."); /* We cannot modify 'fixed' because it is const, so we make a copy and * modify 'fixed_copy' instead */ if (fixed_copy == fixed) { fixed_copy = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (fixed_copy == 0) { - IGRAPH_ERROR("Failed to copy 'fixed' vector.", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - + IGRAPH_CHECK_OOM(fixed_copy, "Insufficient memory for label propagation."); IGRAPH_FINALLY(igraph_free, fixed_copy); IGRAPH_CHECK(igraph_vector_bool_init_copy(fixed_copy, fixed)); IGRAPH_FINALLY(igraph_vector_bool_destroy, fixed_copy); @@ -211,173 +633,46 @@ igraph_error_t igraph_community_label_propagation(const igraph_t *graph, } } else { for (i = 0; i < no_of_nodes; i++) { - VECTOR(*membership)[i] = i + 1; + VECTOR(*membership)[i] = i; } } - reversed_mode = IGRAPH_REVERSE_MODE(mode); - /* From this point onwards we use 'fixed_copy' instead of 'fixed' */ + switch (lpa_variant) { + case IGRAPH_LPA_FAST: + IGRAPH_CHECK(community_fast_label_propagation(graph, membership, mode, weights, fixed_copy)); + break; - /* Create an adjacency/incidence list representation for efficiency. - * For the unweighted case, the adjacency list is enough. For the - * weighted case, we need the incidence list */ - if (weights) { - IGRAPH_CHECK(igraph_inclist_init(graph, &il, reversed_mode, IGRAPH_LOOPS_ONCE)); - IGRAPH_FINALLY(igraph_inclist_destroy, &il); - } else { - IGRAPH_CHECK(igraph_adjlist_init(graph, &al, reversed_mode, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE)); - IGRAPH_FINALLY(igraph_adjlist_destroy, &al); - } - - /* Create storage space for counting distinct labels and dominant ones */ - IGRAPH_VECTOR_INIT_FINALLY(&label_counters, no_of_nodes + 1); - IGRAPH_VECTOR_INT_INIT_FINALLY(&dominant_labels, 0); - IGRAPH_VECTOR_INT_INIT_FINALLY(&nonzero_labels, 0); - IGRAPH_CHECK(igraph_vector_int_reserve(&dominant_labels, 2)); - - /* Initialize node ordering vector with only the not fixed nodes */ - if (fixed_copy) { - IGRAPH_VECTOR_INT_INIT_FINALLY(&node_order, no_of_not_fixed_nodes); - for (i = 0, j = 0; i < no_of_nodes; i++) { - if (!VECTOR(*fixed_copy)[i]) { - VECTOR(node_order)[j] = i; - j++; - } - } - } else { - IGRAPH_CHECK(igraph_vector_int_init_range(&node_order, 0, no_of_nodes)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &node_order); - } - - /* There are two alternating types of iterations, one for changing labels and - the other one for checking the end condition - every vertex in the graph has - a label to which the maximum number of its neighbors belongs. If control_iteration - is true, we are just checking the end condition and not relabeling nodes. */ - control_iteration = true; - running = true; - while (running) { - igraph_integer_t v1, num_neis; - igraph_real_t max_count; - igraph_vector_int_t *neis; - igraph_vector_int_t *ineis; - igraph_bool_t was_zero; - - IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 8); - - if (control_iteration) { - /* If we are in the control iteration, we expect in the beginning of - the iteration that all vertices meet the end condition, so 'running' is false. - If some of them does not, 'running' is set to true later in the code. */ - running = false; - } else { - /* Shuffle the node ordering vector if we are in the label updating iteration */ - IGRAPH_CHECK(igraph_vector_int_shuffle(&node_order)); - } - - RNG_BEGIN(); - /* In the prescribed order, loop over the vertices and reassign labels */ - for (i = 0; i < no_of_not_fixed_nodes; i++) { - v1 = VECTOR(node_order)[i]; - - /* Count the weights corresponding to different labels */ - igraph_vector_int_clear(&dominant_labels); - igraph_vector_int_clear(&nonzero_labels); - max_count = 0.0; - if (weights) { - ineis = igraph_inclist_get(&il, v1); - num_neis = igraph_vector_int_size(ineis); - for (j = 0; j < num_neis; j++) { - k = VECTOR(*membership)[IGRAPH_OTHER(graph, VECTOR(*ineis)[j], v1)]; - if (k == 0) { - continue; /* skip if it has no label yet */ - } - was_zero = (VECTOR(label_counters)[k] == 0); - VECTOR(label_counters)[k] += VECTOR(*weights)[VECTOR(*ineis)[j]]; - if (was_zero && VECTOR(label_counters)[k] != 0) { - /* counter just became nonzero */ - IGRAPH_CHECK(igraph_vector_int_push_back(&nonzero_labels, k)); - } - if (max_count < VECTOR(label_counters)[k]) { - max_count = VECTOR(label_counters)[k]; - IGRAPH_CHECK(igraph_vector_int_resize(&dominant_labels, 1)); - VECTOR(dominant_labels)[0] = k; - } else if (max_count == VECTOR(label_counters)[k]) { - IGRAPH_CHECK(igraph_vector_int_push_back(&dominant_labels, k)); - } - } - } else { - neis = igraph_adjlist_get(&al, v1); - num_neis = igraph_vector_int_size(neis); - for (j = 0; j < num_neis; j++) { - k = VECTOR(*membership)[VECTOR(*neis)[j]]; - if (k == 0) { - continue; /* skip if it has no label yet */ - } - VECTOR(label_counters)[k]++; - if (VECTOR(label_counters)[k] == 1) { - /* counter just became nonzero */ - IGRAPH_CHECK(igraph_vector_int_push_back(&nonzero_labels, k)); - } - if (max_count < VECTOR(label_counters)[k]) { - max_count = VECTOR(label_counters)[k]; - IGRAPH_CHECK(igraph_vector_int_resize(&dominant_labels, 1)); - VECTOR(dominant_labels)[0] = k; - } else if (max_count == VECTOR(label_counters)[k]) { - IGRAPH_CHECK(igraph_vector_int_push_back(&dominant_labels, k)); - } - } - } + case IGRAPH_LPA_RETENTION: + IGRAPH_CHECK(community_label_propagation(graph, membership, mode, weights, fixed_copy, /* retention */ true )); + break; - if (igraph_vector_int_size(&dominant_labels) > 0) { - if (control_iteration) { - /* Check if the _current_ label of the node is also dominant */ - if (VECTOR(label_counters)[VECTOR(*membership)[v1]] != max_count) { - /* Nope, we need at least one more iteration */ - running = true; - } - } - else { - /* Select randomly from the dominant labels */ - k = RNG_INTEGER(0, igraph_vector_int_size(&dominant_labels) - 1); - VECTOR(*membership)[v1] = VECTOR(dominant_labels)[k]; - } - } - - /* Clear the nonzero elements in label_counters */ - num_neis = igraph_vector_int_size(&nonzero_labels); - for (j = 0; j < num_neis; j++) { - VECTOR(label_counters)[VECTOR(nonzero_labels)[j]] = 0; - } - } - RNG_END(); + case IGRAPH_LPA_DOMINANCE: + IGRAPH_CHECK(community_label_propagation(graph, membership, mode, weights, fixed_copy, /* retention */ false)); + break; - /* Alternating between control iterations and label updating iterations */ - control_iteration = !control_iteration; + default: + IGRAPH_ERROR("Invalid igraph_lpa_variant_t.", IGRAPH_EINVAL); } - if (weights) { - igraph_inclist_destroy(&il); - } else { - igraph_adjlist_destroy(&al); - } - IGRAPH_FINALLY_CLEAN(1); + /* Permute labels in increasing order */ + igraph_vector_int_t relabel_label; + IGRAPH_CHECK(igraph_vector_int_init(&relabel_label, no_of_nodes)); + igraph_vector_int_fill(&relabel_label, -1); + IGRAPH_FINALLY(igraph_vector_int_destroy, &relabel_label); - /* Shift back the membership vector, permute labels in increasing order */ - /* We recycle label_counters here :) and use it as an integer vector from now on */ - igraph_vector_fill(&label_counters, -1); j = 0; unlabelled_left = false; for (i = 0; i < no_of_nodes; i++) { - k = VECTOR(*membership)[i] - 1; + k = VECTOR(*membership)[i]; if (k >= 0) { - if (VECTOR(label_counters)[k] == -1) { + if (VECTOR(relabel_label)[k] == -1) { /* We have seen this label for the first time */ - VECTOR(label_counters)[k] = j; + VECTOR(relabel_label)[k] = j; k = j; j++; } else { - k = (igraph_integer_t) VECTOR(label_counters)[k]; + k = VECTOR(relabel_label)[k]; } } else { /* This is an unlabeled vertex */ @@ -386,9 +681,6 @@ igraph_error_t igraph_community_label_propagation(const igraph_t *graph, VECTOR(*membership)[i] = k; } - /* From this point on, unlabelled nodes are represented with -1 (no longer 0). */ -#define IS_UNLABELLED(x) (VECTOR(*membership)[x] < 0) - /* If any nodes are left unlabelled, we assign the remaining labels to them, * as well as to all unlabelled nodes reachable from them. * @@ -401,9 +693,25 @@ igraph_error_t igraph_community_label_propagation(const igraph_t *graph, igraph_dqueue_int_t q; igraph_vector_int_t neis; - /* In the directed case, the outcome depends on the node ordering, thus we - * shuffle nodes one more time. */ - IGRAPH_CHECK(igraph_vector_int_shuffle(&node_order)); + igraph_vector_int_t node_order; + /* Initialize node ordering vector with only the not fixed nodes */ + if (fixed) { + no_of_not_fixed_nodes = 0; + IGRAPH_VECTOR_INT_INIT_FINALLY(&node_order, no_of_nodes); + for (i = 0; i < no_of_nodes; i++) { + if (!VECTOR(*fixed)[i]) { + VECTOR(node_order)[no_of_not_fixed_nodes] = i; + no_of_not_fixed_nodes++; + } + } + IGRAPH_CHECK(igraph_vector_int_resize(&node_order, no_of_not_fixed_nodes)); + } else { + IGRAPH_CHECK(igraph_vector_int_init_range(&node_order, 0, no_of_nodes)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &node_order); + no_of_not_fixed_nodes = no_of_nodes; + } + /* Shuffle the node ordering vector */ + igraph_vector_int_shuffle(&node_order); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); @@ -411,23 +719,23 @@ igraph_error_t igraph_community_label_propagation(const igraph_t *graph, IGRAPH_FINALLY(igraph_dqueue_int_destroy, &q); for (i=0; i < no_of_not_fixed_nodes; ++i) { - igraph_integer_t v = VECTOR(node_order)[i]; + igraph_int_t v = VECTOR(node_order)[i]; /* Is this node unlabelled? */ if (IS_UNLABELLED(v)) { /* If yes, we label it, and do a BFS to apply the same label * to all other unlabelled nodes reachable from it */ - igraph_dqueue_int_push(&q, v); + IGRAPH_CHECK(igraph_dqueue_int_push(&q, v)); VECTOR(*membership)[v] = j; while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t ni, num_neis; - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t ni, num_neis; + igraph_int_t actnode = igraph_dqueue_int_pop(&q); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); num_neis = igraph_vector_int_size(&neis); for (ni = 0; ni < num_neis; ++ni) { - igraph_integer_t neighbor = VECTOR(neis)[ni]; + igraph_int_t neighbor = VECTOR(neis)[ni]; if (IS_UNLABELLED(neighbor)) { VECTOR(*membership)[neighbor] = j; IGRAPH_CHECK(igraph_dqueue_int_push(&q, neighbor)); @@ -440,14 +748,12 @@ igraph_error_t igraph_community_label_propagation(const igraph_t *graph, igraph_vector_int_destroy(&neis); igraph_dqueue_int_destroy(&q); - IGRAPH_FINALLY_CLEAN(2); + igraph_vector_int_destroy(&node_order); + IGRAPH_FINALLY_CLEAN(3); } - igraph_vector_int_destroy(&node_order); - igraph_vector_destroy(&label_counters); - igraph_vector_int_destroy(&dominant_labels); - igraph_vector_int_destroy(&nonzero_labels); - IGRAPH_FINALLY_CLEAN(4); + igraph_vector_int_destroy(&relabel_label); + IGRAPH_FINALLY_CLEAN(1); if (fixed != fixed_copy) { igraph_vector_bool_destroy(fixed_copy); diff --git a/src/vendor/cigraph/src/community/leading_eigenvector.c b/src/vendor/cigraph/src/community/leading_eigenvector.c index e80e9234245..f25b63a59d2 100644 --- a/src/vendor/cigraph/src/community/leading_eigenvector.c +++ b/src/vendor/cigraph/src/community/leading_eigenvector.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -84,9 +82,9 @@ typedef struct igraph_i_community_leading_eigenvector_data_t { igraph_adjlist_t *adjlist; igraph_inclist_t *inclist; igraph_vector_t *tmp; - igraph_integer_t no_of_edges; + igraph_int_t no_of_edges; igraph_vector_int_t *mymembership; - igraph_integer_t comm; + igraph_int_t comm; const igraph_vector_t *weights; const igraph_t *graph; igraph_vector_t *strength; @@ -99,26 +97,26 @@ static igraph_error_t igraph_i_community_leading_eigenvector( int n, void *extra) { igraph_i_community_leading_eigenvector_data_t *data = extra; - igraph_integer_t size = n; + igraph_int_t size = n; igraph_vector_int_t *idx = data->idx; igraph_vector_int_t *idx2 = data->idx2; igraph_vector_t *tmp = data->tmp; igraph_adjlist_t *adjlist = data->adjlist; igraph_real_t ktx, ktx2; - igraph_integer_t no_of_edges = data->no_of_edges; + igraph_int_t no_of_edges = data->no_of_edges; igraph_vector_int_t *mymembership = data->mymembership; - igraph_integer_t comm = data->comm; + igraph_int_t comm = data->comm; /* Ax */ - for (igraph_integer_t j = 0; j < size; j++) { - igraph_integer_t oldid = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < size; j++) { + igraph_int_t oldid = VECTOR(*idx)[j]; igraph_vector_int_t *neis = igraph_adjlist_get(adjlist, oldid); - igraph_integer_t nlen = igraph_vector_int_size(neis); + igraph_int_t nlen = igraph_vector_int_size(neis); to[j] = 0.0; VECTOR(*tmp)[j] = 0.0; - for (igraph_integer_t k = 0; k < nlen; k++) { - igraph_integer_t nei = VECTOR(*neis)[k]; - igraph_integer_t neimemb = VECTOR(*mymembership)[nei]; + for (igraph_int_t k = 0; k < nlen; k++) { + igraph_int_t nei = VECTOR(*neis)[k]; + igraph_int_t neimemb = VECTOR(*mymembership)[nei]; if (neimemb == comm) { to[j] += from[ VECTOR(*idx2)[nei] ]; VECTOR(*tmp)[j] += 1; @@ -128,10 +126,10 @@ static igraph_error_t igraph_i_community_leading_eigenvector( /* Now calculate k^Tx/2m */ ktx = 0.0; ktx2 = 0.0; - for (igraph_integer_t j = 0; j < size; j++) { - igraph_integer_t oldid = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < size; j++) { + igraph_int_t oldid = VECTOR(*idx)[j]; igraph_vector_int_t *neis = igraph_adjlist_get(adjlist, oldid); - igraph_integer_t degree = igraph_vector_int_size(neis); + igraph_int_t degree = igraph_vector_int_size(neis); ktx += from[j] * degree; ktx2 += degree; } @@ -139,8 +137,8 @@ static igraph_error_t igraph_i_community_leading_eigenvector( ktx2 = ktx2 / no_of_edges / 2.0; /* Now calculate Bx */ - for (igraph_integer_t j = 0; j < size; j++) { - igraph_integer_t oldid = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < size; j++) { + igraph_int_t oldid = VECTOR(*idx)[j]; igraph_vector_int_t *neis = igraph_adjlist_get(adjlist, oldid); igraph_real_t degree = igraph_vector_int_size(neis); to[j] = to[j] - ktx * degree; @@ -148,7 +146,7 @@ static igraph_error_t igraph_i_community_leading_eigenvector( } /* -d_ij summa l in G B_il */ - for (igraph_integer_t j = 0; j < size; j++) { + for (igraph_int_t j = 0; j < size; j++) { to[j] -= VECTOR(*tmp)[j] * from[j]; } @@ -161,31 +159,31 @@ static igraph_error_t igraph_i_community_leading_eigenvector_weighted( int n, void *extra) { igraph_i_community_leading_eigenvector_data_t *data = extra; - igraph_integer_t size = n; + igraph_int_t size = n; igraph_vector_int_t *idx = data->idx; igraph_vector_int_t *idx2 = data->idx2; igraph_vector_t *tmp = data->tmp; igraph_inclist_t *inclist = data->inclist; igraph_real_t ktx, ktx2; igraph_vector_int_t *mymembership = data->mymembership; - igraph_integer_t comm = data->comm; + igraph_int_t comm = data->comm; const igraph_vector_t *weights = data->weights; const igraph_t *graph = data->graph; igraph_vector_t *strength = data->strength; igraph_real_t sw = data->sumweights; /* Ax */ - for (igraph_integer_t j = 0; j < size; j++) { - igraph_integer_t oldid = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < size; j++) { + igraph_int_t oldid = VECTOR(*idx)[j]; igraph_vector_int_t *inc = igraph_inclist_get(inclist, oldid); - igraph_integer_t nlen = igraph_vector_int_size(inc); + igraph_int_t nlen = igraph_vector_int_size(inc); to[j] = 0.0; VECTOR(*tmp)[j] = 0.0; - for (igraph_integer_t k = 0; k < nlen; k++) { - igraph_integer_t edge = VECTOR(*inc)[k]; + for (igraph_int_t k = 0; k < nlen; k++) { + igraph_int_t edge = VECTOR(*inc)[k]; igraph_real_t w = VECTOR(*weights)[edge]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, oldid); - igraph_integer_t neimemb = VECTOR(*mymembership)[nei]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, oldid); + igraph_int_t neimemb = VECTOR(*mymembership)[nei]; if (neimemb == comm) { to[j] += from[ VECTOR(*idx2)[nei] ] * w; VECTOR(*tmp)[j] += w; @@ -195,8 +193,8 @@ static igraph_error_t igraph_i_community_leading_eigenvector_weighted( /* k^Tx/2m */ ktx = 0.0; ktx2 = 0.0; - for (igraph_integer_t j = 0; j < size; j++) { - igraph_integer_t oldid = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < size; j++) { + igraph_int_t oldid = VECTOR(*idx)[j]; igraph_real_t str = VECTOR(*strength)[oldid]; ktx += from[j] * str; ktx2 += str; @@ -205,15 +203,15 @@ static igraph_error_t igraph_i_community_leading_eigenvector_weighted( ktx2 = ktx2 / sw / 2.0; /* Bx */ - for (igraph_integer_t j = 0; j < size; j++) { - igraph_integer_t oldid = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < size; j++) { + igraph_int_t oldid = VECTOR(*idx)[j]; igraph_real_t str = VECTOR(*strength)[oldid]; to[j] = to[j] - ktx * str; VECTOR(*tmp)[j] = VECTOR(*tmp)[j] - ktx2 * str; } /* -d_ij summa l in G B_il */ - for (igraph_integer_t j = 0; j < size; j++) { + for (igraph_int_t j = 0; j < size; j++) { to[j] -= VECTOR(*tmp)[j] * from[j]; } @@ -335,28 +333,28 @@ igraph_error_t igraph_community_leading_eigenvector( const igraph_vector_t *weights, igraph_matrix_int_t *merges, igraph_vector_int_t *membership, - igraph_integer_t steps, + igraph_int_t steps, igraph_arpack_options_t *options, igraph_real_t *modularity, igraph_bool_t start, igraph_vector_t *eigenvalues, igraph_vector_list_t *eigenvectors, - igraph_vector_t *history, + igraph_vector_int_t *history, igraph_community_leading_eigenvector_callback_t *callback, void *callback_extra) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_dqueue_int_t tosplit; igraph_vector_int_t idx, idx2; igraph_vector_t mymerges; igraph_vector_t strength, tmp; igraph_vector_t start_vec; - igraph_integer_t staken = 0; + igraph_int_t staken = 0; igraph_adjlist_t adjlist; igraph_inclist_t inclist; - igraph_integer_t i, j, k, l; - igraph_integer_t communities; + igraph_int_t i, j, k, l; + igraph_int_t communities; igraph_vector_int_t vmembership, *mymembership = membership; igraph_i_community_leading_eigenvector_data_t extra; igraph_arpack_storage_t storage; @@ -380,7 +378,7 @@ igraph_error_t igraph_community_leading_eigenvector( if (start && membership && igraph_vector_int_size(membership) != no_of_nodes) { - IGRAPH_ERROR("Supplied memberhsip vector length does not match number of vertices.", + IGRAPH_ERROR("Supplied membership vector length does not match number of vertices.", IGRAPH_EINVAL); } @@ -414,24 +412,24 @@ igraph_error_t igraph_community_leading_eigenvector( if (!start) { /* Calculate the weakly connected components in the graph and use them as * an initial split */ - IGRAPH_CHECK(igraph_connected_components(graph, mymembership, &idx, 0, IGRAPH_WEAK)); + IGRAPH_CHECK(igraph_connected_components(graph, mymembership, &idx, NULL, IGRAPH_WEAK)); communities = igraph_vector_int_size(&idx); if (history) { - IGRAPH_CHECK(igraph_vector_push_back(history, + IGRAPH_CHECK(igraph_vector_int_push_back(history, IGRAPH_LEVC_HIST_START_FULL)); } } else { /* Just create the idx vector for the given membership vector */ communities = igraph_vector_int_max(mymembership) + 1; if (history) { - IGRAPH_CHECK(igraph_vector_push_back(history, + IGRAPH_CHECK(igraph_vector_int_push_back(history, IGRAPH_LEVC_HIST_START_GIVEN)); - IGRAPH_CHECK(igraph_vector_push_back(history, communities)); + IGRAPH_CHECK(igraph_vector_int_push_back(history, communities)); } IGRAPH_CHECK(igraph_vector_int_resize(&idx, communities)); igraph_vector_int_null(&idx); for (i = 0; i < no_of_nodes; i++) { - igraph_integer_t t = VECTOR(*mymembership)[i]; + igraph_int_t t = VECTOR(*mymembership)[i]; VECTOR(idx)[t] += 1; } } @@ -456,8 +454,8 @@ igraph_error_t igraph_community_leading_eigenvector( IGRAPH_CHECK(igraph_vector_list_push_back_new(eigenvectors, NULL)); } if (history) { - IGRAPH_CHECK(igraph_vector_push_back(history, IGRAPH_LEVC_HIST_SPLIT)); - IGRAPH_CHECK(igraph_vector_push_back(history, i - 1)); + IGRAPH_CHECK(igraph_vector_int_push_back(history, IGRAPH_LEVC_HIST_SPLIT)); + IGRAPH_CHECK(igraph_vector_int_push_back(history, i - 1)); } } staken = communities - 1; @@ -504,9 +502,9 @@ igraph_error_t igraph_community_leading_eigenvector( extra.mymembership = mymembership; while (!igraph_dqueue_int_empty(&tosplit) && staken < steps) { - igraph_integer_t comm = igraph_dqueue_int_pop_back(&tosplit); + igraph_int_t comm = igraph_dqueue_int_pop_back(&tosplit); /* depth first search */ - igraph_integer_t size = 0; + igraph_int_t size = 0; IGRAPH_ALLOW_INTERRUPTION(); @@ -540,27 +538,33 @@ igraph_error_t igraph_community_leading_eigenvector( * convergence in most cases. */ options->start = 1; options->mxiter = options->mxiter > 10000 ? options->mxiter : 10000; /* use more iterations, we've had convergence problems with 3000 */ - RNG_BEGIN(); + for (i = 0; i < options->n; i++) { storage.resid[i] = (i % 2 ? 1 : -1) + RNG_UNIF(-0.1, 0.1); } - RNG_END(); - igraph_vector_view(&start_vec, storage.resid, options->n); - IGRAPH_CHECK(igraph_vector_shuffle(&start_vec)); + + start_vec = igraph_vector_view(storage.resid, options->n); + igraph_vector_shuffle(&start_vec); { igraph_error_t retval; igraph_error_handler_t *errh = igraph_set_error_handler(igraph_i_error_handler_none); - retval = igraph_arpack_rssolve(arpcb1, &extra, options, &storage, /*values=*/ 0, /*vectors=*/ 0); + retval = igraph_arpack_rssolve(arpcb1, &extra, options, &storage, /*values=*/ NULL, /*vectors=*/ NULL); igraph_set_error_handler(errh); - if (retval != IGRAPH_SUCCESS && retval != IGRAPH_ARPACK_MAXIT && retval != IGRAPH_ARPACK_NOSHIFT) { - IGRAPH_ERROR("ARPACK call failed", retval); + if (retval == IGRAPH_EARPACK) { + /* TODO(ntamas): get last ARPACK error code. Some errors are OK. */ + igraph_arpack_error_t arpack_error = igraph_arpack_get_last_error(); + if (arpack_error != IGRAPH_ARPACK_MAXIT && arpack_error != IGRAPH_ARPACK_NOSHIFT) { + IGRAPH_ERROR(igraph_arpack_error_to_string(arpack_error), IGRAPH_EARPACK); + } + } else if (retval != IGRAPH_SUCCESS) { + IGRAPH_ERROR("Leading eigenvector calculation failed.", retval); } } if (options->nconv < 1) { - IGRAPH_ERROR("ARPACK did not converge", IGRAPH_ARPACK_FAILED); + IGRAPH_ERROR(igraph_arpack_error_to_string(IGRAPH_ARPACK_FAILED), IGRAPH_EARPACK); } /* Ok, we have the leading eigenvector of the modularity matrix */ @@ -595,10 +599,9 @@ igraph_error_t igraph_community_leading_eigenvector( /* ---------------------------------------------------------------*/ if (callback) { - igraph_vector_t vv; + const igraph_vector_t vv = igraph_vector_view(storage.v, size);; igraph_error_t ret; - igraph_vector_view(&vv, storage.v, size); IGRAPH_CHECK_CALLBACK( callback( mymembership, comm, storage.d[0], &vv, arpcb1, @@ -627,9 +630,9 @@ igraph_error_t igraph_community_leading_eigenvector( if (storage.d[0] <= 0) { if (history) { - IGRAPH_CHECK(igraph_vector_push_back(history, + IGRAPH_CHECK(igraph_vector_int_push_back(history, IGRAPH_LEVC_HIST_FAILED)); - IGRAPH_CHECK(igraph_vector_push_back(history, comm)); + IGRAPH_CHECK(igraph_vector_int_push_back(history, comm)); } continue; } @@ -646,9 +649,9 @@ igraph_error_t igraph_community_leading_eigenvector( } if (l == 0 || l == size) { if (history) { - IGRAPH_CHECK(igraph_vector_push_back(history, + IGRAPH_CHECK(igraph_vector_int_push_back(history, IGRAPH_LEVC_HIST_FAILED)); - IGRAPH_CHECK(igraph_vector_push_back(history, comm)); + IGRAPH_CHECK(igraph_vector_int_push_back(history, comm)); } continue; } @@ -661,9 +664,9 @@ igraph_error_t igraph_community_leading_eigenvector( } if (mod <= 1e-8) { if (history) { - IGRAPH_CHECK(igraph_vector_push_back(history, + IGRAPH_CHECK(igraph_vector_int_push_back(history, IGRAPH_LEVC_HIST_FAILED)); - IGRAPH_CHECK(igraph_vector_push_back(history, comm)); + IGRAPH_CHECK(igraph_vector_int_push_back(history, comm)); } continue; } @@ -673,7 +676,7 @@ igraph_error_t igraph_community_leading_eigenvector( /* Rewrite the mymembership vector */ for (j = 0; j < size; j++) { if (storage.v[j] < 0) { - igraph_integer_t oldid = VECTOR(idx)[j]; + igraph_int_t oldid = VECTOR(idx)[j]; VECTOR(*mymembership)[oldid] = communities - 1; } } @@ -682,8 +685,8 @@ igraph_error_t igraph_community_leading_eigenvector( IGRAPH_CHECK(igraph_vector_push_back(&mymerges, comm)); IGRAPH_CHECK(igraph_vector_push_back(&mymerges, communities - 1)); if (history) { - IGRAPH_CHECK(igraph_vector_push_back(history, IGRAPH_LEVC_HIST_SPLIT)); - IGRAPH_CHECK(igraph_vector_push_back(history, comm)); + IGRAPH_CHECK(igraph_vector_int_push_back(history, IGRAPH_LEVC_HIST_SPLIT)); + IGRAPH_CHECK(igraph_vector_int_push_back(history, comm)); } /* Store the resulting communities in the queue if needed */ @@ -719,8 +722,8 @@ igraph_error_t igraph_community_leading_eigenvector( j = 0; IGRAPH_CHECK(igraph_matrix_int_resize(merges, l / 2, 2)); for (i = l; i > 0; i -= 2) { - igraph_integer_t from = VECTOR(mymerges)[i - 1]; - igraph_integer_t to = VECTOR(mymerges)[i - 2]; + igraph_int_t from = VECTOR(mymerges)[i - 1]; + igraph_int_t to = VECTOR(mymerges)[i - 2]; MATRIX(*merges, j, 0) = VECTOR(mymerges)[i - 2]; MATRIX(*merges, j, 1) = VECTOR(mymerges)[i - 1]; if (VECTOR(idx)[from] != 0) { @@ -798,13 +801,13 @@ igraph_error_t igraph_community_leading_eigenvector( * Time complexity: O(|V|), the number of vertices. */ igraph_error_t igraph_le_community_to_membership(const igraph_matrix_int_t *merges, - igraph_integer_t steps, + igraph_int_t steps, igraph_vector_int_t *membership, igraph_vector_int_t *csize) { - igraph_integer_t no_of_nodes = igraph_vector_int_size(membership); + igraph_int_t no_of_nodes = igraph_vector_int_size(membership); igraph_vector_int_t fake_memb; - igraph_integer_t components, i; + igraph_int_t components, i; if (no_of_nodes > 0) { components = igraph_vector_int_max(membership) + 1; @@ -839,7 +842,7 @@ igraph_error_t igraph_le_community_to_membership(const igraph_matrix_int_t *merg } } - IGRAPH_CHECK(igraph_community_to_membership(merges, components, steps, &fake_memb, 0)); + IGRAPH_CHECK(igraph_community_to_membership(merges, components, steps, &fake_memb, NULL)); /* Ok, now we have the membership of the initial components, rewrite the original membership vector. */ diff --git a/src/vendor/cigraph/src/community/leiden.c b/src/vendor/cigraph/src/community/leiden.c index 1231c5ce851..8667b8b6b04 100644 --- a/src/vendor/cigraph/src/community/leiden.c +++ b/src/vendor/cigraph/src/community/leiden.c @@ -1,9 +1,6 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + igraph library. + Copyright (C) 2020-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_community.h" @@ -32,78 +26,90 @@ #include "igraph_memory.h" #include "igraph_random.h" #include "igraph_stack.h" +#include "igraph_structural.h" #include "igraph_vector.h" #include "igraph_vector_list.h" #include "core/interruption.h" -/* Move nodes in order to improve the quality of a partition. +/* Move vertices in order to improve the quality of a partition. * - * This function considers each node and greedily moves it to a neighboring + * This function considers each vertex and greedily moves it to a neighboring * community that maximizes the improvement in the quality of a partition. * Only moves that strictly improve the quality are considered. * - * The nodes are examined in a queue, and initially all nodes are put in the - * queue in a random order. Nodes are popped from the queue when they are - * examined, and only neighbors of nodes that are moved (which are not part of - * the cluster the node was moved to) are pushed to the queue again. + * The vertices are examined in a queue, and initially all vertices are put in the + * queue in a random order. Vertices are popped from the queue when they are + * examined, and only neighbors of vertices that are moved (which are not part of + * the cluster the vertex was moved to) are pushed to the queue again. * - * The \c membership vector is used as the starting point to move around nodes, + * The \p membership vector is used as the starting point to move around vertices, * and is updated in-place. * */ -static igraph_error_t igraph_i_community_leiden_fastmovenodes( +static igraph_error_t leiden_fastmove_vertices( const igraph_t *graph, - const igraph_inclist_t *edges_per_node, - const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights, - const igraph_real_t resolution_parameter, - igraph_integer_t *nb_clusters, + const igraph_inclist_t *edges_per_vertex, + const igraph_vector_t *edge_weights, + const igraph_vector_t *vertex_out_weights, + const igraph_vector_t *vertex_in_weights, + const igraph_real_t resolution, + igraph_int_t *nb_clusters, igraph_vector_int_t *membership, igraph_bool_t *changed) { - igraph_dqueue_int_t unstable_nodes; - igraph_real_t max_diff = 0.0, diff = 0.0; - const igraph_integer_t n = igraph_vcount(graph); - igraph_bitset_t neighbor_cluster_added, node_is_stable; - igraph_vector_t cluster_weights, edge_weights_per_cluster; + const igraph_int_t n = igraph_vcount(graph); + const igraph_bool_t directed = (vertex_in_weights != NULL); + igraph_dqueue_int_t unstable_vertices; + igraph_real_t max_diff, diff; + igraph_bitset_t neighbor_cluster_added, vertex_is_stable; + igraph_vector_t cluster_out_weights, cluster_in_weights; + igraph_vector_t edge_weights_per_cluster; igraph_vector_int_t neighbor_clusters; - igraph_vector_int_t node_order; - igraph_vector_int_t nb_nodes_per_cluster; + igraph_vector_int_t vertex_order; + igraph_vector_int_t nb_vertices_per_cluster; igraph_stack_int_t empty_clusters; - igraph_integer_t c, nb_neigh_clusters; + igraph_int_t c, nb_neigh_clusters; int iter = 0; - /* Initialize queue of unstable nodes and whether node is stable. Only - * unstable nodes are in the queue. */ - IGRAPH_BITSET_INIT_FINALLY(&node_is_stable, n); + /* Initialize queue of unstable vertices and whether vertex is stable. Only + * unstable vertices are in the queue. */ + IGRAPH_BITSET_INIT_FINALLY(&vertex_is_stable, n); - IGRAPH_DQUEUE_INT_INIT_FINALLY(&unstable_nodes, n); + IGRAPH_DQUEUE_INT_INIT_FINALLY(&unstable_vertices, n); - /* Shuffle nodes */ - IGRAPH_CHECK(igraph_vector_int_init_range(&node_order, 0, n)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &node_order); - IGRAPH_CHECK(igraph_vector_int_shuffle(&node_order)); + /* Shuffle vertices */ + IGRAPH_CHECK(igraph_vector_int_init_range(&vertex_order, 0, n)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &vertex_order); + igraph_vector_int_shuffle(&vertex_order); /* Add to the queue */ - for (igraph_integer_t i = 0; i < n; i++) { - IGRAPH_CHECK(igraph_dqueue_int_push(&unstable_nodes, VECTOR(node_order)[i])); + for (igraph_int_t i = 0; i < n; i++) { + IGRAPH_CHECK(igraph_dqueue_int_push(&unstable_vertices, VECTOR(vertex_order)[i])); } - /* Initialize cluster weights and nb nodes */ - IGRAPH_VECTOR_INIT_FINALLY(&cluster_weights, n); - IGRAPH_VECTOR_INT_INIT_FINALLY(&nb_nodes_per_cluster, n); - for (igraph_integer_t i = 0; i < n; i++) { + /* Initialize cluster weights and nb vertices */ + IGRAPH_VECTOR_INIT_FINALLY(&cluster_out_weights, n); + if (directed) { + IGRAPH_VECTOR_INIT_FINALLY(&cluster_in_weights, n); + } + IGRAPH_VECTOR_INT_INIT_FINALLY(&nb_vertices_per_cluster, n); + for (igraph_int_t i = 0; i < n; i++) { c = VECTOR(*membership)[i]; - VECTOR(cluster_weights)[c] += VECTOR(*node_weights)[i]; - VECTOR(nb_nodes_per_cluster)[c] += 1; + VECTOR(cluster_out_weights)[c] += VECTOR(*vertex_out_weights)[i]; + if (directed) { + VECTOR(cluster_in_weights)[c] += VECTOR(*vertex_in_weights)[i]; + } + VECTOR(nb_vertices_per_cluster)[c] += 1; } /* Initialize empty clusters */ IGRAPH_STACK_INT_INIT_FINALLY(&empty_clusters, n); - for (c = 0; c < n; c++) - if (VECTOR(nb_nodes_per_cluster)[c] == 0) { + for (c = 0; c < n; c++) { + if (VECTOR(nb_vertices_per_cluster)[c] == 0) { IGRAPH_CHECK(igraph_stack_int_push(&empty_clusters, c)); } + } /* Initialize vectors to be used in calculating differences */ IGRAPH_VECTOR_INIT_FINALLY(&edge_weights_per_cluster, n); @@ -113,16 +119,19 @@ static igraph_error_t igraph_i_community_leiden_fastmovenodes( IGRAPH_VECTOR_INT_INIT_FINALLY(&neighbor_clusters, n); /* Iterate while the queue is not empty */ - while (!igraph_dqueue_int_empty(&unstable_nodes)) { - igraph_integer_t v = igraph_dqueue_int_pop(&unstable_nodes); - igraph_integer_t best_cluster, current_cluster = VECTOR(*membership)[v]; - igraph_integer_t degree; + while (!igraph_dqueue_int_empty(&unstable_vertices)) { + igraph_int_t v = igraph_dqueue_int_pop(&unstable_vertices); + igraph_int_t best_cluster, current_cluster = VECTOR(*membership)[v]; + igraph_int_t degree; igraph_vector_int_t *edges; - /* Remove node from current cluster */ - VECTOR(cluster_weights)[current_cluster] -= VECTOR(*node_weights)[v]; - VECTOR(nb_nodes_per_cluster)[current_cluster]--; - if (VECTOR(nb_nodes_per_cluster)[current_cluster] == 0) { + /* Remove vertex from current cluster */ + VECTOR(cluster_out_weights)[current_cluster] -= VECTOR(*vertex_out_weights)[v]; + if (directed) { + VECTOR(cluster_in_weights)[current_cluster] -= VECTOR(*vertex_in_weights)[v]; + } + VECTOR(nb_vertices_per_cluster)[current_cluster]--; + if (VECTOR(nb_vertices_per_cluster)[current_cluster] == 0) { IGRAPH_CHECK(igraph_stack_int_push(&empty_clusters, current_cluster)); } @@ -133,11 +142,11 @@ static igraph_error_t igraph_i_community_leiden_fastmovenodes( nb_neigh_clusters = 1; /* Determine the edge weight to each neighboring cluster */ - edges = igraph_inclist_get(edges_per_node, v); + edges = igraph_inclist_get(edges_per_vertex, v); degree = igraph_vector_int_size(edges); - for (igraph_integer_t i = 0; i < degree; i++) { - igraph_integer_t e = VECTOR(*edges)[i]; - igraph_integer_t u = IGRAPH_OTHER(graph, e, v); + for (igraph_int_t i = 0; i < degree; i++) { + igraph_int_t e = VECTOR(*edges)[i]; + igraph_int_t u = IGRAPH_OTHER(graph, e, v); if (u != v) { c = VECTOR(*membership)[u]; if (!IGRAPH_BIT_TEST(neighbor_cluster_added, c)) { @@ -150,10 +159,23 @@ static igraph_error_t igraph_i_community_leiden_fastmovenodes( /* Calculate maximum diff */ best_cluster = current_cluster; - max_diff = VECTOR(edge_weights_per_cluster)[current_cluster] - VECTOR(*node_weights)[v] * VECTOR(cluster_weights)[current_cluster] * resolution_parameter; - for (igraph_integer_t i = 0; i < nb_neigh_clusters; i++) { + max_diff = VECTOR(edge_weights_per_cluster)[current_cluster]; + if (directed) { + max_diff -= + (VECTOR(*vertex_in_weights)[v] * VECTOR(cluster_out_weights)[current_cluster] + + VECTOR(*vertex_out_weights)[v] * VECTOR(cluster_in_weights)[current_cluster]) * resolution; + } else { + max_diff -= VECTOR(*vertex_out_weights)[v] * VECTOR(cluster_out_weights)[current_cluster] * resolution; + } + for (igraph_int_t i = 0; i < nb_neigh_clusters; i++) { c = VECTOR(neighbor_clusters)[i]; - diff = VECTOR(edge_weights_per_cluster)[c] - VECTOR(*node_weights)[v] * VECTOR(cluster_weights)[c] * resolution_parameter; + diff = VECTOR(edge_weights_per_cluster)[c]; + if (directed) { + diff -= (VECTOR(*vertex_out_weights)[v] * VECTOR(cluster_in_weights)[c] + + VECTOR(*vertex_in_weights)[v] * VECTOR(cluster_out_weights)[c]) * resolution; + } else { + diff -= VECTOR(*vertex_out_weights)[v] * VECTOR(cluster_out_weights)[c] * resolution; + } /* Only consider strictly improving moves. * Note that this is important in considering convergence. */ @@ -165,27 +187,30 @@ static igraph_error_t igraph_i_community_leiden_fastmovenodes( IGRAPH_BIT_CLEAR(neighbor_cluster_added, c); } - /* Move node to best cluster */ - VECTOR(cluster_weights)[best_cluster] += VECTOR(*node_weights)[v]; - VECTOR(nb_nodes_per_cluster)[best_cluster]++; + /* Move vertex to best cluster */ + VECTOR(cluster_out_weights)[best_cluster] += VECTOR(*vertex_out_weights)[v]; + if (directed) { + VECTOR(cluster_in_weights)[best_cluster] += VECTOR(*vertex_in_weights)[v]; + } + VECTOR(nb_vertices_per_cluster)[best_cluster]++; if (best_cluster == igraph_stack_int_top(&empty_clusters)) { igraph_stack_int_pop(&empty_clusters); } - /* Mark node as stable */ - IGRAPH_BIT_SET(node_is_stable, v); + /* Mark vertex as stable */ + IGRAPH_BIT_SET(vertex_is_stable, v); /* Add stable neighbours that are not part of the new cluster to the queue */ if (best_cluster != current_cluster) { *changed = true; VECTOR(*membership)[v] = best_cluster; - for (igraph_integer_t i = 0; i < degree; i++) { - igraph_integer_t e = VECTOR(*edges)[i]; - igraph_integer_t u = IGRAPH_OTHER(graph, e, v); - if (IGRAPH_BIT_TEST(node_is_stable, u) && VECTOR(*membership)[u] != best_cluster) { - IGRAPH_CHECK(igraph_dqueue_int_push(&unstable_nodes, u)); - IGRAPH_BIT_CLEAR(node_is_stable, u); + for (igraph_int_t i = 0; i < degree; i++) { + igraph_int_t e = VECTOR(*edges)[i]; + igraph_int_t u = IGRAPH_OTHER(graph, e, v); + if (IGRAPH_BIT_TEST(vertex_is_stable, u) && VECTOR(*membership)[u] != best_cluster) { + IGRAPH_CHECK(igraph_dqueue_int_push(&unstable_vertices, u)); + IGRAPH_BIT_CLEAR(vertex_is_stable, u); } } } @@ -199,30 +224,36 @@ static igraph_error_t igraph_i_community_leiden_fastmovenodes( igraph_bitset_destroy(&neighbor_cluster_added); igraph_vector_destroy(&edge_weights_per_cluster); igraph_stack_int_destroy(&empty_clusters); - igraph_vector_int_destroy(&nb_nodes_per_cluster); - igraph_vector_destroy(&cluster_weights); - igraph_vector_int_destroy(&node_order); - igraph_dqueue_int_destroy(&unstable_nodes); - igraph_bitset_destroy(&node_is_stable); - IGRAPH_FINALLY_CLEAN(9); + igraph_vector_int_destroy(&nb_vertices_per_cluster); + if (directed) igraph_vector_destroy(&cluster_in_weights); + igraph_vector_destroy(&cluster_out_weights); + igraph_vector_int_destroy(&vertex_order); + igraph_dqueue_int_destroy(&unstable_vertices); + igraph_bitset_destroy(&vertex_is_stable); + if (directed) { + IGRAPH_FINALLY_CLEAN(10); + } else { + IGRAPH_FINALLY_CLEAN(9); + } return IGRAPH_SUCCESS; } /* Clean a refined membership vector. * - * This function examines all nodes in \c node_subset and updates \c - * refined_membership to ensure that the clusters are numbered consecutively, - * starting from \c nb_refined_clusters. The \c nb_refined_clusters is also - * updated itself. If C is the initial \c nb_refined_clusters and C' the - * resulting \c nb_refined_clusters, then nodes in \c node_subset are numbered + * This function examines all vertices in \p vertex_subset and updates + * \p refined_membership to ensure that the clusters are numbered consecutively, + * starting from \p nb_refined_clusters. The \p nb_refined_clusters is also + * updated itself. If C is the initial \p nb_refined_clusters and C' the + * resulting \p nb_refined_clusters, then vertices in \p vertex_subset are numbered * C, C + 1, ..., C' - 1. */ -static igraph_error_t igraph_i_community_leiden_clean_refined_membership( - const igraph_vector_int_t* node_subset, +static igraph_error_t leiden_clean_refined_membership( + const igraph_vector_int_t* vertex_subset, igraph_vector_int_t *refined_membership, - igraph_integer_t* nb_refined_clusters) { - const igraph_integer_t n = igraph_vector_int_size(node_subset); + igraph_int_t* nb_refined_clusters) { + + const igraph_int_t n = igraph_vector_int_size(vertex_subset); igraph_vector_int_t new_cluster; IGRAPH_VECTOR_INT_INIT_FINALLY(&new_cluster, n); @@ -230,9 +261,9 @@ static igraph_error_t igraph_i_community_leiden_clean_refined_membership( /* Clean clusters. We will store the new cluster + 1 so that cluster == 0 * indicates that no membership was assigned yet. */ *nb_refined_clusters += 1; - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t v = VECTOR(*node_subset)[i]; - igraph_integer_t c = VECTOR(*refined_membership)[v]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t v = VECTOR(*vertex_subset)[i]; + igraph_int_t c = VECTOR(*refined_membership)[v]; if (VECTOR(new_cluster)[c] == 0) { VECTOR(new_cluster)[c] = *nb_refined_clusters; *nb_refined_clusters += 1; @@ -240,9 +271,9 @@ static igraph_error_t igraph_i_community_leiden_clean_refined_membership( } /* Assign new cluster */ - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t v = VECTOR(*node_subset)[i]; - igraph_integer_t c = VECTOR(*refined_membership)[v]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t v = VECTOR(*vertex_subset)[i]; + igraph_int_t c = VECTOR(*refined_membership)[v]; VECTOR(*refined_membership)[v] = VECTOR(new_cluster)[c] - 1; } /* We used the cluster + 1, so correct */ @@ -254,17 +285,17 @@ static igraph_error_t igraph_i_community_leiden_clean_refined_membership( return IGRAPH_SUCCESS; } -/* Merge nodes for a subset of the nodes. This is used to refine a partition. +/* Merge vertices for a subset of the vertices. This is used to refine a partition. * - * The nodes included in \c node_subset are assumed to be the nodes i for which + * The vertices included in \p vertex_subset are assumed to be the vertices i for which * membership[i] = cluster_subset. * - * All nodes in \c node_subset are initialized to a singleton partition in \c + * All vertices in \p vertex_subset are initialized to a singleton partition in \p * refined_membership. Only singleton clusters can be merged if they are - * sufficiently well connected to the current subgraph induced by \c - * node_subset. + * sufficiently well connected to the current subgraph induced by \p + * vertex_subset. * - * We only examine each node once. Instead of greedily choosing the maximum + * We only examine each vertex once. Instead of greedily choosing the maximum * possible cluster to merge with, the cluster is chosen randomly among all * possibilities that do not decrease the quality of the partition. The * probability of choosing a certain cluster is proportional to exp(diff/beta). @@ -272,71 +303,84 @@ static igraph_error_t igraph_i_community_leiden_clean_refined_membership( * improvement. For beta to infinity this converges to a uniform distribution * among all eligible clusters. * - * The \c refined_membership is updated for node in \c node_subset. The number - * of refined clusters, \c nb_refined_clusters is used to set the actual refined + * The \p refined_membership is updated for vertex in \p vertex_subset. The number + * of refined clusters, \p nb_refined_clusters is used to set the actual refined * cluster membership and is updated after this routine. Within each cluster - * (i.e. for a given \c node_subset), the refined membership is initially simply - * set to 0, ..., n - 1 (for n nodes in \c node_subset). However, for each \c - * node_subset the refined membership should of course be unique. Hence, after - * merging, the refined membership starts with \c nb_refined_clusters, which is - * also updated to ensure that the resulting \c nb_refined_clusters counts all + * (i.e. for a given \p vertex_subset), the refined membership is initially simply + * set to 0, ..., n - 1 (for n vertices in \p vertex_subset). However, for each \p + * vertex_subset the refined membership should of course be unique. Hence, after + * merging, the refined membership starts with \p nb_refined_clusters, which is + * also updated to ensure that the resulting \p nb_refined_clusters counts all * refined clusters that have already been processed. See - * igraph_i_community_leiden_clean_refined_membership for more information about + * leiden_clean_refined_membership for more information about * this aspect. */ -static igraph_error_t igraph_i_community_leiden_mergenodes( +static igraph_error_t leiden_merge_vertices( const igraph_t *graph, - const igraph_inclist_t *edges_per_node, - const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights, - const igraph_vector_int_t *node_subset, + const igraph_inclist_t *edges_per_vertex, + const igraph_vector_t *edge_weights, + const igraph_vector_t *vertex_out_weights, + const igraph_vector_t *vertex_in_weights, + const igraph_vector_int_t *vertex_subset, const igraph_vector_int_t *membership, - const igraph_integer_t cluster_subset, - const igraph_real_t resolution_parameter, + const igraph_int_t cluster_subset, + const igraph_real_t resolution, const igraph_real_t beta, - igraph_integer_t *nb_refined_clusters, + igraph_int_t *nb_refined_clusters, igraph_vector_int_t *refined_membership) { - igraph_vector_int_t node_order; + + const igraph_bool_t directed = (vertex_in_weights != NULL); + igraph_vector_int_t vertex_order; igraph_bitset_t non_singleton_cluster, neighbor_cluster_added; - igraph_real_t max_diff, total_cum_trans_diff, diff = 0.0, total_node_weight = 0.0; - const igraph_integer_t n = igraph_vector_int_size(node_subset); - igraph_vector_t cluster_weights, cum_trans_diff, edge_weights_per_cluster, external_edge_weight_per_cluster_in_subset; + igraph_real_t max_diff, total_cum_trans_diff, diff; + igraph_real_t total_vertex_out_weight = 0.0, total_vertex_in_weight = 0.0; + const igraph_int_t n = igraph_vector_int_size(vertex_subset); + igraph_vector_t cluster_out_weights, cluster_in_weights; + igraph_vector_t cum_trans_diff, edge_weights_per_cluster, external_edge_weight_per_cluster_in_subset; igraph_vector_int_t neighbor_clusters; - igraph_vector_int_t *edges, nb_nodes_per_cluster; - igraph_integer_t degree, nb_neigh_clusters; + igraph_vector_int_t *edges, nb_vertices_per_cluster; + igraph_int_t degree, nb_neigh_clusters; /* Initialize cluster weights */ - IGRAPH_VECTOR_INIT_FINALLY(&cluster_weights, n); + IGRAPH_VECTOR_INIT_FINALLY(&cluster_out_weights, n); + if (directed) { + IGRAPH_VECTOR_INIT_FINALLY(&cluster_in_weights, n); + } - /* Initialize number of nodes per cluster */ - IGRAPH_VECTOR_INT_INIT_FINALLY(&nb_nodes_per_cluster, n); + /* Initialize number of vertices per cluster */ + IGRAPH_VECTOR_INT_INIT_FINALLY(&nb_vertices_per_cluster, n); /* Initialize external edge weight per cluster in subset */ IGRAPH_VECTOR_INIT_FINALLY(&external_edge_weight_per_cluster_in_subset, n); /* Initialize administration for a singleton partition */ - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t v = VECTOR(*node_subset)[i]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t v = VECTOR(*vertex_subset)[i]; VECTOR(*refined_membership)[v] = i; - VECTOR(cluster_weights)[i] += VECTOR(*node_weights)[v]; - VECTOR(nb_nodes_per_cluster)[i] += 1; - total_node_weight += VECTOR(*node_weights)[v]; + VECTOR(cluster_out_weights)[i] += VECTOR(*vertex_out_weights)[v]; + total_vertex_out_weight += VECTOR(*vertex_out_weights)[v]; + if (directed) { + VECTOR(cluster_in_weights)[i] += VECTOR(*vertex_in_weights)[v]; + total_vertex_in_weight += VECTOR(*vertex_in_weights)[v]; + } + VECTOR(nb_vertices_per_cluster)[i] += 1; /* Find out neighboring clusters */ - edges = igraph_inclist_get(edges_per_node, v); + edges = igraph_inclist_get(edges_per_vertex, v); degree = igraph_vector_int_size(edges); - for (igraph_integer_t j = 0; j < degree; j++) { - igraph_integer_t e = VECTOR(*edges)[j]; - igraph_integer_t u = IGRAPH_OTHER(graph, e, v); + for (igraph_int_t j = 0; j < degree; j++) { + igraph_int_t e = VECTOR(*edges)[j]; + igraph_int_t u = IGRAPH_OTHER(graph, e, v); if (u != v && VECTOR(*membership)[u] == cluster_subset) { VECTOR(external_edge_weight_per_cluster_in_subset)[i] += VECTOR(*edge_weights)[e]; } } } - /* Shuffle nodes */ - IGRAPH_CHECK(igraph_vector_int_init_copy(&node_order, node_subset)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &node_order); - IGRAPH_CHECK(igraph_vector_int_shuffle(&node_order)); + /* Shuffle vertices */ + IGRAPH_CHECK(igraph_vector_int_init_copy(&vertex_order, vertex_subset)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &vertex_order); + igraph_vector_int_shuffle(&vertex_order); /* Initialize non singleton clusters */ IGRAPH_BITSET_INIT_FINALLY(&non_singleton_cluster, n); @@ -351,33 +395,43 @@ static igraph_error_t igraph_i_community_leiden_mergenodes( /* Initialize cumulative transformed difference */ IGRAPH_VECTOR_INIT_FINALLY(&cum_trans_diff, n); - RNG_BEGIN(); - - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t v = VECTOR(node_order)[i]; - igraph_integer_t chosen_cluster, best_cluster, current_cluster = VECTOR(*refined_membership)[v]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t v = VECTOR(vertex_order)[i]; + igraph_int_t chosen_cluster, best_cluster, current_cluster = VECTOR(*refined_membership)[v]; + igraph_real_t vertex_weight_prod; + + if (directed) { + vertex_weight_prod = + VECTOR(cluster_out_weights)[current_cluster] * (total_vertex_in_weight - VECTOR(cluster_in_weights)[current_cluster]) + + VECTOR(cluster_in_weights)[current_cluster] * (total_vertex_out_weight - VECTOR(cluster_out_weights)[current_cluster]); + } else { + vertex_weight_prod = VECTOR(cluster_out_weights)[current_cluster] * (total_vertex_out_weight - VECTOR(cluster_out_weights)[current_cluster]); + } if (!IGRAPH_BIT_TEST(non_singleton_cluster, current_cluster) && (VECTOR(external_edge_weight_per_cluster_in_subset)[current_cluster] >= - VECTOR(cluster_weights)[current_cluster] * (total_node_weight - VECTOR(cluster_weights)[current_cluster]) * resolution_parameter)) { - /* Remove node from current cluster, which is then a singleton by + vertex_weight_prod * resolution)) { + /* Remove vertex from current cluster, which is then a singleton by * definition. */ - VECTOR(cluster_weights)[current_cluster] = 0.0; - VECTOR(nb_nodes_per_cluster)[current_cluster] = 0; + VECTOR(cluster_out_weights)[current_cluster] = 0.0; + if (directed) { + VECTOR(cluster_in_weights)[current_cluster] = 0.0; + } + VECTOR(nb_vertices_per_cluster)[current_cluster] = 0; /* Find out neighboring clusters */ - edges = igraph_inclist_get(edges_per_node, v); + edges = igraph_inclist_get(edges_per_vertex, v); degree = igraph_vector_int_size(edges); /* Also add current cluster to ensure it can be chosen. */ VECTOR(neighbor_clusters)[0] = current_cluster; IGRAPH_BIT_SET(neighbor_cluster_added, current_cluster); nb_neigh_clusters = 1; - for (igraph_integer_t j = 0; j < degree; j++) { - igraph_integer_t e = VECTOR(*edges)[j]; - igraph_integer_t u = IGRAPH_OTHER(graph, e, v); + for (igraph_int_t j = 0; j < degree; j++) { + igraph_int_t e = VECTOR(*edges)[j]; + igraph_int_t u = IGRAPH_OTHER(graph, e, v); if (u != v && VECTOR(*membership)[u] == cluster_subset) { - igraph_integer_t c = VECTOR(*refined_membership)[u]; + igraph_int_t c = VECTOR(*refined_membership)[u]; if (!IGRAPH_BIT_TEST(neighbor_cluster_added, c)) { IGRAPH_BIT_SET(neighbor_cluster_added, c); VECTOR(neighbor_clusters)[nb_neigh_clusters++] = c; @@ -390,10 +444,26 @@ static igraph_error_t igraph_i_community_leiden_mergenodes( best_cluster = current_cluster; max_diff = 0.0; total_cum_trans_diff = 0.0; - for (igraph_integer_t j = 0; j < nb_neigh_clusters; j++) { - igraph_integer_t c = VECTOR(neighbor_clusters)[j]; - if (VECTOR(external_edge_weight_per_cluster_in_subset)[c] >= VECTOR(cluster_weights)[c] * (total_node_weight - VECTOR(cluster_weights)[c]) * resolution_parameter) { - diff = VECTOR(edge_weights_per_cluster)[c] - VECTOR(*node_weights)[v] * VECTOR(cluster_weights)[c] * resolution_parameter; + for (igraph_int_t j = 0; j < nb_neigh_clusters; j++) { + igraph_int_t c = VECTOR(neighbor_clusters)[j]; + + if (directed) { + vertex_weight_prod = + VECTOR(cluster_out_weights)[c] * (total_vertex_in_weight - VECTOR(cluster_in_weights)[c]) + + VECTOR(cluster_in_weights)[c] * (total_vertex_out_weight - VECTOR(cluster_out_weights)[c]); + } else { + vertex_weight_prod = VECTOR(cluster_out_weights)[c] * (total_vertex_out_weight - VECTOR(cluster_out_weights)[c]); + } + + if (VECTOR(external_edge_weight_per_cluster_in_subset)[c] >= vertex_weight_prod * resolution) { + diff = VECTOR(edge_weights_per_cluster)[c]; + if (directed) { + diff -= (VECTOR(*vertex_out_weights)[v] * VECTOR(cluster_in_weights)[c] + + VECTOR(*vertex_in_weights)[v] * VECTOR(cluster_out_weights)[c]) * resolution; + } else { + diff -= VECTOR(*vertex_out_weights)[v] * VECTOR(cluster_out_weights)[c] * resolution; + } + if (diff > max_diff) { best_cluster = c; @@ -412,25 +482,28 @@ static igraph_error_t igraph_i_community_leiden_mergenodes( IGRAPH_BIT_CLEAR(neighbor_cluster_added, c); } - /* Determine the neighboring cluster to which the currently selected node + /* Determine the neighboring cluster to which the currently selected vertex * will be moved. */ if (total_cum_trans_diff < IGRAPH_INFINITY) { igraph_real_t r = RNG_UNIF(0, total_cum_trans_diff); - igraph_integer_t chosen_idx; + igraph_int_t chosen_idx; igraph_vector_binsearch_slice(&cum_trans_diff, r, &chosen_idx, 0, nb_neigh_clusters); chosen_cluster = VECTOR(neighbor_clusters)[chosen_idx]; } else { chosen_cluster = best_cluster; } - /* Move node to randomly chosen cluster */ - VECTOR(cluster_weights)[chosen_cluster] += VECTOR(*node_weights)[v]; - VECTOR(nb_nodes_per_cluster)[chosen_cluster]++; + /* Move vertex to randomly chosen cluster */ + VECTOR(cluster_out_weights)[chosen_cluster] += VECTOR(*vertex_out_weights)[v]; + if (directed) { + VECTOR(cluster_in_weights)[chosen_cluster] += VECTOR(*vertex_in_weights)[v]; + } + VECTOR(nb_vertices_per_cluster)[chosen_cluster]++; - for (igraph_integer_t j = 0; j < degree; j++) { - igraph_integer_t e = VECTOR(*edges)[j]; - igraph_integer_t u = IGRAPH_OTHER(graph, e, v); + for (igraph_int_t j = 0; j < degree; j++) { + igraph_int_t e = VECTOR(*edges)[j]; + igraph_int_t u = IGRAPH_OTHER(graph, e, v); if (VECTOR(*membership)[u] == cluster_subset) { if (VECTOR(*refined_membership)[u] == chosen_cluster) { VECTOR(external_edge_weight_per_cluster_in_subset)[chosen_cluster] -= VECTOR(*edge_weights)[e]; @@ -449,20 +522,23 @@ static igraph_error_t igraph_i_community_leiden_mergenodes( } /* end if singleton and may be merged */ } - RNG_END(); - - IGRAPH_CHECK(igraph_i_community_leiden_clean_refined_membership(node_subset, refined_membership, nb_refined_clusters)); + IGRAPH_CHECK(leiden_clean_refined_membership(vertex_subset, refined_membership, nb_refined_clusters)); igraph_vector_destroy(&cum_trans_diff); igraph_vector_int_destroy(&neighbor_clusters); igraph_bitset_destroy(&neighbor_cluster_added); igraph_vector_destroy(&edge_weights_per_cluster); igraph_bitset_destroy(&non_singleton_cluster); - igraph_vector_int_destroy(&node_order); + igraph_vector_int_destroy(&vertex_order); igraph_vector_destroy(&external_edge_weight_per_cluster_in_subset); - igraph_vector_int_destroy(&nb_nodes_per_cluster); - igraph_vector_destroy(&cluster_weights); - IGRAPH_FINALLY_CLEAN(9); + igraph_vector_int_destroy(&nb_vertices_per_cluster); + if (directed) igraph_vector_destroy(&cluster_in_weights); + igraph_vector_destroy(&cluster_out_weights); + if (directed) { + IGRAPH_FINALLY_CLEAN(10); + } else { + IGRAPH_FINALLY_CLEAN(9); + } return IGRAPH_SUCCESS; } @@ -474,58 +550,75 @@ static igraph_error_t igraph_i_community_leiden_mergenodes( * in the membership vector), and that each item in the list of integer vectors * is empty. */ -static igraph_error_t igraph_i_community_get_clusters(const igraph_vector_int_t *membership, igraph_vector_int_list_t *clusters) { - igraph_integer_t n = igraph_vector_int_size(membership); - igraph_vector_int_t *cluster; +static igraph_error_t leiden_get_clusters( + const igraph_vector_int_t *membership, + igraph_vector_int_list_t *clusters) { - for (igraph_integer_t i = 0; i < n; i++) { - /* Get cluster for node i */ - cluster = igraph_vector_int_list_get_ptr(clusters, VECTOR(*membership)[i]); + const igraph_int_t n = igraph_vector_int_size(membership); - /* Add node i to cluster vector */ + for (igraph_int_t i = 0; i < n; i++) { + /* Get cluster for vertex i */ + igraph_vector_int_t *cluster = igraph_vector_int_list_get_ptr(clusters, VECTOR(*membership)[i]); + + /* Add vertex i to cluster vector */ IGRAPH_CHECK(igraph_vector_int_push_back(cluster, i)); } return IGRAPH_SUCCESS; } -/* Aggregate the graph based on the \c refined membership while setting the - * membership of each aggregated node according to the \c membership. +/* Aggregate the graph based on the \p refined membership while setting the + * membership of each aggregated vertex according to the \p membership. * * Technically speaking we have that - * aggregated_membership[refined_membership[v]] = membership[v] for each node v. + * aggregated_membership[refined_membership[v]] = membership[v] for each vertex v. * - * The new aggregated graph is returned in \c aggregated_graph. This graph - * object should not yet be initialized, `igraph_create` is called on it, and + * The new aggregated graph is returned in \p aggregated_graph. This graph + * object should not yet be initialized, igraph_create() is called on it, and * responsibility for destroying the object lies with the calling method * - * The remaining results, aggregated_edge_weights, aggregate_node_weights and + * The remaining results, aggregated_edge_weights, aggregate_vertex_weights and * aggregated_membership are all expected to be initialized. * */ -static igraph_error_t igraph_i_community_leiden_aggregate( - const igraph_t *graph, const igraph_inclist_t *edges_per_node, const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights, - const igraph_vector_int_t *membership, const igraph_vector_int_t *refined_membership, const igraph_integer_t nb_refined_clusters, - igraph_t *aggregated_graph, igraph_vector_t *aggregated_edge_weights, igraph_vector_t *aggregated_node_weights, igraph_vector_int_t *aggregated_membership) { +static igraph_error_t leiden_aggregate( + const igraph_t *graph, + const igraph_inclist_t *edges_per_vertex, + const igraph_vector_t *edge_weights, + const igraph_vector_t *vertex_out_weights, + const igraph_vector_t *vertex_in_weights, + const igraph_vector_int_t *membership, + const igraph_vector_int_t *refined_membership, + const igraph_int_t nb_refined_clusters, + igraph_t *aggregated_graph, + igraph_vector_t *aggregated_edge_weights, + igraph_vector_t *aggregated_vertex_out_weights, + igraph_vector_t *aggregated_vertex_in_weights, + igraph_vector_int_t *aggregated_membership) { + + const igraph_bool_t directed = (vertex_in_weights != NULL); igraph_vector_int_t aggregated_edges; igraph_vector_t edge_weight_to_cluster; igraph_vector_int_list_t refined_clusters; igraph_vector_int_t *incident_edges; igraph_vector_int_t neighbor_clusters; igraph_bitset_t neighbor_cluster_added; - igraph_integer_t c, degree, nb_neigh_clusters; + igraph_int_t c, degree, nb_neigh_clusters; /* Get refined clusters */ IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(&refined_clusters, nb_refined_clusters); - IGRAPH_CHECK(igraph_i_community_get_clusters(refined_membership, &refined_clusters)); + IGRAPH_CHECK(leiden_get_clusters(refined_membership, &refined_clusters)); /* Initialize new edges */ IGRAPH_VECTOR_INT_INIT_FINALLY(&aggregated_edges, 0); /* We clear the aggregated edge weights, we will push each new edge weight */ igraph_vector_clear(aggregated_edge_weights); - /* Simply resize the aggregated node weights and membership, they can be set directly */ - IGRAPH_CHECK(igraph_vector_resize(aggregated_node_weights, nb_refined_clusters)); + /* Simply resize the aggregated vertex weights and membership, they can be set directly */ + IGRAPH_CHECK(igraph_vector_resize(aggregated_vertex_out_weights, nb_refined_clusters)); + if (directed) { + IGRAPH_CHECK(igraph_vector_resize(aggregated_vertex_in_weights, nb_refined_clusters)); + } IGRAPH_CHECK(igraph_vector_int_resize(aggregated_membership, nb_refined_clusters)); IGRAPH_VECTOR_INIT_FINALLY(&edge_weight_to_cluster, nb_refined_clusters); @@ -537,21 +630,24 @@ static igraph_error_t igraph_i_community_leiden_aggregate( /* Check per cluster */ for (c = 0; c < nb_refined_clusters; c++) { igraph_vector_int_t* refined_cluster = igraph_vector_int_list_get_ptr(&refined_clusters, c); - igraph_integer_t n_c = igraph_vector_int_size(refined_cluster); - igraph_integer_t v = -1; + igraph_int_t n_c = igraph_vector_int_size(refined_cluster); + igraph_int_t v = -1; /* Calculate the total edge weight to other clusters */ - VECTOR(*aggregated_node_weights)[c] = 0.0; + VECTOR(*aggregated_vertex_out_weights)[c] = 0.0; + if (directed) { + VECTOR(*aggregated_vertex_in_weights)[c] = 0.0; + } nb_neigh_clusters = 0; - for (igraph_integer_t i = 0; i < n_c; i++) { + for (igraph_int_t i = 0; i < n_c; i++) { v = VECTOR(*refined_cluster)[i]; - incident_edges = igraph_inclist_get(edges_per_node, v); + incident_edges = igraph_inclist_get(edges_per_vertex, v); degree = igraph_vector_int_size(incident_edges); - for (igraph_integer_t j = 0; j < degree; j++) { - igraph_integer_t e = VECTOR(*incident_edges)[j]; - igraph_integer_t u = IGRAPH_OTHER(graph, e, v); - igraph_integer_t c2 = VECTOR(*refined_membership)[u]; + for (igraph_int_t j = 0; j < degree; j++) { + igraph_int_t e = VECTOR(*incident_edges)[j]; + igraph_int_t u = IGRAPH_OTHER(graph, e, v); + igraph_int_t c2 = VECTOR(*refined_membership)[u]; if (c2 > c) { if (!IGRAPH_BIT_TEST(neighbor_cluster_added, c2)) { @@ -562,12 +658,15 @@ static igraph_error_t igraph_i_community_leiden_aggregate( } } - VECTOR(*aggregated_node_weights)[c] += VECTOR(*node_weights)[v]; + VECTOR(*aggregated_vertex_out_weights)[c] += VECTOR(*vertex_out_weights)[v]; + if (directed) { + VECTOR(*aggregated_vertex_in_weights)[c] += VECTOR(*vertex_in_weights)[v]; + } } /* Add actual edges from this cluster to the other clusters */ - for (igraph_integer_t i = 0; i < nb_neigh_clusters; i++) { - igraph_integer_t c2 = VECTOR(neighbor_clusters)[i]; + for (igraph_int_t i = 0; i < nb_neigh_clusters; i++) { + igraph_int_t c2 = VECTOR(neighbor_clusters)[i]; /* Add edge */ IGRAPH_CHECK(igraph_vector_int_push_back(&aggregated_edges, c)); @@ -592,7 +691,7 @@ static igraph_error_t igraph_i_community_leiden_aggregate( igraph_destroy(aggregated_graph); IGRAPH_CHECK(igraph_create(aggregated_graph, &aggregated_edges, nb_refined_clusters, - IGRAPH_UNDIRECTED)); + directed)); igraph_vector_int_destroy(&aggregated_edges); IGRAPH_FINALLY_CLEAN(1); @@ -604,13 +703,17 @@ static igraph_error_t igraph_i_community_leiden_aggregate( * * The quality is defined as * - * 1 / 2m sum_ij (A_ij - gamma n_i n_j)d(s_i, s_j) + * 1 / 2m sum_ij (A_ij - gamma n_i n_j) d(s_i, s_j) + * + * for undirected graphs and as + * + * 1 / m sum_ij (A_ij - gamma n^out_i n^in_j) d(s_i, s_j) * * where m is the total edge weight, A_ij is the weight of edge (i, j), gamma is - * the so-called resolution parameter, n_i is the node weight of node i, s_i is - * the cluster of node i and d(x, y) = 1 if and only if x = y and 0 otherwise. + * the so-called resolution parameter, n_i is the vertex weight of vertex i, s_i is + * the cluster of vertex i and d(x, y) = 1 if and only if x = y and 0 otherwise. * - * Note that by setting n_i = k_i the degree of node i and dividing gamma by 2m, + * Note that by setting n_i = k_i the degree of vertex i and dividing gamma by 2m, * we effectively optimize modularity. By setting n_i = 1 we optimize the * Constant Potts Model. * @@ -618,113 +721,148 @@ static igraph_error_t igraph_i_community_leiden_aggregate( * * 1 / 2m sum_c (e_c - gamma N_c^2) * - * where e_c = sum_ij A_ij d(s_i, c)d(s_j, c) is (twice) the internal edge - * weight in cluster c and N_c = sum_i n_i d(s_i, c) is the sum of the node - * weights inside cluster c. This is how the quality is calculated in practice. - * + * where e_c = sum_ij A_ij d(s_i, c)d(s_j, c) is the internal edge weight + * in cluster c (or twice this value if undirected) and + * N_c = sum_i n_i d(s_i, c) is the sum of the vertex weights inside cluster c. + * This is how the quality is calculated in practice. */ -static igraph_error_t igraph_i_community_leiden_quality( - const igraph_t *graph, const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights, - const igraph_vector_int_t *membership, const igraph_integer_t nb_comms, const igraph_real_t resolution_parameter, +static igraph_error_t leiden_quality( + const igraph_t *graph, + const igraph_vector_t *edge_weights, + const igraph_vector_t *vertex_out_weights, + const igraph_vector_t *vertex_in_weights, + const igraph_vector_int_t *membership, + const igraph_int_t nb_clusters, + const igraph_real_t resolution, igraph_real_t *quality) { - igraph_vector_t cluster_weights; + + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); + const igraph_bool_t directed = (vertex_in_weights != NULL); + const igraph_real_t directed_multiplier = directed ? 1.0 : 2.0; + igraph_vector_t cluster_out_weights, cluster_in_weights; igraph_real_t total_edge_weight = 0.0; - igraph_eit_t eit; - igraph_integer_t i, c, n = igraph_vcount(graph); *quality = 0.0; - /* Create the edgelist */ - IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), &eit)); - IGRAPH_FINALLY(igraph_eit_destroy, &eit); - - while (!IGRAPH_EIT_END(eit)) { - igraph_integer_t e = IGRAPH_EIT_GET(eit); - igraph_integer_t from = IGRAPH_FROM(graph, e), to = IGRAPH_TO(graph, e); + for (igraph_int_t e=0; e < ecount; e++) { + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); total_edge_weight += VECTOR(*edge_weights)[e]; - /* We add the internal edge weights */ + + /* We add the internal edge weights. */ if (VECTOR(*membership)[from] == VECTOR(*membership)[to]) { - *quality += 2 * VECTOR(*edge_weights)[e]; + *quality += directed_multiplier * VECTOR(*edge_weights)[e]; } - IGRAPH_EIT_NEXT(eit); } - igraph_eit_destroy(&eit); - IGRAPH_FINALLY_CLEAN(1); - /* Initialize cluster weights and nb nodes */ - IGRAPH_VECTOR_INIT_FINALLY(&cluster_weights, n); - for (i = 0; i < n; i++) { - c = VECTOR(*membership)[i]; - VECTOR(cluster_weights)[c] += VECTOR(*node_weights)[i]; + /* Initialize and compute cluster weights. */ + + IGRAPH_VECTOR_INIT_FINALLY(&cluster_out_weights, vcount); + if (directed) { + IGRAPH_VECTOR_INIT_FINALLY(&cluster_in_weights, vcount); } - /* We subtract gamma * N_c^2 */ - for (c = 0; c < nb_comms; c++) { - *quality -= resolution_parameter * VECTOR(cluster_weights)[c] * VECTOR(cluster_weights)[c]; + for (igraph_int_t i = 0; i < vcount; i++) { + igraph_int_t c = VECTOR(*membership)[i]; + VECTOR(cluster_out_weights)[c] += VECTOR(*vertex_out_weights)[i]; + if (directed) { + VECTOR(cluster_in_weights)[c] += VECTOR(*vertex_in_weights)[i]; + } + } + + /* We subtract gamma * N^out_c * N^in_c */ + + for (igraph_int_t c = 0; c < nb_clusters; c++) { + if (directed) { + *quality -= resolution * VECTOR(cluster_out_weights)[c] * VECTOR(cluster_in_weights)[c]; + } else { + *quality -= resolution * VECTOR(cluster_out_weights)[c] * VECTOR(cluster_out_weights)[c]; + } } - igraph_vector_destroy(&cluster_weights); + if (directed) { + igraph_vector_destroy(&cluster_in_weights); + IGRAPH_FINALLY_CLEAN(1); + } + igraph_vector_destroy(&cluster_out_weights); IGRAPH_FINALLY_CLEAN(1); - /* We normalise by 2m */ - *quality /= (2.0 * total_edge_weight); + /* We normalise by m or 2m depending on directedness */ + *quality /= (directed_multiplier * total_edge_weight); return IGRAPH_SUCCESS; } /* This is the core of the Leiden algorithm and relies on subroutines to - * perform the three different phases: (1) local moving of nodes, (2) + * perform the three different phases: (1) local moving of vertices, (2) * refinement of the partition and (3) aggregation of the network based on the * refined partition, using the non-refined partition to create an initial * partition for the aggregate network. */ -static igraph_error_t igraph_i_community_leiden( +static igraph_error_t community_leiden( const igraph_t *graph, - igraph_vector_t *edge_weights, igraph_vector_t *node_weights, - const igraph_real_t resolution_parameter, const igraph_real_t beta, - igraph_vector_int_t *membership, igraph_integer_t *nb_clusters, igraph_real_t *quality, + igraph_vector_t *edge_weights, + igraph_vector_t *vertex_out_weights, + igraph_vector_t *vertex_in_weights, + igraph_real_t resolution, + igraph_real_t beta, + igraph_vector_int_t *membership, + igraph_int_t *nb_clusters, + igraph_real_t *quality, igraph_bool_t *changed) { - igraph_integer_t nb_refined_clusters; - igraph_integer_t i, c, n = igraph_vcount(graph); + + const igraph_int_t n = igraph_vcount(graph); + const igraph_bool_t directed = (vertex_in_weights != NULL); + igraph_int_t nb_refined_clusters; + igraph_int_t i, c; igraph_t aggregated_graph, *i_graph; - igraph_vector_t aggregated_edge_weights, aggregated_node_weights; + igraph_vector_t aggregated_edge_weights; + igraph_vector_t aggregated_vertex_out_weights, aggregated_vertex_in_weights; igraph_vector_int_t aggregated_membership; - igraph_vector_t *i_edge_weights, *i_node_weights; + igraph_vector_t *i_edge_weights; + igraph_vector_t *i_vertex_out_weights, *i_vertex_in_weights; igraph_vector_int_t *i_membership; - igraph_vector_t tmp_edge_weights, tmp_node_weights; + igraph_vector_t tmp_edge_weights, tmp_vertex_out_weights, tmp_vertex_in_weights; igraph_vector_int_t tmp_membership; igraph_vector_int_t refined_membership; - igraph_vector_int_t aggregate_node; + igraph_vector_int_t aggregate_vertex; igraph_vector_int_list_t clusters; - igraph_inclist_t edges_per_node; + igraph_inclist_t edges_per_vertex; igraph_bool_t continue_clustering; - igraph_integer_t level = 0; + igraph_int_t level = 0; /* Initialize temporary weights and membership to be used in aggregation */ IGRAPH_VECTOR_INIT_FINALLY(&tmp_edge_weights, 0); - IGRAPH_VECTOR_INIT_FINALLY(&tmp_node_weights, 0); + IGRAPH_VECTOR_INIT_FINALLY(&tmp_vertex_out_weights, 0); + if (directed) { + IGRAPH_VECTOR_INIT_FINALLY(&tmp_vertex_in_weights, 0); + } IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp_membership, 0); /* Initialize clusters */ IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(&clusters, n); - /* Initialize aggregate nodes, which initially is identical to simply the - * nodes in the graph. */ - IGRAPH_CHECK(igraph_vector_int_init_range(&aggregate_node, 0, n)); - IGRAPH_FINALLY(igraph_vector_int_destroy, &aggregate_node); + /* Initialize aggregate vertices, which initially is identical to simply the + * vertices in the graph. */ + IGRAPH_CHECK(igraph_vector_int_init_range(&aggregate_vertex, 0, n)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &aggregate_vertex); /* Initialize refined membership */ IGRAPH_VECTOR_INT_INIT_FINALLY(&refined_membership, 0); /* Initialize aggregated graph */ - IGRAPH_CHECK(igraph_empty(&aggregated_graph, 0, IGRAPH_UNDIRECTED)); + IGRAPH_CHECK(igraph_empty(&aggregated_graph, 0, directed)); IGRAPH_FINALLY(igraph_destroy, &aggregated_graph); /* Initialize aggregated edge weights */ IGRAPH_VECTOR_INIT_FINALLY(&aggregated_edge_weights, 0); - /* Initialize aggregated node weights */ - IGRAPH_VECTOR_INIT_FINALLY(&aggregated_node_weights, 0); + /* Initialize aggregated vertex weights */ + IGRAPH_VECTOR_INIT_FINALLY(&aggregated_vertex_out_weights, 0); + if (directed) { + IGRAPH_VECTOR_INIT_FINALLY(&aggregated_vertex_in_weights, 0); + } /* Initialize aggregated membership */ IGRAPH_VECTOR_INT_INIT_FINALLY(&aggregated_membership, 0); @@ -732,36 +870,33 @@ static igraph_error_t igraph_i_community_leiden( /* Set actual graph, weights and membership to be used. */ i_graph = (igraph_t*)graph; i_edge_weights = edge_weights; - i_node_weights = node_weights; + i_vertex_out_weights = vertex_out_weights; + i_vertex_in_weights = directed ? vertex_in_weights : NULL; i_membership = membership; - /* Clean membership and count number of *clusters */ - + /* Clean membership: ensure that cluster indices are 0 <= c < n. */ IGRAPH_CHECK(igraph_reindex_membership(i_membership, NULL, nb_clusters)); - if (*nb_clusters > n) { - IGRAPH_ERROR("Too many communities in membership vector.", IGRAPH_EINVAL); - } - - /* We start out with no changes, whenever a node is moved, this will be set to true. */ + /* We start out with no changes, whenever a vertex is moved, this will be set to true. */ *changed = false; do { /* Get incidence list for fast iteration */ - IGRAPH_CHECK(igraph_inclist_init( i_graph, &edges_per_node, IGRAPH_ALL, IGRAPH_LOOPS_TWICE)); - IGRAPH_FINALLY(igraph_inclist_destroy, &edges_per_node); - - /* Move around the nodes in order to increase the quality */ - IGRAPH_CHECK(igraph_i_community_leiden_fastmovenodes(i_graph, - &edges_per_node, - i_edge_weights, i_node_weights, - resolution_parameter, - nb_clusters, - i_membership, - changed)); + IGRAPH_CHECK(igraph_inclist_init( i_graph, &edges_per_vertex, IGRAPH_ALL, IGRAPH_LOOPS_TWICE)); + IGRAPH_FINALLY(igraph_inclist_destroy, &edges_per_vertex); + + /* Move around the vertices in order to increase the quality */ + IGRAPH_CHECK(leiden_fastmove_vertices(i_graph, + &edges_per_vertex, + i_edge_weights, + i_vertex_out_weights, i_vertex_in_weights, + resolution, + nb_clusters, + i_membership, + changed)); /* We only continue clustering if not all clusters are represented by a - * single node yet + * single vertex yet */ continue_clustering = (*nb_clusters < igraph_vcount(i_graph)); @@ -769,13 +904,13 @@ static igraph_error_t igraph_i_community_leiden( /* Set original membership */ if (level > 0) { for (i = 0; i < n; i++) { - igraph_integer_t v_aggregate = VECTOR(aggregate_node)[i]; + igraph_int_t v_aggregate = VECTOR(aggregate_vertex)[i]; VECTOR(*membership)[i] = VECTOR(*i_membership)[v_aggregate]; } } - /* Get node sets for each cluster. */ - IGRAPH_CHECK(igraph_i_community_get_clusters(i_membership, &clusters)); + /* Get vertex sets for each cluster. */ + IGRAPH_CHECK(leiden_get_clusters(i_membership, &clusters)); /* Ensure refined membership is correct size */ IGRAPH_CHECK(igraph_vector_int_resize(&refined_membership, igraph_vcount(i_graph))); @@ -784,12 +919,13 @@ static igraph_error_t igraph_i_community_leiden( nb_refined_clusters = 0; for (c = 0; c < *nb_clusters; c++) { igraph_vector_int_t* cluster = igraph_vector_int_list_get_ptr(&clusters, c); - IGRAPH_CHECK(igraph_i_community_leiden_mergenodes(i_graph, - &edges_per_node, - i_edge_weights, i_node_weights, - cluster, i_membership, c, - resolution_parameter, beta, - &nb_refined_clusters, &refined_membership)); + IGRAPH_CHECK(leiden_merge_vertices(i_graph, + &edges_per_vertex, + i_edge_weights, + i_vertex_out_weights, i_vertex_in_weights, + cluster, i_membership, c, + resolution, beta, + &nb_refined_clusters, &refined_membership)); /* Empty cluster */ igraph_vector_int_clear(cluster); } @@ -801,20 +937,26 @@ static igraph_error_t igraph_i_community_leiden( nb_refined_clusters = *nb_clusters; } - /* Keep track of aggregate node. */ + /* Keep track of aggregate vertex. */ for (i = 0; i < n; i++) { - /* Current aggregate node */ - igraph_integer_t v_aggregate = VECTOR(aggregate_node)[i]; - /* New aggregate node */ - VECTOR(aggregate_node)[i] = VECTOR(refined_membership)[v_aggregate]; + /* Current aggregate vertex */ + igraph_int_t v_aggregate = VECTOR(aggregate_vertex)[i]; + /* New aggregate vertex */ + VECTOR(aggregate_vertex)[i] = VECTOR(refined_membership)[v_aggregate]; } - IGRAPH_CHECK(igraph_i_community_leiden_aggregate( - i_graph, &edges_per_node, i_edge_weights, i_node_weights, - i_membership, &refined_membership, nb_refined_clusters, - &aggregated_graph, &tmp_edge_weights, &tmp_node_weights, &tmp_membership)); - - /* On the lowest level, the actual graph and node and edge weights and + IGRAPH_CHECK(leiden_aggregate( + i_graph, + &edges_per_vertex, + i_edge_weights, + i_vertex_out_weights, i_vertex_in_weights, + i_membership, &refined_membership, nb_refined_clusters, + &aggregated_graph, + &tmp_edge_weights, + &tmp_vertex_out_weights, directed ? &tmp_vertex_in_weights : NULL, + &tmp_membership)); + + /* On the lowest level, the actual graph and vertex and edge weights and * membership are used. On higher levels, we will use the aggregated graph * and associated vectors. */ @@ -822,42 +964,58 @@ static igraph_error_t igraph_i_community_leiden( /* Set actual graph, weights and membership to be used. */ i_graph = &aggregated_graph; i_edge_weights = &aggregated_edge_weights; - i_node_weights = &aggregated_node_weights; + i_vertex_out_weights = &aggregated_vertex_out_weights; + if (directed) { + i_vertex_in_weights = &aggregated_vertex_in_weights; + } i_membership = &aggregated_membership; } /* Update the aggregated administration. */ IGRAPH_CHECK(igraph_vector_update(i_edge_weights, &tmp_edge_weights)); - IGRAPH_CHECK(igraph_vector_update(i_node_weights, &tmp_node_weights)); + IGRAPH_CHECK(igraph_vector_update(i_vertex_out_weights, &tmp_vertex_out_weights)); + if (directed) { + IGRAPH_CHECK(igraph_vector_update(i_vertex_in_weights, &tmp_vertex_in_weights)); + } IGRAPH_CHECK(igraph_vector_int_update(i_membership, &tmp_membership)); level += 1; } /* We are done iterating, so we destroy the incidence list */ - igraph_inclist_destroy(&edges_per_node); + igraph_inclist_destroy(&edges_per_vertex); IGRAPH_FINALLY_CLEAN(1); } while (continue_clustering); /* Free aggregated graph and associated vectors */ igraph_vector_int_destroy(&aggregated_membership); - igraph_vector_destroy(&aggregated_node_weights); + if (directed) igraph_vector_destroy(&aggregated_vertex_in_weights); + igraph_vector_destroy(&aggregated_vertex_out_weights); igraph_vector_destroy(&aggregated_edge_weights); igraph_destroy(&aggregated_graph); - IGRAPH_FINALLY_CLEAN(4); /* Free remaining memory */ igraph_vector_int_destroy(&refined_membership); - igraph_vector_int_destroy(&aggregate_node); + igraph_vector_int_destroy(&aggregate_vertex); igraph_vector_int_list_destroy(&clusters); igraph_vector_int_destroy(&tmp_membership); - igraph_vector_destroy(&tmp_node_weights); + igraph_vector_destroy(&tmp_vertex_out_weights); + if (directed) igraph_vector_destroy(&tmp_vertex_in_weights); igraph_vector_destroy(&tmp_edge_weights); - IGRAPH_FINALLY_CLEAN(6); + + if (directed) { + IGRAPH_FINALLY_CLEAN(12); + } else { + IGRAPH_FINALLY_CLEAN(10); + } /* Calculate quality */ if (quality) { - IGRAPH_CHECK(igraph_i_community_leiden_quality(graph, edge_weights, node_weights, membership, *nb_clusters, resolution_parameter, quality)); + IGRAPH_CHECK(leiden_quality(graph, + edge_weights, vertex_out_weights, vertex_in_weights, + membership, + *nb_clusters, resolution, + quality)); } return IGRAPH_SUCCESS; @@ -875,29 +1033,29 @@ static igraph_error_t igraph_i_community_leiden( * It is similar to the multilevel algorithm, often called the Louvain * algorithm, but it is faster and yields higher quality solutions. It can * optimize both modularity and the Constant Potts Model, which does not suffer - * from the resolution-limit (see Tragg, Van Dooren & Nesterov). + * from the resolution-limit (see Traag, Van Dooren & Nesterov). * * - * The Leiden algorithm consists of three phases: (1) local moving of nodes, (2) + * The Leiden algorithm consists of three phases: (1) local moving of vertices, (2) * refinement of the partition and (3) aggregation of the network based on the * refined partition, using the non-refined partition to create an initial * partition for the aggregate network. In the local move procedure in the - * Leiden algorithm, only nodes whose neighborhood has changed are visited. Only + * Leiden algorithm, only vertices whose neighborhood has changed are visited. Only * moves that strictly improve the quality function are made. The refinement is * done by restarting from a singleton partition within each cluster and * gradually merging the subclusters. When aggregating, a single cluster may - * then be represented by several nodes (which are the subclusters identified in + * then be represented by several vertices (which are the subclusters identified in * the refinement). * * * The Leiden algorithm provides several guarantees. The Leiden algorithm is * typically iterated: the output of one iteration is used as the input for the - * next iteration. At each iteration all clusters are guaranteed to be + * next iteration. At each iteration all clusters are guaranteed to be (weakly) * connected and well-separated. After an iteration in which nothing has - * changed, all nodes and some parts are guaranteed to be locally optimally + * changed, all vertices and some parts are guaranteed to be locally optimally * assigned. Note that even if a single iteration did not result in any change, * it is still possible that a subsequent iteration might find some - * improvement. Each iteration explores different subsets of nodes to consider + * improvement. Each iteration explores different subsets of vertices to consider * for moving from one cluster to another. Finally, asymptotically, all subsets * of all clusters are guaranteed to be locally optimally assigned. For more * details, please see Traag, Waltman & van Eck (2019). @@ -909,15 +1067,29 @@ static igraph_error_t igraph_i_community_leiden( * 1 / 2m sum_ij (A_ij - γ n_i n_j) δ(s_i, s_j) * * - * where m is the total edge weight, A_ij is the weight of edge + * in the undirected case and + * + * + * 1 / m sum_ij (A_ij - γ n^out_i n^in_j) δ(s_i, s_j) + * + * + * in the directed case. + * Here \c m is the total edge weight, A_ij is the weight of edge * (i, j), \c γ is the so-called resolution parameter, n_i - * is the node weight of node \c i, s_i is the cluster of node + * is the vertex weight of vertex \c i (separate out- and in-weights are used + * with directed graphs), s_i is the cluster of vertex * \c i and δ(x, y) = 1 if and only if x = y and 0 - * otherwise. By setting n_i = k_i, the degree of node \c i, and - * dividing \c γ by 2m, we effectively obtain an expression for - * modularity. Hence, the standard modularity will be optimized when you supply - * the degrees as \c node_weights and by supplying as a resolution parameter - * 1/(2m), with \c m the number of edges. + * otherwise. + * + * + * By setting n_i = k_i, the degree of vertex \c i, and + * dividing \c γ by 2m (by \c m in the directed case), we effectively + * obtain an expression for modularity. Hence, the standard modularity will be + * optimized when you supply the degrees (out- and in-degrees with directed graphs) + * as the vertex weights and by supplying as a resolution parameter + * 1/(2m) (1/m with directed graphs). + * Use the \ref igraph_community_leiden_simple() convenience function to + * compute vertex weights automatically for modularity maximization. * * * References: @@ -934,14 +1106,20 @@ static igraph_error_t igraph_i_community_leiden( * Phys. Rev. E 84, 016114 (2011). * https://doi.org/10.1103/PhysRevE.84.016114 * - * \param graph The input graph. It must be an undirected graph. - * \param edge_weights Numeric vector containing edge weights. If \c NULL, every edge - * has equal weight of 1. The weights need not be non-negative. - * \param node_weights Numeric vector containing node weights. If \c NULL, every node - * has equal weight of 1. - * \param resolution_parameter The resolution parameter used, which is - * represented by gamma in the objective function mentioned in the - * documentation. + * \param graph The input graph. + * \param edge_weights Numeric vector containing edge weights. If \c NULL, + * every edge has equal weight of 1. The weights need not be non-negative. + * \param vertex_out_weights Numeric vector containing vertex weights, or vertex + * out-weights for directed graphs. If \c NULL, every vertex has equal + * weight of 1. + * \param vertex_in_weights Numeric vector containing vertex in-weights for + * directed graphs. If set to \c NULL, in-weights are assumed to be the same + * as out-weights, which effectively ignores edge directions. + * Must be \c NULL for undirected graphs. + * \param n_iterations Iterate the core Leiden algorithm the indicated number + * of times. If this is a negative number, it will continue iterating until + * an iteration did not change the clustering. Two iterations are often + * sufficient, thus 2 is a reasonable default. * \param beta The randomness used in the refinement step when merging. A small * amount of randomness (\c beta = 0.01) typically works well. * \param start Start from membership vector. If this is true, the optimization @@ -955,7 +1133,7 @@ static igraph_error_t igraph_i_community_leiden( * must hence be properly initialized. When finding clusters from scratch it * is typically started using a singleton clustering. This can be achieved * using \ref igraph_vector_int_init_range(). - * \param nb_clusters The number of clusters contained in \c membership. + * \param nb_clusters The number of clusters contained in the final \p membership. * If \c NULL, the number of clusters will not be returned. * \param quality The quality of the partition, in terms of the objective * function as included in the documentation. If \c NULL the quality will @@ -964,16 +1142,30 @@ static igraph_error_t igraph_i_community_leiden( * * Time complexity: near linear on sparse graphs. * + * \sa \ref igraph_community_leiden_simple() for a simplified interface + * that allows specifying an objective function directly and does not require + * vertex weights. + * * \example examples/simple/igraph_community_leiden.c */ -igraph_error_t igraph_community_leiden(const igraph_t *graph, - const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights, - const igraph_real_t resolution_parameter, const igraph_real_t beta, const igraph_bool_t start, - const igraph_integer_t n_iterations, - igraph_vector_int_t *membership, igraph_integer_t *nb_clusters, igraph_real_t *quality) { - igraph_vector_t *i_edge_weights, *i_node_weights; - igraph_integer_t i_nb_clusters; - igraph_integer_t n = igraph_vcount(graph); +igraph_error_t igraph_community_leiden( + const igraph_t *graph, + const igraph_vector_t *edge_weights, + const igraph_vector_t *vertex_out_weights, + const igraph_vector_t *vertex_in_weights, + igraph_real_t resolution, + igraph_real_t beta, + igraph_bool_t start, + igraph_int_t n_iterations, + igraph_vector_int_t *membership, + igraph_int_t *nb_clusters, + igraph_real_t *quality) { + + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); + const igraph_bool_t directed = igraph_is_directed(graph); + igraph_vector_t *i_edge_weights, *i_vertex_out_weights, *i_vertex_in_weights; + igraph_int_t i_nb_clusters; if (!nb_clusters) { nb_clusters = &i_nb_clusters; @@ -984,23 +1176,18 @@ igraph_error_t igraph_community_leiden(const igraph_t *graph, IGRAPH_ERROR("Cannot start optimization if membership is missing.", IGRAPH_EINVAL); } - if (igraph_vector_int_size(membership) != n) { - IGRAPH_ERROR("Initial membership length does not equal the number of vertices.", IGRAPH_EINVAL); + if (igraph_vector_int_size(membership) != vcount) { + IGRAPH_ERROR("Membership vector length does not equal the number of vertices.", IGRAPH_EINVAL); } } else { if (!membership) IGRAPH_ERROR("Membership vector should be supplied and initialized, " "even when not starting optimization from it.", IGRAPH_EINVAL); - IGRAPH_CHECK(igraph_vector_int_range(membership, 0, n)); + IGRAPH_CHECK(igraph_vector_int_range(membership, 0, vcount)); } - - if (igraph_is_directed(graph)) { - IGRAPH_ERROR("Leiden algorithm is only implemented for undirected graphs.", IGRAPH_EINVAL); - } - - /* Check edge weights to possibly use default */ + /* Check edge weights to possibly use default. */ if (!edge_weights) { i_edge_weights = IGRAPH_CALLOC(1, igraph_vector_t); IGRAPH_CHECK_OOM(i_edge_weights, "Leiden algorithm failed, could not allocate memory for edge weights."); @@ -1009,19 +1196,51 @@ igraph_error_t igraph_community_leiden(const igraph_t *graph, IGRAPH_FINALLY(igraph_vector_destroy, i_edge_weights); igraph_vector_fill(i_edge_weights, 1); } else { + if (igraph_vector_size(edge_weights) != ecount) { + IGRAPH_ERRORF("Edge weight vector length (%" IGRAPH_PRId ") does not match number of edges (%" IGRAPH_PRId ").", + IGRAPH_EINVAL, igraph_vector_size(edge_weights), ecount); + } i_edge_weights = (igraph_vector_t*)edge_weights; } - /* Check edge weights to possibly use default */ - if (!node_weights) { - i_node_weights = IGRAPH_CALLOC(1, igraph_vector_t); - IGRAPH_CHECK_OOM(i_node_weights, "Leiden algorithm failed, could not allocate memory for node weights."); - IGRAPH_FINALLY(igraph_free, i_node_weights); - IGRAPH_CHECK(igraph_vector_init(i_node_weights, n)); - IGRAPH_FINALLY(igraph_vector_destroy, i_node_weights); - igraph_vector_fill(i_node_weights, 1); + /* Check vertex out-weights to possibly use default. */ + if (!vertex_out_weights) { + i_vertex_out_weights = IGRAPH_CALLOC(1, igraph_vector_t); + IGRAPH_CHECK_OOM(i_vertex_out_weights, "Leiden algorithm failed, could not allocate memory for vertex weights."); + IGRAPH_FINALLY(igraph_free, i_vertex_out_weights); + IGRAPH_VECTOR_INIT_FINALLY(i_vertex_out_weights, vcount); + igraph_vector_fill(i_vertex_out_weights, 1); + } else { + if (igraph_vector_size(vertex_out_weights) != vcount) { + IGRAPH_ERRORF("Vertex %sweight vector length (%" IGRAPH_PRId ") does not match number of vertices (%" IGRAPH_PRId ").", + IGRAPH_EINVAL, + directed ? "out-" : "", + igraph_vector_size(vertex_out_weights), vcount); + } + i_vertex_out_weights = (igraph_vector_t*)vertex_out_weights; + } + + if (directed) { + /* When in-weights are not given for a directed graph, + * assume that they are the same as the out-weights. + * This effectively ignores edge directions. */ + if (vertex_in_weights) { + if (igraph_vector_size(vertex_in_weights) != vcount) { + IGRAPH_ERRORF("Vertex in-weight vector length (%" IGRAPH_PRId ") does not match number of vertices (%" IGRAPH_PRId ").", + IGRAPH_EINVAL, + igraph_vector_size(vertex_in_weights), vcount); + } + i_vertex_in_weights = (igraph_vector_t*)vertex_in_weights; + } else { + i_vertex_in_weights = i_vertex_out_weights; + } } else { - i_node_weights = (igraph_vector_t*)node_weights; + /* In-weights must be NULL in the undirected case. */ + if (vertex_in_weights) { + IGRAPH_ERROR("Vertex in-weights must not be given for undirected graphs.", IGRAPH_EINVAL); + } else { + i_vertex_in_weights = NULL; + } } /* Perform actual Leiden algorithm iteratively. We either @@ -1029,15 +1248,16 @@ igraph_error_t igraph_community_leiden(const igraph_t *graph, * iterations until the quality remains unchanged. Even if * a single iteration did not change anything, a subsequent * iteration may still find some improvement. This is because - * each iteration explores different subsets of nodes. + * each iteration explores different subsets of vertices. */ igraph_bool_t changed = true; - for (igraph_integer_t itr = 0; + for (igraph_int_t itr = 0; n_iterations < 0 ? changed : itr < n_iterations; itr++) { - IGRAPH_CHECK(igraph_i_community_leiden(graph, i_edge_weights, i_node_weights, - resolution_parameter, beta, - membership, nb_clusters, quality, &changed)); + IGRAPH_CHECK(community_leiden(graph, + i_edge_weights, i_vertex_out_weights, i_vertex_in_weights, + resolution, beta, + membership, nb_clusters, quality, &changed)); } if (!edge_weights) { @@ -1046,11 +1266,238 @@ igraph_error_t igraph_community_leiden(const igraph_t *graph, IGRAPH_FINALLY_CLEAN(2); } - if (!node_weights) { - igraph_vector_destroy(i_node_weights); - IGRAPH_FREE(i_node_weights); + if (!vertex_out_weights) { + igraph_vector_destroy(i_vertex_out_weights); + IGRAPH_FREE(i_vertex_out_weights); IGRAPH_FINALLY_CLEAN(2); } return IGRAPH_SUCCESS; } + +/** + * \function igraph_community_leiden_simple + * \brief Finding community structure using the Leiden algorithm, simple interface. + * + * This is a simplified interface to \ref igraph_community_leiden() for + * convenience purposes. Instead of requiring vertex weights, it allows + * choosing from a set of objective functions to maximize. It implements + * these objective functions by passing suitable vertex weights to + * \ref igraph_community_leiden(), as explained in the documentation of + * that function. + * + * \param graph The input graph. May be directed or undirected. + * \param weights The edge weights. If \c NULL, all weights are assumed to be 1. + * \param objective The objective function to maximize. + * \clist + * \cli IGRAPH_LEIDEN_OBJECTIVE_MODULARITY + * Use the generalized modularity, defined as + * Q = 1/(2m) sum_ij (A_ij - γ k_i k_j / (2m)) δ(c_i, c_j) + * for undirected graphs and as + * Q = 1/m sum_ij (A_ij - γ k^out_i k^in_j / m) δ(c_i, c_j) + * for directed graphs. This effectively uses a multigraph configuration + * model as the null model. Edge weights must not be negative. + * \cli IGRAPH_LEIDEN_OBJECTIVE_CPM + * Use the constant Potts model, whose objective function is defined as + * Q = 1/(2m) sum_ij (A_ij - γ) δ(c_i, c_j) + * for undirected graphs and as + * Q = 1/m sum_ij (A_ij - γ) δ(c_i, c_j) + * for directed graphs. Edge weights are allowed to be negative. + * Edge directions have no impact on the result. + * \cli IGRAPH_LEIDEN_OBJECTIVE_ER + * Use an objective function based on the multigraph Erdős-Rényi G(n,p) + * null model, defined as + * Q = 1/(2m) sum_ij (A_ij - γ p) δ(c_i, c_j) + * for undirected graphs and as + * Q = 1/m sum_ij (A_ij - γ p) δ(c_i, c_j) + * for directed graphs. \c p is the weighted density, i.e. the average + * link strength between all vertex pairs (whether adjacent or not). + * Edge weights must not be negative. Edge directions have no impact on + * the result. + * \endclist + * In the above formulas, \c A is the adjacency matrix, \c m is the total + * edge weight, \c k are the (out- and in-) degrees, \c γ is the resolution + * parameter, and δ(c_i, c_j) is 1 if vertices \c i and \c j + * are in the same community and 0 otherwise. Edge directions are only + * relevant with \c IGRAPH_LEIDEN_OBJECTIVE_MODULARITY. The other two + * objective functions are equivalent between directed and undirected graphs: + * the formal difference is due to each edge being included twice in + * undirected (symmetric) adjacency matrices. + * \param resolution The resolution parameter, which is represented by γ in + * the objective functions detailed above. + * \param beta The randomness used in the refinement step when merging. A small + * amount of randomness (\c beta = 0.01) typically works well. + * \param start Start from membership vector. If this is true, the optimization + * will start from the provided membership vector. If this is false, the + * optimization will start from a singleton partition. + * \param n_iterations Iterate the core Leiden algorithm the indicated number + * of times. If this is a negative number, it will continue iterating until + * an iteration did not change the clustering. Two iterations are often + * sufficient, thus 2 is a reasonable default. + * \param membership The membership vector. If \p start is set to \c false, + * it will be resized appropriately. If \p start is \c true, it must be + * a valid membership vector for the given \p graph. + * \param nb_clusters The number of clusters contained in the final \p membership. + * If \c NULL, the number of clusters will not be returned. + * \param quality The quality of the partition, in terms of the objective + * function selected by \p objective. If \c NULL the quality will + * not be calculated. + * \return Error code. + * + * Time complexity: near linear on sparse graphs. + * + * \sa \ref igraph_community_leiden() for a more flexible interface that + * allows specifying raw vertex weights. + */ +igraph_error_t igraph_community_leiden_simple( + const igraph_t *graph, + const igraph_vector_t *weights, + igraph_leiden_objective_t objective, + igraph_real_t resolution, + igraph_real_t beta, + igraph_bool_t start, + igraph_int_t n_iterations, + igraph_vector_int_t *membership, + igraph_int_t *nb_clusters, + igraph_real_t *quality) { + + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); + const igraph_bool_t directed = igraph_is_directed(graph); + igraph_vector_t vertex_out_weights, vertex_in_weights; + igraph_vector_int_t i_membership, *p_membership; + igraph_real_t min_weight = IGRAPH_INFINITY; + + /* Basic weight vector validation, calculate properties used for validation steps + * specific to different objective functions. */ + if (weights) { + if (igraph_vector_size(weights) != ecount) { + IGRAPH_ERROR("Edge weight vector length does not match number of edges.", IGRAPH_EINVAL); + } + for (igraph_int_t i=0; i < ecount; i++) { + igraph_real_t w = VECTOR(*weights)[i]; + if (w < min_weight) { + min_weight = w; + } + if (! isfinite(w)) { + IGRAPH_ERRORF("Edge weights must not be infinite or NaN, got %g.", + IGRAPH_EINVAL, w); + } + } + } + + IGRAPH_VECTOR_INIT_FINALLY(&vertex_out_weights, vcount); + if (directed) { + IGRAPH_VECTOR_INIT_FINALLY(&vertex_in_weights, vcount); + } + + /* igraph_community_leiden() always requires an initialized membership vector + * of the correct size to be given. We relax this requirement to the case + * when start = true. */ + if (start) { + if (!membership) { + IGRAPH_ERROR("Requesting to start the computation from a specific " + "community assignment, but no membership vector given.", + IGRAPH_EINVAL); + } + if (igraph_vector_int_size(membership) != vcount) { + IGRAPH_ERRORF("Requesting to start the computation from a specific " + "community assignment, but the given membership vector " + "has a different size (%" IGRAPH_PRId " than the vertex " + "count (%" IGRAPH_PRId ").", + IGRAPH_EINVAL, + igraph_vector_int_size(membership), vcount); + } + p_membership = membership; + } else { + if (!membership) { + IGRAPH_VECTOR_INT_INIT_FINALLY(&i_membership, vcount); + p_membership = &i_membership; + } else { + IGRAPH_CHECK(igraph_vector_int_resize(membership, vcount)); + p_membership = membership; + } + } + + switch (objective) { + case IGRAPH_LEIDEN_OBJECTIVE_MODULARITY: + if (min_weight < 0) { + IGRAPH_ERRORF("Edge weights must not be negative for Leiden community " + "detection with modularity objective function, got %g.", + IGRAPH_EINVAL, + min_weight); + } + + IGRAPH_CHECK(igraph_strength( + graph, &vertex_out_weights, + igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS, weights)); + if (directed) { + IGRAPH_CHECK(igraph_strength( + graph, &vertex_in_weights, + igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS, weights)); + } + + /* If directed, the sum of vertex_out_weights is the total edge weight. + * If undirected, it is twice the total edge weight. */ + resolution /= igraph_vector_sum(&vertex_out_weights); + + break; + + case IGRAPH_LEIDEN_OBJECTIVE_CPM: + /* TODO: Potential minor optimization is to use the same vector for both. */ + igraph_vector_fill(&vertex_out_weights, 1); + if (directed) { + igraph_vector_fill(&vertex_in_weights, 1); + } + + break; + + case IGRAPH_LEIDEN_OBJECTIVE_ER: + if (min_weight < 0) { + IGRAPH_ERRORF("Edge weights must not be negative for Leiden community " + "detection with ER objective function, got %g.", + IGRAPH_EINVAL, + min_weight); + } + + /* TODO: Potential minor optimization is to use the same vector for both. */ + igraph_vector_fill(&vertex_out_weights, 1); + if (directed) { + igraph_vector_fill(&vertex_in_weights, 1); + } + + { + igraph_real_t p; + /* Note: Loops must be allowed, as the aggregation step of the + * algorithm effectively creates them. */ + IGRAPH_CHECK(igraph_density(graph, weights, &p, /* loops */ true)); + resolution *= p; + } + + break; + + + default: + IGRAPH_ERROR("Invalid objective function for Leiden community detection.", + IGRAPH_EINVAL); + } + + IGRAPH_CHECK(igraph_community_leiden( + graph, weights, + &vertex_out_weights, directed ? &vertex_in_weights : NULL, + resolution, beta, start, n_iterations, p_membership, nb_clusters, quality)); + + if (!membership) { + igraph_vector_int_destroy(&i_membership); + IGRAPH_FINALLY_CLEAN(1); + } + + if (directed) { + igraph_vector_destroy(&vertex_in_weights); + IGRAPH_FINALLY_CLEAN(1); + } + igraph_vector_destroy(&vertex_out_weights); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} diff --git a/src/vendor/cigraph/src/community/louvain.c b/src/vendor/cigraph/src/community/louvain.c index 72e3035100b..e76c79f98dd 100644 --- a/src/vendor/cigraph/src/community/louvain.c +++ b/src/vendor/cigraph/src/community/louvain.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -34,14 +32,14 @@ /* Structure storing a community */ typedef struct { - igraph_integer_t size; /* Size of the community */ + igraph_int_t size; /* Size of the community */ igraph_real_t weight_inside; /* Sum of edge weights inside community */ igraph_real_t weight_all; /* Sum of edge weights starting/ending in the community */ } igraph_i_multilevel_community; /* Global community list structure */ typedef struct { - igraph_integer_t communities_no, vertices_no; /* Number of communities, number of vertices */ + igraph_int_t communities_no, vertices_no; /* Number of communities, number of vertices */ igraph_real_t weight_sum; /* Sum of edges weight in the whole graph */ igraph_i_multilevel_community *item; /* List of communities */ igraph_vector_int_t *membership; /* Community IDs */ @@ -55,7 +53,7 @@ static igraph_real_t igraph_i_multilevel_community_modularity( igraph_real_t result = 0.0; igraph_real_t m = communities->weight_sum; - for (igraph_integer_t i = 0; i < communities->vertices_no; i++) { + for (igraph_int_t i = 0; i < communities->vertices_no; i++) { if (communities->item[i].size > 0) { result += (communities->item[i].weight_inside - resolution * communities->item[i].weight_all * communities->item[i].weight_all / m) / m; } @@ -65,13 +63,13 @@ static igraph_real_t igraph_i_multilevel_community_modularity( } typedef struct { - igraph_integer_t from; - igraph_integer_t to; - igraph_integer_t id; + igraph_int_t from; + igraph_int_t to; + igraph_int_t id; } igraph_i_multilevel_link; static int igraph_i_multilevel_link_cmp(const void *a, const void *b) { - igraph_integer_t diff; + igraph_int_t diff; diff = ((igraph_i_multilevel_link*)a)->from - ((igraph_i_multilevel_link*)b)->from; @@ -94,8 +92,8 @@ static int igraph_i_multilevel_link_cmp(const void *a, const void *b) { /* removes multiple edges and returns new edge IDs for each edge in |E|log|E| */ static igraph_error_t igraph_i_multilevel_simplify_multiple(igraph_t *graph, igraph_vector_int_t *eids) { - igraph_integer_t ecount = igraph_ecount(graph); - igraph_integer_t l = -1, last_from = -1, last_to = -1; + igraph_int_t ecount = igraph_ecount(graph); + igraph_int_t l = -1, last_from = -1, last_to = -1; igraph_bool_t directed = igraph_is_directed(graph); igraph_vector_int_t edges; igraph_i_multilevel_link *links; @@ -107,7 +105,7 @@ static igraph_error_t igraph_i_multilevel_simplify_multiple(igraph_t *graph, igr IGRAPH_CHECK_OOM(links, "Multi-level community structure detection failed."); IGRAPH_FINALLY(igraph_free, links); - for (igraph_integer_t i = 0; i < ecount; i++) { + for (igraph_int_t i = 0; i < ecount; i++) { links[i].from = IGRAPH_FROM(graph, i); links[i].to = IGRAPH_TO(graph, i); links[i].id = i; @@ -117,7 +115,7 @@ static igraph_error_t igraph_i_multilevel_simplify_multiple(igraph_t *graph, igr igraph_i_multilevel_link_cmp); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - for (igraph_integer_t i = 0; i < ecount; i++) { + for (igraph_int_t i = 0; i < ecount; i++) { if (links[i].from == last_from && links[i].to == last_to) { VECTOR(*eids)[links[i].id] = l; continue; @@ -126,8 +124,8 @@ static igraph_error_t igraph_i_multilevel_simplify_multiple(igraph_t *graph, igr last_from = links[i].from; last_to = links[i].to; - igraph_vector_int_push_back(&edges, last_from); - igraph_vector_int_push_back(&edges, last_to); + IGRAPH_CHECK(igraph_vector_int_push_back(&edges, last_from)); + IGRAPH_CHECK(igraph_vector_int_push_back(&edges, last_to)); l++; @@ -147,12 +145,12 @@ static igraph_error_t igraph_i_multilevel_simplify_multiple(igraph_t *graph, igr } typedef struct { - igraph_integer_t community; + igraph_int_t community; igraph_real_t weight; } igraph_i_multilevel_community_link; static int igraph_i_multilevel_community_link_cmp(const void *a, const void *b) { - igraph_integer_t diff = ( + igraph_int_t diff = ( ((igraph_i_multilevel_community_link*)a)->community - ((igraph_i_multilevel_community_link*)b)->community ); @@ -175,14 +173,14 @@ static int igraph_i_multilevel_community_link_cmp(const void *a, const void *b) static igraph_error_t igraph_i_multilevel_community_links( const igraph_t *graph, const igraph_i_multilevel_community_list *communities, - igraph_integer_t vertex, igraph_vector_int_t *edges, + igraph_int_t vertex, igraph_vector_int_t *edges, igraph_real_t *weight_all, igraph_real_t *weight_inside, igraph_real_t *weight_loop, igraph_vector_int_t *links_community, igraph_vector_t *links_weight) { - igraph_integer_t n, last = -1, c = -1; + igraph_int_t n, last = -1, c = -1; igraph_real_t weight = 1; - igraph_integer_t to, to_community; - igraph_integer_t community = VECTOR(*(communities->membership))[vertex]; + igraph_int_t to, to_community; + igraph_int_t community = VECTOR(*(communities->membership))[vertex]; igraph_i_multilevel_community_link *links; *weight_all = *weight_inside = *weight_loop = 0; @@ -191,15 +189,15 @@ static igraph_error_t igraph_i_multilevel_community_links( igraph_vector_clear(links_weight); /* Get the list of incident edges */ - IGRAPH_CHECK(igraph_incident(graph, edges, vertex, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(graph, edges, vertex, IGRAPH_ALL, IGRAPH_LOOPS)); n = igraph_vector_int_size(edges); links = IGRAPH_CALLOC(n, igraph_i_multilevel_community_link); IGRAPH_CHECK_OOM(links, "Multi-level community structure detection failed."); IGRAPH_FINALLY(igraph_free, links); - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t eidx = VECTOR(*edges)[i]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t eidx = VECTOR(*edges)[i]; weight = VECTOR(*communities->weights)[eidx]; to = IGRAPH_OTHER(graph, eidx, vertex); @@ -227,7 +225,7 @@ static igraph_error_t igraph_i_multilevel_community_links( /* Sort links by community ID and merge the same */ igraph_qsort((void*)links, (size_t) n, sizeof(igraph_i_multilevel_community_link), igraph_i_multilevel_community_link_cmp); - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { to_community = links[i].community; if (to_community != last) { IGRAPH_CHECK(igraph_vector_int_push_back(links_community, to_community)); @@ -247,7 +245,7 @@ static igraph_error_t igraph_i_multilevel_community_links( static igraph_real_t igraph_i_multilevel_community_modularity_gain( const igraph_i_multilevel_community_list *communities, - igraph_integer_t community, igraph_integer_t vertex, + igraph_int_t community, igraph_int_t vertex, igraph_real_t weight_all, igraph_real_t weight_inside, const igraph_real_t resolution) { IGRAPH_UNUSED(vertex); @@ -263,8 +261,8 @@ static igraph_real_t igraph_i_multilevel_community_modularity_gain( * igraph_membership_reindex call */ static igraph_error_t igraph_i_multilevel_shrink(igraph_t *graph, igraph_vector_int_t *membership) { igraph_vector_int_t edges; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t directed = igraph_is_directed(graph); IGRAPH_ASSERT(igraph_vector_int_size(membership) == no_of_nodes); @@ -279,7 +277,7 @@ static igraph_error_t igraph_i_multilevel_shrink(igraph_t *graph, igraph_vector_ /* Create the new edgelist */ IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, /* bycol= */ false)); - for (igraph_integer_t i=0; i < 2*no_of_edges; i++) { + for (igraph_int_t i=0; i < 2*no_of_edges; i++) { VECTOR(edges)[i] = VECTOR(*membership)[ VECTOR(edges)[i] ]; } @@ -328,8 +326,8 @@ static igraph_error_t igraph_i_community_multilevel_step( igraph_real_t *modularity, const igraph_real_t resolution) { - igraph_integer_t vcount = igraph_vcount(graph); - igraph_integer_t ecount = igraph_ecount(graph); + igraph_int_t vcount = igraph_vcount(graph); + igraph_int_t ecount = igraph_ecount(graph); igraph_real_t q, pass_q; /* int pass; // used only for debugging */ igraph_bool_t changed; @@ -362,7 +360,7 @@ static igraph_error_t igraph_i_community_multilevel_step( IGRAPH_FINALLY(igraph_free, communities.item); /* Still initializing the communities data structure */ - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { VECTOR(*communities.membership)[i] = i; communities.item[i].size = 1; communities.item[i].weight_inside = 0; @@ -370,8 +368,8 @@ static igraph_error_t igraph_i_community_multilevel_step( } /* Some more initialization :) */ - for (igraph_integer_t i = 0; i < ecount; i++) { - igraph_integer_t ffrom = IGRAPH_FROM(graph, i), fto = IGRAPH_TO(graph, i); + for (igraph_int_t i = 0; i < ecount; i++) { + igraph_int_t ffrom = IGRAPH_FROM(graph, i), fto = IGRAPH_TO(graph, i); igraph_real_t weight = 1; weight = VECTOR(*weights)[i]; @@ -385,9 +383,8 @@ static igraph_error_t igraph_i_community_multilevel_step( q = igraph_i_multilevel_community_modularity(&communities, resolution); /* pass = 1; */ - RNG_BEGIN(); do { /* Pass begin */ - igraph_integer_t temp_communities_no = communities.communities_no; + igraph_int_t temp_communities_no = communities.communities_no; pass_q = q; changed = false; @@ -400,21 +397,21 @@ static igraph_error_t igraph_i_community_multilevel_step( * have a measurable performance impact, hence the single inversion. * See https://github.com/igraph/igraph/issues/2650 for details. */ if (vcount > 1) { - igraph_integer_t i1 = RNG_INTEGER(0, vcount-1); - igraph_integer_t i2 = RNG_INTEGER(0, vcount-1); - igraph_integer_t tmp = VECTOR(node_order)[i1]; + igraph_int_t i1 = RNG_INTEGER(0, vcount-1); + igraph_int_t i2 = RNG_INTEGER(0, vcount-1); + igraph_int_t tmp = VECTOR(node_order)[i1]; VECTOR(node_order)[i1] = VECTOR(node_order)[i2]; VECTOR(node_order)[i2] = tmp; } - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { /* Exclude vertex from its current community */ igraph_real_t weight_all = 0; igraph_real_t weight_inside = 0; igraph_real_t weight_loop = 0; igraph_real_t max_q_gain = 0; igraph_real_t max_weight; - igraph_integer_t old_id, new_id, n, ni; + igraph_int_t old_id, new_id, n, ni; ni = VECTOR(node_order)[i]; @@ -443,8 +440,8 @@ static igraph_error_t igraph_i_community_multilevel_step( max_weight = weight_inside; n = igraph_vector_int_size(&links_community); - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t c = VECTOR(links_community)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t c = VECTOR(links_community)[j]; igraph_real_t w = VECTOR(links_weight)[j]; igraph_real_t q_gain = @@ -489,7 +486,6 @@ static igraph_error_t igraph_i_community_multilevel_step( IGRAPH_ALLOW_INTERRUPTION(); } while (changed && (q > pass_q)); /* Pass end */ - RNG_END(); if (modularity) { *modularity = q; @@ -518,7 +514,7 @@ static igraph_error_t igraph_i_community_multilevel_step( IGRAPH_CHECK(igraph_vector_update(&links_weight, weights)); igraph_vector_null(weights); - for (igraph_integer_t i = 0; i < ecount; i++) { + for (igraph_int_t i = 0; i < ecount; i++) { VECTOR(*weights)[VECTOR(edges)[i]] += VECTOR(links_weight)[i]; } @@ -605,9 +601,9 @@ igraph_error_t igraph_community_multilevel(const igraph_t *graph, igraph_vector_int_t m; igraph_vector_int_t level_membership; igraph_real_t prev_q = -1, q = -1; - igraph_integer_t level = 1; - igraph_integer_t vcount = igraph_vcount(graph); - igraph_integer_t ecount = igraph_ecount(graph); + igraph_int_t level = 1; + igraph_int_t vcount = igraph_vcount(graph); + igraph_int_t ecount = igraph_ecount(graph); /* Initial sanity checks on the input parameters */ if (igraph_is_directed(graph)) { @@ -648,7 +644,7 @@ igraph_error_t igraph_community_multilevel(const igraph_t *graph, if (memberships || membership) { /* Put each vertex in its own community */ - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { VECTOR(level_membership)[i] = i; } } @@ -663,7 +659,7 @@ igraph_error_t igraph_community_multilevel(const igraph_t *graph, while (true) { /* Remember the previous modularity and vertex count, do a single step */ - igraph_integer_t step_vcount = igraph_vcount(&g); + igraph_int_t step_vcount = igraph_vcount(&g); prev_q = q; IGRAPH_CHECK(igraph_i_community_multilevel_step(&g, &w, &m, &q, resolution)); @@ -674,7 +670,7 @@ igraph_error_t igraph_community_multilevel(const igraph_t *graph, } if (memberships || membership) { - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { /* Readjust the membership vector */ VECTOR(level_membership)[i] = VECTOR(m)[ VECTOR(level_membership)[i] ]; } @@ -721,7 +717,7 @@ igraph_error_t igraph_community_multilevel(const igraph_t *graph, /* If we need the final membership vector, copy it to the output */ if (membership) { IGRAPH_CHECK(igraph_vector_int_resize(membership, vcount)); - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { VECTOR(*membership)[i] = VECTOR(level_membership)[i]; } } diff --git a/src/vendor/cigraph/src/community/modularity.c b/src/vendor/cigraph/src/community/modularity.c index 5fb03e62cf0..3541a3e3e26 100644 --- a/src/vendor/cigraph/src/community/modularity.c +++ b/src/vendor/cigraph/src/community/modularity.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -122,16 +120,16 @@ igraph_error_t igraph_modularity(const igraph_t *graph, const igraph_bool_t directed, igraph_real_t *modularity) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); const igraph_vector_int_t *p_membership; igraph_vector_int_t i_membership; igraph_bool_t using_i_membership = false; igraph_vector_t k_out, k_in; - igraph_integer_t min_cluster_id, max_cluster_id, no_of_partitions; + igraph_int_t min_cluster_id, max_cluster_id, no_of_partitions; igraph_real_t e; /* count/fraction of edges/weights within partitions */ igraph_real_t m; /* edge count / weight sum */ - igraph_integer_t c1, c2; + igraph_int_t c1, c2; /* Only consider the graph as directed if it actually is directed */ igraph_bool_t use_directed = directed && igraph_is_directed(graph); igraph_real_t directed_multiplier = (use_directed ? 1 : 2); @@ -177,7 +175,7 @@ igraph_error_t igraph_modularity(const igraph_t *graph, IGRAPH_ERROR("Weight vector size differs from number of edges.", IGRAPH_EINVAL); m = 0.0; - for (igraph_integer_t i = 0; i < ecount; i++) { + for (igraph_int_t i = 0; i < ecount; i++) { igraph_real_t w = VECTOR(*weights)[i]; if (w < 0) { IGRAPH_ERROR("Negative weight in weight vector.", IGRAPH_EINVAL); @@ -193,7 +191,7 @@ igraph_error_t igraph_modularity(const igraph_t *graph, } } else { m = ecount; - for (igraph_integer_t i = 0; i < ecount; i++) { + for (igraph_int_t i = 0; i < ecount; i++) { c1 = VECTOR(*p_membership)[ IGRAPH_FROM(graph, i) ]; c2 = VECTOR(*p_membership)[ IGRAPH_TO(graph, i) ]; if (c1 == c2) { @@ -217,7 +215,7 @@ igraph_error_t igraph_modularity(const igraph_t *graph, if (m > 0) { *modularity = e; - for (igraph_integer_t i = 0; i < no_of_partitions; i++) { + for (igraph_int_t i = 0; i < no_of_partitions; i++) { *modularity -= resolution * VECTOR(k_out)[i] * VECTOR(k_in)[i]; } } else { @@ -242,8 +240,8 @@ static igraph_error_t igraph_i_modularity_matrix_get_adjacency( /* Specifically used to handle weights and/or ignore direction */ igraph_eit_t edgeit; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t from, to; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t from, to; IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, no_of_nodes)); igraph_matrix_null(res); @@ -252,7 +250,7 @@ static igraph_error_t igraph_i_modularity_matrix_get_adjacency( if (weights) { for (; !IGRAPH_EIT_END(edgeit); IGRAPH_EIT_NEXT(edgeit)) { - igraph_integer_t edge = IGRAPH_EIT_GET(edgeit); + igraph_int_t edge = IGRAPH_EIT_GET(edgeit); from = IGRAPH_FROM(graph, edge); to = IGRAPH_TO(graph, edge); MATRIX(*res, from, to) += VECTOR(*weights)[edge]; @@ -262,7 +260,7 @@ static igraph_error_t igraph_i_modularity_matrix_get_adjacency( } } else { for (; !IGRAPH_EIT_END(edgeit); IGRAPH_EIT_NEXT(edgeit)) { - igraph_integer_t edge = IGRAPH_EIT_GET(edgeit); + igraph_int_t edge = IGRAPH_EIT_GET(edgeit); from = IGRAPH_FROM(graph, edge); to = IGRAPH_TO(graph, edge); MATRIX(*res, from, to) += 1; @@ -327,8 +325,8 @@ igraph_error_t igraph_modularity_matrix(const igraph_t *graph, igraph_matrix_t *modmat, igraph_bool_t directed) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); const igraph_real_t sw = weights ? igraph_vector_sum(weights) : no_of_edges; igraph_vector_t deg, in_deg, out_deg; igraph_real_t scaling_factor; @@ -366,8 +364,8 @@ igraph_error_t igraph_modularity_matrix(const igraph_t *graph, scaling_factor = resolution / sw; - for (igraph_integer_t j = 0; j < no_of_nodes; j++) { - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t j = 0; j < no_of_nodes; j++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { MATRIX(*modmat, i, j) -= VECTOR(out_deg)[i] * VECTOR(in_deg)[j] * scaling_factor; } } @@ -382,8 +380,8 @@ igraph_error_t igraph_modularity_matrix(const igraph_t *graph, scaling_factor = resolution / 2.0 / sw; - for (igraph_integer_t j = 0; j < no_of_nodes; j++) { - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t j = 0; j < no_of_nodes; j++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { MATRIX(*modmat, i, j) -= VECTOR(deg)[i] * VECTOR(deg)[j] * scaling_factor; } } diff --git a/src/vendor/cigraph/src/community/optimal_modularity.c b/src/vendor/cigraph/src/community/optimal_modularity.c index f91a330a849..23aebf476c9 100644 --- a/src/vendor/cigraph/src/community/optimal_modularity.c +++ b/src/vendor/cigraph/src/community/optimal_modularity.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -58,14 +56,18 @@ * with a couple of hundred vertices might be possible. * * \param graph The input graph. It may be undirected or directed. + * \param weights Vector giving the weights of the edges. If it is + * \c NULL then each edge is supposed to have the same weight. + * \param resolution Resolution parameter. Must be greater than or equal to 0. + * Lower values favor fewer, larger communities; higher values favor more, + * smaller communities. Set it to 1 to use the classical definition of + * modularity. * \param modularity Pointer to a real number, or a null pointer. * If it is not a null pointer, then a optimal modularity value * is returned here. * \param membership Pointer to a vector, or a null pointer. If not a * null pointer, then the membership vector of the optimal * community structure is stored here. - * \param weights Vector giving the weights of the edges. If it is - * \c NULL then each edge is supposed to have the same weight. * \return Error code. * When GLPK is not available, \c IGRAPH_UNIMPLEMENTED is returned. * @@ -78,19 +80,20 @@ */ igraph_error_t igraph_community_optimal_modularity(const igraph_t *graph, - igraph_real_t *modularity, - igraph_vector_int_t *membership, - const igraph_vector_t *weights) { + const igraph_vector_t *weights, + const igraph_real_t resolution, + igraph_real_t *modularity, + igraph_vector_int_t *membership) { #ifndef HAVE_GLPK IGRAPH_ERROR("GLPK is not available.", IGRAPH_UNIMPLEMENTED); #else - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); const igraph_bool_t directed = igraph_is_directed(graph); - igraph_integer_t no_of_variables; - igraph_integer_t i, j, k, l; + igraph_int_t no_of_variables; + igraph_int_t i, j, k, l; int st; int idx[] = { 0, 0, 0, 0 }; double coef[] = { 0.0, 1.0, 1.0, -2.0 }; @@ -101,6 +104,10 @@ igraph_error_t igraph_community_optimal_modularity(const igraph_t *graph, glp_prob *ip; glp_iocp parm; + if (resolution < 0.0) { + IGRAPH_ERRORF("Resolution must be positive, got %g.", IGRAPH_EINVAL, resolution); + } + if (weights) { if (igraph_vector_size(weights) != no_of_edges) { IGRAPH_ERROR("Weight vector length must agree with number of edges.", IGRAPH_EINVAL); @@ -132,7 +139,7 @@ igraph_error_t igraph_community_optimal_modularity(const igraph_t *graph, igraph_vector_int_null(pmembership); if (modularity) { - IGRAPH_CHECK(igraph_modularity(graph, pmembership, NULL, 1, igraph_is_directed(graph), modularity)); + IGRAPH_CHECK(igraph_modularity(graph, pmembership, NULL, resolution, igraph_is_directed(graph), modularity)); } if (! membership) { @@ -237,10 +244,12 @@ igraph_error_t igraph_community_optimal_modularity(const igraph_t *graph, for (j = i + 1; j < no_of_nodes; j++) { c = -VECTOR(indegree)[i] * VECTOR(outdegree)[j] / total_weight \ -VECTOR(outdegree)[i] * VECTOR(indegree)[j] / total_weight; + c *= resolution; glp_set_obj_coef(ip, st + IDX(i, j), c); } /* special case for (i,i) */ c = -VECTOR(indegree)[i] * VECTOR(outdegree)[i] / total_weight; + c *= resolution; glp_set_obj_coef(ip, st + IDX(i, i), c); } @@ -274,7 +283,7 @@ igraph_error_t igraph_community_optimal_modularity(const igraph_t *graph, } if (membership) { - igraph_integer_t comm = 0; /* id of the last community that was found */ + igraph_int_t comm = 0; /* id of the last community that was found */ IGRAPH_CHECK(igraph_vector_int_resize(membership, no_of_nodes)); for (i = 0; i < no_of_nodes; i++) { diff --git a/src/vendor/cigraph/src/community/spinglass/NetDataTypes.cpp b/src/vendor/cigraph/src/community/spinglass/NetDataTypes.cpp index fecfacd670f..5f83300ba2f 100644 --- a/src/vendor/cigraph/src/community/spinglass/NetDataTypes.cpp +++ b/src/vendor/cigraph/src/community/spinglass/NetDataTypes.cpp @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -83,7 +82,7 @@ NLink *NNode::Get_LinkToNeighbour(const NNode* neighbour) { } } -igraph_integer_t NNode::Disconnect_From(NNode* neighbour) { +igraph_int_t NNode::Disconnect_From(NNode* neighbour) { //sollen doppelte Links erlaubt sein?? s.o. neighbours.fDelete(neighbour); n_links.fDelete(Get_LinkToNeighbour(neighbour)); @@ -92,8 +91,8 @@ igraph_integer_t NNode::Disconnect_From(NNode* neighbour) { return 1; } -igraph_integer_t NNode::Disconnect_From_All() { - igraph_integer_t number_of_neighbours = 0; +igraph_int_t NNode::Disconnect_From_All() { + igraph_int_t number_of_neighbours = 0; while (neighbours.Size()) { Disconnect_From(neighbours.Pop()); number_of_neighbours++; diff --git a/src/vendor/cigraph/src/community/spinglass/NetDataTypes.h b/src/vendor/cigraph/src/community/spinglass/NetDataTypes.h index 0e8dbef6364..aa9432f894e 100644 --- a/src/vendor/cigraph/src/community/spinglass/NetDataTypes.h +++ b/src/vendor/cigraph/src/community/spinglass/NetDataTypes.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -57,15 +56,15 @@ struct HUGE_INDEX { unsigned int field_index; - igraph_integer_t in_field_index; + igraph_int_t in_field_index; }; template class HugeArray { - igraph_integer_t size = 2; + igraph_int_t size = 2; unsigned int highest_field_index = 0; - const igraph_integer_t max_bit_left = 1UL << 31; //wir setzen das 31. Bit auf 1 - igraph_integer_t max_index = 0; + const igraph_int_t max_bit_left = 1UL << 31; //wir setzen das 31. Bit auf 1 + igraph_int_t max_index = 0; DATA *data; DATA *fields[32]; public: @@ -73,11 +72,11 @@ class HugeArray { HugeArray(const HugeArray &) = delete; HugeArray & operator = (const HugeArray &) = delete; ~HugeArray(); - HUGE_INDEX get_huge_index(igraph_integer_t) const; - DATA &Set(igraph_integer_t index); - DATA Get(igraph_integer_t index) { return Set(index); } - DATA &operator[](igraph_integer_t index) { return Set(index); } - igraph_integer_t Size() const { return max_index; } + HUGE_INDEX get_huge_index(igraph_int_t) const; + DATA &Set(igraph_int_t index); + DATA Get(igraph_int_t index) { return Set(index); } + DATA &operator[](igraph_int_t index) { return Set(index); } + igraph_int_t Size() const { return max_index; } } ; //############################################################################################### @@ -93,11 +92,11 @@ class DLItem { friend class DLList_Iter; L_DATA item; - igraph_integer_t index; + igraph_int_t index; DLItem *previous; DLItem *next; - DLItem(L_DATA i, igraph_integer_t ind); - DLItem(L_DATA i, igraph_integer_t ind, DLItem *p, DLItem *n); + DLItem(L_DATA i, igraph_int_t ind); + DLItem(L_DATA i, igraph_int_t ind, DLItem *p, DLItem *n); public: void del() { delete item; @@ -110,7 +109,7 @@ class DLList { protected: DLItem *head; DLItem *tail; - igraph_integer_t number_of_items = 0; + igraph_int_t number_of_items = 0; virtual DLItem *pInsert(L_DATA, DLItem*); virtual L_DATA pDelete(DLItem*); public: @@ -118,14 +117,14 @@ class DLList { DLList(const DLList &) = delete; DLList & operator = (const DLList &) = delete; virtual ~DLList(); - igraph_integer_t Size() const { + igraph_int_t Size() const { return number_of_items; } int fDelete(L_DATA); virtual L_DATA Push(L_DATA); virtual L_DATA Pop(); - virtual L_DATA Get(igraph_integer_t); - igraph_integer_t Is_In_List(L_DATA); + virtual L_DATA Get(igraph_int_t); + igraph_int_t Is_In_List(L_DATA); void delete_items(); }; @@ -134,13 +133,13 @@ class DL_Indexed_List : public DLList { DLItem *pInsert(L_DATA, DLItem*) final; L_DATA pDelete(DLItem*) final; HugeArray*> array; - igraph_integer_t last_index = 0; + igraph_int_t last_index = 0; public: DL_Indexed_List() = default; L_DATA Push(L_DATA) final; L_DATA Pop() final; - L_DATA Get(igraph_integer_t) final; + L_DATA Get(igraph_int_t) final; }; //##################################################################################################### @@ -166,9 +165,9 @@ template class DLList_Iter { class NLink; class NNode { - igraph_integer_t index; - igraph_integer_t cluster_index; - igraph_integer_t marker = 0; + igraph_int_t index; + igraph_int_t cluster_index; + igraph_int_t marker = 0; double weight = 0.0; DLList neighbours; //list with pointers to neighbours @@ -176,7 +175,7 @@ class NNode { DLList *global_link_list; char name[SPINGLASS_MAX_NAME_LEN]; public : - NNode(igraph_integer_t ind, igraph_integer_t c_ind, DLList *ll, const char *n) : + NNode(igraph_int_t ind, igraph_int_t c_ind, DLList *ll, const char *n) : index(ind), cluster_index(c_ind), global_link_list(ll) { strcpy(name, n); @@ -185,22 +184,22 @@ public : NNode &operator=(const NNode &) = delete; ~NNode() { Disconnect_From_All(); } - igraph_integer_t Get_Index() const { + igraph_int_t Get_Index() const { return index; } - igraph_integer_t Get_ClusterIndex() const { + igraph_int_t Get_ClusterIndex() const { return cluster_index; } - igraph_integer_t Get_Marker() const { + igraph_int_t Get_Marker() const { return marker; } - void Set_Marker(igraph_integer_t m) { + void Set_Marker(igraph_int_t m) { marker = m; } - void Set_ClusterIndex(igraph_integer_t ci) { + void Set_ClusterIndex(igraph_int_t ci) { cluster_index = ci; } - igraph_integer_t Get_Degree() const { + igraph_int_t Get_Degree() const { return (neighbours.Size()); } const char *Get_Name() { @@ -222,8 +221,8 @@ public : const DLList *Get_Links() const { return &n_links; } - igraph_integer_t Disconnect_From(NNode*); - igraph_integer_t Disconnect_From_All(); + igraph_int_t Disconnect_From(NNode*); + igraph_int_t Disconnect_From_All(); NLink *Get_LinkToNeighbour(const NNode *neighbour); }; @@ -299,10 +298,10 @@ template HugeArray::~HugeArray() { } template -HUGE_INDEX HugeArray::get_huge_index(igraph_integer_t index) const { +HUGE_INDEX HugeArray::get_huge_index(igraph_int_t index) const { HUGE_INDEX h_index; unsigned int shift_index = 0; - igraph_integer_t help_index; + igraph_int_t help_index; help_index = index; if (index < 2) { h_index.field_index = 0; @@ -315,19 +314,19 @@ HUGE_INDEX HugeArray::get_huge_index(igraph_integer_t index) const { shift_index++; } h_index.field_index = 31 - shift_index; // das hoechste besetzte Bit im Index - help_index = igraph_integer_t(1) << h_index.field_index; // in help_index wird das hoechste besetzte Bit von Index gesetzt + help_index = igraph_int_t(1) << h_index.field_index; // in help_index wird das hoechste besetzte Bit von Index gesetzt h_index.in_field_index = (index ^ help_index); // index XOR help_index, womit alle bits unter dem hoechsten erhalten bleiben return h_index; } template -DATA &HugeArray::Set(igraph_integer_t index) { - igraph_integer_t data_size; +DATA &HugeArray::Set(igraph_int_t index) { + igraph_int_t data_size; while (size < index + 1) { highest_field_index++; - data_size = igraph_integer_t(1) << highest_field_index; + data_size = igraph_int_t(1) << highest_field_index; data = new DATA[data_size]; - for (igraph_integer_t i = 0; i < data_size; i++) { + for (igraph_int_t i = 0; i < data_size; i++) { data[i] = 0; } size = size + data_size; //overflow noch abfangen @@ -344,11 +343,11 @@ DATA &HugeArray::Set(igraph_integer_t index) { //############################################################################### template -DLItem::DLItem(L_DATA i, igraph_integer_t ind) : +DLItem::DLItem(L_DATA i, igraph_int_t ind) : item(i), index(ind), previous(nullptr), next(nullptr) { } template -DLItem::DLItem(L_DATA i, igraph_integer_t ind, DLItem *p, DLItem *n) : +DLItem::DLItem(L_DATA i, igraph_int_t ind, DLItem *p, DLItem *n) : item(i), index(ind), previous(p), next(n) { } //###################################################################################################################### @@ -435,7 +434,7 @@ L_DATA DLList::Pop() { template -L_DATA DLList::Get(igraph_integer_t pos) { +L_DATA DLList::Get(igraph_int_t pos) { if ((pos < 1) || (pos > (number_of_items + 1))) { return 0; } @@ -448,9 +447,9 @@ L_DATA DLList::Get(igraph_integer_t pos) { //gibt Index des gesuchte Listenelement zurueck, besser waere eigentlich zeiger template -igraph_integer_t DLList::Is_In_List(L_DATA data) { +igraph_int_t DLList::Is_In_List(L_DATA data) { DLItem *cur = head, *next; - igraph_integer_t pos = 0; + igraph_int_t pos = 0; while (cur) { next = cur->next; if (cur->item == data) { @@ -501,7 +500,7 @@ L_DATA DL_Indexed_List::Pop() { } template -L_DATA DL_Indexed_List::Get(igraph_integer_t pos) { +L_DATA DL_Indexed_List::Get(igraph_int_t pos) { if (pos > this->number_of_items - 1) { return 0; } diff --git a/src/vendor/cigraph/src/community/spinglass/NetRoutines.cpp b/src/vendor/cigraph/src/community/spinglass/NetRoutines.cpp index 67e4298bab8..d25b9969a89 100644 --- a/src/vendor/cigraph/src/community/spinglass/NetRoutines.cpp +++ b/src/vendor/cigraph/src/community/spinglass/NetRoutines.cpp @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -51,20 +50,20 @@ igraph_error_t igraph_i_read_network_spinglass( const igraph_t *graph, const igraph_vector_t *weights, network *net, igraph_bool_t use_weights) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); double sum_weight; - for (igraph_integer_t vid = 0; vid < no_of_nodes; vid++) { + for (igraph_int_t vid = 0; vid < no_of_nodes; vid++) { char name[SPINGLASS_MAX_NAME_LEN]; snprintf(name, sizeof(name) / sizeof(name[0]), "%" IGRAPH_PRId "", vid+1); net->node_list.Push(new NNode(vid, 0, &net->link_list, name)); } sum_weight = 0.0; - for (igraph_integer_t eid = 0; eid < no_of_edges; eid++) { - igraph_integer_t v1 = IGRAPH_FROM(graph, eid); - igraph_integer_t v2 = IGRAPH_TO(graph, eid); + for (igraph_int_t eid = 0; eid < no_of_edges; eid++) { + igraph_int_t v1 = IGRAPH_FROM(graph, eid); + igraph_int_t v2 = IGRAPH_TO(graph, eid); igraph_real_t w = use_weights ? VECTOR(*weights)[eid] : 1.0; NNode *node1 = net->node_list.Get(v1); diff --git a/src/vendor/cigraph/src/community/spinglass/NetRoutines.h b/src/vendor/cigraph/src/community/spinglass/NetRoutines.h index 98fd5fef453..d36f7601bf6 100644 --- a/src/vendor/cigraph/src/community/spinglass/NetRoutines.h +++ b/src/vendor/cigraph/src/community/spinglass/NetRoutines.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/community/spinglass/clustertool.cpp b/src/vendor/cigraph/src/community/spinglass/clustertool.cpp index 5aaccb43e83..37a8a828cc6 100644 --- a/src/vendor/cigraph/src/community/spinglass/clustertool.cpp +++ b/src/vendor/cigraph/src/community/spinglass/clustertool.cpp @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -61,7 +60,7 @@ static igraph_error_t igraph_i_community_spinglass_orig( igraph_real_t *temperature, igraph_vector_int_t *membership, igraph_vector_int_t *csize, - igraph_integer_t spins, + igraph_int_t spins, igraph_bool_t parupdate, igraph_real_t starttemp, igraph_real_t stoptemp, @@ -76,7 +75,7 @@ static igraph_error_t igraph_i_community_spinglass_negative( igraph_real_t *temperature, igraph_vector_int_t *membership, igraph_vector_int_t *csize, - igraph_integer_t spins, + igraph_int_t spins, igraph_bool_t parupdate, igraph_real_t starttemp, igraph_real_t stoptemp, @@ -171,7 +170,7 @@ igraph_error_t igraph_community_spinglass(const igraph_t *graph, igraph_real_t *temperature, igraph_vector_int_t *membership, igraph_vector_int_t *csize, - igraph_integer_t spins, + igraph_int_t spins, igraph_bool_t parupdate, igraph_real_t starttemp, igraph_real_t stoptemp, @@ -212,7 +211,7 @@ static igraph_error_t igraph_i_community_spinglass_orig( igraph_real_t *temperature, igraph_vector_int_t *membership, igraph_vector_int_t *csize, - igraph_integer_t spins, + igraph_int_t spins, igraph_bool_t parupdate, igraph_real_t starttemp, igraph_real_t stoptemp, @@ -220,8 +219,8 @@ static igraph_error_t igraph_i_community_spinglass_orig( igraph_spincomm_update_t update_rule, igraph_real_t gamma) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t changes, runs; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t changes, runs; igraph_bool_t use_weights = false; bool zeroT; double kT, acc, prob; @@ -303,9 +302,6 @@ static igraph_error_t igraph_i_community_spinglass_orig( PottsModel pm(&net, spins, update_rule); - /* initialize the random number generator */ - RNG_BEGIN(); - if ((stoptemp == 0.0) && (starttemp == 0.0)) { zeroT = true; } else { @@ -355,8 +351,6 @@ static igraph_error_t igraph_i_community_spinglass_orig( pm.WriteClusters(modularity, temperature, csize, membership, kT, gamma); - RNG_END(); - return IGRAPH_SUCCESS; } @@ -387,11 +381,12 @@ static igraph_error_t igraph_i_community_spinglass_orig( * cohesion index of the community will be stored here. * \param adhesion Pointer to a real variable, if not \c NULL the * adhesion index of the community will be stored here. - * \param inner_links Pointer to an integer, if not \c NULL the - * number of edges within the community is stored here. - * \param outer_links Pointer to an integer, if not \c NULL the + * \param inner_links Pointer to a real, if not \c NULL the + * number of edges within the community (or the sum of their weights) + * is stored here. + * \param outer_links Pointer to a real, if not \c NULL the * number of edges between the community and the rest of the graph - * will be stored here. + * (or the sum of their weights) will be stored here. * \param spins The number of spins to use, this can be higher than * the actual number of clusters in the network, in which case some * clusters will contain zero vertices. @@ -422,13 +417,13 @@ static igraph_error_t igraph_i_community_spinglass_orig( igraph_error_t igraph_community_spinglass_single(const igraph_t *graph, const igraph_vector_t *weights, - igraph_integer_t vertex, + igraph_int_t vertex, igraph_vector_int_t *community, igraph_real_t *cohesion, igraph_real_t *adhesion, - igraph_integer_t *inner_links, - igraph_integer_t *outer_links, - igraph_integer_t spins, + igraph_real_t *inner_links, + igraph_real_t *outer_links, + igraph_int_t spins, igraph_spincomm_update_t update_rule, igraph_real_t gamma) { IGRAPH_HANDLE_EXCEPTIONS( @@ -472,9 +467,6 @@ igraph_error_t igraph_community_spinglass_single(const igraph_t *graph, PottsModel pm(&net, spins, update_rule); - /* initialize the random number generator */ - RNG_BEGIN(); - /* to be expected, if we want to find the community around a particular node*/ /* the initial conf is needed, because otherwise, the degree of the nodes is not in the weight property, stupid!!! */ @@ -482,8 +474,6 @@ igraph_error_t igraph_community_spinglass_single(const igraph_t *graph, snprintf(startnode, sizeof(startnode) / sizeof(startnode[0]), "%" IGRAPH_PRId "", vertex + 1); pm.FindCommunityFromStart(gamma, startnode, community, cohesion, adhesion, inner_links, outer_links); - - RNG_END(); ); return IGRAPH_SUCCESS; @@ -496,7 +486,7 @@ static igraph_error_t igraph_i_community_spinglass_negative( igraph_real_t *temperature, igraph_vector_int_t *membership, igraph_vector_int_t *csize, - igraph_integer_t spins, + igraph_int_t spins, igraph_bool_t parupdate, igraph_real_t starttemp, igraph_real_t stoptemp, @@ -505,8 +495,8 @@ static igraph_error_t igraph_i_community_spinglass_negative( igraph_real_t gamma, igraph_real_t gamma_minus) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t runs; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t runs; igraph_bool_t use_weights = false; bool zeroT; double kT, acc; @@ -602,9 +592,6 @@ static igraph_error_t igraph_i_community_spinglass_negative( PottsModelN pm(&net, spins, directed); - /* initialize the random number generator */ - RNG_BEGIN(); - if ((stoptemp == 0.0) && (starttemp == 0.0)) { zeroT = true; } else { @@ -641,7 +628,5 @@ static igraph_error_t igraph_i_community_spinglass_negative( igraph_matrix_destroy(&adhesion); IGRAPH_FINALLY_CLEAN(2); - RNG_END(); - return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/community/spinglass/pottsmodel_2.cpp b/src/vendor/cigraph/src/community/spinglass/pottsmodel_2.cpp index 355f19a608f..cdc12860c40 100644 --- a/src/vendor/cigraph/src/community/spinglass/pottsmodel_2.cpp +++ b/src/vendor/cigraph/src/community/spinglass/pottsmodel_2.cpp @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -53,12 +52,12 @@ using namespace std; //################################################################################################# -PottsModel::PottsModel(network *n, igraph_integer_t qvalue, int m) : +PottsModel::PottsModel(network *n, igraph_int_t qvalue, int m) : net(n), q(qvalue), operation_mode(m), Qmatrix(qvalue+1) { DLList_Iter iter; const NNode *n_cur; - igraph_integer_t *i_ptr; + igraph_int_t *i_ptr; //needed in calculating modularity Qa = new double[q + 1]; //weights for each spin state needed in Monte Carlo process @@ -75,10 +74,10 @@ PottsModel::PottsModel(network *n, igraph_integer_t qvalue, int m) : if (k_max < n_cur->Get_Degree()) { k_max = n_cur->Get_Degree(); } - i_ptr = new igraph_integer_t; + i_ptr = new igraph_int_t; *i_ptr = 0; new_spins.Push(i_ptr); - i_ptr = new igraph_integer_t; + i_ptr = new igraph_int_t; *i_ptr = 0; previous_spins.Push(i_ptr); n_cur = iter.Next(); @@ -104,8 +103,8 @@ PottsModel::~PottsModel() { //when called with positve one. //This may be handy, if you want to warm up the network. //#################################################### -igraph_integer_t PottsModel::assign_initial_conf(igraph_integer_t spin) { - igraph_integer_t s; +igraph_int_t PottsModel::assign_initial_conf(igraph_int_t spin) { + igraph_int_t s; DLList_Iter iter; DLList_Iter l_iter; NNode *n_cur; @@ -113,7 +112,7 @@ igraph_integer_t PottsModel::assign_initial_conf(igraph_integer_t spin) { double sum_weight; // initialize colorfield - for (igraph_integer_t i = 0; i <= q; i++) { + for (igraph_int_t i = 0; i <= q; i++) { color_field[i] = 0.0; } // @@ -160,7 +159,7 @@ igraph_integer_t PottsModel::assign_initial_conf(igraph_integer_t spin) { double PottsModel::initialize_Qmatrix() { DLList_Iter l_iter; NLink *l_cur; - igraph_integer_t i, j; + igraph_int_t i, j; //initialize with zeros num_of_links = net->link_list.Size(); for (i = 0; i <= q; i++) { @@ -195,7 +194,7 @@ double PottsModel::initialize_Qmatrix() { //#################################################################### double PottsModel::calculate_Q() { double Q = 0.0; - for (igraph_integer_t i = 0; i <= q; i++) { + for (igraph_int_t i = 0; i <= q; i++) { Q += Qmatrix[i][i] - Qa[i] * Qa[i] / double(2.0 * net->sum_weights); } Q /= double(2.0 * net->sum_weights); @@ -231,15 +230,15 @@ double PottsModel::FindStartTemp(double gamma, double prob, double ts) { //max sweeps is the maximum number of sweeps it should perform, //if it does not converge earlier //############################################################## -igraph_integer_t PottsModel::HeatBathParallelLookupZeroTemp(double gamma, double prob, unsigned int max_sweeps) { +igraph_int_t PottsModel::HeatBathParallelLookupZeroTemp(double gamma, double prob, unsigned int max_sweeps) { DLList_Iter net_iter; DLList_Iter l_iter; - DLList_Iter i_iter, i_iter2; + DLList_Iter i_iter, i_iter2; NNode *node, *n_cur; NLink *l_cur; unsigned int sweep; - igraph_integer_t *SPIN, *P_SPIN, old_spin, new_spin, spin_opt; - igraph_integer_t changes; + igraph_int_t *SPIN, *P_SPIN, old_spin, new_spin, spin_opt; + igraph_int_t changes; double h, delta = 0, deltaE, deltaEmin, w, degree; bool cyclic = false; @@ -255,7 +254,7 @@ igraph_integer_t PottsModel::HeatBathParallelLookupZeroTemp(double gamma, double while (!net_iter.End()) { // How many neighbors of each type? // set them all zero - for (igraph_integer_t i = 0; i <= q; i++) { + for (igraph_int_t i = 0; i <= q; i++) { neighbours[i] = 0; } degree = node->Get_Weight(); @@ -290,7 +289,7 @@ igraph_integer_t PottsModel::HeatBathParallelLookupZeroTemp(double gamma, double spin_opt = old_spin; deltaEmin = 0.0; - for (igraph_integer_t spin = 1; spin <= q; spin++) { // all possible spin states + for (igraph_int_t spin = 1; spin <= q; spin++) { // all possible spin states if (spin != old_spin) { h = color_field[spin] + delta - color_field[old_spin]; deltaE = double(neighbours[old_spin] - neighbours[spin]) + gamma * prob * double(h); @@ -370,10 +369,10 @@ double PottsModel::HeatBathLookupZeroTemp(double gamma, double prob, unsigned in DLList_Iter l_iter; NNode *node, *n_cur; NLink *l_cur; - igraph_integer_t new_spin, spin_opt, old_spin; + igraph_int_t new_spin, spin_opt, old_spin; unsigned int sweep; - igraph_integer_t r; - igraph_integer_t changes; + igraph_int_t r; + igraph_int_t changes; double delta = 0, h, deltaE, deltaEmin, w, degree; sweep = 0; @@ -381,12 +380,12 @@ double PottsModel::HeatBathLookupZeroTemp(double gamma, double prob, unsigned in while (sweep < max_sweeps) { sweep++; //ueber alle Knoten im Netz - for (igraph_integer_t n = 0; n < num_of_nodes; n++) { + for (igraph_int_t n = 0; n < num_of_nodes; n++) { r = RNG_INTEGER(0, num_of_nodes - 1); node = net->node_list.Get(r); // Wir zaehlen, wieviele Nachbarn von jedem spin vorhanden sind // erst mal alles Null setzen - for (igraph_integer_t i = 0; i <= q; i++) { + for (igraph_int_t i = 0; i <= q; i++) { neighbours[i] = 0; } degree = node->Get_Weight(); @@ -421,7 +420,7 @@ double PottsModel::HeatBathLookupZeroTemp(double gamma, double prob, unsigned in spin_opt = old_spin; deltaEmin = 0.0; - for (igraph_integer_t spin = 1; spin <= q; spin++) { // alle moeglichen Spins + for (igraph_int_t spin = 1; spin <= q; spin++) { // alle moeglichen Spins if (spin != old_spin) { h = color_field[spin] + delta - color_field[old_spin]; deltaE = double(neighbours[old_spin] - neighbours[spin]) + gamma * prob * double(h); @@ -469,20 +468,20 @@ double PottsModel::HeatBathLookupZeroTemp(double gamma, double prob, unsigned in //##################################################################################### //This function performs a parallel update at Terperature T //##################################################################################### -igraph_integer_t PottsModel::HeatBathParallelLookup(double gamma, double prob, double kT, unsigned int max_sweeps) { +igraph_int_t PottsModel::HeatBathParallelLookup(double gamma, double prob, double kT, unsigned int max_sweeps) { DLList_Iter net_iter; DLList_Iter l_iter; - DLList_Iter i_iter, i_iter2; + DLList_Iter i_iter, i_iter2; NNode *node, *n_cur; NLink *l_cur; - igraph_integer_t new_spin, spin_opt, old_spin; - igraph_integer_t *SPIN, *P_SPIN; + igraph_int_t new_spin, spin_opt, old_spin; + igraph_int_t *SPIN, *P_SPIN; unsigned int sweep; - igraph_integer_t max_q; - igraph_integer_t changes; + igraph_int_t max_q; + igraph_int_t changes; double h, delta = 0, norm, r, beta, minweight, prefac = 0, w, degree; bool cyclic = false/*, found*/; - igraph_integer_t number_of_nodes; + igraph_int_t number_of_nodes; sweep = 0; changes = 1; @@ -496,7 +495,7 @@ igraph_integer_t PottsModel::HeatBathParallelLookup(double gamma, double prob, d SPIN = i_iter.First(&new_spins); while (!net_iter.End()) { // Initialize neighbours and weights - for (igraph_integer_t i = 0; i <= q; i++) { + for (igraph_int_t i = 0; i <= q; i++) { neighbours[i] = 0; weights[i] = 0; } @@ -535,7 +534,7 @@ igraph_integer_t PottsModel::HeatBathParallelLookup(double gamma, double prob, d beta = 1.0 / kT * prefac; minweight = 0.0; weights[old_spin] = 0.0; - for (igraph_integer_t spin = 1; spin <= q; spin++) { // loop over all possible new spins + for (igraph_int_t spin = 1; spin <= q; spin++) { // loop over all possible new spins if (spin != old_spin) { // only if we have a different than old spin! h = color_field[spin] + delta - color_field[old_spin]; weights[spin] = double(neighbours[old_spin] - neighbours[spin]) + gamma * prob * double(h); @@ -544,7 +543,7 @@ igraph_integer_t PottsModel::HeatBathParallelLookup(double gamma, double prob, d } } } // for spin - for (igraph_integer_t spin = 1; spin <= q; spin++) { // loop over all possibe spins + for (igraph_int_t spin = 1; spin <= q; spin++) { // loop over all possibe spins weights[spin] -= minweight; // subtract minweight // to avoid numerical problems with large exponents weights[spin] = exp(-beta * weights[spin]); @@ -614,8 +613,8 @@ igraph_integer_t PottsModel::HeatBathParallelLookup(double gamma, double prob, d } // while markov max_q = 0; - for (igraph_integer_t i = 1; i <= q; i++) if (color_field[i] > max_q) { - max_q = igraph_integer_t(color_field[i]); + for (igraph_int_t i = 1; i <= q; i++) if (color_field[i] > max_q) { + max_q = igraph_int_t(color_field[i]); } //again, we would not like to end up in cyclic attractors @@ -635,26 +634,26 @@ double PottsModel::HeatBathLookup(double gamma, double prob, double kT, unsigned DLList_Iter l_iter; NNode *node, *n_cur; NLink *l_cur; - igraph_integer_t new_spin, spin_opt, old_spin; + igraph_int_t new_spin, spin_opt, old_spin; unsigned int sweep; - igraph_integer_t max_q; - igraph_integer_t rn; - igraph_integer_t changes; + igraph_int_t max_q; + igraph_int_t rn; + igraph_int_t changes; double degree, w, delta = 0, h; double norm, r, beta, minweight, prefac = 0; - igraph_integer_t number_of_nodes; + igraph_int_t number_of_nodes; sweep = 0; changes = 0; number_of_nodes = net->node_list.Size(); while (sweep < max_sweeps) { sweep++; //loop over all nodes in network - for (igraph_integer_t n = 0; n < number_of_nodes; n++) { + for (igraph_int_t n = 0; n < number_of_nodes; n++) { rn = RNG_INTEGER(0, number_of_nodes - 1); node = net->node_list.Get(rn); // initialize the neighbours and the weights - for (igraph_integer_t i = 0; i <= q; i++) { + for (igraph_int_t i = 0; i <= q; i++) { neighbours[i] = 0.0; weights[i] = 0.0; } @@ -695,7 +694,7 @@ double PottsModel::HeatBathLookup(double gamma, double prob, double kT, unsigned beta = 1.0 / kT * prefac; minweight = 0.0; weights[old_spin] = 0.0; - for (igraph_integer_t spin = 1; spin <= q; spin++) { // all possible new spins + for (igraph_int_t spin = 1; spin <= q; spin++) { // all possible new spins if (spin != old_spin) { // except the old one! h = color_field[spin] - (color_field[old_spin] - delta); weights[spin] = neighbours[old_spin] - neighbours[spin] + gamma * prob * h; @@ -704,7 +703,7 @@ double PottsModel::HeatBathLookup(double gamma, double prob, double kT, unsigned } } } // for spin - for (igraph_integer_t spin = 1; spin <= q; spin++) { // all possible new spins + for (igraph_int_t spin = 1; spin <= q; spin++) { // all possible new spins weights[spin] -= minweight; // subtract minweigt // for numerical stability weights[spin] = exp(-beta * weights[spin]); @@ -756,8 +755,8 @@ double PottsModel::HeatBathLookup(double gamma, double prob, double kT, unsigned } // while markov max_q = 0; - for (igraph_integer_t i = 1; i <= q; i++) if (color_field[i] > max_q) { - max_q = igraph_integer_t(color_field[i] + 0.5); + for (igraph_int_t i = 1; i <= q; i++) if (color_field[i] > max_q) { + max_q = igraph_int_t(color_field[i] + 0.5); } acceptance = double(changes) / double(number_of_nodes) / double(sweep); @@ -773,8 +772,8 @@ double PottsModel::FindCommunityFromStart( igraph_vector_int_t *result, igraph_real_t *cohesion, igraph_real_t *adhesion, - igraph_integer_t *my_inner_links, - igraph_integer_t *my_outer_links) const { + igraph_real_t *my_inner_links, + igraph_real_t *my_outer_links) const { DLList_Iter iter, iter2; DLList_Iter l_iter; DLList to_do; @@ -783,8 +782,8 @@ double PottsModel::FindCommunityFromStart( NLink *l_cur; bool found = false, add = false, remove = false; double degree, delta_aff_add, delta_aff_rem, max_delta_aff, Ks = 0.0, Kr = 0, kis, kir, w; - igraph_integer_t community_marker = 5; - igraph_integer_t to_do_marker = 10; + igraph_int_t community_marker = 5; + igraph_int_t to_do_marker = 10; double inner_links = 0, outer_links = 0, aff_r, aff_s; // find the node in the network @@ -983,14 +982,14 @@ double PottsModel::FindCommunityFromStart( node = iter.Next(); } } - igraph_integer_t size = community.Size(); + igraph_int_t size = community.Size(); return size; } //################################################################################################ // this Function writes the clusters to disk //################################################################################################ -igraph_integer_t PottsModel::WriteClusters(igraph_real_t *modularity, +igraph_int_t PottsModel::WriteClusters(igraph_real_t *modularity, igraph_real_t *temperature, igraph_vector_int_t *csize, igraph_vector_int_t *membership, @@ -1007,7 +1006,7 @@ igraph_integer_t PottsModel::WriteClusters(igraph_real_t *modularity, if (csize || membership || modularity) { // TODO: count the number of clusters - for (igraph_integer_t spin = 1; spin <= q; spin++) { + for (igraph_int_t spin = 1; spin <= q; spin++) { inner_links[spin] = 0; outer_links[spin] = 0; nodes[spin] = 0; @@ -1031,7 +1030,7 @@ igraph_integer_t PottsModel::WriteClusters(igraph_real_t *modularity, } if (modularity) { *modularity = 0.0; - for (igraph_integer_t spin = 1; spin <= q; spin++) { + for (igraph_int_t spin = 1; spin <= q; spin++) { if (nodes[spin] > 0) { double t1 = inner_links[spin] / net->sum_weights / 2.0; double t2 = (inner_links[spin] + outer_links[spin]) / @@ -1043,7 +1042,7 @@ igraph_integer_t PottsModel::WriteClusters(igraph_real_t *modularity, } if (csize) { igraph_vector_int_clear(csize); - for (igraph_integer_t spin = 1; spin <= q; spin++) { + for (igraph_int_t spin = 1; spin <= q; spin++) { if (nodes[spin] > 0) { inner_links[spin] /= 2; IGRAPH_CHECK(igraph_vector_int_push_back(csize, nodes[spin])); @@ -1053,9 +1052,9 @@ igraph_integer_t PottsModel::WriteClusters(igraph_real_t *modularity, //die Elemente der Cluster if (membership) { - igraph_integer_t no = -1; + igraph_int_t no = -1; IGRAPH_CHECK(igraph_vector_int_resize(membership, num_of_nodes)); - for (igraph_integer_t spin = 1; spin <= q; spin++) { + for (igraph_int_t spin = 1; spin <= q; spin++) { if (nodes[spin] > 0) { no++; } @@ -1073,7 +1072,7 @@ igraph_integer_t PottsModel::WriteClusters(igraph_real_t *modularity, } //################################################################################################# -PottsModelN::PottsModelN(network *n, igraph_integer_t num_communities, bool directed) : +PottsModelN::PottsModelN(network *n, igraph_int_t num_communities, bool directed) : net(n), q(num_communities), num_nodes(net->node_list.Size()), is_directed(directed) { } //####################################################### @@ -1098,7 +1097,7 @@ PottsModelN::~PottsModelN() { } void PottsModelN::assign_initial_conf(bool init_spins) { - igraph_integer_t s; + igraph_int_t s; DLList_Iter l_iter; const NNode *n_cur; const NLink *l_cur; @@ -1119,7 +1118,7 @@ void PottsModelN::assign_initial_conf(bool init_spins) { degree_pos_out = new double[num_nodes]; //Postive outdegree of the nodes (or sum of weights) degree_neg_out = new double[num_nodes]; //Negative outdegree of the nodes (or sum of weights) - spin = new igraph_integer_t[num_nodes]; //The spin state of each node + spin = new igraph_int_t[num_nodes]; //The spin state of each node } if (is_init) { @@ -1144,11 +1143,11 @@ void PottsModelN::assign_initial_conf(bool init_spins) { //...and of weights and neighbours for in the HeathBathLookup weights = new double[q + 1]; //The weights for changing to another spin state neighbours = new double[q + 1]; //The number of neighbours (or weights) in different spin states - csize = new igraph_integer_t[q + 1]; //The number of nodes in each community + csize = new igraph_int_t[q + 1]; //The number of nodes in each community //Initialize communities - for (igraph_integer_t i = 0; i <= q; i++) { + for (igraph_int_t i = 0; i <= q; i++) { degree_community_pos_in[i] = 0.0; degree_community_neg_in[i] = 0.0; degree_community_pos_out[i] = 0.0; @@ -1159,7 +1158,7 @@ void PottsModelN::assign_initial_conf(bool init_spins) { //Initialize vectors if (init_spins) { - for (igraph_integer_t i = 0; i < num_nodes; i++) { + for (igraph_int_t i = 0; i < num_nodes; i++) { degree_pos_in[i] = 0.0; degree_neg_in[i] = 0.0; degree_pos_out[i] = 0.0; @@ -1178,7 +1177,7 @@ void PottsModelN::assign_initial_conf(bool init_spins) { double sum_weight_pos_in, sum_weight_pos_out, sum_weight_neg_in, sum_weight_neg_out; - for (igraph_integer_t v = 0; v < num_nodes; v++) { + for (igraph_int_t v = 0; v < num_nodes; v++) { if (init_spins) { s = RNG_INTEGER(1, q); //The new spin s spin[v] = s; @@ -1266,13 +1265,13 @@ double PottsModelN::HeatBathLookup(double gamma, double lambda, double t, unsign * the old_spin is the spin of the node we are currently * changing. */ - igraph_integer_t new_spin, spin_opt, old_spin; + igraph_int_t new_spin, spin_opt, old_spin; unsigned int sweep; //current sweep - igraph_integer_t changes/*, problemcount*/; //Number of changes and number of problems encountered + igraph_int_t changes/*, problemcount*/; //Number of changes and number of problems encountered double exp_old_spin; //The expectation value for the old spin double exp_spin; //The expectation value for the other spin(s) - igraph_integer_t v; //The node we will be investigating + igraph_int_t v; //The node we will be investigating //The variables required for the calculations double delta_pos_out, delta_pos_in, delta_neg_out, delta_neg_in; @@ -1303,7 +1302,7 @@ double PottsModelN::HeatBathLookup(double gamma, double lambda, double t, unsign while (sweep < max_sweeps) { sweep++; //loop over all nodes in network - for (igraph_integer_t n = 0; n < num_nodes; n++) { + for (igraph_int_t n = 0; n < num_nodes; n++) { //Look for a random node v = RNG_INTEGER(0, num_nodes - 1); //We will be investigating node v @@ -1313,7 +1312,7 @@ double PottsModelN::HeatBathLookup(double gamma, double lambda, double t, unsign /*******************************************/ // initialize the neighbours and the weights // problemcount = 0; - for (igraph_integer_t i = 0; i <= q; i++) { + for (igraph_int_t i = 0; i <= q; i++) { neighbours[i] = 0.0; weights[i] = 0.0; } @@ -1471,7 +1470,7 @@ double PottsModelN::FindStartTemp(double gamma, double lambda, double ts) { return kT; } -igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, +igraph_int_t PottsModelN::WriteClusters(igraph_real_t *modularity, igraph_real_t *temperature, igraph_vector_int_t *community_size, igraph_vector_int_t *membership, @@ -1486,16 +1485,16 @@ igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, printf("Start writing clusters.\n"); #endif //Reassign each community so that we retrieve a community assignment 1 through num_communities - auto *cluster_assign = new igraph_integer_t[q + 1]; - for (igraph_integer_t i = 0; i <= q; i++) { + auto *cluster_assign = new igraph_int_t[q + 1]; + for (igraph_int_t i = 0; i <= q; i++) { cluster_assign[i] = 0; } - igraph_integer_t num_clusters = 0; + igraph_int_t num_clusters = 0; //Find out what the new communities will be - for (igraph_integer_t i = 0; i < num_nodes; i++) { - igraph_integer_t s = spin[i]; + for (igraph_int_t i = 0; i < num_nodes; i++) { + igraph_int_t s = spin[i]; if (cluster_assign[s] == 0) { num_clusters++; cluster_assign[s] = num_clusters; @@ -1507,11 +1506,11 @@ igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, //And now assign each node to its new community q = num_clusters; - for (igraph_integer_t i = 0; i < num_nodes; i++) { + for (igraph_int_t i = 0; i < num_nodes; i++) { #ifdef SPINGLASS_DEBUG printf("Setting node %d to %d.\n", i, cluster_assign[spin[i]]); #endif - igraph_integer_t s = cluster_assign[spin[i]]; + igraph_int_t s = cluster_assign[spin[i]]; spin[i] = s; #ifdef SPINGLASS_DEBUG printf("Have set node %d to %d.\n", i, s); @@ -1528,7 +1527,7 @@ igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, if (community_size) { //Initialize the vector IGRAPH_CHECK(igraph_vector_int_resize(community_size, q)); - for (igraph_integer_t spin_opt = 1; spin_opt <= q; spin_opt++) { + for (igraph_int_t spin_opt = 1; spin_opt <= q; spin_opt++) { //Set the community size VECTOR(*community_size)[spin_opt - 1] = csize[spin_opt]; } @@ -1537,7 +1536,7 @@ igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, //Set the membership if (membership) { IGRAPH_CHECK(igraph_vector_int_resize(membership, num_nodes)); - for (igraph_integer_t i = 0; i < num_nodes; i++) { + for (igraph_int_t i = 0; i < num_nodes; i++) { VECTOR(*membership)[ i ] = spin[i] - 1; } } @@ -1554,7 +1553,7 @@ igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, num_links_neg = new double *[q + 1] ; //memory allocated for elements of each column. - for ( igraph_integer_t i = 0 ; i < q + 1 ; i++) { + for ( igraph_int_t i = 0 ; i < q + 1 ; i++) { num_links_pos[i] = new double[q + 1]; num_links_neg[i] = new double[q + 1]; } @@ -1562,8 +1561,8 @@ igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, //Init num_links - for (igraph_integer_t i = 0; i <= q; i++) { - for (igraph_integer_t j = 0; j <= q; j++) { + for (igraph_int_t i = 0; i <= q; i++) { + for (igraph_int_t j = 0; j <= q; j++) { num_links_pos[i][j] = 0.0; num_links_neg[i][j] = 0.0; } @@ -1576,8 +1575,8 @@ igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, while (!iter_l.End()) { w = l_cur->Get_Weight(); - igraph_integer_t a = spin[l_cur->Get_Start()->Get_Index()]; - igraph_integer_t b = spin[l_cur->Get_End()->Get_Index()]; + igraph_int_t a = spin[l_cur->Get_Start()->Get_Index()]; + igraph_int_t b = spin[l_cur->Get_End()->Get_Index()]; if (w > 0) { num_links_pos[a][b] += w; if (!is_directed && a != b) { //Only one edge is defined in case it is undirected @@ -1608,8 +1607,8 @@ igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, //We don't take into account the lambda or gamma for //computing the modularity and adhesion, since they //are then incomparable to other definitions. - for (igraph_integer_t i = 1; i <= q; i++) { - for (igraph_integer_t j = 1; j <= q; j++) { + for (igraph_int_t i = 1; i <= q; i++) { + for (igraph_int_t j = 1; j <= q; j++) { if (!is_directed && i == j) expected = degree_community_pos_out[i] * degree_community_pos_in[j] / (m_p == 0 ? 1 : 2 * m_p) - degree_community_neg_out[i] * degree_community_neg_in[j] / (m_n == 0 ? 1 : 2 * m_n); @@ -1674,7 +1673,7 @@ igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, } //for i //free the allocated memory - for ( igraph_integer_t i = 0 ; i < q + 1 ; i++ ) { + for ( igraph_int_t i = 0 ; i < q + 1 ; i++ ) { delete [] num_links_pos[i] ; delete [] num_links_neg[i]; } @@ -1693,8 +1692,8 @@ igraph_integer_t PottsModelN::WriteClusters(igraph_real_t *modularity, if (polarization) { double sum_ad = 0.0; - for (igraph_integer_t i = 0; i < q; i++) { - for (igraph_integer_t j = 0; j < q; j++) { + for (igraph_int_t i = 0; i < q; i++) { + for (igraph_int_t j = 0; j < q; j++) { if (i != j) { sum_ad -= MATRIX(*normalised_adhesion, i, j); } diff --git a/src/vendor/cigraph/src/community/spinglass/pottsmodel_2.h b/src/vendor/cigraph/src/community/spinglass/pottsmodel_2.h index 1cecba4268c..a92861f94b4 100644 --- a/src/vendor/cigraph/src/community/spinglass/pottsmodel_2.h +++ b/src/vendor/cigraph/src/community/spinglass/pottsmodel_2.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -69,39 +68,39 @@ class SimpleMatrix { class PottsModel { private: //these lists are needed to keep track of spin states for parallel update mode - DL_Indexed_List new_spins; - DL_Indexed_List previous_spins; + DL_Indexed_List new_spins; + DL_Indexed_List previous_spins; HugeArray*> correlation; network *net; - igraph_integer_t q; + igraph_int_t q; unsigned int operation_mode; SimpleMatrix Qmatrix; double* Qa; double* weights; double total_degree_sum; - igraph_integer_t num_of_nodes; - igraph_integer_t num_of_links; - igraph_integer_t k_max = 0; + igraph_int_t num_of_nodes; + igraph_int_t num_of_links; + igraph_int_t k_max = 0; double acceptance = 0; double* neighbours; double* color_field; public: - PottsModel(network *net, igraph_integer_t q, int norm_by_degree); + PottsModel(network *net, igraph_int_t q, int norm_by_degree); ~PottsModel(); - igraph_integer_t assign_initial_conf(igraph_integer_t spin); + igraph_int_t assign_initial_conf(igraph_int_t spin); double initialize_Qmatrix(); double calculate_Q(); double FindStartTemp(double gamma, double prob, double ts); - igraph_integer_t HeatBathParallelLookupZeroTemp(double gamma, double prob, unsigned int max_sweeps); + igraph_int_t HeatBathParallelLookupZeroTemp(double gamma, double prob, unsigned int max_sweeps); double HeatBathLookupZeroTemp(double gamma, double prob, unsigned int max_sweeps); - igraph_integer_t HeatBathParallelLookup(double gamma, double prob, double kT, unsigned int max_sweeps); + igraph_int_t HeatBathParallelLookup(double gamma, double prob, double kT, unsigned int max_sweeps); double HeatBathLookup(double gamma, double prob, double kT, unsigned int max_sweeps); - igraph_integer_t WriteClusters(igraph_real_t *modularity, + igraph_int_t WriteClusters(igraph_real_t *modularity, igraph_real_t *temperature, igraph_vector_int_t *csize, igraph_vector_int_t *membership, double kT, double gamma) const; @@ -110,8 +109,8 @@ class PottsModel { igraph_vector_int_t *result, igraph_real_t *cohesion, igraph_real_t *adhesion, - igraph_integer_t *inner_links, - igraph_integer_t *outer_links) const; + igraph_real_t *inner_links, + igraph_real_t *outer_links) const; }; @@ -120,10 +119,10 @@ class PottsModelN { HugeArray*> correlation; network *net; - igraph_integer_t q; //number of communities + igraph_int_t q; //number of communities double m_p; //number of positive ties (or sum of degrees), this equals the number of edges only if it is undirected and each edge has a weight of 1 double m_n; //number of negative ties (or sum of degrees) - igraph_integer_t num_nodes; //number of nodes + igraph_int_t num_nodes; //number of nodes bool is_directed; bool is_init = false; @@ -138,19 +137,19 @@ class PottsModelN { double *degree_community_pos_out = nullptr; //Positive sum of outegree for communities double *degree_community_neg_out = nullptr; //Negative sum of outdegree for communities - igraph_integer_t *csize = nullptr; //The number of nodes in each community - igraph_integer_t *spin = nullptr; //The membership of each node + igraph_int_t *csize = nullptr; //The number of nodes in each community + igraph_int_t *spin = nullptr; //The membership of each node double *neighbours = nullptr; //Array of neighbours of a vertex in each community double *weights = nullptr; //Weights of all possible transitions to another community public: - PottsModelN(network *n, igraph_integer_t num_communities, bool directed); + PottsModelN(network *n, igraph_int_t num_communities, bool directed); ~PottsModelN(); void assign_initial_conf(bool init_spins); double FindStartTemp(double gamma, double lambda, double ts); double HeatBathLookup(double gamma, double lambda, double t, unsigned int max_sweeps); - igraph_integer_t WriteClusters(igraph_real_t *modularity, + igraph_int_t WriteClusters(igraph_real_t *modularity, igraph_real_t *temperature, igraph_vector_int_t *community_size, igraph_vector_int_t *membership, diff --git a/src/vendor/cigraph/src/community/voronoi.c b/src/vendor/cigraph/src/community/voronoi.c index fc3fabeefb7..fc3d0d71486 100644 --- a/src/vendor/cigraph/src/community/voronoi.c +++ b/src/vendor/cigraph/src/community/voronoi.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -43,8 +43,8 @@ * Time complexity: TODO. */ static igraph_error_t igraph_i_local_relative_density(const igraph_t *graph, igraph_vector_t *res, igraph_vs_t vs) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t vs_size; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t vs_size; igraph_vector_int_t nei_mask; /* which nodes are in the local neighbourhood? */ igraph_vector_int_t nei_done; /* which local nodes have already been processed? -- avoids duplicate processing in multigraphs */ igraph_lazy_adjlist_t al; @@ -63,17 +63,17 @@ static igraph_error_t igraph_i_local_relative_density(const igraph_t *graph, igr IGRAPH_CHECK(igraph_vector_resize(res, vs_size)); - for (igraph_integer_t i=0; ! IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t w = IGRAPH_VIT_GET(vit); - igraph_integer_t int_count = 0, ext_count = 0; + for (igraph_int_t i=0; ! IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { + igraph_int_t w = IGRAPH_VIT_GET(vit); + igraph_int_t int_count = 0, ext_count = 0; igraph_vector_int_t *w_neis = igraph_lazy_adjlist_get(&al, w); IGRAPH_CHECK_OOM(w_neis, "Cannot calculate local relative density."); - igraph_integer_t dw = igraph_vector_int_size(w_neis); + igraph_int_t dw = igraph_vector_int_size(w_neis); /* mark neighbours of w, as well as w itself */ - for (igraph_integer_t j=0; j < dw; ++j) { + for (igraph_int_t j=0; j < dw; ++j) { VECTOR(nei_mask)[ VECTOR(*w_neis)[j] ] = i + 1; } VECTOR(nei_mask)[w] = i + 1; @@ -82,8 +82,8 @@ static igraph_error_t igraph_i_local_relative_density(const igraph_t *graph, igr int_count += dw; VECTOR(nei_done)[w] = i + 1; - for (igraph_integer_t j=0; j < dw; ++j) { - igraph_integer_t v = VECTOR(*w_neis)[j]; + for (igraph_int_t j=0; j < dw; ++j) { + igraph_int_t v = VECTOR(*w_neis)[j]; if (VECTOR(nei_done)[v] == i + 1) { continue; @@ -94,10 +94,10 @@ static igraph_error_t igraph_i_local_relative_density(const igraph_t *graph, igr igraph_vector_int_t *v_neis = igraph_lazy_adjlist_get(&al, v); IGRAPH_CHECK_OOM(v_neis, "Cannot calculate local relative density."); - igraph_integer_t dv = igraph_vector_int_size(v_neis); + igraph_int_t dv = igraph_vector_int_size(v_neis); - for (igraph_integer_t k=0; k < dv; ++k) { - igraph_integer_t u = VECTOR(*v_neis)[k]; + for (igraph_int_t k=0; k < dv; ++k) { + igraph_int_t u = VECTOR(*v_neis)[k]; if (VECTOR(nei_mask)[u] == i + 1) { int_count += 1; @@ -160,10 +160,10 @@ static igraph_error_t choose_generators( igraph_neimode_t mode, igraph_real_t r) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t ord; igraph_bitset_t excluded; - igraph_integer_t excluded_count; + igraph_int_t excluded_count; igraph_inclist_t il; igraph_2wheap_t q; igraph_real_t radius_max; @@ -186,8 +186,8 @@ static igraph_error_t choose_generators( radius_max = -IGRAPH_INFINITY; igraph_vector_int_clear(generators); - for (igraph_integer_t i=0; i < no_of_nodes; i++) { - igraph_integer_t g = VECTOR(ord)[i]; + for (igraph_int_t i=0; i < no_of_nodes; i++) { + igraph_int_t g = VECTOR(ord)[i]; if (IGRAPH_BIT_TEST(excluded, g)) continue; @@ -196,7 +196,7 @@ static igraph_error_t choose_generators( igraph_2wheap_clear(&q); IGRAPH_CHECK(igraph_2wheap_push_with_index(&q, g, -0.0)); while (!igraph_2wheap_empty(&q)) { - igraph_integer_t vid = igraph_2wheap_max_index(&q); + igraph_int_t vid = igraph_2wheap_max_index(&q); igraph_real_t mindist = -igraph_2wheap_deactivate_max(&q); /* Exceeded cutoff distance, do not search further along this path. */ @@ -215,9 +215,9 @@ static igraph_error_t choose_generators( } igraph_vector_int_t *inc_edges = igraph_inclist_get(&il, vid); - igraph_integer_t inc_count = igraph_vector_int_size(inc_edges); - for (igraph_integer_t j=0; j < inc_count; j++) { - igraph_integer_t edge = VECTOR(*inc_edges)[j]; + igraph_int_t inc_count = igraph_vector_int_size(inc_edges); + for (igraph_int_t j=0; j < inc_count; j++) { + igraph_int_t edge = VECTOR(*inc_edges)[j]; igraph_real_t weight = VECTOR(*lengths)[edge]; /* Optimization: do not follow infinite-length edges. */ @@ -225,7 +225,7 @@ static igraph_error_t choose_generators( continue; } - igraph_integer_t to = IGRAPH_OTHER(graph, edge, vid); + igraph_int_t to = IGRAPH_OTHER(graph, edge, vid); igraph_real_t altdist = mindist + weight; if (!igraph_2wheap_has_elem(&q, to)) { @@ -516,8 +516,8 @@ igraph_error_t igraph_community_voronoi( const igraph_vector_t *lengths, const igraph_vector_t *weights, igraph_neimode_t mode, igraph_real_t r) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_t local_rel_dens; igraph_vector_t lengths2; /* lengths2 = lengths / ecc */ igraph_vector_int_t imembership, igenerators; @@ -536,21 +536,10 @@ igraph_error_t igraph_community_voronoi( IGRAPH_ERROR("Edge length vector size does not match edge count.", IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_is_simple(graph, &simple)); + IGRAPH_CHECK(igraph_is_simple(graph, &simple, mode == IGRAPH_ALL ? IGRAPH_UNDIRECTED : IGRAPH_DIRECTED)); if (! simple) { IGRAPH_ERROR("The graph must be simple for Voronoi communities.", IGRAPH_EINVAL); } - if (igraph_is_directed(graph) && mode == IGRAPH_ALL) { - igraph_bool_t has_mutual; - /* When the graph is directed but edge directions are ignored, - * mutual edges are effectively multi-edges. */ - IGRAPH_CHECK(igraph_has_mutual(graph, &has_mutual, false)); - if (has_mutual) { - IGRAPH_ERROR("The graph must be simple for Voronoi communities. " - "Mutual directed edges are effectively multi-edges when ignoring edge directions.", - IGRAPH_EINVAL); - } - } if (no_of_edges == 0) { /* Also handles no_of_nodes <= 1 */ @@ -605,7 +594,7 @@ igraph_error_t igraph_community_voronoi( IGRAPH_CHECK(igraph_ecc(graph, &lengths2, igraph_ess_all(IGRAPH_EDGEORDER_ID), 3, true, true)); /* Note: ECC is never NaN but it may be Inf */ - for (igraph_integer_t i=0; i < no_of_edges; i++) { + for (igraph_int_t i=0; i < no_of_edges; i++) { VECTOR(lengths2)[i] = 1 / (VECTOR(lengths2)[i]); } if (lengths) { diff --git a/src/vendor/cigraph/src/community/walktrap/walktrap.cpp b/src/vendor/cigraph/src/community/walktrap/walktrap.cpp index 4efadc9d804..bd419e4ed27 100644 --- a/src/vendor/cigraph/src/community/walktrap/walktrap.cpp +++ b/src/vendor/cigraph/src/community/walktrap/walktrap.cpp @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -131,14 +130,14 @@ using namespace igraph::walktrap; igraph_error_t igraph_community_walktrap(const igraph_t *graph, const igraph_vector_t *weights, - igraph_integer_t steps, + igraph_int_t steps, igraph_matrix_int_t *merges, igraph_vector_t *modularity, igraph_vector_int_t *membership) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t comp_count; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t comp_count; igraph_matrix_int_t imerges, *pmerges = merges; igraph_vector_t imodularity, *pmodularity = modularity; @@ -206,7 +205,7 @@ igraph_error_t igraph_community_walktrap(const igraph_t *graph, ); if (membership) { - igraph_integer_t m; + igraph_int_t m; m = no_of_nodes > 0 ? igraph_vector_which_max(pmodularity) : 0; IGRAPH_CHECK(igraph_community_to_membership(pmerges, no_of_nodes, /*steps=*/ m, diff --git a/src/vendor/cigraph/src/community/walktrap/walktrap_communities.cpp b/src/vendor/cigraph/src/community/walktrap/walktrap_communities.cpp index 8b363dda164..4435351738e 100644 --- a/src/vendor/cigraph/src/community/walktrap/walktrap_communities.cpp +++ b/src/vendor/cigraph/src/community/walktrap/walktrap_communities.cpp @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/community/walktrap/walktrap_communities.h b/src/vendor/cigraph/src/community/walktrap/walktrap_communities.h index 6017c3a20fd..fc37fac84ad 100644 --- a/src/vendor/cigraph/src/community/walktrap/walktrap_communities.h +++ b/src/vendor/cigraph/src/community/walktrap/walktrap_communities.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -124,7 +123,7 @@ class Community { class Communities { private: igraph_matrix_int_t *merges; - igraph_integer_t mergeidx; + igraph_int_t mergeidx; igraph_vector_t *modularity; public: diff --git a/src/vendor/cigraph/src/community/walktrap/walktrap_graph.cpp b/src/vendor/cigraph/src/community/walktrap/walktrap_graph.cpp index 56e31fc5668..eede1490454 100644 --- a/src/vendor/cigraph/src/community/walktrap/walktrap_graph.cpp +++ b/src/vendor/cigraph/src/community/walktrap/walktrap_graph.cpp @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -146,8 +145,8 @@ igraph_error_t Graph::convert_from_igraph(const igraph_t *graph, const igraph_vector_t *weights) { Graph &G = *this; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); // Avoid warnings with GCC when compiling with LTO. IGRAPH_ASSUME(no_of_nodes >= 0); @@ -161,7 +160,7 @@ igraph_error_t Graph::convert_from_igraph(const igraph_t *graph, Edge_list EL; - for (igraph_integer_t i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { igraph_real_t w = weights ? VECTOR(*weights)[i] : 1.0; EL.add(IGRAPH_FROM(graph, i), IGRAPH_TO(graph, i), w); } diff --git a/src/vendor/cigraph/src/community/walktrap/walktrap_graph.h b/src/vendor/cigraph/src/community/walktrap/walktrap_graph.h index 2347e8cff83..1c66ceef61b 100644 --- a/src/vendor/cigraph/src/community/walktrap/walktrap_graph.h +++ b/src/vendor/cigraph/src/community/walktrap/walktrap_graph.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA diff --git a/src/vendor/cigraph/src/community/walktrap/walktrap_heap.cpp b/src/vendor/cigraph/src/community/walktrap/walktrap_heap.cpp index dcb0518f18a..df17d07573b 100644 --- a/src/vendor/cigraph/src/community/walktrap/walktrap_heap.cpp +++ b/src/vendor/cigraph/src/community/walktrap/walktrap_heap.cpp @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/community/walktrap/walktrap_heap.h b/src/vendor/cigraph/src/community/walktrap/walktrap_heap.h index 90b4f31f69b..675bbe1bee5 100644 --- a/src/vendor/cigraph/src/community/walktrap/walktrap_heap.h +++ b/src/vendor/cigraph/src/community/walktrap/walktrap_heap.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA diff --git a/src/vendor/cigraph/src/config.h.in b/src/vendor/cigraph/src/config.h.in index ca06c907829..953e3e4393a 100644 --- a/src/vendor/cigraph/src/config.h.in +++ b/src/vendor/cigraph/src/config.h.in @@ -26,6 +26,7 @@ #cmakedefine HAVE_GLPK 1 #cmakedefine HAVE_LIBXML 1 +#cmakedefine HAVE_INFOMAP 1 #cmakedefine INTERNAL_BLAS 1 #cmakedefine INTERNAL_LAPACK 1 diff --git a/src/vendor/cigraph/src/connectivity/cohesive_blocks.c b/src/vendor/cigraph/src/connectivity/cohesive_blocks.c index 7850d0e24df..f84e5d5283a 100644 --- a/src/vendor/cigraph/src/connectivity/cohesive_blocks.c +++ b/src/vendor/cigraph/src/connectivity/cohesive_blocks.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -36,7 +35,7 @@ #include "core/interruption.h" static void igraph_i_cohesive_blocks_free_graphs(igraph_vector_ptr_t *ptr) { - igraph_integer_t i, n = igraph_vector_ptr_size(ptr); + igraph_int_t i, n = igraph_vector_ptr_size(ptr); for (i = 0; i < n; i++) { igraph_t *g = VECTOR(*ptr)[i]; @@ -56,15 +55,15 @@ static void igraph_i_cohesive_blocks_free_graphs(igraph_vector_ptr_t *ptr) { static igraph_error_t igraph_i_cb_components(igraph_t *graph, const igraph_vector_bool_t *excluded, igraph_vector_int_t *components, - igraph_integer_t *no, + igraph_int_t *no, /* working area follows */ igraph_vector_int_t *compid, igraph_dqueue_int_t *Q, igraph_vector_int_t *neis) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t i; - igraph_integer_t cno = 0; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i; + igraph_int_t cno = 0; igraph_vector_int_clear(components); igraph_dqueue_int_clear(Q); @@ -85,12 +84,14 @@ static igraph_error_t igraph_i_cb_components(igraph_t *graph, VECTOR(*compid)[i] = ++cno; while (!igraph_dqueue_int_empty(Q)) { - igraph_integer_t node = igraph_dqueue_int_pop(Q); - igraph_integer_t j, n; - IGRAPH_CHECK(igraph_neighbors(graph, neis, node, IGRAPH_ALL)); + igraph_int_t node = igraph_dqueue_int_pop(Q); + igraph_int_t j, n; + IGRAPH_CHECK(igraph_neighbors( + graph, neis, node, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); n = igraph_vector_int_size(neis); for (j = 0; j < n; j++) { - igraph_integer_t v = VECTOR(*neis)[j]; + igraph_int_t v = VECTOR(*neis)[j]; if (VECTOR(*excluded)[v]) { if (VECTOR(*compid)[v] != cno) { VECTOR(*compid)[v] = cno; @@ -117,9 +118,9 @@ static igraph_error_t igraph_i_cb_components(igraph_t *graph, static igraph_bool_t igraph_i_cb_isin(const igraph_vector_int_t *needle, const igraph_vector_int_t *haystack) { - igraph_integer_t nlen = igraph_vector_int_size(needle); - igraph_integer_t hlen = igraph_vector_int_size(haystack); - igraph_integer_t np = 0, hp = 0; + igraph_int_t nlen = igraph_vector_int_size(needle); + igraph_int_t hlen = igraph_vector_int_size(haystack); + igraph_int_t np = 0, hp = 0; if (hlen < nlen) { return false; @@ -222,8 +223,8 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, igraph_vector_int_t Qparent; igraph_vector_int_t Qcohesion; igraph_vector_bool_t Qcheck; - igraph_integer_t Qptr = 0; - igraph_integer_t conn; + igraph_int_t Qptr = 0; + igraph_int_t conn; igraph_bool_t is_simple; igraph_t *graph_copy; @@ -243,7 +244,7 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_is_simple(graph, &is_simple)); + IGRAPH_CHECK(igraph_is_simple(graph, &is_simple, IGRAPH_DIRECTED)); if (!is_simple) { IGRAPH_ERROR("Cohesive blocking only works on simple graphs.", IGRAPH_EINVAL); @@ -295,11 +296,11 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, while (Qptr < igraph_vector_ptr_size(&Q)) { igraph_t *mygraph = VECTOR(Q)[Qptr]; igraph_bool_t mycheck = VECTOR(Qcheck)[Qptr]; - igraph_integer_t mynodes = igraph_vcount(mygraph); - igraph_integer_t i, nsep; - igraph_integer_t no, kept = 0; - igraph_integer_t cptr = 0; - igraph_integer_t nsepv = 0; + igraph_int_t mynodes = igraph_vcount(mygraph); + igraph_int_t i, nsep; + igraph_int_t no, kept = 0; + igraph_int_t cptr = 0; + igraph_int_t nsepv = 0; igraph_bool_t addedsep = false; IGRAPH_ALLOW_INTERRUPTION(); @@ -313,9 +314,9 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, igraph_vector_bool_null(&marked); for (i = 0; i < nsep; i++) { igraph_vector_int_t *v = igraph_vector_int_list_get_ptr(&separators, i); - igraph_integer_t j, n = igraph_vector_int_size(v); + igraph_int_t j, n = igraph_vector_int_size(v); for (j = 0; j < n; j++) { - igraph_integer_t vv = VECTOR(*v)[j]; + igraph_int_t vv = VECTOR(*v)[j]; if (!VECTOR(marked)[vv]) { nsepv++; VECTOR(marked)[vv] = true; @@ -346,12 +347,12 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, for (i = 0; i < no; i++) { igraph_t *newgraph; - igraph_integer_t maxdeg; + igraph_int_t maxdeg; igraph_vector_int_clear(&compvertices); while (true) { - igraph_integer_t v = VECTOR(components)[cptr++]; + igraph_int_t v = VECTOR(components)[cptr++]; if (v < 0) { break; } @@ -372,7 +373,7 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, IGRAPH_CHECK(igraph_maxdegree(newgraph, &maxdeg, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS)); if (maxdeg > VECTOR(Qcohesion)[Qptr]) { - igraph_integer_t newconn; + igraph_int_t newconn; kept++; IGRAPH_CHECK(igraph_vector_ptr_push_back(&Q, newgraph)); IGRAPH_FINALLY_CLEAN(2); @@ -408,9 +409,9 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, IGRAPH_FINALLY_CLEAN(8); if (blocks || cohesion || parent || block_tree) { - igraph_integer_t noblocks = Qptr, badblocks = 0; + igraph_int_t noblocks = Qptr, badblocks = 0; igraph_vector_bool_t removed; - igraph_integer_t i, resptr = 0; + igraph_int_t i, resptr = 0; igraph_vector_int_t rewritemap; IGRAPH_CHECK(igraph_vector_bool_init(&removed, noblocks)); @@ -419,7 +420,7 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, IGRAPH_FINALLY(igraph_vector_int_destroy, &rewritemap); for (i = 1; i < noblocks; i++) { - igraph_integer_t p = VECTOR(Qparent)[i]; + igraph_int_t p = VECTOR(Qparent)[i]; while (VECTOR(removed)[p]) { p = VECTOR(Qparent)[p]; } @@ -431,7 +432,7 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, /* Rewrite the mappings */ for (i = 1; i < Qptr; i++) { - igraph_integer_t j, n, p = VECTOR(Qparent)[i]; + igraph_int_t j, n, p = VECTOR(Qparent)[i]; igraph_vector_int_t *mapping, *pmapping; if (p == 0) { @@ -443,7 +444,7 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, n = igraph_vector_int_size(mapping); for (j = 0; j < n; j++) { - igraph_integer_t v = VECTOR(*mapping)[j]; + igraph_int_t v = VECTOR(*mapping)[j]; VECTOR(*mapping)[j] = VECTOR(*pmapping)[v]; } } @@ -452,7 +453,7 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, not ensured that the found blocks are not subsets of each other. We check this now. */ for (i = 1; i < noblocks; i++) { - igraph_integer_t j, ic; + igraph_int_t j, ic; igraph_vector_int_t *ivec; if (!VECTOR(Qcheck)[i] || VECTOR(removed)[i]) { continue; @@ -461,7 +462,7 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, ic = VECTOR(Qcohesion)[i]; for (j = 1; j < noblocks; j++) { igraph_vector_int_t *jvec; - igraph_integer_t jc; + igraph_int_t jc; if (j == i || !VECTOR(Qcheck)[j] || VECTOR(removed)[j]) { continue; } @@ -496,7 +497,7 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, VECTOR(*cohesion)[resptr] = VECTOR(Qcohesion)[i]; } if (parent || block_tree) { - igraph_integer_t p = VECTOR(Qparent)[i]; + igraph_int_t p = VECTOR(Qparent)[i]; while (p >= 0 && VECTOR(removed)[p]) { p = VECTOR(Qparent)[p]; } @@ -522,7 +523,7 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, /* Plus the original graph */ if (blocks) { - igraph_integer_t num_vertices = igraph_vcount(graph); + igraph_int_t num_vertices = igraph_vcount(graph); igraph_vector_int_t *orig = igraph_vector_int_list_get_ptr(blocks, 0); IGRAPH_CHECK(igraph_vector_int_resize(orig, num_vertices)); for (i = 0; i < num_vertices; i++) { @@ -532,7 +533,7 @@ igraph_error_t igraph_cohesive_blocks(const igraph_t *graph, if (block_tree) { igraph_vector_int_t edges; - igraph_integer_t eptr = 0; + igraph_int_t eptr = 0; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, noblocks * 2 - 2); for (i = 1; i < Qptr; i++) { if (VECTOR(removed)[i]) { diff --git a/src/vendor/cigraph/src/connectivity/components.c b/src/vendor/cigraph/src/connectivity/components.c index b9009a01eef..4c8da280315 100644 --- a/src/vendor/cigraph/src/connectivity/components.c +++ b/src/vendor/cigraph/src/connectivity/components.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -27,7 +26,6 @@ #include "igraph_bitset.h" #include "igraph_dqueue.h" #include "igraph_interface.h" -#include "igraph_memory.h" #include "igraph_progress.h" #include "igraph_stack.h" #include "igraph_structural.h" @@ -38,27 +36,13 @@ static igraph_error_t igraph_i_connected_components_weak( const igraph_t *graph, igraph_vector_int_t *membership, - igraph_vector_int_t *csize, igraph_integer_t *no + igraph_vector_int_t *csize, igraph_int_t *no ); static igraph_error_t igraph_i_connected_components_strong( const igraph_t *graph, igraph_vector_int_t *membership, - igraph_vector_int_t *csize, igraph_integer_t *no + igraph_vector_int_t *csize, igraph_int_t *no ); -/** - * \ingroup structural - * \function igraph_clusters - * \brief Calculates the (weakly or strongly) connected components in a graph (deprecated alias). - * - * \deprecated-by igraph_connected_components 0.10 - */ - -igraph_error_t igraph_clusters(const igraph_t *graph, igraph_vector_int_t *membership, - igraph_vector_int_t *csize, igraph_integer_t *no, - igraph_connectedness_t mode) { - return igraph_connected_components(graph, membership, csize, no, mode); -} - /** * \ingroup structural * \function igraph_connected_components @@ -97,7 +81,7 @@ igraph_error_t igraph_clusters(const igraph_t *graph, igraph_vector_int_t *membe igraph_error_t igraph_connected_components( const igraph_t *graph, igraph_vector_int_t *membership, - igraph_vector_int_t *csize, igraph_integer_t *no, igraph_connectedness_t mode + igraph_vector_int_t *csize, igraph_int_t *no, igraph_connectedness_t mode ) { if (mode == IGRAPH_WEAK || !igraph_is_directed(graph)) { return igraph_i_connected_components_weak(graph, membership, csize, no); @@ -110,11 +94,11 @@ igraph_error_t igraph_connected_components( static igraph_error_t igraph_i_connected_components_weak( const igraph_t *graph, igraph_vector_int_t *membership, - igraph_vector_int_t *csize, igraph_integer_t *no + igraph_vector_int_t *csize, igraph_int_t *no ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_components; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_components; igraph_bitset_t already_added; igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; igraph_vector_int_t neis = IGRAPH_VECTOR_NULL; @@ -157,8 +141,8 @@ static igraph_error_t igraph_i_connected_components_weak( /* The algorithm */ no_of_components = 0; - for (igraph_integer_t first_node = 0; first_node < no_of_nodes; ++first_node) { - igraph_integer_t act_component_size; + for (igraph_int_t first_node = 0; first_node < no_of_nodes; ++first_node) { + igraph_int_t act_component_size; if (IGRAPH_BIT_TEST(already_added, first_node)) { continue; @@ -173,11 +157,13 @@ static igraph_error_t igraph_i_connected_components_weak( IGRAPH_CHECK(igraph_dqueue_int_push(&q, first_node)); while ( !igraph_dqueue_int_empty(&q) ) { - igraph_integer_t act_node = igraph_dqueue_int_pop(&q); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, act_node, IGRAPH_ALL)); - igraph_integer_t nei_count = igraph_vector_int_size(&neis); - for (igraph_integer_t i = 0; i < nei_count; i++) { - igraph_integer_t neighbor = VECTOR(neis)[i]; + igraph_int_t act_node = igraph_dqueue_int_pop(&q); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, act_node, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); + igraph_int_t nei_count = igraph_vector_int_size(&neis); + for (igraph_int_t i = 0; i < nei_count; i++) { + igraph_int_t neighbor = VECTOR(neis)[i]; if (IGRAPH_BIT_TEST(already_added, neighbor)) { continue; } @@ -216,13 +202,13 @@ static igraph_error_t igraph_i_connected_components_weak( static igraph_error_t igraph_i_connected_components_strong( const igraph_t *graph, igraph_vector_int_t *membership, - igraph_vector_int_t *csize, igraph_integer_t *no + igraph_vector_int_t *csize, igraph_int_t *no ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t next_nei = IGRAPH_VECTOR_NULL; - igraph_integer_t num_seen; + igraph_int_t num_seen; igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; - igraph_integer_t no_of_components = 0; + igraph_int_t no_of_components = 0; igraph_vector_int_t out = IGRAPH_VECTOR_NULL; igraph_adjlist_t adjlist; @@ -269,7 +255,7 @@ static igraph_error_t igraph_i_connected_components_strong( IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); num_seen = 0; - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { const igraph_vector_int_t *tmp; IGRAPH_ALLOW_INTERRUPTION(); @@ -281,14 +267,14 @@ static igraph_error_t igraph_i_connected_components_strong( IGRAPH_CHECK(igraph_dqueue_int_push(&q, i)); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t act_node = igraph_dqueue_int_back(&q); + igraph_int_t act_node = igraph_dqueue_int_back(&q); tmp = igraph_adjlist_get(&adjlist, act_node); if (VECTOR(next_nei)[act_node] == 0) { /* this is the first time we've met this vertex */ VECTOR(next_nei)[act_node]++; } else if (VECTOR(next_nei)[act_node] <= igraph_vector_int_size(tmp)) { /* we've already met this vertex but it has more children */ - igraph_integer_t neighbor = VECTOR(*tmp)[VECTOR(next_nei)[act_node] - 1]; + igraph_int_t neighbor = VECTOR(*tmp)[VECTOR(next_nei)[act_node] - 1]; if (VECTOR(next_nei)[neighbor] == 0) { IGRAPH_CHECK(igraph_dqueue_int_push(&q, neighbor)); } @@ -324,8 +310,8 @@ static igraph_error_t igraph_i_connected_components_strong( num_seen = 0; while (!igraph_vector_int_empty(&out)) { - igraph_integer_t act_component_size; - igraph_integer_t grandfather = igraph_vector_int_pop_back(&out); + igraph_int_t act_component_size; + igraph_int_t grandfather = igraph_vector_int_pop_back(&out); if (VECTOR(next_nei)[grandfather] != 0) { continue; @@ -346,11 +332,11 @@ static igraph_error_t igraph_i_connected_components_strong( } while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t act_node = igraph_dqueue_int_pop_back(&q); + igraph_int_t act_node = igraph_dqueue_int_pop_back(&q); const igraph_vector_int_t *tmp = igraph_adjlist_get(&adjlist, act_node); - const igraph_integer_t n = igraph_vector_int_size(tmp); - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t neighbor = VECTOR(*tmp)[i]; + const igraph_int_t n = igraph_vector_int_size(tmp); + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t neighbor = VECTOR(*tmp)[i]; if (VECTOR(next_nei)[neighbor] != 0) { continue; } @@ -447,8 +433,8 @@ igraph_error_t igraph_is_connected(const igraph_t *graph, igraph_bool_t *res, igraph_connectedness_t mode) { igraph_cached_property_t prop; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no; if (!igraph_is_directed(graph)) { mode = IGRAPH_WEAK; @@ -496,9 +482,9 @@ igraph_error_t igraph_is_connected(const igraph_t *graph, igraph_bool_t *res, } static igraph_error_t igraph_i_is_connected_weak(const igraph_t *graph, igraph_bool_t *res) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t added_count; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t added_count; igraph_bitset_t already_added; igraph_vector_int_t neis; igraph_dqueue_int_t q; @@ -528,13 +514,15 @@ static igraph_error_t igraph_i_is_connected_weak(const igraph_t *graph, igraph_b while (! igraph_dqueue_int_empty(&q)) { IGRAPH_ALLOW_INTERRUPTION(); - const igraph_integer_t actnode = igraph_dqueue_int_pop(&q); + const igraph_int_t actnode = igraph_dqueue_int_pop(&q); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, IGRAPH_ALL)); - const igraph_integer_t nei_count = igraph_vector_int_size(&neis); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, actnode, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); + const igraph_int_t nei_count = igraph_vector_int_size(&neis); - for (igraph_integer_t i = 0; i < nei_count; i++) { - const igraph_integer_t neighbor = VECTOR(neis)[i]; + for (igraph_int_t i = 0; i < nei_count; i++) { + const igraph_int_t neighbor = VECTOR(neis)[i]; if (IGRAPH_BIT_TEST(already_added, neighbor)) { continue; } @@ -571,41 +559,13 @@ static igraph_error_t igraph_i_is_connected_weak(const igraph_t *graph, igraph_b return IGRAPH_SUCCESS; } -/** - * \function igraph_decompose_destroy - * \brief Frees the contents of a pointer vector holding graphs. - * - * This function destroys and frees all igraph_t - * objects held in \p complist. However, it does not destroy - * \p complist itself. Use \ref igraph_vector_ptr_destroy() to destroy - * \p complist. - * - * \param complist The list of graphs to destroy. - * - * Time complexity: O(n), n is the number of items. - * - * \deprecated 0.10.0 - */ - -void igraph_decompose_destroy(igraph_vector_ptr_t *complist) { - igraph_integer_t i, n; - - n = igraph_vector_ptr_size(complist); - for (i = 0; i < n; i++) { - if (VECTOR(*complist)[i] != 0) { - igraph_destroy(VECTOR(*complist)[i]); - IGRAPH_FREE(VECTOR(*complist)[i]); - } - } -} - static igraph_error_t igraph_i_decompose_weak(const igraph_t *graph, igraph_graph_list_t *components, - igraph_integer_t maxcompno, igraph_integer_t minelements); + igraph_int_t maxcompno, igraph_int_t minelements); static igraph_error_t igraph_i_decompose_strong(const igraph_t *graph, igraph_graph_list_t *components, - igraph_integer_t maxcompno, igraph_integer_t minelements); + igraph_int_t maxcompno, igraph_int_t minelements); /** * \function igraph_decompose @@ -642,7 +602,7 @@ static igraph_error_t igraph_i_decompose_strong(const igraph_t *graph, igraph_error_t igraph_decompose(const igraph_t *graph, igraph_graph_list_t *components, igraph_connectedness_t mode, - igraph_integer_t maxcompno, igraph_integer_t minelements) { + igraph_int_t maxcompno, igraph_int_t minelements) { if (!igraph_is_directed(graph)) { mode = IGRAPH_WEAK; } @@ -659,17 +619,17 @@ igraph_error_t igraph_decompose(const igraph_t *graph, igraph_graph_list_t *comp static igraph_error_t igraph_i_decompose_weak(const igraph_t *graph, igraph_graph_list_t *components, - igraph_integer_t maxcompno, igraph_integer_t minelements) { + igraph_int_t maxcompno, igraph_int_t minelements) { - igraph_integer_t actstart; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t resco = 0; /* number of graphs created so far */ + igraph_int_t actstart; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t resco = 0; /* number of graphs created so far */ igraph_bitset_t already_added; igraph_dqueue_int_t q; igraph_vector_int_t verts; igraph_vector_int_t neis; igraph_vector_int_t vids_old2new; - igraph_integer_t i; + igraph_int_t i; igraph_t newg; @@ -685,6 +645,7 @@ static igraph_error_t igraph_i_decompose_weak(const igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&verts, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&vids_old2new, no_of_nodes); + igraph_vector_int_fill(&vids_old2new, -1); /* vids_old2new would have been created internally in igraph_induced_subgraph(), but it is slow if the graph is large and consists of many small components, @@ -709,12 +670,14 @@ static igraph_error_t igraph_i_decompose_weak(const igraph_t *graph, /* add the neighbors, recursively */ while (!igraph_dqueue_int_empty(&q) ) { /* pop from the queue of this component */ - igraph_integer_t actvert = igraph_dqueue_int_pop(&q); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, actvert, IGRAPH_ALL)); - igraph_integer_t nei_count = igraph_vector_int_size(&neis); + igraph_int_t actvert = igraph_dqueue_int_pop(&q); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, actvert, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); + igraph_int_t nei_count = igraph_vector_int_size(&neis); /* iterate over the neighbors */ for (i = 0; i < nei_count; i++) { - igraph_integer_t neighbor = VECTOR(neis)[i]; + igraph_int_t neighbor = VECTOR(neis)[i]; if (IGRAPH_BIT_TEST(already_added, neighbor)) { continue; } @@ -735,7 +698,7 @@ static igraph_error_t igraph_i_decompose_weak(const igraph_t *graph, IGRAPH_CHECK(igraph_i_induced_subgraph_map( graph, &newg, igraph_vss_vector(&verts), IGRAPH_SUBGRAPH_AUTO, &vids_old2new, - /* invmap = */ 0, /* map_is_prepared = */ 1 + /* invmap = */ NULL, /* map_is_prepared = */ true )); IGRAPH_FINALLY(igraph_destroy, &newg); IGRAPH_CHECK(igraph_graph_list_push_back(components, &newg)); @@ -761,19 +724,19 @@ static igraph_error_t igraph_i_decompose_weak(const igraph_t *graph, static igraph_error_t igraph_i_decompose_strong(const igraph_t *graph, igraph_graph_list_t *components, - igraph_integer_t maxcompno, igraph_integer_t minelements) { + igraph_int_t maxcompno, igraph_int_t minelements) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); /* this is a heap used twice for checking what nodes have * been counted already */ igraph_vector_int_t next_nei = IGRAPH_VECTOR_NULL; - igraph_integer_t i, n, num_seen; + igraph_int_t i, n, num_seen; igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; - igraph_integer_t no_of_components = 0; + igraph_int_t no_of_components = 0; igraph_vector_int_t out = IGRAPH_VECTOR_NULL; const igraph_vector_int_t* tmp; @@ -792,6 +755,8 @@ static igraph_error_t igraph_i_decompose_strong(const igraph_t *graph, /* The result */ IGRAPH_VECTOR_INT_INIT_FINALLY(&vids_old2new, no_of_nodes); + igraph_vector_int_fill(&vids_old2new, -1); + IGRAPH_VECTOR_INT_INIT_FINALLY(&verts, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&next_nei, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&out, 0); @@ -830,7 +795,7 @@ static igraph_error_t igraph_i_decompose_strong(const igraph_t *graph, * until there is no more */ while (!igraph_dqueue_int_empty(&q)) { /* this looks up but does NOT consume the queue */ - igraph_integer_t act_node = igraph_dqueue_int_back(&q); + igraph_int_t act_node = igraph_dqueue_int_back(&q); /* get all neighbors of this node */ tmp = igraph_adjlist_get(&adjlist, act_node); @@ -842,7 +807,7 @@ static igraph_error_t igraph_i_decompose_strong(const igraph_t *graph, } else if (VECTOR(next_nei)[act_node] <= igraph_vector_int_size(tmp)) { /* we've already met this vertex but it has more children */ - igraph_integer_t neighbor = VECTOR(*tmp)[VECTOR(next_nei)[act_node] - 1]; + igraph_int_t neighbor = VECTOR(*tmp)[VECTOR(next_nei)[act_node] - 1]; if (VECTOR(next_nei)[neighbor] == 0) { /* add the root of the other children to the queue */ IGRAPH_CHECK(igraph_dqueue_int_push(&q, neighbor)); @@ -882,7 +847,7 @@ static igraph_error_t igraph_i_decompose_strong(const igraph_t *graph, num_seen = 0; while (!igraph_vector_int_empty(&out) && no_of_components < maxcompno) { /* consume the vector from the last element */ - igraph_integer_t grandfather = igraph_vector_int_pop_back(&out); + igraph_int_t grandfather = igraph_vector_int_pop_back(&out); /* been here, done that * NOTE: next_nei is initialized as [0, 0, ...] */ @@ -910,11 +875,11 @@ static igraph_error_t igraph_i_decompose_strong(const igraph_t *graph, while (!igraph_dqueue_int_empty(&q)) { /* consume the queue from this node */ - igraph_integer_t act_node = igraph_dqueue_int_pop_back(&q); + igraph_int_t act_node = igraph_dqueue_int_pop_back(&q); tmp = igraph_adjlist_get(&adjlist, act_node); n = igraph_vector_int_size(tmp); for (i = 0; i < n; i++) { - igraph_integer_t neighbor = VECTOR(*tmp)[i]; + igraph_int_t neighbor = VECTOR(*tmp)[i]; if (VECTOR(next_nei)[neighbor] != 0) { continue; } @@ -1065,13 +1030,13 @@ igraph_error_t igraph_articulation_points(const igraph_t *graph, igraph_vector_i */ igraph_error_t igraph_biconnected_components(const igraph_t *graph, - igraph_integer_t *no, + igraph_int_t *no, igraph_vector_int_list_t *tree_edges, igraph_vector_int_list_t *component_edges, igraph_vector_int_list_t *components, igraph_vector_int_t *articulation_points) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t nextptr; igraph_vector_int_t num, low; igraph_bitset_t found; @@ -1079,9 +1044,9 @@ igraph_error_t igraph_biconnected_components(const igraph_t *graph, igraph_stack_int_t path; igraph_stack_int_t edgestack; igraph_inclist_t inclist; - igraph_integer_t counter, rootdfs = 0; + igraph_int_t counter, rootdfs = 0; igraph_vector_int_t vertex_added; - igraph_integer_t comps = 0; + igraph_int_t comps = 0; igraph_vector_int_list_t *mycomponents = components, vcomponents; IGRAPH_VECTOR_INT_INIT_FINALLY(&nextptr, no_of_nodes); @@ -1117,7 +1082,7 @@ igraph_error_t igraph_biconnected_components(const igraph_t *graph, IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(mycomponents, 0); } - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(low)[i] != 0) { continue; /* already visited */ @@ -1130,16 +1095,16 @@ igraph_error_t igraph_biconnected_components(const igraph_t *graph, rootdfs = 0; VECTOR(low)[i] = VECTOR(num)[i] = counter++; while (!igraph_stack_int_empty(&path)) { - igraph_integer_t n; - igraph_integer_t act = igraph_stack_int_top(&path); - igraph_integer_t actnext = VECTOR(nextptr)[act]; + igraph_int_t n; + igraph_int_t act = igraph_stack_int_top(&path); + igraph_int_t actnext = VECTOR(nextptr)[act]; adjedges = igraph_inclist_get(&inclist, act); n = igraph_vector_int_size(adjedges); if (actnext < n) { /* Step down (maybe) */ - igraph_integer_t edge = VECTOR(*adjedges)[actnext]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, act); + igraph_int_t edge = VECTOR(*adjedges)[actnext]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, act); if (VECTOR(low)[nei] == 0) { if (act == i) { rootdfs++; @@ -1158,7 +1123,7 @@ igraph_error_t igraph_biconnected_components(const igraph_t *graph, /* Step up */ igraph_stack_int_pop(&path); if (!igraph_stack_int_empty(&path)) { - igraph_integer_t prev = igraph_stack_int_top(&path); + igraph_int_t prev = igraph_stack_int_top(&path); /* Update LOW value if needed */ if (VECTOR(low)[act] < VECTOR(low)[prev]) { VECTOR(low)[prev] = VECTOR(low)[act]; @@ -1187,9 +1152,9 @@ igraph_error_t igraph_biconnected_components(const igraph_t *graph, } while (!igraph_stack_int_empty(&edgestack)) { - igraph_integer_t e = igraph_stack_int_pop(&edgestack); - igraph_integer_t from = IGRAPH_FROM(graph, e); - igraph_integer_t to = IGRAPH_TO(graph, e); + igraph_int_t e = igraph_stack_int_pop(&edgestack); + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); if (tree_edges) { IGRAPH_CHECK(igraph_vector_int_push_back(v, e)); } @@ -1210,18 +1175,18 @@ igraph_error_t igraph_biconnected_components(const igraph_t *graph, if (component_edges) { igraph_vector_int_t *nodes = igraph_vector_int_list_get_ptr(mycomponents, comps - 1); - igraph_integer_t ii, no_vert = igraph_vector_int_size(nodes); + igraph_int_t ii, no_vert = igraph_vector_int_size(nodes); igraph_vector_int_t *vv; IGRAPH_CHECK(igraph_vector_int_list_push_back_new(component_edges, &vv)); for (ii = 0; ii < no_vert; ii++) { - igraph_integer_t vert = VECTOR(*nodes)[ii]; + igraph_int_t vert = VECTOR(*nodes)[ii]; igraph_vector_int_t *edges = igraph_inclist_get(&inclist, vert); - igraph_integer_t j, nn = igraph_vector_int_size(edges); + igraph_int_t j, nn = igraph_vector_int_size(edges); for (j = 0; j < nn; j++) { - igraph_integer_t e = VECTOR(*edges)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, e, vert); + igraph_int_t e = VECTOR(*edges)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, e, vert); if (VECTOR(vertex_added)[nei] == comps && nei < vert) { IGRAPH_CHECK(igraph_vector_int_push_back(vv, e)); } @@ -1265,8 +1230,6 @@ igraph_error_t igraph_biconnected_components(const igraph_t *graph, * \function igraph_is_biconnected * \brief Checks whether a graph is biconnected. * - * \experimental - * * A graph is biconnected if the removal of any single vertex (and * its incident edges) does not disconnect it. * @@ -1290,7 +1253,7 @@ igraph_error_t igraph_biconnected_components(const igraph_t *graph, igraph_error_t igraph_is_biconnected(const igraph_t *graph, igraph_bool_t *res) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t nextptr; igraph_vector_int_t num, low; igraph_stack_int_t path; @@ -1329,20 +1292,20 @@ igraph_error_t igraph_is_biconnected(const igraph_t *graph, igraph_bool_t *res) IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &inclist, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &inclist); - const igraph_integer_t root = 0; /* start DFS from vertex 0 */ - igraph_integer_t counter = 1; - igraph_integer_t rootdfs = 0; + const igraph_int_t root = 0; /* start DFS from vertex 0 */ + igraph_int_t counter = 1; + igraph_int_t rootdfs = 0; IGRAPH_CHECK(igraph_stack_int_push(&path, root)); VECTOR(low)[root] = VECTOR(num)[root] = counter++; while (!igraph_stack_int_empty(&path)) { - igraph_integer_t act = igraph_stack_int_top(&path); - igraph_integer_t actnext = VECTOR(nextptr)[act]; + igraph_int_t act = igraph_stack_int_top(&path); + igraph_int_t actnext = VECTOR(nextptr)[act]; const igraph_vector_int_t *neis = igraph_lazy_adjlist_get(&inclist, act); - const igraph_integer_t n = igraph_vector_int_size(neis); + const igraph_int_t n = igraph_vector_int_size(neis); if (actnext < n) { /* Step down (maybe) */ - igraph_integer_t nei = VECTOR(*neis)[actnext]; + igraph_int_t nei = VECTOR(*neis)[actnext]; if (VECTOR(low)[nei] == 0) { if (act == root) { rootdfs++; @@ -1360,7 +1323,7 @@ igraph_error_t igraph_is_biconnected(const igraph_t *graph, igraph_bool_t *res) /* Step up */ igraph_stack_int_pop(&path); if (!igraph_stack_int_empty(&path)) { - igraph_integer_t prev = igraph_stack_int_top(&path); + igraph_int_t prev = igraph_stack_int_top(&path); /* Update LOW value if needed */ if (VECTOR(low)[act] < VECTOR(low)[prev]) { VECTOR(low)[prev] = VECTOR(low)[act]; @@ -1442,14 +1405,14 @@ igraph_error_t igraph_bridges(const igraph_t *graph, igraph_vector_int_t *bridge Additionally, we use explicit stacks instead of recursion to avoid stack overflow. */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_inclist_t il; igraph_bitset_t visited; igraph_vector_int_t vis; /* vis[u] time when vertex u was first visited */ igraph_vector_int_t low; /* low[u] is the lowest visit time of vertices reachable from u */ igraph_vector_int_t incoming_edge; igraph_stack_int_t su, si; - igraph_integer_t time; + igraph_int_t time; IGRAPH_CHECK(igraph_inclist_init(graph, &il, IGRAPH_ALL, IGRAPH_LOOPS_TWICE)); IGRAPH_FINALLY(igraph_inclist_destroy, &il); @@ -1468,7 +1431,7 @@ igraph_error_t igraph_bridges(const igraph_t *graph, igraph_vector_int_t *bridge igraph_vector_int_clear(bridges); time = 0; - for (igraph_integer_t start = 0; start < no_of_nodes; ++start) { + for (igraph_int_t start = 0; start < no_of_nodes; ++start) { if (! IGRAPH_BIT_TEST(visited, start)) { /* Perform a DFS from 'start'. * The top of the su stack is u, the vertex currently being visited. @@ -1479,8 +1442,8 @@ igraph_error_t igraph_bridges(const igraph_t *graph, igraph_vector_int_t *bridge IGRAPH_CHECK(igraph_stack_int_push(&si, 0)); while (! igraph_stack_int_empty(&su)) { - igraph_integer_t u = igraph_stack_int_pop(&su); - igraph_integer_t i = igraph_stack_int_pop(&si); + igraph_int_t u = igraph_stack_int_pop(&su); + igraph_int_t i = igraph_stack_int_pop(&si); if (i == 0) { /* We are at the first step of visiting vertex u. */ @@ -1499,8 +1462,8 @@ igraph_error_t igraph_bridges(const igraph_t *graph, igraph_vector_int_t *bridge IGRAPH_CHECK(igraph_stack_int_push(&su, u)); IGRAPH_CHECK(igraph_stack_int_push(&si, i+1)); - igraph_integer_t edge = VECTOR(*incedges)[i]; - igraph_integer_t v = IGRAPH_OTHER(graph, edge, u); + igraph_int_t edge = VECTOR(*incedges)[i]; + igraph_int_t v = IGRAPH_OTHER(graph, edge, u); if (! IGRAPH_BIT_TEST(visited, v)) { VECTOR(incoming_edge)[v] = edge; @@ -1515,9 +1478,9 @@ igraph_error_t igraph_bridges(const igraph_t *graph, igraph_vector_int_t *bridge * We are ready to update the 'low' value of its parent w, and decide * whether its incoming edge is a bridge. */ - igraph_integer_t edge = VECTOR(incoming_edge)[u]; + igraph_int_t edge = VECTOR(incoming_edge)[u]; if (edge >= 0) { - igraph_integer_t w = IGRAPH_OTHER(graph, edge, u); /* parent of u in DFS tree */ + igraph_int_t w = IGRAPH_OTHER(graph, edge, u); /* parent of u in DFS tree */ VECTOR(low)[w] = VECTOR(low)[w] < VECTOR(low)[u] ? VECTOR(low)[w] : VECTOR(low)[u]; if (VECTOR(low)[u] > VECTOR(vis)[w]) { IGRAPH_CHECK(igraph_vector_int_push_back(bridges, edge)); @@ -1589,14 +1552,14 @@ igraph_error_t igraph_bridges(const igraph_t *graph, igraph_vector_int_t *bridge * vertices; \ref igraph_neighborhood() to find vertices within a given distance. */ igraph_error_t igraph_subcomponent( - const igraph_t *graph, igraph_vector_int_t *res, igraph_integer_t vertex, + const igraph_t *graph, igraph_vector_int_t *res, igraph_int_t vertex, igraph_neimode_t mode ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; igraph_bitset_t already_added; - igraph_integer_t i, vsize; + igraph_int_t i, vsize; igraph_vector_int_t tmp = IGRAPH_VECTOR_NULL; if (vertex < 0 || vertex >= no_of_nodes) { @@ -1618,14 +1581,14 @@ igraph_error_t igraph_subcomponent( IGRAPH_BIT_SET(already_added, vertex); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); IGRAPH_ALLOW_INTERRUPTION(); - IGRAPH_CHECK(igraph_neighbors(graph, &tmp, actnode, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, &tmp, actnode, mode, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE)); vsize = igraph_vector_int_size(&tmp); for (i = 0; i < vsize; i++) { - igraph_integer_t neighbor = VECTOR(tmp)[i]; + igraph_int_t neighbor = VECTOR(tmp)[i]; if (IGRAPH_BIT_TEST(already_added, neighbor)) { continue; diff --git a/src/vendor/cigraph/src/connectivity/percolation.c b/src/vendor/cigraph/src/connectivity/percolation.c index d28b481031d..7534a97392d 100644 --- a/src/vendor/cigraph/src/connectivity/percolation.c +++ b/src/vendor/cigraph/src/connectivity/percolation.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2025 The igraph development team This program is free software; you can redistribute it and/or modify @@ -40,9 +40,9 @@ static void percolate_edge(igraph_vector_int_t *links, igraph_vector_int_t *sizes, - igraph_integer_t *biggest, - igraph_integer_t a, - igraph_integer_t b) { + igraph_int_t *biggest, + igraph_int_t a, + igraph_int_t b) { // Find head of each tree while (VECTOR(*links)[a] != a) { @@ -60,7 +60,7 @@ static void percolate_edge(igraph_vector_int_t *links, } // Make smaller child of larger - igraph_integer_t parent, child; + igraph_int_t parent, child; if (VECTOR(*sizes)[a] < VECTOR(*sizes)[b]) { parent = b; child = a; @@ -107,12 +107,12 @@ igraph_error_t igraph_edgelist_percolation( igraph_vector_int_t *giant_size, igraph_vector_int_t *vertex_count) { - igraph_integer_t biggest = 1; - igraph_integer_t vertices_added = 0; - igraph_integer_t lower, upper; + igraph_int_t biggest = 1; + igraph_int_t vertices_added = 0; + igraph_int_t lower, upper; int iter = 0; - igraph_integer_t ecount = igraph_vector_int_size(edges); + igraph_int_t ecount = igraph_vector_int_size(edges); if (ecount % 2 == 1) { IGRAPH_ERROR("Invalid edge list, odd number of elements.", IGRAPH_EINVAL); @@ -137,7 +137,7 @@ igraph_error_t igraph_edgelist_percolation( IGRAPH_ERROR("Invalid vertex ID.", IGRAPH_EINVVID); } - const igraph_integer_t vcount = upper + 1; + const igraph_int_t vcount = upper + 1; igraph_vector_int_t sizes; IGRAPH_VECTOR_INT_INIT_FINALLY(&sizes, vcount); @@ -145,14 +145,14 @@ igraph_error_t igraph_edgelist_percolation( igraph_vector_int_t links; IGRAPH_VECTOR_INT_INIT_FINALLY(&links, vcount); - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { VECTOR(sizes)[i] = -1; VECTOR(links)[i] = i; } - for (igraph_integer_t i = 0; i < ecount; i++) { - const igraph_integer_t from = VECTOR(*edges)[2*i]; - const igraph_integer_t to = VECTOR(*edges)[2*i + 1]; + for (igraph_int_t i = 0; i < ecount; i++) { + const igraph_int_t from = VECTOR(*edges)[2*i]; + const igraph_int_t to = VECTOR(*edges)[2*i + 1]; if (VECTOR(sizes)[from] == -1) { vertices_added++; VECTOR(sizes)[from] = 1; @@ -225,16 +225,16 @@ igraph_error_t igraph_bond_percolation( if (edge_order == NULL) { IGRAPH_CHECK(igraph_vector_int_init_range(&i_edge_order, 0, igraph_ecount(graph))); IGRAPH_FINALLY(igraph_vector_int_destroy, &i_edge_order); - IGRAPH_CHECK(igraph_vector_int_shuffle(&i_edge_order)); + igraph_vector_int_shuffle(&i_edge_order); p_edge_order = &i_edge_order; } else { // Verify that there are no duplicates. - const igraph_integer_t no_of_added_edges = igraph_vector_int_size(edge_order); + const igraph_int_t no_of_added_edges = igraph_vector_int_size(edge_order); igraph_bitset_t present_edges; IGRAPH_BITSET_INIT_FINALLY(&present_edges, no_of_added_edges); - for (igraph_integer_t i = 0; i < no_of_added_edges; i++) { + for (igraph_int_t i = 0; i < no_of_added_edges; i++) { if (IGRAPH_BIT_TEST(present_edges, VECTOR(*edge_order)[i])) { IGRAPH_ERROR("Duplicate edges in edge order vector.", IGRAPH_EINVAL); } @@ -247,7 +247,7 @@ igraph_error_t igraph_bond_percolation( // Initialize edge list. igraph_edges() will validate edge IDs. IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 2 * igraph_vector_int_size(p_edge_order)); - IGRAPH_CHECK(igraph_edges(graph, igraph_ess_vector(p_edge_order), &edges)); + IGRAPH_CHECK(igraph_edges(graph, igraph_ess_vector(p_edge_order), &edges, /* bycol = */ 0)); // Defer to igraph_edgelist_percolation() IGRAPH_CHECK(igraph_edgelist_percolation(&edges, giant_size, vertex_count)); @@ -267,9 +267,9 @@ igraph_error_t igraph_bond_percolation( static igraph_error_t percolate_site(const igraph_t *graph, igraph_vector_int_t *links, igraph_vector_int_t *sizes, - igraph_integer_t *biggest, - igraph_integer_t *edges_added, - igraph_integer_t vertex, + igraph_int_t *biggest, + igraph_int_t *edges_added, + igraph_int_t vertex, igraph_vector_int_t *neighbors) { if (VECTOR(*sizes)[vertex] != 0) { @@ -278,10 +278,10 @@ static igraph_error_t percolate_site(const igraph_t *graph, VECTOR(*sizes)[vertex] = 1; - IGRAPH_CHECK(igraph_neighbors(graph, neighbors, vertex, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors(graph, neighbors, vertex, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); - igraph_integer_t neighbor_count = igraph_vector_int_size(neighbors); - for (igraph_integer_t i = 0; i < neighbor_count; i++) { + igraph_int_t neighbor_count = igraph_vector_int_size(neighbors); + for (igraph_int_t i = 0; i < neighbor_count; i++) { // Do not add edges to vertices that have not been added. if (VECTOR(*sizes)[VECTOR(*neighbors)[i]] == 0) { continue; @@ -331,7 +331,7 @@ igraph_error_t igraph_site_percolation( igraph_vector_int_t *edge_count, const igraph_vector_int_t *vertex_order) { - const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_int_t vcount = igraph_vcount(graph); const igraph_vector_int_t *p_vertex_order; igraph_vector_int_t i_vertex_order; int iter = 0; @@ -340,16 +340,16 @@ igraph_error_t igraph_site_percolation( if (vertex_order == NULL) { IGRAPH_CHECK(igraph_vector_int_init_range(&i_vertex_order, 0, vcount)); IGRAPH_FINALLY(igraph_vector_int_destroy, &i_vertex_order); - IGRAPH_CHECK(igraph_vector_int_shuffle(&i_vertex_order)); + igraph_vector_int_shuffle(&i_vertex_order); p_vertex_order = &i_vertex_order; } else { p_vertex_order = vertex_order; } // Initialize variables - igraph_integer_t number_percolated = igraph_vector_int_size(p_vertex_order); - igraph_integer_t biggest = 1; // largest component size so far - igraph_integer_t edges_added = 0; // no. of edges added so far + igraph_int_t number_percolated = igraph_vector_int_size(p_vertex_order); + igraph_int_t biggest = 1; // largest component size so far + igraph_int_t edges_added = 0; // no. of edges added so far igraph_vector_int_t sizes; IGRAPH_VECTOR_INT_INIT_FINALLY(&sizes, vcount); @@ -357,7 +357,7 @@ igraph_error_t igraph_site_percolation( igraph_vector_int_t links; IGRAPH_VECTOR_INT_INIT_FINALLY(&links, vcount); - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { VECTOR(sizes)[i] = 0; VECTOR(links)[i] = i; } @@ -373,8 +373,8 @@ igraph_error_t igraph_site_percolation( } // Percolation - for (igraph_integer_t i = 0; i < number_percolated; i++) { - const igraph_integer_t vid = VECTOR(*p_vertex_order)[i]; + for (igraph_int_t i = 0; i < number_percolated; i++) { + const igraph_int_t vid = VECTOR(*p_vertex_order)[i]; if (vid < 0 || vid >= vcount) { IGRAPH_ERROR("Invalid vertex ID.", IGRAPH_EINVVID); } diff --git a/src/vendor/cigraph/src/connectivity/reachability.c b/src/vendor/cigraph/src/connectivity/reachability.c index 1b5560f36a8..06c2aa1b9a3 100644 --- a/src/vendor/cigraph/src/connectivity/reachability.c +++ b/src/vendor/cigraph/src/connectivity/reachability.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -30,8 +30,6 @@ * \function igraph_reachability * \brief Calculates which vertices are reachable from each vertex in the graph. * - * \experimental - * * The resulting list will contain one bitset for each strongly connected component. * The bitset for component i will have its j-th bit set, if vertex j is reachable * from some vertex in component i in 0 or more steps. @@ -67,7 +65,7 @@ * |C| is the number of strongly connected components (at most |V|), * |V| is the number of vertices, and * |E| is the number of edges respectively, - * and w is the bit width of \type igraph_integer_t, typically the + * and w is the bit width of \type igraph_int_t, typically the * word size of the machine (32 or 64). */ @@ -75,12 +73,12 @@ igraph_error_t igraph_reachability( const igraph_t *graph, igraph_vector_int_t *membership, igraph_vector_int_t *csize, - igraph_integer_t *no_of_components, + igraph_int_t *no_of_components, igraph_bitset_list_t *reach, igraph_neimode_t mode) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_comps; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_comps; igraph_adjlist_t adjlist, dag; if (mode != IGRAPH_ALL && mode != IGRAPH_OUT && mode != IGRAPH_IN) { @@ -101,10 +99,10 @@ igraph_error_t igraph_reachability( IGRAPH_CHECK(igraph_bitset_list_resize(reach, no_of_comps)); - for (igraph_integer_t comp = 0; comp < no_of_comps; comp++) { + for (igraph_int_t comp = 0; comp < no_of_comps; comp++) { IGRAPH_CHECK(igraph_bitset_resize(igraph_bitset_list_get_ptr(reach, comp), no_of_nodes)); } - for (igraph_integer_t v = 0; v < no_of_nodes; v++) { + for (igraph_int_t v = 0; v < no_of_nodes; v++) { IGRAPH_BIT_SET(*igraph_bitset_list_get_ptr(reach, VECTOR(*membership)[v]), v); } @@ -118,12 +116,12 @@ igraph_error_t igraph_reachability( IGRAPH_CHECK(igraph_adjlist_init_empty(&dag, no_of_comps)); IGRAPH_FINALLY(igraph_adjlist_destroy, &dag); - for (igraph_integer_t v = 0; v < no_of_nodes; v++) { + for (igraph_int_t v = 0; v < no_of_nodes; v++) { const igraph_vector_int_t *neighbours = igraph_adjlist_get(&adjlist, v); igraph_vector_int_t *dag_neighbours = igraph_adjlist_get(&dag, VECTOR(*membership)[v]); - const igraph_integer_t n = igraph_vector_int_size(neighbours); - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t w = VECTOR(*neighbours)[i]; + const igraph_int_t n = igraph_vector_int_size(neighbours); + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t w = VECTOR(*neighbours)[i]; if (VECTOR(*membership)[v] != VECTOR(*membership)[w]) { IGRAPH_CHECK(igraph_vector_int_push_back(dag_neighbours, VECTOR(*membership)[w])); } @@ -132,12 +130,12 @@ igraph_error_t igraph_reachability( /* Iterate through strongly connected components in reverser topological order, * exploiting the fact that they are indexed in topological order. */ - for (igraph_integer_t i = 0; i < no_of_comps; i++) { - const igraph_integer_t comp = mode == IGRAPH_IN ? i : no_of_comps - i - 1; + for (igraph_int_t i = 0; i < no_of_comps; i++) { + const igraph_int_t comp = mode == IGRAPH_IN ? i : no_of_comps - i - 1; const igraph_vector_int_t *dag_neighbours = igraph_adjlist_get(&dag, comp); igraph_bitset_t *from_bitset = igraph_bitset_list_get_ptr(reach, comp); - const igraph_integer_t n = igraph_vector_int_size(dag_neighbours); - for (igraph_integer_t j = 0; j < n; j++) { + const igraph_int_t n = igraph_vector_int_size(dag_neighbours); + for (igraph_int_t j = 0; j < n; j++) { const igraph_bitset_t *to_bitset = igraph_bitset_list_get_ptr(reach, VECTOR(*dag_neighbours)[j]); igraph_bitset_or(from_bitset, from_bitset, to_bitset); } @@ -156,8 +154,6 @@ igraph_error_t igraph_reachability( * \function igraph_count_reachable * \brief The number of vertices reachable from each vertex in the graph. * - * \experimental - * * \param graph The graph object to analyze. * \param counts Integer vector. counts[v] will store the number * of vertices reachable from vertex \c v, including \c v itself. @@ -176,7 +172,7 @@ igraph_error_t igraph_reachability( * |C| is the number of strongly connected components (at most |V|), * |V| is the number of vertices, and * |E| is the number of edges respectively, - * and w is the bit width of \type igraph_integer_t, typically the + * and w is the bit width of \type igraph_int_t, typically the * word size of the machine (32 or 64). */ @@ -185,7 +181,7 @@ igraph_error_t igraph_count_reachable(const igraph_t *graph, igraph_neimode_t mode) { igraph_vector_int_t membership; - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_bitset_list_t reach; IGRAPH_VECTOR_INT_INIT_FINALLY(&membership, 0); @@ -194,7 +190,7 @@ igraph_error_t igraph_count_reachable(const igraph_t *graph, IGRAPH_CHECK(igraph_reachability(graph, &membership, NULL, NULL, &reach, mode)); IGRAPH_CHECK(igraph_vector_int_resize(counts, igraph_vcount(graph))); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { VECTOR(*counts)[i] = igraph_bitset_popcount(igraph_bitset_list_get_ptr(&reach, VECTOR(membership)[i])); } @@ -211,8 +207,6 @@ igraph_error_t igraph_count_reachable(const igraph_t *graph, * \function igraph_transitive_closure * \brief Computes the transitive closure of a graph. * - * \experimental - * * The resulting graph will have an edge from vertex \c i to vertex \c j * if \c j is reachable from \c i. * @@ -229,7 +223,7 @@ igraph_error_t igraph_count_reachable(const igraph_t *graph, * |E| is the number of edges, respectively. */ igraph_error_t igraph_transitive_closure(const igraph_t *graph, igraph_t *closure) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); const igraph_bool_t directed = igraph_is_directed(graph); igraph_vector_int_t membership, edges; igraph_bitset_list_t reach; @@ -240,9 +234,9 @@ igraph_error_t igraph_transitive_closure(const igraph_t *graph, igraph_t *closur IGRAPH_CHECK(igraph_reachability(graph, &membership, NULL, NULL, &reach, IGRAPH_OUT)); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - for (igraph_integer_t u = 0; u < no_of_nodes; u++) { + for (igraph_int_t u = 0; u < no_of_nodes; u++) { const igraph_bitset_t *row = igraph_bitset_list_get_ptr(&reach, VECTOR(membership)[u]); - for (igraph_integer_t v = directed ? 0 : u + 1; v < no_of_nodes; v++) { + for (igraph_int_t v = directed ? 0 : u + 1; v < no_of_nodes; v++) { if (u != v && IGRAPH_BIT_TEST(*row, v)) { IGRAPH_CHECK(igraph_vector_int_push_back(&edges, u)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, v)); diff --git a/src/vendor/cigraph/src/connectivity/separators.c b/src/vendor/cigraph/src/connectivity/separators.c index ece42ecfc13..5c52d217a94 100644 --- a/src/vendor/cigraph/src/connectivity/separators.c +++ b/src/vendor/cigraph/src/connectivity/separators.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -55,7 +54,7 @@ static igraph_error_t igraph_i_is_separator( igraph_bool_t *is_minimal ) { - const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_int_t vcount = igraph_vcount(graph); /* mark[v] means: * @@ -69,7 +68,7 @@ static igraph_error_t igraph_i_is_separator( igraph_vector_int_t neis; igraph_dqueue_int_t Q; igraph_vit_t vit; - igraph_integer_t S_size = 0, S_visited_count = 0; + igraph_int_t S_size = 0, S_visited_count = 0; IGRAPH_CHECK(igraph_vit_create(graph, S, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); @@ -86,7 +85,7 @@ static igraph_error_t igraph_i_is_separator( /* Mark and count vertices in S, taking care not to double-count * when duplicate vertices were passed in. */ for (; ! IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) { - const igraph_integer_t u = IGRAPH_VIT_GET(vit); + const igraph_int_t u = IGRAPH_VIT_GET(vit); if (! IN_S(u)) { SET_IN_S(u); S_size++; @@ -104,7 +103,7 @@ static igraph_error_t igraph_i_is_separator( for (IGRAPH_VIT_RESET(vit); ! IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) { - const igraph_integer_t u = IGRAPH_VIT_GET(vit); + const igraph_int_t u = IGRAPH_VIT_GET(vit); if (VISITED(u)) { continue; } @@ -133,10 +132,10 @@ static igraph_error_t igraph_i_is_separator( */ /* Sum of in-degrees of visited vertices in S. */ - igraph_integer_t degsum = 0; + igraph_int_t degsum = 0; /* Number of in-edges of vertices in S that were traversed. */ - igraph_integer_t edgecount = 0; + igraph_int_t edgecount = 0; /* Have we already traversed an edge leaving S? */ igraph_bool_t exited = false; @@ -144,23 +143,25 @@ static igraph_error_t igraph_i_is_separator( IGRAPH_CHECK(igraph_dqueue_int_push(&Q, u)); while (! igraph_dqueue_int_empty(&Q)) { - const igraph_integer_t v = igraph_dqueue_int_pop(&Q); + const igraph_int_t v = igraph_dqueue_int_pop(&Q); if (VISITED(v)) { continue; } SET_VISITED(v); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, v, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); - const igraph_integer_t dv = igraph_vector_int_size(&neis); + const igraph_int_t dv = igraph_vector_int_size(&neis); if (IN_S(v)) { degsum += dv; S_visited_count++; } - for (igraph_integer_t i=0; i < dv; i++) { - const igraph_integer_t w = VECTOR(neis)[i]; + for (igraph_int_t i=0; i < dv; i++) { + const igraph_int_t w = VECTOR(neis)[i]; /* Decide whether to traverse the v -> w edge. */ if (!exited || !IN_S(v) || IN_S(w)) { @@ -230,18 +231,20 @@ static igraph_error_t igraph_i_is_separator( #define FLIP_REACHED(x) (VECTOR(mark)[x] ^= 4) /* Flip the reachability status of x in S. */ for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) { - const igraph_integer_t u = IGRAPH_VIT_GET(vit); - IGRAPH_CHECK(igraph_neighbors(graph, &Sneis, u, IGRAPH_ALL)); - const igraph_integer_t du = igraph_vector_int_size(&Sneis); - for (igraph_integer_t i=0; i < du; i++) { - - igraph_integer_t v = VECTOR(Sneis)[i]; + const igraph_int_t u = IGRAPH_VIT_GET(vit); + IGRAPH_CHECK(igraph_neighbors( + graph, &Sneis, u, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); + const igraph_int_t du = igraph_vector_int_size(&Sneis); + for (igraph_int_t i=0; i < du; i++) { + + igraph_int_t v = VECTOR(Sneis)[i]; if (VISITED(v)) { continue; } /* How many vertices in S were reachable from u? */ - igraph_integer_t S_reached = 0; + igraph_int_t S_reached = 0; IGRAPH_CHECK(igraph_dqueue_int_push(&Q, v)); while (! igraph_dqueue_int_empty(&Q)) { v = igraph_dqueue_int_pop(&Q); @@ -250,12 +253,14 @@ static igraph_error_t igraph_i_is_separator( } SET_VISITED(v); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, v, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); - const igraph_integer_t dv = igraph_vector_int_size(&neis); + const igraph_int_t dv = igraph_vector_int_size(&neis); - for (igraph_integer_t j=0; j < dv; j++) { - const igraph_integer_t w = VECTOR(neis)[j]; + for (igraph_int_t j=0; j < dv; j++) { + const igraph_int_t w = VECTOR(neis)[j]; if (! VISITED(w)) { IGRAPH_CHECK(igraph_dqueue_int_push(&Q, w)); @@ -367,14 +372,14 @@ igraph_error_t igraph_is_minimal_separator(const igraph_t *graph, static igraph_error_t igraph_i_connected_components_leaveout(const igraph_adjlist_t *adjlist, igraph_vector_int_t *components, igraph_vector_int_t *leaveout, - igraph_integer_t *mark, + igraph_int_t *mark, igraph_dqueue_int_t *Q) { /* Another trick: we use the same 'leaveout' vector to mark the * vertices that were already found in the BFS */ - igraph_integer_t i, no_of_nodes = igraph_adjlist_size(adjlist); + igraph_int_t i, no_of_nodes = igraph_adjlist_size(adjlist); igraph_dqueue_int_clear(Q); igraph_vector_int_clear(components); @@ -390,11 +395,11 @@ static igraph_error_t igraph_i_connected_components_leaveout(const igraph_adjlis IGRAPH_CHECK(igraph_vector_int_push_back(components, i)); while (!igraph_dqueue_int_empty(Q)) { - igraph_integer_t act_node = igraph_dqueue_int_pop(Q); + igraph_int_t act_node = igraph_dqueue_int_pop(Q); igraph_vector_int_t *neis = igraph_adjlist_get(adjlist, act_node); - igraph_integer_t j, n = igraph_vector_int_size(neis); + igraph_int_t j, n = igraph_vector_int_size(neis); for (j = 0; j < n; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; if (VECTOR(*leaveout)[nei] == *mark) { continue; } @@ -416,7 +421,7 @@ static igraph_bool_t igraph_i_separators_is_not_seen_yet( const igraph_vector_int_list_t *comps, const igraph_vector_int_t *newc ) { - igraph_integer_t co, nocomps = igraph_vector_int_list_size(comps); + igraph_int_t co, nocomps = igraph_vector_int_list_size(comps); for (co = 0; co < nocomps; co++) { igraph_vector_int_t *act = igraph_vector_int_list_get_ptr(comps, co); @@ -433,17 +438,17 @@ static igraph_error_t igraph_i_separators_store(igraph_vector_int_list_t *separa const igraph_adjlist_t *adjlist, igraph_vector_int_t *components, igraph_vector_int_t *leaveout, - igraph_integer_t *mark, + igraph_int_t *mark, igraph_vector_int_t *sorter) { /* We need to store N(C), the neighborhood of C, but only if it is * not already stored among the separators. */ - igraph_integer_t cptr = 0, next, complen = igraph_vector_int_size(components); + igraph_int_t cptr = 0, next, complen = igraph_vector_int_size(components); while (cptr < complen) { - igraph_integer_t saved = cptr; + igraph_int_t saved = cptr; igraph_vector_int_clear(sorter); /* Calculate N(C) for the next C */ @@ -455,9 +460,9 @@ static igraph_error_t igraph_i_separators_store(igraph_vector_int_list_t *separa while ( (next = VECTOR(*components)[cptr++]) != -1) { igraph_vector_int_t *neis = igraph_adjlist_get(adjlist, next); - igraph_integer_t j, nn = igraph_vector_int_size(neis); + igraph_int_t j, nn = igraph_vector_int_size(neis); for (j = 0; j < nn; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; if (VECTOR(*leaveout)[nei] != *mark) { IGRAPH_CHECK(igraph_vector_int_push_back(sorter, nei)); VECTOR(*leaveout)[nei] = *mark; @@ -542,11 +547,11 @@ igraph_error_t igraph_all_minimal_st_separators( * The try_next pointer show the next separator to try as a basis. */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t leaveout; - igraph_integer_t try_next = 0; - igraph_integer_t mark = 1; - igraph_integer_t v; + igraph_int_t try_next = 0; + igraph_int_t mark = 1; + igraph_int_t v; igraph_adjlist_t adjlist; igraph_vector_int_t components; @@ -575,10 +580,10 @@ igraph_error_t igraph_all_minimal_st_separators( /* Mark v and its neighbors */ igraph_vector_int_t *neis = igraph_adjlist_get(&adjlist, v); - igraph_integer_t i, n = igraph_vector_int_size(neis); + igraph_int_t i, n = igraph_vector_int_size(neis); VECTOR(leaveout)[v] = mark; for (i = 0; i < n; i++) { - igraph_integer_t nei = VECTOR(*neis)[i]; + igraph_int_t nei = VECTOR(*neis)[i]; VECTOR(leaveout)[nei] = mark; } @@ -602,19 +607,19 @@ igraph_error_t igraph_all_minimal_st_separators( * mutate the vector_list later, and this can potentially invalidate * the pointer */ igraph_vector_int_t basis = *(igraph_vector_int_list_get_ptr(separators, try_next)); - igraph_integer_t b, basislen = igraph_vector_int_size(&basis); + igraph_int_t b, basislen = igraph_vector_int_size(&basis); for (b = 0; b < basislen; b++) { /* Remove N(x) U basis */ - igraph_integer_t x = VECTOR(basis)[b]; + igraph_int_t x = VECTOR(basis)[b]; igraph_vector_int_t *neis = igraph_adjlist_get(&adjlist, x); - igraph_integer_t i, n = igraph_vector_int_size(neis); + igraph_int_t i, n = igraph_vector_int_size(neis); for (i = 0; i < basislen; i++) { - igraph_integer_t sn = VECTOR(basis)[i]; + igraph_int_t sn = VECTOR(basis)[i]; VECTOR(leaveout)[sn] = mark; } for (i = 0; i < n; i++) { - igraph_integer_t nei = VECTOR(*neis)[i]; + igraph_int_t nei = VECTOR(*neis)[i]; VECTOR(leaveout)[nei] = mark; } @@ -649,8 +654,8 @@ static igraph_error_t igraph_i_minimum_size_separators_append( igraph_vector_int_list_t *old, igraph_vector_int_list_t *new ) { - igraph_integer_t olen = igraph_vector_int_list_size(old); - igraph_integer_t j; + igraph_int_t olen = igraph_vector_int_list_size(old); + igraph_int_t j; while (!igraph_vector_int_list_empty(new)) { igraph_vector_int_t *newvec = igraph_vector_int_list_tail_ptr(new); @@ -683,9 +688,9 @@ static igraph_error_t igraph_i_minimum_size_separators_append( * Finds the k largest degree vertices. */ static igraph_error_t igraph_i_minimum_size_separators_topkdeg( - const igraph_t *graph, igraph_vector_int_t *res, const igraph_integer_t k + const igraph_t *graph, igraph_vector_int_t *res, const igraph_int_t k ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t deg, order; IGRAPH_VECTOR_INT_INIT_FINALLY(°, no_of_nodes); @@ -695,9 +700,9 @@ static igraph_error_t igraph_i_minimum_size_separators_topkdeg( * faster IGRAPH_LOOPS here instead of the slower IGRAPH_NO_LOOPS. */ IGRAPH_CHECK(igraph_degree(graph, °, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS)); - IGRAPH_CHECK(igraph_vector_int_order1(°, &order, no_of_nodes)); + IGRAPH_CHECK(igraph_i_vector_int_order(°, &order, no_of_nodes)); IGRAPH_CHECK(igraph_vector_int_resize(res, k)); - for (igraph_integer_t i = 0; i < k; i++) { + for (igraph_int_t i = 0; i < k; i++) { VECTOR(*res)[i] = VECTOR(order)[no_of_nodes - 1 - i]; } @@ -716,6 +721,14 @@ static igraph_error_t igraph_i_minimum_size_separators_topkdeg( * A vertex set is a separator if its removal disconnects the graph. * * + * If the graph is already disconnected, no separators are returned. + * Note that this convention differs from that used by some other + * funtions such as \ref igraph_all_minimal_st_separators(). + * + * + * Complete graphs have no vertex separators. + * + * * The implementation is based on the following paper: * Arkady Kanevsky: Finding all minimum-size separating vertex sets in * a graph, Networks 23, 533--541, 1993. @@ -723,7 +736,7 @@ static igraph_error_t igraph_i_minimum_size_separators_topkdeg( * * \param graph The input graph, which must be undirected. * \param separators An initialized list of integer vectors, the separators - * are stored here. It is a list of pointers to igraph_vector_int_t + * are stored here. It is a list of pointers to \type igraph_vector_int_t * objects. Each vector will contain the IDs of the vertices in * the separator. The separators are returned in an arbitrary order. * \return Error code. @@ -737,11 +750,11 @@ igraph_error_t igraph_minimum_size_separators( const igraph_t *graph, igraph_vector_int_list_t *separators ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t conn; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t conn; igraph_vector_int_t X; - igraph_integer_t k, n; + igraph_int_t k, n; igraph_bool_t issepX; igraph_t Gbar; igraph_vector_t phi; @@ -762,8 +775,9 @@ igraph_error_t igraph_minimum_size_separators( k = conn; /* Special cases for low connectivity, two exits here! */ - if (conn == 0) { - /* Nothing to do */ + if (conn == 0 || conn == no_of_nodes - 1) { + /* Nothing to do on disconnected or complete graphs: + * there are no separators. */ return IGRAPH_SUCCESS; } else if (conn == 1) { igraph_vector_int_t ap; @@ -771,25 +785,13 @@ igraph_error_t igraph_minimum_size_separators( IGRAPH_CHECK(igraph_articulation_points(graph, &ap)); n = igraph_vector_int_size(&ap); IGRAPH_CHECK(igraph_vector_int_list_resize(separators, n)); - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { igraph_vector_int_t *v = igraph_vector_int_list_get_ptr(separators, i); IGRAPH_CHECK(igraph_vector_int_push_back(v, VECTOR(ap)[i])); } igraph_vector_int_destroy(&ap); IGRAPH_FINALLY_CLEAN(1); return IGRAPH_SUCCESS; - } else if (conn == no_of_nodes - 1) { - IGRAPH_CHECK(igraph_vector_int_list_resize(separators, no_of_nodes)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_vector_int_t *v = igraph_vector_int_list_get_ptr(separators, i); - IGRAPH_CHECK(igraph_vector_int_resize(v, no_of_nodes - 1)); - for (igraph_integer_t j = 0, k = 0; j < no_of_nodes; j++) { - if (j != i) { - VECTOR(*v)[k++] = j; - } - } - } - return IGRAPH_SUCCESS; } /* Work on a copy of 'graph' */ @@ -818,12 +820,12 @@ igraph_error_t igraph_minimum_size_separators( /* ---------------------------------------------------------------- */ /* 3 If v[j] != x[i] and v[j] is not adjacent to x[i] then */ - for (igraph_integer_t i = 0; i < k; i++) { + for (igraph_int_t i = 0; i < k; i++) { IGRAPH_ALLOW_INTERRUPTION(); - for (igraph_integer_t j = 0; j < no_of_nodes; j++) { - igraph_integer_t xi = VECTOR(X)[i]; + for (igraph_int_t j = 0; j < no_of_nodes; j++) { + igraph_int_t xi = VECTOR(X)[i]; igraph_real_t phivalue; igraph_bool_t conn; diff --git a/src/vendor/cigraph/src/constructors/adjacency.c b/src/vendor/cigraph/src/constructors/adjacency.c index 9b7ff671e26..7043e000237 100644 --- a/src/vendor/cigraph/src/constructors/adjacency.c +++ b/src/vendor/cigraph/src/constructors/adjacency.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -26,9 +25,9 @@ #include "igraph_interface.h" #include "igraph_sparsemat.h" -static igraph_error_t igraph_i_adjacency_directed( +static igraph_error_t igraph_i_adjacency_directed_or_plus( const igraph_matrix_t *adjmatrix, igraph_vector_int_t *edges, - igraph_loops_t loops + igraph_adjacency_t mode, igraph_loops_t loops ); static igraph_error_t igraph_i_adjacency_max( const igraph_matrix_t *adjmatrix, igraph_vector_int_t *edges, @@ -52,7 +51,7 @@ static igraph_error_t igraph_i_adjacency_min( ); static igraph_error_t igraph_i_adjust_loop_edge_count( - igraph_integer_t* count, igraph_loops_t loops + igraph_int_t* count, igraph_loops_t loops ) { /* The compiler should be smart enough to figure out that this can be * inlined */ @@ -74,21 +73,25 @@ static igraph_error_t igraph_i_adjust_loop_edge_count( return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_adjacency_directed( +static igraph_error_t igraph_i_adjacency_directed_or_plus( const igraph_matrix_t *adjmatrix, igraph_vector_int_t *edges, - igraph_loops_t loops + igraph_adjacency_t mode, igraph_loops_t loops ) { + const igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j, k; + /* For sake of consistency with the rest of the library, IGRAPH_LOOPS_TWICE + * is treated as IGRAPH_LOOPS_ONCE for directed graphs */ + if (mode == IGRAPH_ADJ_DIRECTED && loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } - for (i = 0; i < no_of_nodes; i++) { - for (j = 0; j < no_of_nodes; j++) { - igraph_integer_t M = MATRIX(*adjmatrix, i, j); + for (igraph_int_t j = 0; j < no_of_nodes; j++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t M = MATRIX(*adjmatrix, i, j); if (i == j) { IGRAPH_CHECK(igraph_i_adjust_loop_edge_count(&M, loops)); } - for (k = 0; k < M; k++) { + for (igraph_int_t k = 0; k < M; k++) { IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); } @@ -103,8 +106,8 @@ static igraph_error_t igraph_i_adjacency_max( igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j, k, M1, M2; + igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); + igraph_int_t i, j, k, M1, M2; for (i = 0; i < no_of_nodes; i++) { /* do the loops first */ @@ -152,25 +155,35 @@ static igraph_error_t igraph_i_adjacency_upper( igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j, k, M; + const igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); + igraph_int_t M; + + /* IGRAPH_LOOPS_TWICE is treated as IGRAPH_LOOPS_ONCE -- it makes no sense + * for loops to appear twice in the adjacency matrix when the lower triangle + * is empty; double-counting of loops in undirected graphs happens because + * the upper and the lower triangle are added on top of each other on the + * diagonal. See discussion in #2501: + * + * https://github.com/igraph/igraph/issues/2501#issuecomment-1949345675 */ + if (loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } - for (i = 0; i < no_of_nodes; i++) { - /* do the loops first */ - M = MATRIX(*adjmatrix, i, i); - if (M) { - IGRAPH_CHECK(igraph_i_adjust_loop_edge_count(&M, loops)); - for (k = 0; k < M; k++) { - IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + for (igraph_int_t j = 0; j < no_of_nodes; j++) { + for (igraph_int_t i = 0; i < j; i++) { + M = MATRIX(*adjmatrix, i, j); + for (igraph_int_t k = 0; k < M; k++) { IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); } } - /* then the rest */ - for (j = i + 1; j < no_of_nodes; j++) { - M = MATRIX(*adjmatrix, i, j); - for (k = 0; k < M; k++) { - IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + /* do the loops as well */ + M = MATRIX(*adjmatrix, j, j); + if (M) { + IGRAPH_CHECK(igraph_i_adjust_loop_edge_count(&M, loops)); + for (igraph_int_t k = 0; k < M; k++) { + IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); } } @@ -183,25 +196,36 @@ static igraph_error_t igraph_i_adjacency_lower( igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j, k, M; + const igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); + igraph_int_t M; + + /* IGRAPH_LOOPS_TWICE is treated as IGRAPH_LOOPS_ONCE -- it makes no sense + * for loops to appear twice in the adjacency matrix when the lower triangle + * is empty; double-counting of loops in undirected graphs happens because + * the upper and the lower triangle are added on top of each other on the + * diagonal. See discussion in #2501: + * + * https://github.com/igraph/igraph/issues/2501#issuecomment-1949345675 */ + if (loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } - for (i = 0; i < no_of_nodes; i++) { - for (j = 0; j < i; j++) { - M = MATRIX(*adjmatrix, i, j); - for (k = 0; k < M; k++) { - IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + for (igraph_int_t j = 0; j < no_of_nodes; j++) { + /* do the loops first */ + M = MATRIX(*adjmatrix, j, j); + if (M) { + IGRAPH_CHECK(igraph_i_adjust_loop_edge_count(&M, loops)); + for (igraph_int_t k = 0; k < M; k++) { + IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); } } - /* do the loops as well */ - M = MATRIX(*adjmatrix, i, i); - if (M) { - IGRAPH_CHECK(igraph_i_adjust_loop_edge_count(&M, loops)); - for (k = 0; k < M; k++) { - IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + for (igraph_int_t i = j+1; i < no_of_nodes; i++) { + M = MATRIX(*adjmatrix, i, j); + for (igraph_int_t k = 0; k < M; k++) { IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); } } } @@ -213,8 +237,8 @@ static igraph_error_t igraph_i_adjacency_min( igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j, k, M1, M2; + igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); + igraph_int_t i, j, k, M1, M2; for (i = 0; i < no_of_nodes; i++) { /* do the loops first */ @@ -253,7 +277,9 @@ static igraph_error_t igraph_i_adjacency_min( * * The order of the vertices in the matrix is preserved, i.e. the vertex * corresponding to the first row/column will be vertex with id 0, the - * next row is for vertex 1, etc. + * next row is for vertex 1, etc. No guarantees are given about the ordering + * of edges. + * * \param graph Pointer to an uninitialized graph object. * \param adjmatrix The adjacency matrix. How it is interpreted * depends on the \p mode argument. @@ -262,35 +288,31 @@ static igraph_error_t igraph_i_adjacency_min( * row i and column j in the adjacency matrix \p adjmatrix): * \clist * \cli IGRAPH_ADJ_DIRECTED - * The graph will be directed and - * an element gives the number of edges between two vertices. + * The graph will be directed and an element gives the number of edges + * between two vertices. * \cli IGRAPH_ADJ_UNDIRECTED - * The graph will be undirected and - * an element gives the number of edges between two vertices. - * If the input matrix is not symmetric, an error is thrown. + * The graph will be undirected and an element gives the number of + * edges between two vertices. If the input matrix is not symmetric, + * an error is thrown. * \cli IGRAPH_ADJ_MAX - * An undirected graph will be created - * and the number of edges between vertices - * i and j is max(A(i,j), A(j,i)). + * An undirected graph will be created and the number of edges between + * vertices i and j is max(A(i,j), A(j,i)). * \cli IGRAPH_ADJ_MIN - * An undirected graph will be created - * with min(A(i,j), A(j,i)) - * edges between vertices i and j. + * An undirected graph will be created with min(A(i,j), A(j,i)) edges + * between vertices i and j. * \cli IGRAPH_ADJ_PLUS - * An undirected graph will be created - * with A(i,j)+A(j,i) edges + * An undirected graph will be created with A(i,j)+A(j,i) edges * between vertices i and j. * \cli IGRAPH_ADJ_UPPER - * An undirected graph will be created. - * Only the upper right triangle (including the diagonal) is - * used for the number of edges. + * An undirected graph will be created. Only the upper right triangle + * (including the diagonal) is used for the number of edges. * \cli IGRAPH_ADJ_LOWER - * An undirected graph will be created. - * Only the lower left triangle (including the diagonal) is - * used for the number of edges. + * An undirected graph will be created. Only the lower left triangle + * (including the diagonal) is used for the number of edges. * \endclist - * \param loops Constant to specify how the diagonal of the matrix should be - * treated when creating loop edges. + * \param loops Constant of type \ref igraph_loops_t to specify how the diagonal + * of the matrix should be treated when creating loop edges. Ignored for + * modes \c IGRAPH_ADJ_DIRECTED, \c IGRAPH_ADJ_UPPER and \c IGRAPH_ADJ_LOWER. * \clist * \cli IGRAPH_NO_LOOPS * Ignore the diagonal of the input matrix and do not create loops. @@ -303,14 +325,12 @@ static igraph_error_t igraph_i_adjacency_min( * will return an error code. * \endclist * \return Error code, - * \c IGRAPH_NONSQUARE: non-square matrix. - * \c IGRAPH_EINVAL: Negative entry was found in adjacency matrix, or an - * odd number was found in the diagonal with \c IGRAPH_LOOPS_TWICE + * \c IGRAPH_EINVAL: Non-square adjacency matrix, negative entry in + * adjacency matrix, or an odd number was found in the diagonal with + * \c IGRAPH_LOOPS_TWICE * * Time complexity: O(|V||V|), * |V| is the number of vertices in the graph. - * - * \example examples/simple/igraph_adjacency.c */ igraph_error_t igraph_adjacency( igraph_t *graph, const igraph_matrix_t *adjmatrix, igraph_adjacency_t mode, @@ -318,11 +338,11 @@ igraph_error_t igraph_adjacency( ) { igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); + igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); /* Some checks */ if (igraph_matrix_nrow(adjmatrix) != igraph_matrix_ncol(adjmatrix)) { - IGRAPH_ERROR("Adjacency matrices must be square.", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Adjacency matrices must be square.", IGRAPH_EINVAL); } if (no_of_nodes != 0 && igraph_matrix_min(adjmatrix) < 0) { @@ -336,7 +356,8 @@ igraph_error_t igraph_adjacency( no_of_nodes = igraph_matrix_nrow(adjmatrix); switch (mode) { case IGRAPH_ADJ_DIRECTED: - IGRAPH_CHECK(igraph_i_adjacency_directed(adjmatrix, &edges, loops)); + case IGRAPH_ADJ_PLUS: + IGRAPH_CHECK(igraph_i_adjacency_directed_or_plus(adjmatrix, &edges, mode, loops)); break; case IGRAPH_ADJ_MAX: IGRAPH_CHECK(igraph_i_adjacency_max(adjmatrix, &edges, loops)); @@ -353,9 +374,6 @@ igraph_error_t igraph_adjacency( case IGRAPH_ADJ_MIN: IGRAPH_CHECK(igraph_i_adjacency_min(adjmatrix, &edges, loops)); break; - case IGRAPH_ADJ_PLUS: - IGRAPH_CHECK(igraph_i_adjacency_directed(adjmatrix, &edges, loops)); - break; default: IGRAPH_ERROR("Invalid adjacency mode.", IGRAPH_EINVAL); } @@ -427,11 +445,16 @@ static igraph_error_t igraph_i_weighted_adjacency_directed( igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j; + const igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - for (i = 0; i < no_of_nodes; i++) { - for (j = 0; j < no_of_nodes; j++) { + /* For sake of consistency with the rest of the library, IGRAPH_LOOPS_TWICE + * is treated as IGRAPH_LOOPS_ONCE for directed graphs */ + if (loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } + + for (igraph_int_t j = 0; j < no_of_nodes; j++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { igraph_real_t M = MATRIX(*adjmatrix, i, j); if (M != 0.0) { if (i == j) { @@ -457,8 +480,8 @@ static igraph_error_t igraph_i_weighted_adjacency_plus( igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j; + igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); + igraph_int_t i, j; igraph_real_t M; for (i = 0; i < no_of_nodes; i++) { @@ -492,8 +515,8 @@ static igraph_error_t igraph_i_weighted_adjacency_max( igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j; + igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); + igraph_int_t i, j; igraph_real_t M1, M2; for (i = 0; i < no_of_nodes; i++) { @@ -534,20 +557,35 @@ static igraph_error_t igraph_i_weighted_adjacency_undirected( /* We do not use igraph_matrix_is_symmetric() for this check, as we need to * allow symmetric matrices with NaN values. igraph_matrix_is_symmetric() * returns false for these as NaN != NaN. */ - igraph_integer_t n = igraph_matrix_nrow(adjmatrix); - for (igraph_integer_t i=0; i < n; i++) { - for (igraph_integer_t j=0; j < i; j++) { - igraph_real_t a1 = MATRIX(*adjmatrix, i, j); - igraph_real_t a2 = MATRIX(*adjmatrix, j, i); - if (a1 != a2 && ! (isnan(a1) && isnan(a2))) { + const igraph_int_t n = igraph_matrix_nrow(adjmatrix); + for (igraph_int_t i=0; i < n; i++) { + /* do the loops first */ + if (loops) { + igraph_real_t M = MATRIX(*adjmatrix, i, i); + if (M != 0.0) { + igraph_i_adjust_loop_edge_weight(&M, loops); + IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + IGRAPH_CHECK(igraph_vector_push_back(weights, M)); + } + } + + for (igraph_int_t j=0; j < i; j++) { + igraph_real_t M1 = MATRIX(*adjmatrix, i, j); + igraph_real_t M2 = MATRIX(*adjmatrix, j, i); + if (IGRAPH_UNLIKELY(M1 != M2 && ! (isnan(M1) && isnan(M2)))) { IGRAPH_ERROR( "Adjacency matrix should be symmetric to produce an undirected graph.", IGRAPH_EINVAL - ); + ); + } else if (M1 != 0.0) { + IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); + IGRAPH_CHECK(igraph_vector_push_back(weights, M1)); } } } - return igraph_i_weighted_adjacency_max(adjmatrix, edges, weights, loops); + return IGRAPH_SUCCESS; } @@ -558,27 +596,36 @@ static igraph_error_t igraph_i_weighted_adjacency_upper( igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j; + const igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); igraph_real_t M; - for (i = 0; i < no_of_nodes; i++) { - /* do the loops first */ - if (loops) { - M = MATRIX(*adjmatrix, i, i); + /* IGRAPH_LOOPS_TWICE is treated as IGRAPH_LOOPS_ONCE -- it makes no sense + * for loops to appear twice in the adjacency matrix when the lower triangle + * is empty; double-counting of loops in undirected graphs happens because + * the upper and the lower triangle are added on top of each other on the + * diagonal. See discussion in #2501: + * + * https://github.com/igraph/igraph/issues/2501#issuecomment-1949345675 */ + if (loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } + + for (igraph_int_t j = 0; j < no_of_nodes; j++) { + for (igraph_int_t i = 0; i < j; i++) { + igraph_real_t M = MATRIX(*adjmatrix, i, j); if (M != 0.0) { - igraph_i_adjust_loop_edge_weight(&M, loops); - IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); IGRAPH_CHECK(igraph_vector_push_back(weights, M)); } } - /* then the rest */ - for (j = i + 1; j < no_of_nodes; j++) { - igraph_real_t M = MATRIX(*adjmatrix, i, j); + /* do the loops as well */ + if (loops) { + M = MATRIX(*adjmatrix, j, j); if (M != 0.0) { - IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + igraph_i_adjust_loop_edge_weight(&M, loops); + IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); IGRAPH_CHECK(igraph_vector_push_back(weights, M)); } @@ -594,27 +641,37 @@ static igraph_error_t igraph_i_weighted_adjacency_lower( igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j; + const igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); igraph_real_t M; - for (i = 0; i < no_of_nodes; i++) { - for (j = 0; j < i; j++) { - M = MATRIX(*adjmatrix, i, j); + /* IGRAPH_LOOPS_TWICE is treated as IGRAPH_LOOPS_ONCE -- it makes no sense + * for loops to appear twice in the adjacency matrix when the lower triangle + * is empty; double-counting of loops in undirected graphs happens because + * the upper and the lower triangle are added on top of each other on the + * diagonal. See discussion in #2501: + * + * https://github.com/igraph/igraph/issues/2501#issuecomment-1949345675 */ + if (loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } + + for (igraph_int_t j = 0; j < no_of_nodes; j++) { + /* do the loops first */ + if (loops) { + M = MATRIX(*adjmatrix, j, j); if (M != 0.0) { - IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + igraph_i_adjust_loop_edge_weight(&M, loops); + IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); IGRAPH_CHECK(igraph_vector_push_back(weights, M)); } } - /* do the loops as well */ - if (loops) { - M = MATRIX(*adjmatrix, i, i); + for (igraph_int_t i = j+1; i < no_of_nodes; i++) { + M = MATRIX(*adjmatrix, i, j); if (M != 0.0) { - igraph_i_adjust_loop_edge_weight(&M, loops); - IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, i)); + IGRAPH_CHECK(igraph_vector_int_push_back(edges, j)); IGRAPH_CHECK(igraph_vector_push_back(weights, M)); } } @@ -629,8 +686,8 @@ static igraph_error_t igraph_i_weighted_adjacency_min( igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(adjmatrix); - igraph_integer_t i, j; + igraph_int_t no_of_nodes = igraph_matrix_nrow(adjmatrix); + igraph_int_t i, j; igraph_real_t M1, M2; for (i = 0; i < no_of_nodes; i++) { @@ -670,55 +727,43 @@ static igraph_error_t igraph_i_weighted_adjacency_min( * * The order of the vertices in the matrix is preserved, i.e. the vertex * corresponding to the first row/column will be vertex with id 0, the - * next row is for vertex 1, etc. + * next row is for vertex 1, etc. No guarantees are given for the ordering + * of edges. + * * \param graph Pointer to an uninitialized graph object. * \param adjmatrix The weighted adjacency matrix. How it is interpreted * depends on the \p mode argument. The common feature is that * edges with zero weights are considered nonexistent (however, * negative weights are permitted). * \param mode Constant to specify how the given matrix is interpreted - * as an adjacency matrix. Possible values - * (A(i,j) - * is the element in row i and column - * j in the adjacency matrix - * \p adjmatrix): + * as an adjacency matrix. Possible values (A(i,j) is the element in row + * i and column j in the adjacency matrix \p adjmatrix): * \clist * \cli IGRAPH_ADJ_DIRECTED - * the graph will be directed and - * an element gives the weight of the edge between two vertices. + * The graph will be directed and an element specifies the weight of the + * edge between two vertices. * \cli IGRAPH_ADJ_UNDIRECTED - * this is the same as \c IGRAPH_ADJ_MAX, - * for convenience. + * This is the same as \c IGRAPH_ADJ_MAX, for convenience. * \cli IGRAPH_ADJ_MAX - * undirected graph will be created - * and the weight of the edge between vertices - * i and - * j is - * max(A(i,j), A(j,i)). + * An undirected graph will be created and the weight of the edge between + * vertices i and j is max(A(i,j), A(j,i)). * \cli IGRAPH_ADJ_MIN - * undirected graph will be created - * with edge weight min(A(i,j), A(j,i)) - * between vertices - * i and - * j. + * An undirected graph will be created and the weight of the edge between + * vertices i and j is min(A(i,j), A(j,i)). * \cli IGRAPH_ADJ_PLUS - * undirected graph will be created - * with edge weight A(i,j)+A(j,i) - * between vertices - * i and - * j. + * An undirected graph will be created and the weight of the edge between + * vertices i and j is A(i,j)+A(j,i). * \cli IGRAPH_ADJ_UPPER - * undirected graph will be created, - * only the upper right triangle (including the diagonal) is - * used for the edge weights. + * An undirected graph will be created. Only the upper right triangle + * (including the diagonal) is used for the edge weights. * \cli IGRAPH_ADJ_LOWER - * undirected graph will be created, - * only the lower left triangle (including the diagonal) is - * used for the edge weights. + * An undirected graph will be created. Only the lower left triangle + * (including the diagonal) is used for the edge weights. * \endclist * \param weights Pointer to an initialized vector, the weights will be stored here. * \param loops Constant to specify how the diagonal of the matrix should be - * treated when creating loop edges. + * treated when creating loop edges. Ignored for modes + * \c IGRAPH_ADJ_DIRECTED, \c IGRAPH_ADJ_UPPER and \c IGRAPH_ADJ_LOWER. * \clist * \cli IGRAPH_NO_LOOPS * Ignore the diagonal of the input matrix and do not create loops. @@ -730,7 +775,7 @@ static igraph_error_t igraph_i_weighted_adjacency_min( * incident on the corresponding vertex. * \endclist * \return Error code, - * \c IGRAPH_NONSQUARE: non-square matrix. + * \c IGRAPH_EINVAL: non-square matrix. * * Time complexity: O(|V||V|), * |V| is the number of vertices in the graph. @@ -743,11 +788,11 @@ igraph_error_t igraph_weighted_adjacency( ) { igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t no_of_nodes; + igraph_int_t no_of_nodes; /* Some checks */ if (igraph_matrix_nrow(adjmatrix) != igraph_matrix_ncol(adjmatrix)) { - IGRAPH_ERROR("Adjacency matrices must be square.", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Adjacency matrices must be square.", IGRAPH_EINVAL); } IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); @@ -837,15 +882,15 @@ igraph_error_t igraph_weighted_adjacency( igraph_error_t igraph_adjlist(igraph_t *graph, const igraph_adjlist_t *adjlist, igraph_neimode_t mode, igraph_bool_t duplicate) { - const igraph_integer_t no_of_nodes = igraph_adjlist_size(adjlist); - igraph_integer_t no_of_edges = 0; + const igraph_int_t no_of_nodes = igraph_adjlist_size(adjlist); + igraph_int_t no_of_edges = 0; igraph_vector_int_t edges; - igraph_integer_t edgeptr = 0; + igraph_int_t edgeptr = 0; duplicate = duplicate && (mode == IGRAPH_ALL); /* only duplicate if undirected */ - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { no_of_edges += igraph_vector_int_size(igraph_adjlist_get(adjlist, i)); } @@ -855,13 +900,13 @@ igraph_error_t igraph_adjlist(igraph_t *graph, const igraph_adjlist_t *adjlist, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 2 * no_of_edges); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { igraph_vector_int_t *neis = igraph_adjlist_get(adjlist, i); - const igraph_integer_t n = igraph_vector_int_size(neis); - igraph_integer_t loops = 0; + const igraph_int_t n = igraph_vector_int_size(neis); + igraph_int_t loops = 0; - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t nei = VECTOR(*neis)[j]; if (nei == i) { loops++; } else { @@ -888,7 +933,7 @@ igraph_error_t igraph_adjlist(igraph_t *graph, const igraph_adjlist_t *adjlist, IGRAPH_ERROR("Invalid adjacency list, most probably not correctly" " duplicated edges for an undirected graph.", IGRAPH_EINVAL); } - for (igraph_integer_t j = 0; j < loops; j++) { + for (igraph_int_t j = 0; j < loops; j++) { VECTOR(edges)[edgeptr++] = i; VECTOR(edges)[edgeptr++] = i; } @@ -906,21 +951,27 @@ igraph_error_t igraph_adjlist(igraph_t *graph, const igraph_adjlist_t *adjlist, return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_sparse_adjacency_directed( +static igraph_error_t igraph_i_sparse_adjacency_directed_or_plus( igraph_sparsemat_t *adjmatrix, igraph_vector_int_t *edges, - igraph_loops_t loops + igraph_adjacency_t mode, igraph_loops_t loops ) { igraph_sparsemat_iterator_t it; igraph_sparsemat_iterator_init(&it, adjmatrix); + /* For sake of consistency with the rest of the library, IGRAPH_LOOPS_TWICE + * is treated as IGRAPH_LOOPS_ONCE for directed graphs */ + if (mode == IGRAPH_ADJ_DIRECTED && loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } + for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); - igraph_integer_t multi = igraph_sparsemat_iterator_get(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t multi = igraph_sparsemat_iterator_get(&it); if (to == from) { IGRAPH_CHECK(igraph_i_adjust_loop_edge_count(&multi, loops)); } - for (igraph_integer_t count = 0; count < multi; count++) { + for (igraph_int_t count = 0; count < multi; count++) { IGRAPH_CHECK(igraph_vector_int_push_back(edges, from)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, to)); } @@ -937,19 +988,19 @@ static igraph_error_t igraph_i_sparse_adjacency_max( igraph_sparsemat_iterator_init(&it, adjmatrix); for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); if (to < from) { continue; } - igraph_integer_t multi = igraph_sparsemat_iterator_get(&it); + igraph_int_t multi = igraph_sparsemat_iterator_get(&it); if (to == from) { IGRAPH_CHECK(igraph_i_adjust_loop_edge_count(&multi, loops)); } else { other = igraph_sparsemat_get(adjmatrix, to, from); multi = multi > other ? multi : other; } - for (igraph_integer_t count = 0; count < multi; count++) { + for (igraph_int_t count = 0; count < multi; count++) { IGRAPH_CHECK(igraph_vector_int_push_back(edges, from)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, to)); } @@ -967,19 +1018,19 @@ static igraph_error_t igraph_i_sparse_adjacency_min( igraph_sparsemat_iterator_init(&it, adjmatrix); for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); if (to < from) { continue; } - igraph_integer_t multi = igraph_sparsemat_iterator_get(&it); + igraph_int_t multi = igraph_sparsemat_iterator_get(&it); if (to == from) { IGRAPH_CHECK(igraph_i_adjust_loop_edge_count(&multi, loops)); } else { other = igraph_sparsemat_get(adjmatrix, to, from); multi = multi < other ? multi : other; } - for (igraph_integer_t count = 0; count < multi; count++) { + for (igraph_int_t count = 0; count < multi; count++) { IGRAPH_CHECK(igraph_vector_int_push_back(edges, from)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, to)); } @@ -994,18 +1045,29 @@ static igraph_error_t igraph_i_sparse_adjacency_upper( ) { igraph_sparsemat_iterator_t it; + /* IGRAPH_LOOPS_TWICE is treated as IGRAPH_LOOPS_ONCE -- it makes no sense + * for loops to appear twice in the adjacency matrix when the lower triangle + * is empty; double-counting of loops in undirected graphs happens because + * the upper and the lower triangle are added on top of each other on the + * diagonal. See discussion in #2501: + * + * https://github.com/igraph/igraph/issues/2501#issuecomment-1949345675 */ + if (loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } + igraph_sparsemat_iterator_init(&it, adjmatrix); for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); if (to < from) { continue; } - igraph_integer_t multi = igraph_sparsemat_iterator_get(&it); + igraph_int_t multi = igraph_sparsemat_iterator_get(&it); if (to == from) { IGRAPH_CHECK(igraph_i_adjust_loop_edge_count(&multi, loops)); } - for (igraph_integer_t count = 0; count < multi; count++) { + for (igraph_int_t count = 0; count < multi; count++) { IGRAPH_CHECK(igraph_vector_int_push_back(edges, from)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, to)); } @@ -1020,18 +1082,29 @@ static igraph_error_t igraph_i_sparse_adjacency_lower( ) { igraph_sparsemat_iterator_t it; + /* IGRAPH_LOOPS_TWICE is treated as IGRAPH_LOOPS_ONCE -- it makes no sense + * for loops to appear twice in the adjacency matrix when the lower triangle + * is empty; double-counting of loops in undirected graphs happens because + * the upper and the lower triangle are added on top of each other on the + * diagonal. See discussion in #2501: + * + * https://github.com/igraph/igraph/issues/2501#issuecomment-1949345675 */ + if (loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } + igraph_sparsemat_iterator_init(&it, adjmatrix); for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); if (to > from) { continue; } - igraph_integer_t multi = igraph_sparsemat_iterator_get(&it); + igraph_int_t multi = igraph_sparsemat_iterator_get(&it); if (to == from) { IGRAPH_CHECK(igraph_i_adjust_loop_edge_count(&multi, loops)); } - for (igraph_integer_t count = 0; count < multi; count++) { + for (igraph_int_t count = 0; count < multi; count++) { IGRAPH_CHECK(igraph_vector_int_push_back(edges, from)); IGRAPH_CHECK(igraph_vector_int_push_back(edges, to)); } @@ -1052,7 +1125,7 @@ static igraph_error_t igraph_i_sparse_adjacency_undirected( IGRAPH_EINVAL ); } - return igraph_i_sparse_adjacency_upper(adjmatrix, edges, loops); + return igraph_i_sparse_adjacency_max(adjmatrix, edges, loops); } /** @@ -1072,16 +1145,16 @@ igraph_error_t igraph_sparse_adjacency(igraph_t *graph, igraph_sparsemat_t *adjm igraph_adjacency_t mode, igraph_loops_t loops) { igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t no_of_nodes = igraph_sparsemat_nrow(adjmatrix); - igraph_integer_t no_of_nonzeros = igraph_sparsemat_count_nonzero(adjmatrix); - igraph_integer_t approx_no_of_edges; + igraph_int_t no_of_nodes = igraph_sparsemat_nrow(adjmatrix); + igraph_int_t no_of_nonzeros = igraph_sparsemat_count_nonzero(adjmatrix); + igraph_int_t approx_no_of_edges; if (!igraph_sparsemat_is_cc(adjmatrix)) { IGRAPH_ERROR("Sparse adjacency matrix should be in column-compressed " "form.", IGRAPH_EINVAL); } if (no_of_nodes != igraph_sparsemat_ncol(adjmatrix)) { - IGRAPH_ERROR("Adjacency matrix is non-square.", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Adjacency matrix is non-square.", IGRAPH_EINVAL); } if (no_of_nodes != 0 && igraph_sparsemat_min(adjmatrix) < 0) { @@ -1115,7 +1188,8 @@ igraph_error_t igraph_sparse_adjacency(igraph_t *graph, igraph_sparsemat_t *adjm /* Collect the edges */ switch (mode) { case IGRAPH_ADJ_DIRECTED: - IGRAPH_CHECK(igraph_i_sparse_adjacency_directed(adjmatrix, &edges, loops)); + case IGRAPH_ADJ_PLUS: + IGRAPH_CHECK(igraph_i_sparse_adjacency_directed_or_plus(adjmatrix, &edges, mode, loops)); break; case IGRAPH_ADJ_MAX: IGRAPH_CHECK(igraph_i_sparse_adjacency_max(adjmatrix, &edges, loops)); @@ -1132,9 +1206,6 @@ igraph_error_t igraph_sparse_adjacency(igraph_t *graph, igraph_sparsemat_t *adjm case IGRAPH_ADJ_MIN: IGRAPH_CHECK(igraph_i_sparse_adjacency_min(adjmatrix, &edges, loops)); break; - case IGRAPH_ADJ_PLUS: - IGRAPH_CHECK(igraph_i_sparse_adjacency_directed(adjmatrix, &edges, loops)); - break; default: IGRAPH_ERROR("Invalid adjacency mode.", IGRAPH_EINVAL); } @@ -1152,12 +1223,12 @@ static igraph_error_t igraph_i_sparse_weighted_adjacency_max ( ) { igraph_sparsemat_iterator_t it; igraph_sparsemat_iterator_init(&it, adjmatrix); - igraph_integer_t e = 0; + igraph_int_t e = 0; igraph_real_t other; for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); if (to < from) { continue; } @@ -1185,13 +1256,13 @@ static igraph_error_t igraph_i_sparse_weighted_adjacency_min ( igraph_vector_t *weights, igraph_loops_t loops ) { igraph_sparsemat_iterator_t it; - igraph_integer_t e = 0; + igraph_int_t e = 0; igraph_real_t other; igraph_sparsemat_iterator_init(&it, adjmatrix); for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); if (to < from) { continue; } @@ -1219,13 +1290,13 @@ static igraph_error_t igraph_i_sparse_weighted_adjacency_plus ( igraph_vector_t *weights, igraph_loops_t loops ) { igraph_sparsemat_iterator_t it; - igraph_integer_t e = 0; + igraph_int_t e = 0; igraph_real_t other; igraph_sparsemat_iterator_init(&it, adjmatrix); for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); if (to < from) { continue; } @@ -1254,11 +1325,22 @@ static igraph_error_t igraph_i_sparse_weighted_adjacency_upper( ) { igraph_sparsemat_iterator_t it; igraph_sparsemat_iterator_init(&it, adjmatrix); - igraph_integer_t e = 0; + igraph_int_t e = 0; + + /* IGRAPH_LOOPS_TWICE is treated as IGRAPH_LOOPS_ONCE -- it makes no sense + * for loops to appear twice in the adjacency matrix when the lower triangle + * is empty; double-counting of loops in undirected graphs happens because + * the upper and the lower triangle are added on top of each other on the + * diagonal. See discussion in #2501: + * + * https://github.com/igraph/igraph/issues/2501#issuecomment-1949345675 */ + if (loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); igraph_real_t weight = igraph_sparsemat_iterator_get(&it); if (to < from) { continue; @@ -1284,11 +1366,22 @@ static igraph_error_t igraph_i_sparse_weighted_adjacency_lower( ) { igraph_sparsemat_iterator_t it; igraph_sparsemat_iterator_init(&it, adjmatrix); - igraph_integer_t e = 0; + igraph_int_t e = 0; + + /* IGRAPH_LOOPS_TWICE is treated as IGRAPH_LOOPS_ONCE -- it makes no sense + * for loops to appear twice in the adjacency matrix when the lower triangle + * is empty; double-counting of loops in undirected graphs happens because + * the upper and the lower triangle are added on top of each other on the + * diagonal. See discussion in #2501: + * + * https://github.com/igraph/igraph/issues/2501#issuecomment-1949345675 */ + if (loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); igraph_real_t weight = igraph_sparsemat_iterator_get(&it); if (to > from) { continue; @@ -1321,7 +1414,7 @@ static igraph_error_t igraph_i_sparse_weighted_adjacency_undirected ( IGRAPH_EINVAL ); } - return igraph_i_sparse_weighted_adjacency_upper(adjmatrix, edges, weights, loops); + return igraph_i_sparse_weighted_adjacency_max(adjmatrix, edges, weights, loops); } @@ -1331,11 +1424,17 @@ static igraph_error_t igraph_i_sparse_weighted_adjacency_directed( ) { igraph_sparsemat_iterator_t it; igraph_sparsemat_iterator_init(&it, adjmatrix); - igraph_integer_t e = 0; + igraph_int_t e = 0; + + /* For sake of consistency with the rest of the library, IGRAPH_LOOPS_TWICE + * is treated as IGRAPH_LOOPS_ONCE for directed graphs */ + if (loops == IGRAPH_LOOPS_TWICE) { + loops = IGRAPH_LOOPS_ONCE; + } for (; !igraph_sparsemat_iterator_end(&it); igraph_sparsemat_iterator_next(&it)) { - igraph_integer_t from = igraph_sparsemat_iterator_row(&it); - igraph_integer_t to = igraph_sparsemat_iterator_col(&it); + igraph_int_t from = igraph_sparsemat_iterator_row(&it); + igraph_int_t to = igraph_sparsemat_iterator_col(&it); igraph_real_t weight = igraph_sparsemat_iterator_get(&it); if (to == from) { igraph_i_adjust_loop_edge_weight(&weight, loops); @@ -1371,14 +1470,14 @@ igraph_error_t igraph_sparse_weighted_adjacency( igraph_vector_t *weights, igraph_loops_t loops ) { igraph_vector_int_t edges; - igraph_integer_t no_of_nodes = igraph_sparsemat_nrow(adjmatrix); - igraph_integer_t no_of_edges = igraph_sparsemat_count_nonzero(adjmatrix); + igraph_int_t no_of_nodes = igraph_sparsemat_nrow(adjmatrix); + igraph_int_t no_of_edges = igraph_sparsemat_count_nonzero(adjmatrix); if (!igraph_sparsemat_is_cc(adjmatrix)) { IGRAPH_ERROR("Sparse adjacency matrix should be in column-compressed form.", IGRAPH_EINVAL); } if (no_of_nodes != igraph_sparsemat_ncol(adjmatrix)) { - IGRAPH_ERROR("Adjacency matrix is non-square.", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Adjacency matrix is non-square.", IGRAPH_EINVAL); } IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges * 2); diff --git a/src/vendor/cigraph/src/constructors/atlas-edges.h b/src/vendor/cigraph/src/constructors/atlas-edges.h index 6faceda6f0b..accc395f728 100644 --- a/src/vendor/cigraph/src/constructors/atlas-edges.h +++ b/src/vendor/cigraph/src/constructors/atlas-edges.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -27,9 +26,9 @@ #include "igraph_decls.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS -const igraph_integer_t igraph_i_atlas_edges[] = { +const igraph_int_t igraph_i_atlas_edges[] = { 0, 0, 1, 0, 2, 0, @@ -1285,8 +1284,8 @@ const igraph_integer_t igraph_i_atlas_edges[] = { 7, 21, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 2, 3, 2, 4, 2, 5, 2, 6, 3, 4, 3, 5, 3, 6, 4, 5, 4, 6, 5, 6, }; -const igraph_integer_t igraph_i_atlas_edges_pos[] = {0, 2, 4, 6, 10, 12, 16, 22, 30, 32, 36, 42, 48, 56, 64, 72, 82, 92, 104, 118, 120, 124, 130, 136, 144, 152, 160, 168, 178, 188, 198, 208, 218, 228, 240, 252, 264, 276, 288, 300, 314, 328, 342, 356, 370, 384, 400, 416, 432, 448, 466, 484, 504, 526, 528, 532, 538, 544, 552, 560, 568, 576, 584, 594, 604, 614, 624, 634, 644, 654, 664, 674, 686, 698, 710, 722, 734, 746, 758, 770, 782, 794, 806, 818, 830, 842, 854, 868, 882, 896, 910, 924, 938, 952, 966, 980, 994, 1008, 1022, 1036, 1050, 1064, 1078, 1092, 1106, 1120, 1134, 1148, 1164, 1180, 1196, 1212, 1228, 1244, 1260, 1276, 1292, 1308, 1324, 1340, 1356, 1372, 1388, 1404, 1420, 1436, 1452, 1468, 1484, 1500, 1516, 1532, 1550, 1568, 1586, 1604, 1622, 1640, 1658, 1676, 1694, 1712, 1730, 1748, 1766, 1784, 1802, 1820, 1838, 1856, 1874, 1892, 1910, 1928, 1946, 1964, 1984, 2004, 2024, 2044, 2064, 2084, 2104, 2124, 2144, 2164, 2184, 2204, 2224, 2244, 2264, 2284, 2304, 2324, 2344, 2364, 2384, 2406, 2428, 2450, 2472, 2494, 2516, 2538, 2560, 2582, 2604, 2626, 2648, 2670, 2692, 2714, 2738, 2762, 2786, 2810, 2834, 2858, 2882, 2906, 2930, 2956, 2982, 3008, 3034, 3060, 3088, 3116, 3146, 3178, 3180, 3184, 3190, 3196, 3204, 3212, 3220, 3228, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316, 3326, 3336, 3348, 3360, 3372, 3384, 3396, 3408, 3420, 3432, 3444, 3456, 3468, 3480, 3492, 3504, 3516, 3528, 3540, 3552, 3564, 3576, 3588, 3602, 3616, 3630, 3644, 3658, 3672, 3686, 3700, 3714, 3728, 3742, 3756, 3770, 3784, 3798, 3812, 3826, 3840, 3854, 3868, 3882, 3896, 3910, 3924, 3938, 3952, 3966, 3980, 3994, 4008, 4022, 4036, 4050, 4064, 4078, 4092, 4106, 4120, 4134, 4148, 4162, 4178, 4194, 4210, 4226, 4242, 4258, 4274, 4290, 4306, 4322, 4338, 4354, 4370, 4386, 4402, 4418, 4434, 4450, 4466, 4482, 4498, 4514, 4530, 4546, 4562, 4578, 4594, 4610, 4626, 4642, 4658, 4674, 4690, 4706, 4722, 4738, 4754, 4770, 4786, 4802, 4818, 4834, 4850, 4866, 4882, 4898, 4914, 4930, 4946, 4962, 4978, 4994, 5010, 5026, 5042, 5058, 5074, 5090, 5106, 5122, 5138, 5154, 5170, 5186, 5202, 5220, 5238, 5256, 5274, 5292, 5310, 5328, 5346, 5364, 5382, 5400, 5418, 5436, 5454, 5472, 5490, 5508, 5526, 5544, 5562, 5580, 5598, 5616, 5634, 5652, 5670, 5688, 5706, 5724, 5742, 5760, 5778, 5796, 5814, 5832, 5850, 5868, 5886, 5904, 5922, 5940, 5958, 5976, 5994, 6012, 6030, 6048, 6066, 6084, 6102, 6120, 6138, 6156, 6174, 6192, 6210, 6228, 6246, 6264, 6282, 6300, 6318, 6336, 6354, 6372, 6390, 6408, 6426, 6444, 6462, 6480, 6498, 6516, 6534, 6552, 6570, 6588, 6606, 6624, 6642, 6660, 6678, 6696, 6714, 6732, 6750, 6768, 6786, 6804, 6822, 6840, 6858, 6876, 6894, 6912, 6930, 6948, 6968, 6988, 7008, 7028, 7048, 7068, 7088, 7108, 7128, 7148, 7168, 7188, 7208, 7228, 7248, 7268, 7288, 7308, 7328, 7348, 7368, 7388, 7408, 7428, 7448, 7468, 7488, 7508, 7528, 7548, 7568, 7588, 7608, 7628, 7648, 7668, 7688, 7708, 7728, 7748, 7768, 7788, 7808, 7828, 7848, 7868, 7888, 7908, 7928, 7948, 7968, 7988, 8008, 8028, 8048, 8068, 8088, 8108, 8128, 8148, 8168, 8188, 8208, 8228, 8248, 8268, 8288, 8308, 8328, 8348, 8368, 8388, 8408, 8428, 8448, 8468, 8488, 8508, 8528, 8548, 8568, 8588, 8608, 8628, 8648, 8668, 8688, 8708, 8728, 8748, 8768, 8788, 8808, 8828, 8848, 8868, 8888, 8908, 8928, 8948, 8968, 8988, 9008, 9028, 9048, 9068, 9088, 9108, 9128, 9148, 9168, 9188, 9208, 9228, 9248, 9268, 9288, 9308, 9328, 9348, 9368, 9388, 9408, 9428, 9448, 9468, 9488, 9508, 9528, 9548, 9568, 9590, 9612, 9634, 9656, 9678, 9700, 9722, 9744, 9766, 9788, 9810, 9832, 9854, 9876, 9898, 9920, 9942, 9964, 9986, 10008, 10030, 10052, 10074, 10096, 10118, 10140, 10162, 10184, 10206, 10228, 10250, 10272, 10294, 10316, 10338, 10360, 10382, 10404, 10426, 10448, 10470, 10492, 10514, 10536, 10558, 10580, 10602, 10624, 10646, 10668, 10690, 10712, 10734, 10756, 10778, 10800, 10822, 10844, 10866, 10888, 10910, 10932, 10954, 10976, 10998, 11020, 11042, 11064, 11086, 11108, 11130, 11152, 11174, 11196, 11218, 11240, 11262, 11284, 11306, 11328, 11350, 11372, 11394, 11416, 11438, 11460, 11482, 11504, 11526, 11548, 11570, 11592, 11614, 11636, 11658, 11680, 11702, 11724, 11746, 11768, 11790, 11812, 11834, 11856, 11878, 11900, 11922, 11944, 11966, 11988, 12010, 12032, 12054, 12076, 12098, 12120, 12142, 12164, 12186, 12208, 12230, 12252, 12274, 12296, 12318, 12340, 12362, 12384, 12406, 12428, 12450, 12472, 12494, 12516, 12538, 12560, 12582, 12604, 12626, 12648, 12670, 12692, 12714, 12736, 12758, 12780, 12802, 12824, 12848, 12872, 12896, 12920, 12944, 12968, 12992, 13016, 13040, 13064, 13088, 13112, 13136, 13160, 13184, 13208, 13232, 13256, 13280, 13304, 13328, 13352, 13376, 13400, 13424, 13448, 13472, 13496, 13520, 13544, 13568, 13592, 13616, 13640, 13664, 13688, 13712, 13736, 13760, 13784, 13808, 13832, 13856, 13880, 13904, 13928, 13952, 13976, 14000, 14024, 14048, 14072, 14096, 14120, 14144, 14168, 14192, 14216, 14240, 14264, 14288, 14312, 14336, 14360, 14384, 14408, 14432, 14456, 14480, 14504, 14528, 14552, 14576, 14600, 14624, 14648, 14672, 14696, 14720, 14744, 14768, 14792, 14816, 14840, 14864, 14888, 14912, 14936, 14960, 14984, 15008, 15032, 15056, 15080, 15104, 15128, 15152, 15176, 15200, 15224, 15248, 15272, 15296, 15320, 15344, 15368, 15392, 15416, 15440, 15464, 15488, 15512, 15536, 15560, 15584, 15608, 15632, 15656, 15680, 15704, 15728, 15752, 15776, 15800, 15824, 15848, 15872, 15896, 15920, 15944, 15968, 15992, 16016, 16040, 16064, 16088, 16112, 16136, 16160, 16184, 16208, 16232, 16256, 16280, 16304, 16328, 16352, 16376, 16402, 16428, 16454, 16480, 16506, 16532, 16558, 16584, 16610, 16636, 16662, 16688, 16714, 16740, 16766, 16792, 16818, 16844, 16870, 16896, 16922, 16948, 16974, 17000, 17026, 17052, 17078, 17104, 17130, 17156, 17182, 17208, 17234, 17260, 17286, 17312, 17338, 17364, 17390, 17416, 17442, 17468, 17494, 17520, 17546, 17572, 17598, 17624, 17650, 17676, 17702, 17728, 17754, 17780, 17806, 17832, 17858, 17884, 17910, 17936, 17962, 17988, 18014, 18040, 18066, 18092, 18118, 18144, 18170, 18196, 18222, 18248, 18274, 18300, 18326, 18352, 18378, 18404, 18430, 18456, 18482, 18508, 18534, 18560, 18586, 18612, 18638, 18664, 18690, 18716, 18742, 18768, 18794, 18820, 18846, 18872, 18898, 18924, 18950, 18976, 19002, 19028, 19054, 19080, 19106, 19132, 19158, 19184, 19210, 19236, 19262, 19288, 19314, 19340, 19366, 19392, 19418, 19444, 19470, 19496, 19522, 19548, 19574, 19600, 19626, 19652, 19678, 19704, 19730, 19756, 19782, 19810, 19838, 19866, 19894, 19922, 19950, 19978, 20006, 20034, 20062, 20090, 20118, 20146, 20174, 20202, 20230, 20258, 20286, 20314, 20342, 20370, 20398, 20426, 20454, 20482, 20510, 20538, 20566, 20594, 20622, 20650, 20678, 20706, 20734, 20762, 20790, 20818, 20846, 20874, 20902, 20930, 20958, 20986, 21014, 21042, 21070, 21098, 21126, 21154, 21182, 21210, 21238, 21266, 21294, 21322, 21350, 21378, 21406, 21434, 21462, 21490, 21518, 21546, 21574, 21602, 21630, 21658, 21686, 21714, 21742, 21770, 21798, 21826, 21854, 21882, 21910, 21938, 21966, 21994, 22022, 22050, 22078, 22106, 22134, 22162, 22190, 22218, 22246, 22274, 22302, 22330, 22358, 22386, 22414, 22442, 22470, 22498, 22528, 22558, 22588, 22618, 22648, 22678, 22708, 22738, 22768, 22798, 22828, 22858, 22888, 22918, 22948, 22978, 23008, 23038, 23068, 23098, 23128, 23158, 23188, 23218, 23248, 23278, 23308, 23338, 23368, 23398, 23428, 23458, 23488, 23518, 23548, 23578, 23608, 23638, 23668, 23698, 23728, 23758, 23788, 23818, 23848, 23878, 23908, 23938, 23968, 23998, 24028, 24058, 24088, 24118, 24148, 24178, 24208, 24238, 24268, 24298, 24328, 24358, 24388, 24418, 24448, 24480, 24512, 24544, 24576, 24608, 24640, 24672, 24704, 24736, 24768, 24800, 24832, 24864, 24896, 24928, 24960, 24992, 25024, 25056, 25088, 25120, 25152, 25184, 25216, 25248, 25280, 25312, 25344, 25376, 25408, 25440, 25472, 25504, 25536, 25568, 25600, 25632, 25664, 25696, 25728, 25760, 25794, 25828, 25862, 25896, 25930, 25964, 25998, 26032, 26066, 26100, 26134, 26168, 26202, 26236, 26270, 26304, 26338, 26372, 26406, 26440, 26474, 26510, 26546, 26582, 26618, 26654, 26690, 26726, 26762, 26798, 26834, 26872, 26910, 26948, 26986, 27024, 27064, 27104, 27146}; +const igraph_int_t igraph_i_atlas_edges_pos[] = {0, 2, 4, 6, 10, 12, 16, 22, 30, 32, 36, 42, 48, 56, 64, 72, 82, 92, 104, 118, 120, 124, 130, 136, 144, 152, 160, 168, 178, 188, 198, 208, 218, 228, 240, 252, 264, 276, 288, 300, 314, 328, 342, 356, 370, 384, 400, 416, 432, 448, 466, 484, 504, 526, 528, 532, 538, 544, 552, 560, 568, 576, 584, 594, 604, 614, 624, 634, 644, 654, 664, 674, 686, 698, 710, 722, 734, 746, 758, 770, 782, 794, 806, 818, 830, 842, 854, 868, 882, 896, 910, 924, 938, 952, 966, 980, 994, 1008, 1022, 1036, 1050, 1064, 1078, 1092, 1106, 1120, 1134, 1148, 1164, 1180, 1196, 1212, 1228, 1244, 1260, 1276, 1292, 1308, 1324, 1340, 1356, 1372, 1388, 1404, 1420, 1436, 1452, 1468, 1484, 1500, 1516, 1532, 1550, 1568, 1586, 1604, 1622, 1640, 1658, 1676, 1694, 1712, 1730, 1748, 1766, 1784, 1802, 1820, 1838, 1856, 1874, 1892, 1910, 1928, 1946, 1964, 1984, 2004, 2024, 2044, 2064, 2084, 2104, 2124, 2144, 2164, 2184, 2204, 2224, 2244, 2264, 2284, 2304, 2324, 2344, 2364, 2384, 2406, 2428, 2450, 2472, 2494, 2516, 2538, 2560, 2582, 2604, 2626, 2648, 2670, 2692, 2714, 2738, 2762, 2786, 2810, 2834, 2858, 2882, 2906, 2930, 2956, 2982, 3008, 3034, 3060, 3088, 3116, 3146, 3178, 3180, 3184, 3190, 3196, 3204, 3212, 3220, 3228, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316, 3326, 3336, 3348, 3360, 3372, 3384, 3396, 3408, 3420, 3432, 3444, 3456, 3468, 3480, 3492, 3504, 3516, 3528, 3540, 3552, 3564, 3576, 3588, 3602, 3616, 3630, 3644, 3658, 3672, 3686, 3700, 3714, 3728, 3742, 3756, 3770, 3784, 3798, 3812, 3826, 3840, 3854, 3868, 3882, 3896, 3910, 3924, 3938, 3952, 3966, 3980, 3994, 4008, 4022, 4036, 4050, 4064, 4078, 4092, 4106, 4120, 4134, 4148, 4162, 4178, 4194, 4210, 4226, 4242, 4258, 4274, 4290, 4306, 4322, 4338, 4354, 4370, 4386, 4402, 4418, 4434, 4450, 4466, 4482, 4498, 4514, 4530, 4546, 4562, 4578, 4594, 4610, 4626, 4642, 4658, 4674, 4690, 4706, 4722, 4738, 4754, 4770, 4786, 4802, 4818, 4834, 4850, 4866, 4882, 4898, 4914, 4930, 4946, 4962, 4978, 4994, 5010, 5026, 5042, 5058, 5074, 5090, 5106, 5122, 5138, 5154, 5170, 5186, 5202, 5220, 5238, 5256, 5274, 5292, 5310, 5328, 5346, 5364, 5382, 5400, 5418, 5436, 5454, 5472, 5490, 5508, 5526, 5544, 5562, 5580, 5598, 5616, 5634, 5652, 5670, 5688, 5706, 5724, 5742, 5760, 5778, 5796, 5814, 5832, 5850, 5868, 5886, 5904, 5922, 5940, 5958, 5976, 5994, 6012, 6030, 6048, 6066, 6084, 6102, 6120, 6138, 6156, 6174, 6192, 6210, 6228, 6246, 6264, 6282, 6300, 6318, 6336, 6354, 6372, 6390, 6408, 6426, 6444, 6462, 6480, 6498, 6516, 6534, 6552, 6570, 6588, 6606, 6624, 6642, 6660, 6678, 6696, 6714, 6732, 6750, 6768, 6786, 6804, 6822, 6840, 6858, 6876, 6894, 6912, 6930, 6948, 6968, 6988, 7008, 7028, 7048, 7068, 7088, 7108, 7128, 7148, 7168, 7188, 7208, 7228, 7248, 7268, 7288, 7308, 7328, 7348, 7368, 7388, 7408, 7428, 7448, 7468, 7488, 7508, 7528, 7548, 7568, 7588, 7608, 7628, 7648, 7668, 7688, 7708, 7728, 7748, 7768, 7788, 7808, 7828, 7848, 7868, 7888, 7908, 7928, 7948, 7968, 7988, 8008, 8028, 8048, 8068, 8088, 8108, 8128, 8148, 8168, 8188, 8208, 8228, 8248, 8268, 8288, 8308, 8328, 8348, 8368, 8388, 8408, 8428, 8448, 8468, 8488, 8508, 8528, 8548, 8568, 8588, 8608, 8628, 8648, 8668, 8688, 8708, 8728, 8748, 8768, 8788, 8808, 8828, 8848, 8868, 8888, 8908, 8928, 8948, 8968, 8988, 9008, 9028, 9048, 9068, 9088, 9108, 9128, 9148, 9168, 9188, 9208, 9228, 9248, 9268, 9288, 9308, 9328, 9348, 9368, 9388, 9408, 9428, 9448, 9468, 9488, 9508, 9528, 9548, 9568, 9590, 9612, 9634, 9656, 9678, 9700, 9722, 9744, 9766, 9788, 9810, 9832, 9854, 9876, 9898, 9920, 9942, 9964, 9986, 10008, 10030, 10052, 10074, 10096, 10118, 10140, 10162, 10184, 10206, 10228, 10250, 10272, 10294, 10316, 10338, 10360, 10382, 10404, 10426, 10448, 10470, 10492, 10514, 10536, 10558, 10580, 10602, 10624, 10646, 10668, 10690, 10712, 10734, 10756, 10778, 10800, 10822, 10844, 10866, 10888, 10910, 10932, 10954, 10976, 10998, 11020, 11042, 11064, 11086, 11108, 11130, 11152, 11174, 11196, 11218, 11240, 11262, 11284, 11306, 11328, 11350, 11372, 11394, 11416, 11438, 11460, 11482, 11504, 11526, 11548, 11570, 11592, 11614, 11636, 11658, 11680, 11702, 11724, 11746, 11768, 11790, 11812, 11834, 11856, 11878, 11900, 11922, 11944, 11966, 11988, 12010, 12032, 12054, 12076, 12098, 12120, 12142, 12164, 12186, 12208, 12230, 12252, 12274, 12296, 12318, 12340, 12362, 12384, 12406, 12428, 12450, 12472, 12494, 12516, 12538, 12560, 12582, 12604, 12626, 12648, 12670, 12692, 12714, 12736, 12758, 12780, 12802, 12824, 12848, 12872, 12896, 12920, 12944, 12968, 12992, 13016, 13040, 13064, 13088, 13112, 13136, 13160, 13184, 13208, 13232, 13256, 13280, 13304, 13328, 13352, 13376, 13400, 13424, 13448, 13472, 13496, 13520, 13544, 13568, 13592, 13616, 13640, 13664, 13688, 13712, 13736, 13760, 13784, 13808, 13832, 13856, 13880, 13904, 13928, 13952, 13976, 14000, 14024, 14048, 14072, 14096, 14120, 14144, 14168, 14192, 14216, 14240, 14264, 14288, 14312, 14336, 14360, 14384, 14408, 14432, 14456, 14480, 14504, 14528, 14552, 14576, 14600, 14624, 14648, 14672, 14696, 14720, 14744, 14768, 14792, 14816, 14840, 14864, 14888, 14912, 14936, 14960, 14984, 15008, 15032, 15056, 15080, 15104, 15128, 15152, 15176, 15200, 15224, 15248, 15272, 15296, 15320, 15344, 15368, 15392, 15416, 15440, 15464, 15488, 15512, 15536, 15560, 15584, 15608, 15632, 15656, 15680, 15704, 15728, 15752, 15776, 15800, 15824, 15848, 15872, 15896, 15920, 15944, 15968, 15992, 16016, 16040, 16064, 16088, 16112, 16136, 16160, 16184, 16208, 16232, 16256, 16280, 16304, 16328, 16352, 16376, 16402, 16428, 16454, 16480, 16506, 16532, 16558, 16584, 16610, 16636, 16662, 16688, 16714, 16740, 16766, 16792, 16818, 16844, 16870, 16896, 16922, 16948, 16974, 17000, 17026, 17052, 17078, 17104, 17130, 17156, 17182, 17208, 17234, 17260, 17286, 17312, 17338, 17364, 17390, 17416, 17442, 17468, 17494, 17520, 17546, 17572, 17598, 17624, 17650, 17676, 17702, 17728, 17754, 17780, 17806, 17832, 17858, 17884, 17910, 17936, 17962, 17988, 18014, 18040, 18066, 18092, 18118, 18144, 18170, 18196, 18222, 18248, 18274, 18300, 18326, 18352, 18378, 18404, 18430, 18456, 18482, 18508, 18534, 18560, 18586, 18612, 18638, 18664, 18690, 18716, 18742, 18768, 18794, 18820, 18846, 18872, 18898, 18924, 18950, 18976, 19002, 19028, 19054, 19080, 19106, 19132, 19158, 19184, 19210, 19236, 19262, 19288, 19314, 19340, 19366, 19392, 19418, 19444, 19470, 19496, 19522, 19548, 19574, 19600, 19626, 19652, 19678, 19704, 19730, 19756, 19782, 19810, 19838, 19866, 19894, 19922, 19950, 19978, 20006, 20034, 20062, 20090, 20118, 20146, 20174, 20202, 20230, 20258, 20286, 20314, 20342, 20370, 20398, 20426, 20454, 20482, 20510, 20538, 20566, 20594, 20622, 20650, 20678, 20706, 20734, 20762, 20790, 20818, 20846, 20874, 20902, 20930, 20958, 20986, 21014, 21042, 21070, 21098, 21126, 21154, 21182, 21210, 21238, 21266, 21294, 21322, 21350, 21378, 21406, 21434, 21462, 21490, 21518, 21546, 21574, 21602, 21630, 21658, 21686, 21714, 21742, 21770, 21798, 21826, 21854, 21882, 21910, 21938, 21966, 21994, 22022, 22050, 22078, 22106, 22134, 22162, 22190, 22218, 22246, 22274, 22302, 22330, 22358, 22386, 22414, 22442, 22470, 22498, 22528, 22558, 22588, 22618, 22648, 22678, 22708, 22738, 22768, 22798, 22828, 22858, 22888, 22918, 22948, 22978, 23008, 23038, 23068, 23098, 23128, 23158, 23188, 23218, 23248, 23278, 23308, 23338, 23368, 23398, 23428, 23458, 23488, 23518, 23548, 23578, 23608, 23638, 23668, 23698, 23728, 23758, 23788, 23818, 23848, 23878, 23908, 23938, 23968, 23998, 24028, 24058, 24088, 24118, 24148, 24178, 24208, 24238, 24268, 24298, 24328, 24358, 24388, 24418, 24448, 24480, 24512, 24544, 24576, 24608, 24640, 24672, 24704, 24736, 24768, 24800, 24832, 24864, 24896, 24928, 24960, 24992, 25024, 25056, 25088, 25120, 25152, 25184, 25216, 25248, 25280, 25312, 25344, 25376, 25408, 25440, 25472, 25504, 25536, 25568, 25600, 25632, 25664, 25696, 25728, 25760, 25794, 25828, 25862, 25896, 25930, 25964, 25998, 26032, 26066, 26100, 26134, 26168, 26202, 26236, 26270, 26304, 26338, 26372, 26406, 26440, 26474, 26510, 26546, 26582, 26618, 26654, 26690, 26726, 26762, 26798, 26834, 26872, 26910, 26948, 26986, 27024, 27064, 27104, 27146}; -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_CONSTRUCTORS_ATLAS_EDGES_H */ diff --git a/src/vendor/cigraph/src/constructors/atlas.c b/src/vendor/cigraph/src/constructors/atlas.c index b8a6751a197..fac3875de0f 100644 --- a/src/vendor/cigraph/src/constructors/atlas.c +++ b/src/vendor/cigraph/src/constructors/atlas.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2025 The igraph development team This program is free software; you can redistribute it and/or modify @@ -60,10 +60,9 @@ * * \example examples/simple/igraph_atlas.c */ -igraph_error_t igraph_atlas(igraph_t *graph, igraph_integer_t number) { +igraph_error_t igraph_atlas(igraph_t *graph, igraph_int_t number) { - igraph_vector_int_t v; - const igraph_integer_t atlas_size = + const igraph_int_t atlas_size = sizeof(igraph_i_atlas_edges_pos) / sizeof(igraph_i_atlas_edges_pos[0]); if (number < 0 || @@ -74,12 +73,13 @@ igraph_error_t igraph_atlas(igraph_t *graph, igraph_integer_t number) { atlas_size); } - igraph_integer_t pos = igraph_i_atlas_edges_pos[number]; - igraph_integer_t n = igraph_i_atlas_edges[pos]; - igraph_integer_t e = igraph_i_atlas_edges[pos + 1]; + igraph_int_t pos = igraph_i_atlas_edges_pos[number]; + igraph_int_t n = igraph_i_atlas_edges[pos]; + igraph_int_t e = igraph_i_atlas_edges[pos + 1]; + const igraph_vector_int_t edges = igraph_vector_int_view(igraph_i_atlas_edges + pos + 2, e * 2); IGRAPH_CHECK(igraph_create(graph, - igraph_vector_int_view(&v, igraph_i_atlas_edges + pos + 2, e * 2), + &edges, n, IGRAPH_UNDIRECTED)); diff --git a/src/vendor/cigraph/src/constructors/basic_constructors.c b/src/vendor/cigraph/src/constructors/basic_constructors.c index 12f0e16893f..c048e1dd6fd 100644 --- a/src/vendor/cigraph/src/constructors/basic_constructors.c +++ b/src/vendor/cigraph/src/constructors/basic_constructors.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -24,16 +23,6 @@ #include "igraph_interface.h" -/** - * \section about_generators - * - * Graph generators create graphs. - * - * Almost all functions which create graph objects are documented - * here. The exceptions are \ref igraph_induced_subgraph() and alike, these - * create graphs based on another graph. - */ - /** * \ingroup generators @@ -51,10 +40,8 @@ * not. If yes, then the first edge points from the first * vertex ID in \p edges to the second, etc. * \return Error code: - * \c IGRAPH_EINVEVECTOR: invalid edges - * vector (odd number of vertices). - * \c IGRAPH_EINVVID: invalid (negative) - * vertex ID. + * \c IGRAPH_EINVAL: invalid edges vector (odd number of vertices). + * \c IGRAPH_EINVVID: invalid (negative) vertex ID. * * Time complexity: O(|V|+|E|), * |V| is the number of vertices, @@ -64,14 +51,14 @@ * \example examples/simple/igraph_create.c */ igraph_error_t igraph_create(igraph_t *graph, const igraph_vector_int_t *edges, - igraph_integer_t n, igraph_bool_t directed) { + igraph_int_t n, igraph_bool_t directed) { igraph_bool_t has_edges = igraph_vector_int_size(edges) > 0; - igraph_integer_t max; + igraph_int_t max; if (igraph_vector_int_size(edges) % 2 != 0) { - IGRAPH_ERROR("Invalid (odd) edges vector.", IGRAPH_EINVEVECTOR); + IGRAPH_ERROR("Invalid (odd) edges vector.", IGRAPH_EINVAL); } - if (has_edges && !igraph_vector_int_isininterval(edges, 0, IGRAPH_VCOUNT_MAX-1)) { + if (!igraph_vector_int_isininterval(edges, 0, IGRAPH_VCOUNT_MAX-1)) { IGRAPH_ERROR("Invalid (negative or too large) vertex ID.", IGRAPH_EINVVID); } @@ -133,7 +120,7 @@ igraph_error_t igraph_create(igraph_t *graph, const igraph_vector_int_t *edges, * \example examples/simple/igraph_small.c */ -igraph_error_t igraph_small(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, +igraph_error_t igraph_small(igraph_t *graph, igraph_int_t n, igraph_bool_t directed, int first, ...) { igraph_vector_int_t edges; va_list ap; diff --git a/src/vendor/cigraph/src/constructors/circulant.c b/src/vendor/cigraph/src/constructors/circulant.c index cd5eba60cbe..232f966249e 100644 --- a/src/vendor/cigraph/src/constructors/circulant.c +++ b/src/vendor/cigraph/src/constructors/circulant.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -48,13 +48,13 @@ * of shifts. */ -igraph_error_t igraph_circulant(igraph_t *graph, igraph_integer_t n, const igraph_vector_int_t *shifts, igraph_bool_t directed) { +igraph_error_t igraph_circulant(igraph_t *graph, igraph_int_t n, const igraph_vector_int_t *shifts, igraph_bool_t directed) { igraph_vector_int_t edges; igraph_vector_bool_t shift_seen; - igraph_integer_t i, j; - igraph_integer_t limit; - igraph_integer_t shift_size = igraph_vector_int_size(shifts); + igraph_int_t i, j; + igraph_int_t limit; + igraph_int_t shift_size = igraph_vector_int_size(shifts); if (n < 0) { IGRAPH_ERRORF("Number of nodes = %" IGRAPH_PRId " must be non-negative.", IGRAPH_EINVAL, n); @@ -65,7 +65,7 @@ igraph_error_t igraph_circulant(igraph_t *graph, igraph_integer_t n, const igrap IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); { - igraph_integer_t size; + igraph_int_t size; IGRAPH_SAFE_MULT(n, shift_size, &size); IGRAPH_SAFE_MULT(size, 2, &size); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, size)); @@ -76,7 +76,7 @@ igraph_error_t igraph_circulant(igraph_t *graph, igraph_integer_t n, const igrap for (i = 0; i < shift_size; i++) { /* simplify the shift */ - igraph_integer_t shift = VECTOR(*shifts)[i] % n; + igraph_int_t shift = VECTOR(*shifts)[i] % n; if (shift < 0) { shift += n; } diff --git a/src/vendor/cigraph/src/constructors/de_bruijn.c b/src/vendor/cigraph/src/constructors/de_bruijn.c index e7a55d2b7e4..0eb5afb061e 100644 --- a/src/vendor/cigraph/src/constructors/de_bruijn.c +++ b/src/vendor/cigraph/src/constructors/de_bruijn.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -56,14 +55,14 @@ * * Time complexity: O(|V|+|E|), the number of vertices plus the number of edges. */ -igraph_error_t igraph_de_bruijn(igraph_t *graph, igraph_integer_t m, igraph_integer_t n) { +igraph_error_t igraph_de_bruijn(igraph_t *graph, igraph_int_t m, igraph_int_t n) { /* m - number of symbols */ /* n - length of strings */ - igraph_integer_t no_of_nodes, no_of_edges; + igraph_int_t no_of_nodes, no_of_edges; igraph_vector_int_t edges; - igraph_integer_t i, j; + igraph_int_t i, j; int iter = 0; if (m < 0 || n < 0) { @@ -90,17 +89,17 @@ igraph_error_t igraph_de_bruijn(igraph_t *graph, igraph_integer_t m, igraph_inte IGRAPH_SAFE_MULT(no_of_nodes, m, &no_of_edges); { - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; IGRAPH_SAFE_MULT(no_of_edges, 2, &no_of_edges2); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); } for (i = 0; i < no_of_nodes; i++) { - igraph_integer_t basis = (i * m) % no_of_nodes; + igraph_int_t basis = (i * m) % no_of_nodes; for (j = 0; j < m; j++) { - igraph_vector_int_push_back(&edges, i); - igraph_vector_int_push_back(&edges, basis + j); + igraph_vector_int_push_back(&edges, i); /* reserved */ + igraph_vector_int_push_back(&edges, basis + j); /* reserved */ } IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 10); } diff --git a/src/vendor/cigraph/src/constructors/famous.c b/src/vendor/cigraph/src/constructors/famous.c index 4a0b54c66cb..7e963a49a16 100644 --- a/src/vendor/cigraph/src/constructors/famous.c +++ b/src/vendor/cigraph/src/constructors/famous.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -24,18 +23,18 @@ #include "internal/hacks.h" /* strcasecmp */ -const igraph_integer_t igraph_i_famous_bull[] = { +const igraph_int_t igraph_i_famous_bull[] = { 5, 5, 0, 0, 1, 0, 2, 1, 2, 1, 3, 2, 4 }; -const igraph_integer_t igraph_i_famous_chvatal[] = { +const igraph_int_t igraph_i_famous_chvatal[] = { 12, 24, 0, 5, 6, 6, 7, 7, 8, 8, 9, 5, 9, 4, 5, 4, 8, 2, 8, 2, 6, 0, 6, 0, 9, 3, 9, 3, 7, 1, 7, 1, 5, 1, 10, 4, 10, 4, 11, 2, 11, 0, 10, 0, 11, 3, 11, 3, 10, 1, 2 }; -const igraph_integer_t igraph_i_famous_coxeter[] = { +const igraph_int_t igraph_i_famous_coxeter[] = { 28, 42, 0, 0, 1, 0, 2, 0, 7, 1, 4, 1, 13, 2, 3, 2, 8, 3, 6, 3, 9, 4, 5, 4, 12, 5, 6, 5, 11, 6, 10, 7, 19, 7, 24, 8, 20, 8, 23, 9, 14, 9, 22, 10, 15, 10, 21, 11, 16, @@ -43,24 +42,24 @@ const igraph_integer_t igraph_i_famous_coxeter[] = { 16, 20, 17, 20, 21, 23, 21, 26, 22, 24, 22, 27, 23, 25, 24, 26, 25, 27 }; -const igraph_integer_t igraph_i_famous_cubical[] = { +const igraph_int_t igraph_i_famous_cubical[] = { 8, 12, 0, 0, 1, 1, 2, 2, 3, 0, 3, 4, 5, 5, 6, 6, 7, 4, 7, 0, 4, 1, 5, 2, 6, 3, 7 }; -const igraph_integer_t igraph_i_famous_diamond[] = { +const igraph_int_t igraph_i_famous_diamond[] = { 4, 5, 0, 0, 1, 0, 2, 1, 2, 1, 3, 2, 3 }; -const igraph_integer_t igraph_i_famous_dodecahedron[] = { +const igraph_int_t igraph_i_famous_dodecahedron[] = { 20, 30, 0, 0, 1, 0, 4, 0, 5, 1, 2, 1, 6, 2, 3, 2, 7, 3, 4, 3, 8, 4, 9, 5, 10, 5, 11, 6, 10, 6, 14, 7, 13, 7, 14, 8, 12, 8, 13, 9, 11, 9, 12, 10, 15, 11, 16, 12, 17, 13, 18, 14, 19, 15, 16, 15, 19, 16, 17, 17, 18, 18, 19 }; -const igraph_integer_t igraph_i_famous_folkman[] = { +const igraph_int_t igraph_i_famous_folkman[] = { 20, 40, 0, 0, 5, 0, 8, 0, 10, 0, 13, 1, 7, 1, 9, 1, 12, 1, 14, 2, 6, 2, 8, 2, 11, 2, 13, 3, 5, 3, 7, 3, 10, 3, 12, 4, 6, 4, 9, 4, 11, 4, 14, 5, 15, 5, 19, 6, 15, 6, 16, @@ -68,59 +67,59 @@ const igraph_integer_t igraph_i_famous_folkman[] = { 16, 12, 17, 13, 17, 13, 18, 14, 18, 14, 19 }; -const igraph_integer_t igraph_i_famous_franklin[] = { +const igraph_int_t igraph_i_famous_franklin[] = { 12, 18, 0, 0, 1, 0, 2, 0, 6, 1, 3, 1, 7, 2, 4, 2, 10, 3, 5, 3, 11, 4, 5, 4, 6, 5, 7, 6, 8, 7, 9, 8, 9, 8, 11, 9, 10, 10, 11 }; -const igraph_integer_t igraph_i_famous_frucht[] = { +const igraph_int_t igraph_i_famous_frucht[] = { 12, 18, 0, 0, 1, 0, 2, 0, 11, 1, 3, 1, 6, 2, 5, 2, 10, 3, 4, 3, 6, 4, 8, 4, 11, 5, 9, 5, 10, 6, 7, 7, 8, 7, 9, 8, 9, 10, 11 }; -const igraph_integer_t igraph_i_famous_grotzsch[] = { +const igraph_int_t igraph_i_famous_grotzsch[] = { 11, 20, 0, 0, 1, 0, 2, 0, 7, 0, 10, 1, 3, 1, 6, 1, 9, 2, 4, 2, 6, 2, 8, 3, 4, 3, 8, 3, 10, 4, 7, 4, 9, 5, 6, 5, 7, 5, 8, 5, 9, 5, 10 }; -const igraph_integer_t igraph_i_famous_heawood[] = { +const igraph_int_t igraph_i_famous_heawood[] = { 14, 21, 0, 0, 1, 0, 5, 0, 13, 1, 2, 1, 10, 2, 3, 2, 7, 3, 4, 3, 12, 4, 5, 4, 9, 5, 6, 6, 7, 6, 11, 7, 8, 8, 9, 8, 13, 9, 10, 10, 11, 11, 12, 12, 13 }; -const igraph_integer_t igraph_i_famous_herschel[] = { +const igraph_int_t igraph_i_famous_herschel[] = { 11, 18, 0, 0, 2, 0, 3, 0, 4, 0, 5, 1, 2, 1, 3, 1, 6, 1, 7, 2, 10, 3, 9, 4, 8, 4, 9, 5, 8, 5, 10, 6, 8, 6, 9, 7, 8, 7, 10 }; -const igraph_integer_t igraph_i_famous_house[] = { +const igraph_int_t igraph_i_famous_house[] = { 5, 6, 0, 0, 1, 0, 2, 1, 3, 2, 3, 2, 4, 3, 4 }; -const igraph_integer_t igraph_i_famous_housex[] = { +const igraph_int_t igraph_i_famous_housex[] = { 5, 8, 0, 0, 1, 0, 2, 0, 3, 1, 2, 1, 3, 2, 3, 2, 4, 3, 4 }; -const igraph_integer_t igraph_i_famous_icosahedron[] = { +const igraph_int_t igraph_i_famous_icosahedron[] = { 12, 30, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 8, 1, 2, 1, 6, 1, 7, 1, 8, 2, 4, 2, 5, 2, 6, 3, 4, 3, 8, 3, 9, 3, 11, 4, 5, 4, 11, 5, 6, 5, 10, 5, 11, 6, 7, 6, 10, 7, 8, 7, 9, 7, 10, 8, 9, 9, 10, 9, 11, 10, 11 }; -const igraph_integer_t igraph_i_famous_krackhardt_kite[] = { +const igraph_int_t igraph_i_famous_krackhardt_kite[] = { 10, 18, 0, 0, 1, 0, 2, 0, 3, 0, 5, 1, 3, 1, 4, 1, 6, 2, 3, 2, 5, 3, 4, 3, 5, 3, 6, 4, 6, 5, 6, 5, 7, 6, 7, 7, 8, 8, 9 }; -const igraph_integer_t igraph_i_famous_levi[] = { +const igraph_int_t igraph_i_famous_levi[] = { 30, 45, 0, 0, 1, 0, 7, 0, 29, 1, 2, 1, 24, 2, 3, 2, 11, 3, 4, 3, 16, 4, 5, 4, 21, 5, 6, 5, 26, 6, 7, 6, 13, 7, 8, 8, 9, 8, 17, 9, 10, 9, 22, 10, 11, 10, 27, 11, 12, 12, @@ -129,7 +128,7 @@ const igraph_integer_t igraph_i_famous_levi[] = { 28, 28, 29 }; -const igraph_integer_t igraph_i_famous_mcgee[] = { +const igraph_int_t igraph_i_famous_mcgee[] = { 24, 36, 0, 0, 1, 0, 7, 0, 23, 1, 2, 1, 18, 2, 3, 2, 14, 3, 4, 3, 10, 4, 5, 4, 21, 5, 6, 5, 17, 6, 7, 6, 13, 7, 8, 8, 9, 8, 20, 9, 10, 9, 16, 10, 11, 11, 12, 11, 23, 12, @@ -137,7 +136,7 @@ const igraph_integer_t igraph_i_famous_mcgee[] = { 21, 21, 22, 22, 23 }; -const igraph_integer_t igraph_i_famous_meredith[] = { +const igraph_int_t igraph_i_famous_meredith[] = { 70, 140, 0, 0, 4, 0, 5, 0, 6, 1, 4, 1, 5, 1, 6, 2, 4, 2, 5, 2, 6, 3, 4, 3, 5, 3, 6, 7, 11, 7, 12, 7, 13, 8, 11, 8, 12, 8, 13, 9, 11, 9, 12, 9, 13, 10, 11, 10, 12, 10, 13, @@ -155,14 +154,14 @@ const igraph_integer_t igraph_i_famous_meredith[] = { 28, 38, 42, 35, 66, 59, 63, 52, 56, 45, 49 }; -const igraph_integer_t igraph_i_famous_noperfectmatching[] = { +const igraph_int_t igraph_i_famous_noperfectmatching[] = { 16, 27, 0, 0, 1, 0, 2, 0, 3, 1, 2, 1, 3, 2, 3, 2, 4, 3, 4, 4, 5, 5, 6, 5, 7, 6, 12, 6, 13, 7, 8, 7, 9, 8, 9, 8, 10, 8, 11, 9, 10, 9, 11, 10, 11, 12, 13, 12, 14, 12, 15, 13, 14, 13, 15, 14, 15 }; -const igraph_integer_t igraph_i_famous_nonline[] = { +const igraph_int_t igraph_i_famous_nonline[] = { 50, 72, 0, 0, 1, 0, 2, 0, 3, 4, 6, 4, 7, 5, 6, 5, 7, 6, 7, 7, 8, 9, 11, 9, 12, 9, 13, 10, 11, 10, 12, 10, 13, 11, 12, 11, 13, 12, 13, 14, 15, 15, 16, 15, 17, 16, 17, 16, @@ -173,17 +172,17 @@ const igraph_integer_t igraph_i_famous_nonline[] = { 43, 44, 45, 44, 46, 45, 46, 45, 47, 46, 47, 46, 48, 47, 48, 47, 49, 48, 49 }; -const igraph_integer_t igraph_i_famous_octahedron[] = { +const igraph_int_t igraph_i_famous_octahedron[] = { 6, 12, 0, 0, 1, 0, 2, 1, 2, 3, 4, 3, 5, 4, 5, 0, 3, 0, 5, 1, 3, 1, 4, 2, 4, 2, 5 }; -const igraph_integer_t igraph_i_famous_petersen[] = { +const igraph_int_t igraph_i_famous_petersen[] = { 10, 15, 0, 0, 1, 0, 4, 0, 5, 1, 2, 1, 6, 2, 3, 2, 7, 3, 4, 3, 8, 4, 9, 5, 7, 5, 8, 6, 8, 6, 9, 7, 9 }; -const igraph_integer_t igraph_i_famous_robertson[] = { +const igraph_int_t igraph_i_famous_robertson[] = { 19, 38, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 0, 18, 0, 4, 4, 9, 9, 13, 13, @@ -191,18 +190,18 @@ const igraph_integer_t igraph_i_famous_robertson[] = { 7, 14, 3, 14, 3, 11, 11, 18 }; -const igraph_integer_t igraph_i_famous_smallestcyclicgroup[] = { +const igraph_int_t igraph_i_famous_smallestcyclicgroup[] = { 9, 15, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 1, 2, 1, 3, 1, 7, 1, 8, 2, 5, 2, 6, 2, 7, 3, 8, 4, 5, 6, 7 }; -const igraph_integer_t igraph_i_famous_tetrahedron[] = { +const igraph_int_t igraph_i_famous_tetrahedron[] = { 4, 6, 0, 0, 3, 1, 3, 2, 3, 0, 1, 1, 2, 0, 2 }; -const igraph_integer_t igraph_i_famous_thomassen[] = { +const igraph_int_t igraph_i_famous_thomassen[] = { 34, 52, 0, 0, 2, 0, 3, 1, 3, 1, 4, 2, 4, 5, 7, 5, 8, 6, 8, 6, 9, 7, 9, 10, 12, 10, 13, 11, 13, 11, 14, 12, 14, 15, 17, 15, 18, 16, 18, 16, 19, 17, 19, 9, 19, 4, 14, 24, @@ -211,7 +210,7 @@ const igraph_integer_t igraph_i_famous_thomassen[] = { 23, 10, 27, 11, 28, 12, 29, 13, 30, 15, 30, 16, 31, 17, 32, 18, 33 }; -const igraph_integer_t igraph_i_famous_tutte[] = { +const igraph_int_t igraph_i_famous_tutte[] = { 46, 69, 0, 0, 10, 0, 11, 0, 12, 1, 2, 1, 7, 1, 19, 2, 3, 2, 41, 3, 4, 3, 27, 4, 5, 4, 33, 5, 6, 5, 45, 6, 9, 6, 29, 7, 8, 7, 21, 8, 9, 8, 22, 9, 24, 10, 13, 10, 14, 11, @@ -222,20 +221,20 @@ const igraph_integer_t igraph_i_famous_tutte[] = { 40, 39, 41, 40, 41, 42, 43, 43, 45, 44, 45 }; -const igraph_integer_t igraph_i_famous_uniquely3colorable[] = { +const igraph_int_t igraph_i_famous_uniquely3colorable[] = { 12, 22, 0, 0, 1, 0, 3, 0, 6, 0, 8, 1, 4, 1, 7, 1, 9, 2, 3, 2, 6, 2, 7, 2, 9, 2, 11, 3, 4, 3, 10, 4, 5, 4, 11, 5, 6, 5, 7, 5, 8, 5, 10, 8, 11, 9, 10 }; -const igraph_integer_t igraph_i_famous_walther[] = { +const igraph_int_t igraph_i_famous_walther[] = { 25, 31, 0, 0, 1, 1, 2, 1, 8, 2, 3, 2, 13, 3, 4, 3, 16, 4, 5, 5, 6, 5, 19, 6, 7, 6, 20, 7, 21, 8, 9, 8, 13, 9, 10, 9, 22, 10, 11, 10, 20, 11, 12, 13, 14, 14, 15, 14, 23, 15, 16, 15, 17, 17, 18, 18, 19, 18, 24, 20, 24, 22, 23, 23, 24 }; -const igraph_integer_t igraph_i_famous_zachary[] = { +const igraph_int_t igraph_i_famous_zachary[] = { 34, 78, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 10, 0, 11, 0, 12, 0, 13, 0, 17, 0, 19, 0, 21, 0, 31, @@ -250,14 +249,14 @@ const igraph_integer_t igraph_i_famous_zachary[] = { 32, 33 }; -static igraph_error_t igraph_i_famous(igraph_t *graph, const igraph_integer_t *data) { - igraph_integer_t no_of_nodes = data[0]; - igraph_integer_t no_of_edges = data[1]; +static igraph_error_t igraph_i_famous(igraph_t *graph, const igraph_int_t *data) { + igraph_int_t no_of_nodes = data[0]; + igraph_int_t no_of_edges = data[1]; igraph_bool_t directed = (igraph_bool_t) data[2]; - igraph_vector_int_t edges; + const igraph_vector_int_t edges = igraph_vector_int_view(data + 3, 2 * no_of_edges); - igraph_vector_int_view(&edges, data + 3, 2 * no_of_edges); IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed)); + return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/constructors/full.c b/src/vendor/cigraph/src/constructors/full.c index c5774950d1b..583e87f69bf 100644 --- a/src/vendor/cigraph/src/constructors/full.c +++ b/src/vendor/cigraph/src/constructors/full.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -52,11 +51,11 @@ * * \example examples/simple/igraph_full.c */ -igraph_error_t igraph_full(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, +igraph_error_t igraph_full(igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_bool_t loops) { igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; if (n < 0) { IGRAPH_ERROR("Invalid number of vertices.", IGRAPH_EINVAL); @@ -69,8 +68,8 @@ igraph_error_t igraph_full(igraph_t *graph, igraph_integer_t n, igraph_bool_t di IGRAPH_SAFE_MULT(n, n, &no_of_edges2); IGRAPH_SAFE_MULT(no_of_edges2, 2, &no_of_edges2); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); - for (igraph_integer_t i = 0; i < n; i++) { - for (igraph_integer_t j = 0; j < n; j++) { + for (igraph_int_t i = 0; i < n; i++) { + for (igraph_int_t j = 0; j < n; j++) { igraph_vector_int_push_back(&edges, i); /* reserved */ igraph_vector_int_push_back(&edges, j); /* reserved */ } @@ -81,12 +80,12 @@ igraph_error_t igraph_full(igraph_t *graph, igraph_integer_t n, igraph_bool_t di IGRAPH_SAFE_MULT(n, n - 1, &no_of_edges2); IGRAPH_SAFE_MULT(no_of_edges2, 2, &no_of_edges2); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); - for (igraph_integer_t i = 0; i < n; i++) { - for (igraph_integer_t j = 0; j < i; j++) { + for (igraph_int_t i = 0; i < n; i++) { + for (igraph_int_t j = 0; j < i; j++) { igraph_vector_int_push_back(&edges, i); /* reserved */ igraph_vector_int_push_back(&edges, j); /* reserved */ } - for (igraph_integer_t j = i + 1; j < n; j++) { + for (igraph_int_t j = i + 1; j < n; j++) { igraph_vector_int_push_back(&edges, i); /* reserved */ igraph_vector_int_push_back(&edges, j); /* reserved */ } @@ -97,8 +96,8 @@ igraph_error_t igraph_full(igraph_t *graph, igraph_integer_t n, igraph_bool_t di IGRAPH_SAFE_ADD(n, 1, &no_of_edges2); IGRAPH_SAFE_MULT(n, no_of_edges2, &no_of_edges2); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); - for (igraph_integer_t i = 0; i < n; i++) { - for (igraph_integer_t j = i; j < n; j++) { + for (igraph_int_t i = 0; i < n; i++) { + for (igraph_int_t j = i; j < n; j++) { igraph_vector_int_push_back(&edges, i); /* reserved */ igraph_vector_int_push_back(&edges, j); /* reserved */ } @@ -108,8 +107,8 @@ igraph_error_t igraph_full(igraph_t *graph, igraph_integer_t n, igraph_bool_t di /* ecount = n * (n - 1) / 2 */ IGRAPH_SAFE_MULT(n, n - 1, &no_of_edges2); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); - for (igraph_integer_t i = 0; i < n; i++) { - for (igraph_integer_t j = i + 1; j < n; j++) { + for (igraph_int_t i = 0; i < n; i++) { + for (igraph_int_t j = i + 1; j < n; j++) { igraph_vector_int_push_back(&edges, i); /* reserved */ igraph_vector_int_push_back(&edges, j); /* reserved */ } @@ -161,7 +160,7 @@ igraph_error_t igraph_full_multipartite(igraph_t *graph, igraph_vector_int_t edges; igraph_vector_int_t n_acc; - igraph_integer_t no_of_types = igraph_vector_int_size(n); + igraph_int_t no_of_types = igraph_vector_int_size(n); if (no_of_types == 0) { IGRAPH_CHECK(igraph_empty(graph, 0, directed)); @@ -177,16 +176,16 @@ igraph_error_t igraph_full_multipartite(igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&n_acc, no_of_types+1); VECTOR(n_acc)[0] = 0; - for (igraph_integer_t i = 1; i < no_of_types+1; i++) { + for (igraph_int_t i = 1; i < no_of_types+1; i++) { IGRAPH_SAFE_ADD(VECTOR(n_acc)[i-1], VECTOR(*n)[i-1], &VECTOR(n_acc)[i]); } - igraph_integer_t no_of_edges2 = 0; + igraph_int_t no_of_edges2 = 0; - for (igraph_integer_t i = 0; i < no_of_types; i++) { - igraph_integer_t v = VECTOR(*n)[i]; - igraph_integer_t partial_sum = VECTOR(n_acc)[no_of_types] - v; + for (igraph_int_t i = 0; i < no_of_types; i++) { + igraph_int_t v = VECTOR(*n)[i]; + igraph_int_t partial_sum = VECTOR(n_acc)[no_of_types] - v; IGRAPH_SAFE_MULT(partial_sum, v, &partial_sum); IGRAPH_SAFE_ADD(no_of_edges2, partial_sum, &no_of_edges2); } @@ -197,14 +196,14 @@ igraph_error_t igraph_full_multipartite(igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges2); - igraph_integer_t ptr = 0; + igraph_int_t ptr = 0; - for (igraph_integer_t from_type = 0; from_type < no_of_types-1; from_type++) { - igraph_integer_t edge_from = VECTOR(n_acc)[from_type]; - for (igraph_integer_t i = 0; i < VECTOR(*n)[from_type]; i++) { - for (igraph_integer_t to_type = from_type+1; to_type < no_of_types; to_type++) { - igraph_integer_t edge_to = VECTOR(n_acc)[to_type]; - for (igraph_integer_t j = 0; j < VECTOR(*n)[to_type]; j++) { + for (igraph_int_t from_type = 0; from_type < no_of_types-1; from_type++) { + igraph_int_t edge_from = VECTOR(n_acc)[from_type]; + for (igraph_int_t i = 0; i < VECTOR(*n)[from_type]; i++) { + for (igraph_int_t to_type = from_type+1; to_type < no_of_types; to_type++) { + igraph_int_t edge_to = VECTOR(n_acc)[to_type]; + for (igraph_int_t j = 0; j < VECTOR(*n)[to_type]; j++) { if (!directed || mode == IGRAPH_OUT) { VECTOR(edges)[ptr++] = edge_from; VECTOR(edges)[ptr++] = edge_to; @@ -230,8 +229,8 @@ igraph_error_t igraph_full_multipartite(igraph_t *graph, if (types) { IGRAPH_CHECK(igraph_vector_int_resize(types, VECTOR(n_acc)[no_of_types])); if (VECTOR(n_acc)[no_of_types] > 0) { - igraph_integer_t v = 1; - for (igraph_integer_t i = 0; i < VECTOR(n_acc)[no_of_types]; i++) { + igraph_int_t v = 1; + for (igraph_int_t i = 0; i < VECTOR(n_acc)[no_of_types]; i++) { if (i == VECTOR(n_acc)[v]) { v++; } @@ -281,10 +280,10 @@ igraph_error_t igraph_full_multipartite(igraph_t *graph, */ igraph_error_t igraph_turan(igraph_t *graph, igraph_vector_int_t *types, - igraph_integer_t n, - igraph_integer_t r) { - igraph_integer_t quotient; - igraph_integer_t remainder; + igraph_int_t n, + igraph_int_t r) { + igraph_int_t quotient; + igraph_int_t remainder; igraph_vector_int_t subsets; if (n < 0) { @@ -313,7 +312,7 @@ igraph_error_t igraph_turan(igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&subsets, r); igraph_vector_int_fill(&subsets, quotient); - for (igraph_integer_t i = 0; i < remainder; i++) { + for (igraph_int_t i = 0; i < remainder; i++) { VECTOR(subsets)[i]++; } @@ -346,23 +345,23 @@ igraph_error_t igraph_turan(igraph_t *graph, * Time complexity: O(|V|^2) = O(|E|), * where |V| is the number of vertices and |E| is the number of edges. */ -igraph_error_t igraph_full_citation(igraph_t *graph, igraph_integer_t n, +igraph_error_t igraph_full_citation(igraph_t *graph, igraph_int_t n, igraph_bool_t directed) { igraph_vector_int_t edges; - igraph_integer_t ptr = 0; + igraph_int_t ptr = 0; if (n < 0) { IGRAPH_ERROR("Invalid number of vertices.", IGRAPH_EINVAL); } { - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; IGRAPH_SAFE_MULT(n, n-1, &no_of_edges2); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges2); } - for (igraph_integer_t i = 1; i < n; i++) { - for (igraph_integer_t j = 0; j < i; j++) { + for (igraph_int_t i = 1; i < n; i++) { + for (igraph_int_t j = 0; j < i; j++) { VECTOR(edges)[ptr++] = i; VECTOR(edges)[ptr++] = j; } diff --git a/src/vendor/cigraph/src/constructors/generalized_petersen.c b/src/vendor/cigraph/src/constructors/generalized_petersen.c index 0b34f7e8488..a6670454c15 100644 --- a/src/vendor/cigraph/src/constructors/generalized_petersen.c +++ b/src/vendor/cigraph/src/constructors/generalized_petersen.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -55,11 +55,11 @@ * * Time complexity: O(|V|), the number of vertices in the graph. */ -igraph_error_t igraph_generalized_petersen(igraph_t *graph, igraph_integer_t n, igraph_integer_t k) { +igraph_error_t igraph_generalized_petersen(igraph_t *graph, igraph_int_t n, igraph_int_t k) { /* This is a generalized Petersen graph constructor */ igraph_vector_int_t edges; - igraph_integer_t no_of_nodes, no_of_edges2; - igraph_integer_t i; + igraph_int_t no_of_nodes, no_of_edges2; + igraph_int_t i; if (n < 3) { IGRAPH_ERRORF("n = %" IGRAPH_PRId " must be at least 3.", IGRAPH_EINVAL, n); @@ -78,12 +78,12 @@ igraph_error_t igraph_generalized_petersen(igraph_t *graph, igraph_integer_t n, IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); for (i = 0; i < n; i++) { - igraph_vector_int_push_back(&edges, i); - igraph_vector_int_push_back(&edges, (i + 1) % n); - igraph_vector_int_push_back(&edges, i); - igraph_vector_int_push_back(&edges, i + n); - igraph_vector_int_push_back(&edges, i + n); - igraph_vector_int_push_back(&edges, ((i + k) % n) + n); + igraph_vector_int_push_back(&edges, i); /* reserved */ + igraph_vector_int_push_back(&edges, (i + 1) % n); /* reserved */ + igraph_vector_int_push_back(&edges, i); /* reserved */ + igraph_vector_int_push_back(&edges, i + n); /* reserved */ + igraph_vector_int_push_back(&edges, i + n); /* reserved */ + igraph_vector_int_push_back(&edges, ((i + k) % n) + n); /* reserved */ } IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, IGRAPH_UNDIRECTED)); diff --git a/src/vendor/cigraph/src/constructors/kautz.c b/src/vendor/cigraph/src/constructors/kautz.c index 7684847b341..7b68a268651 100644 --- a/src/vendor/cigraph/src/constructors/kautz.c +++ b/src/vendor/cigraph/src/constructors/kautz.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -59,19 +58,19 @@ * like O(|V|+|E|). |V| is the number of vertices, |E| is the number * of edges and \c m and \c n are the corresponding arguments. */ -igraph_error_t igraph_kautz(igraph_t *graph, igraph_integer_t m, igraph_integer_t n) { +igraph_error_t igraph_kautz(igraph_t *graph, igraph_int_t m, igraph_int_t n) { /* m+1 - number of symbols */ /* n+1 - length of strings */ - igraph_integer_t no_of_nodes, no_of_edges; - igraph_integer_t allstrings; - igraph_integer_t i, j, idx = 0; + igraph_int_t no_of_nodes, no_of_edges; + igraph_int_t allstrings; + igraph_int_t i, j, idx = 0; igraph_vector_int_t edges; igraph_vector_int_t digits, table; igraph_vector_int_t index1, index2; - igraph_integer_t actb = 0; - igraph_integer_t actvalue = 0; + igraph_int_t actb = 0; + igraph_int_t actvalue = 0; int iter = 0; if (m < 0 || n < 0) { @@ -89,7 +88,7 @@ igraph_error_t igraph_kautz(igraph_t *graph, igraph_integer_t m, igraph_integer_ /* no_of_nodes = ((m + 1) * pow(m, n)) */ { igraph_real_t m_to_pow_n_real = pow(m, n); - igraph_integer_t m_to_pow_n = m_to_pow_n_real; + igraph_int_t m_to_pow_n = m_to_pow_n_real; if (m_to_pow_n != m_to_pow_n_real) { IGRAPH_ERRORF("Parameters (%" IGRAPH_PRId ", %" IGRAPH_PRId ") too large for Kautz graph.", IGRAPH_EINVAL, m, n); @@ -129,7 +128,7 @@ igraph_error_t igraph_kautz(igraph_t *graph, igraph_integer_t m, igraph_integer_ while (true) { /* at the beginning of the loop, 0:actb contain the valid prefix */ /* we might need to fill it to get a valid string */ - igraph_integer_t z = 0; + igraph_int_t z = 0; if (VECTOR(digits)[actb] == 0) { z = 1; } @@ -153,7 +152,7 @@ igraph_error_t igraph_kautz(igraph_t *graph, igraph_integer_t m, igraph_integer_ /* not yet, we need a valid prefix now */ while (true) { /* try to increase digits at position actb */ - igraph_integer_t next = VECTOR(digits)[actb] + 1; + igraph_int_t next = VECTOR(digits)[actb] + 1; if (actb != 0 && VECTOR(digits)[actb - 1] == next) { next++; } @@ -171,18 +170,18 @@ igraph_error_t igraph_kautz(igraph_t *graph, igraph_integer_t m, igraph_integer_ } { - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; IGRAPH_SAFE_MULT(no_of_edges, 2, &no_of_edges2); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); } /* Now come the edges at last */ for (i = 0; i < no_of_nodes; i++) { - igraph_integer_t fromvalue = VECTOR(index2)[i]; - igraph_integer_t lastdigit = fromvalue % (m + 1); - igraph_integer_t basis = (fromvalue * (m + 1)) % allstrings; + igraph_int_t fromvalue = VECTOR(index2)[i]; + igraph_int_t lastdigit = fromvalue % (m + 1); + igraph_int_t basis = (fromvalue * (m + 1)) % allstrings; for (j = 0; j <= m; j++) { - igraph_integer_t tovalue, to; + igraph_int_t tovalue, to; if (j == lastdigit) { continue; } diff --git a/src/vendor/cigraph/src/constructors/lattices.c b/src/vendor/cigraph/src/constructors/lattices.c index 7ea8e23c5ec..bdbc1c50efb 100644 --- a/src/vendor/cigraph/src/constructors/lattices.c +++ b/src/vendor/cigraph/src/constructors/lattices.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -88,10 +88,10 @@ static igraph_error_t triangular_lattice( igraph_t *graph, igraph_bool_t directed, igraph_bool_t mutual, igraph_bool_t lex_ordering, const igraph_vector_int_t *row_lengths_vector, const igraph_vector_int_t *row_start_vector) { igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t row_count = igraph_vector_int_size(row_lengths_vector); - igraph_integer_t no_of_nodes; + igraph_int_t row_count = igraph_vector_int_size(row_lengths_vector); + igraph_int_t no_of_nodes; igraph_vector_int_t row_lengths_prefix_sum_vector; - igraph_integer_t i, j; + igraph_int_t i, j; if (igraph_vector_int_size(row_lengths_vector) != igraph_vector_int_size(row_start_vector)) { IGRAPH_ERRORF( @@ -122,8 +122,8 @@ static igraph_error_t triangular_lattice( COMPUTE_NUMBER_OF_VERTICES(); /* computing the number of edges in the constructed triangular lattice */ - igraph_integer_t no_of_edges2 = VECTOR(*row_lengths_vector)[row_count - 1] - 1; - igraph_integer_t multiplier = mutual && directed ? 4 : 2; + igraph_int_t no_of_edges2 = VECTOR(*row_lengths_vector)[row_count - 1] - 1; + igraph_int_t multiplier = mutual && directed ? 4 : 2; for (j = 0; j < row_count - 1; j++) { IGRAPH_SAFE_ADD(no_of_edges2, VECTOR(*row_lengths_vector)[j] - 1, &no_of_edges2); IGRAPH_SAFE_ADD(no_of_edges2, MIN(ROW_END(j), ROW_END((j + 1))) - MAX(VECTOR(*row_start_vector)[j], VECTOR(*row_start_vector)[j + 1]) + 1, @@ -135,7 +135,7 @@ static igraph_error_t triangular_lattice( IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); /* constructing the edge array */ - igraph_integer_t k; + igraph_int_t k; for (j = 0; j < row_count; j++) { IGRAPH_ALLOW_INTERRUPTION(); for (i = 0; i < VECTOR(*row_lengths_vector)[j]; i++) { @@ -157,11 +157,11 @@ static igraph_error_t triangular_lattice( return IGRAPH_SUCCESS; } -static igraph_error_t triangular_lattice_triangle_shape(igraph_t *graph, igraph_integer_t size, igraph_bool_t directed, igraph_bool_t mutual) { - igraph_integer_t row_count = size; +static igraph_error_t triangular_lattice_triangle_shape(igraph_t *graph, igraph_int_t size, igraph_bool_t directed, igraph_bool_t mutual) { + igraph_int_t row_count = size; igraph_vector_int_t row_lengths_vector; igraph_vector_int_t row_start_vector; - igraph_integer_t i; + igraph_int_t i; IGRAPH_VECTOR_INT_INIT_FINALLY(&row_lengths_vector, row_count); IGRAPH_VECTOR_INT_INIT_FINALLY(&row_start_vector, row_count); @@ -181,12 +181,12 @@ static igraph_error_t triangular_lattice_triangle_shape(igraph_t *graph, igraph_ } static igraph_error_t triangular_lattice_rectangle_shape( - igraph_t *graph, igraph_integer_t size_x, igraph_integer_t size_y, + igraph_t *graph, igraph_int_t size_x, igraph_int_t size_y, igraph_bool_t directed, igraph_bool_t mutual) { - igraph_integer_t row_count = size_x; + igraph_int_t row_count = size_x; igraph_vector_int_t row_lengths_vector; igraph_vector_int_t row_start_vector; - igraph_integer_t i; + igraph_int_t i; IGRAPH_VECTOR_INT_INIT_FINALLY(&row_lengths_vector, row_count); IGRAPH_VECTOR_INT_INIT_FINALLY(&row_start_vector, row_count); @@ -206,21 +206,21 @@ static igraph_error_t triangular_lattice_rectangle_shape( } static igraph_error_t triangular_lattice_hex_shape( - igraph_t *graph, igraph_integer_t size_x, igraph_integer_t size_y, - igraph_integer_t size_z, igraph_bool_t directed, igraph_bool_t mutual) { - igraph_integer_t row_count = size_y + size_z - 1; + igraph_t *graph, igraph_int_t size_x, igraph_int_t size_y, + igraph_int_t size_z, igraph_bool_t directed, igraph_bool_t mutual) { + igraph_int_t row_count = size_y + size_z - 1; igraph_vector_int_t row_lengths_vector; igraph_vector_int_t row_start_vector; - igraph_integer_t i; + igraph_int_t i; IGRAPH_VECTOR_INT_INIT_FINALLY(&row_lengths_vector, row_count); IGRAPH_VECTOR_INT_INIT_FINALLY(&row_start_vector, row_count); - igraph_integer_t row_length = size_x; - igraph_integer_t row_start = size_y - 1; - igraph_integer_t first_threshold = MIN(size_y - 1, size_z - 1); - igraph_integer_t second_threshold = MAX(size_y - 1, size_z - 1); - igraph_integer_t sgn_flag = size_y < size_z ? 0 : -1; + igraph_int_t row_length = size_x; + igraph_int_t row_start = size_y - 1; + igraph_int_t first_threshold = MIN(size_y - 1, size_z - 1); + igraph_int_t second_threshold = MAX(size_y - 1, size_z - 1); + igraph_int_t sgn_flag = size_y < size_z ? 0 : -1; for (i = 0; i < row_count; i++) { VECTOR(row_lengths_vector)[i] = row_length; @@ -249,8 +249,6 @@ static igraph_error_t triangular_lattice_hex_shape( * \function igraph_triangular_lattice * \brief A triangular lattice with the given shape. * - * \experimental - * * Creates a triangular lattice whose vertices have the form (i, j) for non-negative * integers i and j and (i, j) is generally connected with (i + 1, j), (i, j + 1), * and (i - 1, j + 1). The function constructs a planar dual of the graph @@ -292,7 +290,7 @@ static igraph_error_t triangular_lattice_hex_shape( igraph_error_t igraph_triangular_lattice( igraph_t *graph, const igraph_vector_int_t *dims, igraph_bool_t directed, igraph_bool_t mutual) { - igraph_integer_t num_dims = igraph_vector_int_size(dims); + igraph_int_t num_dims = igraph_vector_int_size(dims); if (igraph_vector_int_any_smaller(dims, 0)) { IGRAPH_ERROR("Invalid dimension vector.", IGRAPH_EINVAL); } @@ -354,10 +352,10 @@ static igraph_error_t hexagonal_lattice( const igraph_vector_int_t *row_lengths_vector, const igraph_vector_int_t *row_start_vector ) { igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t row_count = igraph_vector_int_size(row_lengths_vector); - igraph_integer_t no_of_nodes; + igraph_int_t row_count = igraph_vector_int_size(row_lengths_vector); + igraph_int_t no_of_nodes; igraph_vector_int_t row_lengths_prefix_sum_vector; - igraph_integer_t i, j; + igraph_int_t i, j; igraph_bool_t lex_ordering = false; if (igraph_vector_int_size(row_lengths_vector) != igraph_vector_int_size(row_start_vector)) { @@ -384,8 +382,8 @@ static igraph_error_t hexagonal_lattice( COMPUTE_NUMBER_OF_VERTICES(); /* computing the number of edges in the constructed hex lattice */ - igraph_integer_t no_of_edges2 = VECTOR(*row_lengths_vector)[row_count - 1] - 1; - igraph_integer_t multiplier = mutual && directed ? 4 : 2, low, high; + igraph_int_t no_of_edges2 = VECTOR(*row_lengths_vector)[row_count - 1] - 1; + igraph_int_t multiplier = mutual && directed ? 4 : 2, low, high; for (j = 0; j < row_count - 1; j++) { IGRAPH_SAFE_ADD(no_of_edges2, VECTOR(*row_lengths_vector)[j] - 1, &no_of_edges2); low = MAX((VECTOR(*row_start_vector)[j] - 1), (VECTOR(*row_start_vector)[j + 1])); @@ -398,7 +396,7 @@ static igraph_error_t hexagonal_lattice( IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); /* constructing the edge array */ - igraph_integer_t k; + igraph_int_t k; for (j = 0; j < row_count; j++) { IGRAPH_ALLOW_INTERRUPTION(); for (i = 0; i < VECTOR(*row_lengths_vector)[j]; i++) { @@ -419,12 +417,12 @@ static igraph_error_t hexagonal_lattice( return IGRAPH_SUCCESS; } -static igraph_error_t hexagonal_lattice_triangle_shape(igraph_t *graph, igraph_integer_t size, igraph_bool_t directed, igraph_bool_t mutual) { - igraph_integer_t row_count; +static igraph_error_t hexagonal_lattice_triangle_shape(igraph_t *graph, igraph_int_t size, igraph_bool_t directed, igraph_bool_t mutual) { + igraph_int_t row_count; IGRAPH_SAFE_ADD(size, 2, &row_count); igraph_vector_int_t row_lengths_vector; igraph_vector_int_t row_start_vector; - igraph_integer_t i; + igraph_int_t i; IGRAPH_VECTOR_INT_INIT_FINALLY(&row_lengths_vector, row_count - 1); IGRAPH_VECTOR_INT_INIT_FINALLY(&row_start_vector, row_count - 1); @@ -444,17 +442,17 @@ static igraph_error_t hexagonal_lattice_triangle_shape(igraph_t *graph, igraph_i } static igraph_error_t hexagonal_lattice_rectangle_shape( - igraph_t *graph, igraph_integer_t size_x, igraph_integer_t size_y, + igraph_t *graph, igraph_int_t size_x, igraph_int_t size_y, igraph_bool_t directed, igraph_bool_t mutual ) { - igraph_integer_t row_count; + igraph_int_t row_count; IGRAPH_SAFE_ADD(size_x, 1, &row_count); igraph_vector_int_t row_lengths_vector; igraph_vector_int_t row_start_vector; - igraph_integer_t actual_size_y; + igraph_int_t actual_size_y; IGRAPH_SAFE_ADD(size_y, 1, &actual_size_y); IGRAPH_SAFE_MULT(actual_size_y, 2, &actual_size_y); - igraph_integer_t i; + igraph_int_t i; IGRAPH_VECTOR_INT_INIT_FINALLY(&row_lengths_vector, row_count); IGRAPH_VECTOR_INT_INIT_FINALLY(&row_start_vector, row_count); @@ -479,26 +477,26 @@ static igraph_error_t hexagonal_lattice_rectangle_shape( } static igraph_error_t hexagonal_lattice_hex_shape( - igraph_t *graph, igraph_integer_t size_x, igraph_integer_t size_y, - igraph_integer_t size_z, igraph_bool_t directed, igraph_bool_t mutual + igraph_t *graph, igraph_int_t size_x, igraph_int_t size_y, + igraph_int_t size_z, igraph_bool_t directed, igraph_bool_t mutual ) { - igraph_integer_t row_count = size_y + size_z; + igraph_int_t row_count = size_y + size_z; igraph_vector_int_t row_lengths_vector; igraph_vector_int_t row_start_vector; - igraph_integer_t i; + igraph_int_t i; IGRAPH_VECTOR_INT_INIT_FINALLY(&row_lengths_vector, row_count); IGRAPH_VECTOR_INT_INIT_FINALLY(&row_start_vector, row_count); - igraph_integer_t row_length; + igraph_int_t row_length; IGRAPH_SAFE_MULT(size_x, 2, &row_length); IGRAPH_SAFE_ADD(row_length, 1, &row_length); - igraph_integer_t row_start; + igraph_int_t row_start; IGRAPH_SAFE_MULT(size_y, 2, &row_start); IGRAPH_SAFE_ADD(row_start, -1, &row_start); - igraph_integer_t first_threshold = MIN(size_y - 1, size_z - 1); - igraph_integer_t second_threshold = MAX(size_y - 1, size_z - 1); - igraph_integer_t sgn_flag = size_y < size_z ? 0 : -2; + igraph_int_t first_threshold = MIN(size_y - 1, size_z - 1); + igraph_int_t second_threshold = MAX(size_y - 1, size_z - 1); + igraph_int_t sgn_flag = size_y < size_z ? 0 : -2; for (i = 0; i < row_count; i++) { VECTOR(row_lengths_vector)[i] = row_length; @@ -534,8 +532,6 @@ static igraph_error_t hexagonal_lattice_hex_shape( * \function igraph_hexagonal_lattice * \brief A hexagonal lattice with the given shape. * - * \experimental - * * Creates a hexagonal lattice whose vertices have the form (i, j) for non-negative * integers i and j and (i, j) is generally connected with (i + 1, j), and if i is * odd also with (i - 1, j + 1). The function constructs a planar dual of the graph @@ -576,7 +572,7 @@ static igraph_error_t hexagonal_lattice_hex_shape( igraph_error_t igraph_hexagonal_lattice( igraph_t *graph, const igraph_vector_int_t *dims, igraph_bool_t directed, igraph_bool_t mutual) { - igraph_integer_t num_dims = igraph_vector_int_size(dims); + igraph_int_t num_dims = igraph_vector_int_size(dims); if (igraph_vector_int_any_smaller(dims, 0)) { IGRAPH_ERROR("Invalid dimension vector.", IGRAPH_EINVAL); } diff --git a/src/vendor/cigraph/src/constructors/lcf.c b/src/vendor/cigraph/src/constructors/lcf.c index 44eb78640a8..8df89e2c78c 100644 --- a/src/vendor/cigraph/src/constructors/lcf.c +++ b/src/vendor/cigraph/src/constructors/lcf.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -27,34 +26,39 @@ #include "math/safe_intop.h" /** - * \function igraph_lcf_vector + * \function igraph_lcf * \brief Creates a graph from LCF notation. * - * This function is essentially the same as \ref igraph_lcf(), only - * the way for giving the arguments is different. See \ref - * igraph_lcf() for details. + * LCF notation (named after Lederberg, Coxeter and Frucht) is a concise notation + * for 3-regular Hamiltonian graphs. It consists of three parameters: the + * number of vertices in the graph, a list of shifts giving additional + * edges to a cycle backbone, and another integer giving how many times + * the shifts should be performed. See + * https://mathworld.wolfram.com/LCFNotation.html for details. + * * \param graph Pointer to an uninitialized graph object. - * \param n Integer constant giving the number of vertices. - * \param shifts A vector giving the shifts. - * \param repeats An integer constant giving the number of repeats - * for the shifts. + * \param n Integer constant giving the number of vertices. This + * is normally set to the number of shifts multiplied by the + * number of repeats. + * \param shifts An integer vector giving the shifts. + * \param repeats The number of repeats for the shifts. * \return Error code. * - * \sa \ref igraph_lcf(), \ref igraph_extended_chordal_ring() + * \sa \ref igraph_lcf_small(), \ref igraph_extended_chordal_ring() * * Time complexity: O(|V|+|E|), linear in the number of vertices plus * the number of edges. */ -igraph_error_t igraph_lcf_vector(igraph_t *graph, igraph_integer_t n, - const igraph_vector_int_t *shifts, - igraph_integer_t repeats) { +igraph_error_t igraph_lcf(igraph_t *graph, igraph_int_t n, + const igraph_vector_int_t *shifts, + igraph_int_t repeats) { igraph_vector_int_t edges; - igraph_integer_t no_of_shifts = igraph_vector_int_size(shifts); - igraph_integer_t ptr = 0, i, sptr = 0; - igraph_integer_t no_of_nodes = n; - igraph_integer_t no_of_edges = n + no_of_shifts * repeats; - igraph_integer_t no_of_edges2; + igraph_int_t no_of_shifts = igraph_vector_int_size(shifts); + igraph_int_t ptr = 0, sptr = 0; + igraph_int_t no_of_nodes = n; + igraph_int_t no_of_edges; + igraph_int_t no_of_edges2; if (repeats < 0) { IGRAPH_ERROR("Number of repeats must not be negative.", IGRAPH_EINVAL); @@ -69,7 +73,7 @@ igraph_error_t igraph_lcf_vector(igraph_t *graph, igraph_integer_t n, if (no_of_nodes > 0) { /* Create a ring first */ - for (i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { VECTOR(edges)[ptr++] = i; VECTOR(edges)[ptr++] = i + 1; } @@ -78,9 +82,9 @@ igraph_error_t igraph_lcf_vector(igraph_t *graph, igraph_integer_t n, /* Then add the rest */ while (ptr < 2 * no_of_edges) { - igraph_integer_t sh = VECTOR(*shifts)[sptr % no_of_shifts]; - igraph_integer_t from = sptr % no_of_nodes; - igraph_integer_t to = (no_of_nodes + sptr + sh) % no_of_nodes; + igraph_int_t sh = VECTOR(*shifts)[sptr % no_of_shifts]; + igraph_int_t from = sptr % no_of_nodes; + igraph_int_t to = (no_of_nodes + sptr + sh) % no_of_nodes; VECTOR(edges)[ptr++] = from; VECTOR(edges)[ptr++] = to; sptr++; @@ -95,16 +99,12 @@ igraph_error_t igraph_lcf_vector(igraph_t *graph, igraph_integer_t n, } /** - * \function igraph_lcf - * \brief Creates a graph from LCF notation. + * \function igraph_lcf_small + * \brief Shorthand to create a graph from LCF notation, giving shifts as the arguments. * - * - * LCF is short for Lederberg-Coxeter-Frucht, it is a concise notation for - * 3-regular Hamiltonian graphs. It consists of three parameters: the - * number of vertices in the graph, a list of shifts giving additional - * edges to a cycle backbone, and another integer giving how many times - * the shifts should be performed. See - * https://mathworld.wolfram.com/LCFNotation.html for details. + * This function provides a shorthand to give the shifts of the LCF notation + * directly as function arguments. See \ref igraph_lcf() for an explanation + * of LCF notation. * * \param graph Pointer to an uninitialized graph object. * \param n Integer, the number of vertices in the graph. @@ -112,7 +112,7 @@ igraph_error_t igraph_lcf_vector(igraph_t *graph, igraph_integer_t n, * plus an additional 0 to mark the end of the arguments. * \return Error code. * - * \sa See \ref igraph_lcf_vector() for a similar function using an + * \sa See \ref igraph_lcf() for a similar function using an * \ref igraph_vector_t instead of the variable length argument list; * \ref igraph_circulant() to create circulant graphs. * @@ -121,15 +121,15 @@ igraph_error_t igraph_lcf_vector(igraph_t *graph, igraph_integer_t n, * * \example examples/simple/igraph_lcf.c */ -igraph_error_t igraph_lcf(igraph_t *graph, igraph_integer_t n, ...) { +igraph_error_t igraph_lcf_small(igraph_t *graph, igraph_int_t n, ...) { igraph_vector_int_t shifts; - igraph_integer_t repeats; + igraph_int_t repeats; va_list ap; IGRAPH_VECTOR_INT_INIT_FINALLY(&shifts, 0); va_start(ap, n); - while (1) { + while (true) { igraph_error_t err; int num = va_arg(ap, int); if (num == 0) { @@ -148,7 +148,7 @@ igraph_error_t igraph_lcf(igraph_t *graph, igraph_integer_t n, ...) { repeats = igraph_vector_int_pop_back(&shifts); } - IGRAPH_CHECK(igraph_lcf_vector(graph, n, &shifts, repeats)); + IGRAPH_CHECK(igraph_lcf(graph, n, &shifts, repeats)); igraph_vector_int_destroy(&shifts); IGRAPH_FINALLY_CLEAN(1); diff --git a/src/vendor/cigraph/src/constructors/linegraph.c b/src/vendor/cigraph/src/constructors/linegraph.c index cad6070f0aa..413dd992f9f 100644 --- a/src/vendor/cigraph/src/constructors/linegraph.c +++ b/src/vendor/cigraph/src/constructors/linegraph.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -30,38 +29,38 @@ * with minimal performance improvements on a graph with 70K vertices and 360K * edges. (1.09s instead of 1.10s). I think it's not worth the fuss. */ static igraph_error_t igraph_i_linegraph_undirected(const igraph_t *graph, igraph_t *linegraph) { - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_int_t adjedges, adjedges2; igraph_vector_int_t edges; - igraph_integer_t prev = -1; + igraph_int_t prev = -1; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&adjedges, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&adjedges2, 0); - for (igraph_integer_t e1 = 0; e1 < no_of_edges; e1++) { - igraph_integer_t from = IGRAPH_FROM(graph, e1); - igraph_integer_t to = IGRAPH_TO(graph, e1); - igraph_integer_t n; + for (igraph_int_t e1 = 0; e1 < no_of_edges; e1++) { + igraph_int_t from = IGRAPH_FROM(graph, e1); + igraph_int_t to = IGRAPH_TO(graph, e1); + igraph_int_t n; IGRAPH_ALLOW_INTERRUPTION(); if (from != prev) { - IGRAPH_CHECK(igraph_incident(graph, &adjedges, from, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(graph, &adjedges, from, IGRAPH_ALL, IGRAPH_LOOPS)); } n = igraph_vector_int_size(&adjedges); - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t e2 = VECTOR(adjedges)[i]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t e2 = VECTOR(adjedges)[i]; if (e2 < e1) { IGRAPH_CHECK(igraph_vector_int_push_back(&edges, e1)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, e2)); } } - IGRAPH_CHECK(igraph_incident(graph, &adjedges2, to, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(graph, &adjedges2, to, IGRAPH_ALL, IGRAPH_LOOPS)); n = igraph_vector_int_size(&adjedges2); - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t e2 = VECTOR(adjedges2)[i]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t e2 = VECTOR(adjedges2)[i]; if (e2 < e1) { IGRAPH_CHECK(igraph_vector_int_push_back(&edges, e1)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, e2)); @@ -90,26 +89,26 @@ static igraph_error_t igraph_i_linegraph_undirected(const igraph_t *graph, igrap } static igraph_error_t igraph_i_linegraph_directed(const igraph_t *graph, igraph_t *linegraph) { - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t i, j, n; + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t i, j, n; igraph_vector_int_t adjedges; igraph_vector_int_t edges; - igraph_integer_t prev = -1; + igraph_int_t prev = -1; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&adjedges, 0); for (i = 0; i < no_of_edges; i++) { - igraph_integer_t from = IGRAPH_FROM(graph, i); + igraph_int_t from = IGRAPH_FROM(graph, i); IGRAPH_ALLOW_INTERRUPTION(); if (from != prev) { - IGRAPH_CHECK(igraph_incident(graph, &adjedges, from, IGRAPH_IN)); + IGRAPH_CHECK(igraph_incident(graph, &adjedges, from, IGRAPH_IN, IGRAPH_LOOPS)); } n = igraph_vector_int_size(&adjedges); for (j = 0; j < n; j++) { - igraph_integer_t e = VECTOR(adjedges)[j]; + igraph_int_t e = VECTOR(adjedges)[j]; IGRAPH_CHECK(igraph_vector_int_push_back(&edges, e)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, i)); } diff --git a/src/vendor/cigraph/src/constructors/mycielskian.c b/src/vendor/cigraph/src/constructors/mycielskian.c index 487b869407b..ff0f9eabced 100644 --- a/src/vendor/cigraph/src/constructors/mycielskian.c +++ b/src/vendor/cigraph/src/constructors/mycielskian.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2025 The igraph development team This program is free software; you can redistribute it and/or modify @@ -94,9 +94,9 @@ * Time complexity: O(|V| 2^k + |E| 3^k) where |V| and |E| are the vertex and * edge counts, respectively. */ -igraph_error_t igraph_mycielskian(const igraph_t *graph, igraph_t *res, igraph_integer_t k) { - igraph_integer_t vcount = igraph_vcount(graph); - igraph_integer_t ecount = igraph_ecount(graph); +igraph_error_t igraph_mycielskian(const igraph_t *graph, igraph_t *res, igraph_int_t k) { + igraph_int_t vcount = igraph_vcount(graph); + igraph_int_t ecount = igraph_ecount(graph); igraph_vector_int_t edges; if (k < 0) { @@ -128,10 +128,10 @@ igraph_error_t igraph_mycielskian(const igraph_t *graph, igraph_t *res, igraph_i /* Compute the number of vertices and edges. Since these are exponential in k, * overflow checks are important. */ - igraph_integer_t new_vcount = vcount; - igraph_integer_t new_ecount = ecount; + igraph_int_t new_vcount = vcount; + igraph_int_t new_ecount = ecount; - for (igraph_integer_t i = 0; i < k; i++) { + for (igraph_int_t i = 0; i < k; i++) { // new edges = 3 * old edges + old vertices IGRAPH_SAFE_MULT(new_ecount, 3, &new_ecount); IGRAPH_SAFE_ADD(new_ecount, new_vcount, &new_ecount); @@ -143,18 +143,18 @@ igraph_error_t igraph_mycielskian(const igraph_t *graph, igraph_t *res, igraph_i IGRAPH_CHECK(igraph_vector_int_resize(&edges, new_ecount * 2)); - igraph_integer_t edge_index = 2 * ecount; // Current last edge index in edge vector - igraph_integer_t offset = vcount; // Tracks where new vertices start + igraph_int_t edge_index = 2 * ecount; // Current last edge index in edge vector + igraph_int_t offset = vcount; // Tracks where new vertices start - for (igraph_integer_t i = 0; i < k; i++) { - igraph_integer_t prev_vcount = offset; // Number of vertices before this step - igraph_integer_t w = offset * 2; // The new 'w' node index - igraph_integer_t last_edge_index = edge_index; // Mark where edges before this step end + for (igraph_int_t i = 0; i < k; i++) { + igraph_int_t prev_vcount = offset; // Number of vertices before this step + igraph_int_t w = offset * 2; // The new 'w' node index + igraph_int_t last_edge_index = edge_index; // Mark where edges before this step end // For each edge before this step, add two new edges - for (igraph_integer_t j = 0; j < last_edge_index; j += 2) { - igraph_integer_t v1 = VECTOR(edges)[j]; - igraph_integer_t v2 = VECTOR(edges)[j + 1]; + for (igraph_int_t j = 0; j < last_edge_index; j += 2) { + igraph_int_t v1 = VECTOR(edges)[j]; + igraph_int_t v2 = VECTOR(edges)[j + 1]; VECTOR(edges)[edge_index++] = v1; VECTOR(edges)[edge_index++] = offset + v2; @@ -164,7 +164,7 @@ igraph_error_t igraph_mycielskian(const igraph_t *graph, igraph_t *res, igraph_i } // Add edges connecting each `ui` to `w` (forming a star) - for (igraph_integer_t j = prev_vcount; j < w; j++) { + for (igraph_int_t j = prev_vcount; j < w; j++) { VECTOR(edges)[edge_index++] = j; VECTOR(edges)[edge_index++] = w; } @@ -218,7 +218,7 @@ igraph_error_t igraph_mycielskian(const igraph_t *graph, igraph_t *res, igraph_i * * Time complexity: O(3^k), i.e. exponential in \p k. */ -igraph_error_t igraph_mycielski_graph(igraph_t *graph, igraph_integer_t k) { +igraph_error_t igraph_mycielski_graph(igraph_t *graph, igraph_int_t k) { igraph_t g; if (k < 0) { diff --git a/src/vendor/cigraph/src/constructors/prufer.c b/src/vendor/cigraph/src/constructors/prufer.c index d2de9052d97..bc18212029c 100644 --- a/src/vendor/cigraph/src/constructors/prufer.c +++ b/src/vendor/cigraph/src/constructors/prufer.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -56,23 +55,23 @@ igraph_error_t igraph_from_prufer(igraph_t *graph, const igraph_vector_int_t *prufer) { igraph_vector_int_t degree; igraph_vector_int_t edges; - igraph_integer_t n; - igraph_integer_t i, k; - igraph_integer_t u, v; /* vertices */ - igraph_integer_t ec; + igraph_int_t n; + igraph_int_t i, k; + igraph_int_t u, v; /* vertices */ + igraph_int_t ec; IGRAPH_SAFE_ADD(igraph_vector_int_size(prufer), 2, &n); IGRAPH_VECTOR_INT_INIT_FINALLY(°ree, n); /* initializes vector to zeros */ { - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; IGRAPH_SAFE_MULT(n - 1, 2, &no_of_edges2); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges2); } /* build out-degree vector (i.e. number of child vertices) and verify Prufer sequence */ for (i = 0; i < n - 2; ++i) { - igraph_integer_t w = VECTOR(*prufer)[i]; + igraph_int_t w = VECTOR(*prufer)[i]; if (w >= n || w < 0) { IGRAPH_ERROR("Invalid Prufer sequence.", IGRAPH_EINVAL); } diff --git a/src/vendor/cigraph/src/constructors/regular.c b/src/vendor/cigraph/src/constructors/regular.c index 66965b46dce..426559f336a 100644 --- a/src/vendor/cigraph/src/constructors/regular.c +++ b/src/vendor/cigraph/src/constructors/regular.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -71,11 +70,11 @@ * * \example examples/simple/igraph_star.c */ -igraph_error_t igraph_star(igraph_t *graph, igraph_integer_t n, igraph_star_mode_t mode, - igraph_integer_t center) { +igraph_error_t igraph_star(igraph_t *graph, igraph_int_t n, igraph_star_mode_t mode, + igraph_int_t center) { igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t i; + igraph_int_t i; if (n < 0) { IGRAPH_ERROR("Invalid number of vertices.", IGRAPH_EINVVID); @@ -89,11 +88,11 @@ igraph_error_t igraph_star(igraph_t *graph, igraph_integer_t n, igraph_star_mode } if (mode != IGRAPH_STAR_MUTUAL) { - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; IGRAPH_SAFE_MULT(n-1, 2, &no_of_edges2); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges2); } else { - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; IGRAPH_SAFE_MULT(n-1, 4, &no_of_edges2); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges2); } @@ -191,12 +190,12 @@ igraph_error_t igraph_star(igraph_t *graph, igraph_integer_t n, igraph_star_mode * */ -igraph_error_t igraph_wheel(igraph_t *graph, igraph_integer_t n, igraph_wheel_mode_t mode, - igraph_integer_t center) { +igraph_error_t igraph_wheel(igraph_t *graph, igraph_int_t n, igraph_wheel_mode_t mode, + igraph_int_t center) { igraph_star_mode_t star_mode; igraph_vector_int_t rim_edges = IGRAPH_VECTOR_NULL; - igraph_integer_t i; + igraph_int_t i; /* Firstly creates a star by the function \ref igraph_star() and makes * use of its existing input parameter checking ability, it can check @@ -285,29 +284,6 @@ igraph_error_t igraph_wheel(igraph_t *graph, igraph_integer_t n, igraph_wheel_mo return IGRAPH_SUCCESS; } -/** - * \ingroup generators - * \function igraph_lattice - * \brief Arbitrary dimensional square lattices (deprecated). - * - * \deprecated-by igraph_square_lattice 0.10.0 - */ -igraph_error_t igraph_lattice(igraph_t *graph, const igraph_vector_int_t *dimvector, - igraph_integer_t nei, igraph_bool_t directed, igraph_bool_t mutual, - igraph_bool_t circular) { - igraph_vector_bool_t periodic; - - IGRAPH_VECTOR_BOOL_INIT_FINALLY(&periodic, igraph_vector_int_size(dimvector)); - igraph_vector_bool_fill(&periodic, circular); - - IGRAPH_CHECK(igraph_square_lattice(graph, dimvector, nei, directed, mutual, &periodic)); - - igraph_vector_bool_destroy(&periodic); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} - /** * \ingroup generators * \function igraph_square_lattice @@ -357,15 +333,15 @@ igraph_error_t igraph_lattice(igraph_t *graph, const igraph_vector_int_t *dimvec * is the average degree of the graph, k is the \p nei argument. */ igraph_error_t igraph_square_lattice( - igraph_t *graph, const igraph_vector_int_t *dimvector, igraph_integer_t nei, + igraph_t *graph, const igraph_vector_int_t *dimvector, igraph_int_t nei, igraph_bool_t directed, igraph_bool_t mutual, const igraph_vector_bool_t *periodic ) { - igraph_integer_t dims = igraph_vector_int_size(dimvector); - igraph_integer_t no_of_nodes; + igraph_int_t dims = igraph_vector_int_size(dimvector); + igraph_int_t no_of_nodes; igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t *coords, *weights; - igraph_integer_t i, j; + igraph_int_t *coords, *weights; + igraph_int_t i, j; int carry, pos; int iter = 0; @@ -386,11 +362,11 @@ igraph_error_t igraph_square_lattice( /* init coords & weights */ - coords = IGRAPH_CALLOC(dims, igraph_integer_t); + coords = IGRAPH_CALLOC(dims, igraph_int_t); IGRAPH_CHECK_OOM(coords, "Lattice creation failed."); IGRAPH_FINALLY(igraph_free, coords); - weights = IGRAPH_CALLOC(dims, igraph_integer_t); + weights = IGRAPH_CALLOC(dims, igraph_int_t); IGRAPH_CHECK_OOM(weights, "Lattice creation failed."); IGRAPH_FINALLY(igraph_free, weights); @@ -403,12 +379,12 @@ igraph_error_t igraph_square_lattice( IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); if (mutual && directed) { - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; IGRAPH_SAFE_MULT(no_of_nodes, dims, &no_of_edges2); IGRAPH_SAFE_MULT(no_of_edges2, 2, &no_of_edges2); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); } else { - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; IGRAPH_SAFE_MULT(no_of_nodes, dims, &no_of_edges2); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); } @@ -423,7 +399,7 @@ igraph_error_t igraph_square_lattice( igraph_bool_t is_periodic = IS_PERIODIC(j); if (is_periodic|| coords[j] != VECTOR(*dimvector)[j] - 1) { - igraph_integer_t new_nei; + igraph_int_t new_nei; if (coords[j] != VECTOR(*dimvector)[j] - 1) { new_nei = i + weights[j] + 1; } else { @@ -436,7 +412,7 @@ igraph_error_t igraph_square_lattice( } } /* if is_periodic || coords[j] */ if (mutual && directed && (is_periodic || coords[j] != 0)) { - igraph_integer_t new_nei; + igraph_int_t new_nei; if (coords[j] != 0) { new_nei = i - weights[j] + 1; } else { @@ -514,12 +490,12 @@ igraph_error_t igraph_square_lattice( * * \example examples/simple/igraph_ring.c */ -igraph_error_t igraph_ring(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, +igraph_error_t igraph_ring(igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_bool_t mutual, igraph_bool_t circular) { igraph_vector_int_t edges; - igraph_integer_t no_of_edges, no_of_edges2; - igraph_integer_t i; + igraph_int_t no_of_edges, no_of_edges2; + igraph_int_t i; if (n < 0) { IGRAPH_ERRORF("The number of vertices must be non-negative, got %" IGRAPH_PRId ".", IGRAPH_EINVAL, n); @@ -590,7 +566,7 @@ igraph_error_t igraph_ring(igraph_t *graph, igraph_integer_t n, igraph_bool_t di * Time complexity: O(|V|), the number of vertices in the graph. */ igraph_error_t igraph_path_graph( - igraph_t *graph, igraph_integer_t n, + igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_bool_t mutual) { return igraph_ring(graph, n, directed, mutual, /* circular= */ false); } @@ -620,7 +596,7 @@ igraph_error_t igraph_path_graph( * Time complexity: O(|V|), the number of vertices in the graph. */ igraph_error_t igraph_cycle_graph( - igraph_t *graph, igraph_integer_t n, + igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_bool_t mutual) { return igraph_ring(graph, n, directed, mutual, /* circular= */ true); } @@ -672,13 +648,13 @@ igraph_error_t igraph_cycle_graph( * * \example examples/simple/igraph_kary_tree.c */ -igraph_error_t igraph_kary_tree(igraph_t *graph, igraph_integer_t n, igraph_integer_t children, +igraph_error_t igraph_kary_tree(igraph_t *graph, igraph_int_t n, igraph_int_t children, igraph_tree_mode_t type) { igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t i, j; - igraph_integer_t idx = 0; - igraph_integer_t to = 1; + igraph_int_t i, j; + igraph_int_t idx = 0; + igraph_int_t to = 1; if (n < 0) { IGRAPH_ERROR("Number of vertices cannot be negative.", IGRAPH_EINVAL); @@ -692,7 +668,7 @@ igraph_error_t igraph_kary_tree(igraph_t *graph, igraph_integer_t n, igraph_inte } { - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; if (n > 0) { IGRAPH_SAFE_MULT(n-1, 2, &no_of_edges2); } else { @@ -727,18 +703,6 @@ igraph_error_t igraph_kary_tree(igraph_t *graph, igraph_integer_t n, igraph_inte return IGRAPH_SUCCESS; } -/** - * \ingroup generators - * \function igraph_tree - * \brief Creates a k-ary tree in which almost all vertices have k children (deprecated alias). - * - * \deprecated-by igraph_kary_tree 0.10.0 - */ -igraph_error_t igraph_tree(igraph_t *graph, igraph_integer_t n, igraph_integer_t children, - igraph_tree_mode_t type) { - return igraph_kary_tree(graph, n, children, type); -} - /** * \ingroup generators * \function igraph_symmetric_tree @@ -780,8 +744,8 @@ igraph_error_t igraph_symmetric_tree(igraph_t *graph, const igraph_vector_int_t igraph_tree_mode_t type) { igraph_vector_int_t edges; - igraph_integer_t j, k, temp, no_of_nodes, idx, parent, child, level_end; - igraph_integer_t branching_counts_size = igraph_vector_int_size(branches); + igraph_int_t j, k, temp, no_of_nodes, idx, parent, child, level_end; + igraph_int_t branching_counts_size = igraph_vector_int_size(branches); if (type != IGRAPH_TREE_OUT && type != IGRAPH_TREE_IN && type != IGRAPH_TREE_UNDIRECTED) { IGRAPH_ERROR("Invalid tree orientation type.", IGRAPH_EINVMODE); @@ -800,7 +764,7 @@ igraph_error_t igraph_symmetric_tree(igraph_t *graph, const igraph_vector_int_t /* Trees have precisely |E| = |V| - 1 edges. */ { - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; IGRAPH_SAFE_MULT(no_of_nodes - 1, 2, &no_of_edges2); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges2); } @@ -874,7 +838,7 @@ igraph_error_t igraph_symmetric_tree(igraph_t *graph, const igraph_vector_int_t * \example examples/simple/igraph_regular_tree.c */ -igraph_error_t igraph_regular_tree(igraph_t *graph, igraph_integer_t h, igraph_integer_t k, igraph_tree_mode_t type) { +igraph_error_t igraph_regular_tree(igraph_t *graph, igraph_int_t h, igraph_int_t k, igraph_tree_mode_t type) { igraph_vector_int_t branching_counts; if (h < 1) { @@ -932,19 +896,18 @@ igraph_error_t igraph_regular_tree(igraph_t *graph, igraph_integer_t h, igraph_i * \param directed Whether the graph should be directed. * \return Error code. * - * \sa \ref igraph_ring(), \ref igraph_lcf(), \ref igraph_lcf_vector(), - * \ref igraph_circulant() + * \sa \ref igraph_ring(), \ref igraph_lcf(), \ref igraph_circulant() * * Time complexity: O(|V|+|E|), the number of vertices plus the number * of edges. */ igraph_error_t igraph_extended_chordal_ring( - igraph_t *graph, igraph_integer_t nodes, const igraph_matrix_int_t *W, + igraph_t *graph, igraph_int_t nodes, const igraph_matrix_int_t *W, igraph_bool_t directed) { igraph_vector_int_t edges; - igraph_integer_t period = igraph_matrix_int_ncol(W); - igraph_integer_t nrow = igraph_matrix_int_nrow(W); - igraph_integer_t i, j, mpos = 0, epos = 0; + igraph_int_t period = igraph_matrix_int_ncol(W); + igraph_int_t nrow = igraph_matrix_int_nrow(W); + igraph_int_t i, j, mpos = 0, epos = 0; if (nodes < 3) { IGRAPH_ERROR("An extended chordal ring has at least 3 nodes.", IGRAPH_EINVAL); @@ -957,7 +920,7 @@ igraph_error_t igraph_extended_chordal_ring( { /* ecount = nodes + nodes * nrow */ - igraph_integer_t no_of_edges2; + igraph_int_t no_of_edges2; IGRAPH_SAFE_MULT(nodes, nrow, &no_of_edges2); IGRAPH_SAFE_ADD(no_of_edges2, nodes, &no_of_edges2); IGRAPH_SAFE_MULT(no_of_edges2, 2, &no_of_edges2); @@ -974,8 +937,8 @@ igraph_error_t igraph_extended_chordal_ring( if (nrow > 0) { for (i = 0; i < nodes; i++) { for (j = 0; j < nrow; j++) { - igraph_integer_t offset = MATRIX(*W, j, mpos); - igraph_integer_t v = (i + offset) % nodes; + igraph_int_t offset = MATRIX(*W, j, mpos); + igraph_int_t v = (i + offset) % nodes; if (v < 0) { v += nodes; /* handle negative offsets */ @@ -1001,8 +964,6 @@ igraph_error_t igraph_extended_chordal_ring( * \function igraph_hypercube * \brief The n-dimensional hypercube graph. * - * \experimental - * * The hypercube graph \c Q_n has 2^n vertices and * 2^(n-1) n edges. Two vertices are connected when the binary * representations of their zero-based vertex IDs differs in precisely one bit. @@ -1018,15 +979,15 @@ igraph_error_t igraph_extended_chordal_ring( * Time complexity: O(2^n) */ igraph_error_t igraph_hypercube(igraph_t *graph, - igraph_integer_t n, igraph_bool_t directed) { + igraph_int_t n, igraph_bool_t directed) { /* An n-dimensional hypercube graph has 2^n vertices and 2^(n-1)*n edges. * The maximum possible dimension is calculated with the assumption that * the largest possible edge count is no more than half IGRAPH_INTEGER_MAX, * which is in fact the current limit. */ - const igraph_integer_t maxn = - (IGRAPH_INTEGER_SIZE - 1) - (igraph_integer_t) ceil(log2(IGRAPH_INTEGER_SIZE)); + const igraph_int_t maxn = + (IGRAPH_INTEGER_SIZE - 1) - (igraph_int_t) ceil(log2(IGRAPH_INTEGER_SIZE)); if (n < 0) { IGRAPH_ERROR("Hypercube dimension must not be negative.", IGRAPH_EINVAL); @@ -1040,19 +1001,19 @@ igraph_error_t igraph_hypercube(igraph_t *graph, /* Integer overflow is no longer a concern after the above check. */ - const igraph_integer_t vcount = (igraph_integer_t) 1 << n; - const igraph_integer_t ecount = n > 0 ? ((igraph_integer_t) 1 << (n-1)) * n : 0; /* avoid UBSan warning */ + const igraph_int_t vcount = (igraph_int_t) 1 << n; + const igraph_int_t ecount = n > 0 ? ((igraph_int_t) 1 << (n-1)) * n : 0; /* avoid UBSan warning */ igraph_vector_int_t edges; - igraph_integer_t p; + igraph_int_t p; int iter = 0; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 2*ecount); p = 0; - for (igraph_integer_t v=0; v < vcount; v++) { - igraph_integer_t bit = 1; - for (igraph_integer_t i=0; i < n; i++) { - const igraph_integer_t u = v ^ bit; + for (igraph_int_t v=0; v < vcount; v++) { + igraph_int_t bit = 1; + for (igraph_int_t i=0; i < n; i++) { + const igraph_int_t u = v ^ bit; if (v < u) { VECTOR(edges)[p++] = v; VECTOR(edges)[p++] = u; diff --git a/src/vendor/cigraph/src/constructors/trees.c b/src/vendor/cigraph/src/constructors/trees.c index 16b625ccef5..880de40edeb 100644 --- a/src/vendor/cigraph/src/constructors/trees.c +++ b/src/vendor/cigraph/src/constructors/trees.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -26,8 +26,6 @@ * \function igraph_tree_from_parent_vector * \brief Constructs a tree or forest from a vector encoding the parent of each vertex. * - * \experimental - * * Rooted trees and forests are conveniently represented using a \p parents * vector where the ID of the parent of vertex \c v is stored in parents[v]. * This function serves to construct an igraph graph from a parent vector representation. @@ -74,7 +72,7 @@ igraph_error_t igraph_tree_from_parent_vector( const igraph_vector_int_t *parents, igraph_tree_mode_t type) { - const igraph_integer_t no_of_nodes = igraph_vector_int_size(parents); + const igraph_int_t no_of_nodes = igraph_vector_int_size(parents); igraph_vector_int_t seen; igraph_vector_int_t edges; igraph_bool_t directed, intree; @@ -104,14 +102,14 @@ igraph_error_t igraph_tree_from_parent_vector( IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_nodes > 1024 ? 2048 : 2*(no_of_nodes-1)); igraph_vector_int_clear(&edges); - igraph_integer_t c=1; - for (igraph_integer_t i=0; i < no_of_nodes; i++) { - igraph_integer_t v = i; + igraph_int_t c=1; + for (igraph_int_t i=0; i < no_of_nodes; i++) { + igraph_int_t v = i; if (VECTOR(seen)[v]) continue; while (true) { - igraph_integer_t u; + igraph_int_t u; VECTOR(seen)[v] = c; /* mark v as seen in the current round */ u = VECTOR(*parents)[v]; diff --git a/src/vendor/cigraph/src/core/array.c b/src/vendor/cigraph/src/core/array.c deleted file mode 100644 index 07bc67fad5d..00000000000 --- a/src/vendor/cigraph/src/core/array.c +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- mode: C -*- */ -/* - IGraph library. - Copyright (C) 2006-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - -*/ - -#include "igraph_types.h" -#include "igraph_vector.h" -#include "igraph_array.h" - -#define BASE_IGRAPH_REAL -#include "igraph_pmt.h" -#include "array.pmt" -#include "igraph_pmt_off.h" -#undef BASE_IGRAPH_REAL - -#define BASE_INT -#include "igraph_pmt.h" -#include "array.pmt" -#include "igraph_pmt_off.h" -#undef BASE_INT - -#define BASE_CHAR -#include "igraph_pmt.h" -#include "array.pmt" -#include "igraph_pmt_off.h" -#undef BASE_CHAR - -#define BASE_BOOL -#include "igraph_pmt.h" -#include "array.pmt" -#include "igraph_pmt_off.h" -#undef BASE_BOOL diff --git a/src/vendor/cigraph/src/core/array.pmt b/src/vendor/cigraph/src/core/array.pmt deleted file mode 100644 index 227061f57ab..00000000000 --- a/src/vendor/cigraph/src/core/array.pmt +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- mode: C -*- */ -/* - IGraph library. - Copyright (C) 2006-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - -*/ - -#include "igraph_types.h" - -#include "math/safe_intop.h" - -igraph_error_t FUNCTION(igraph_array3, init)(TYPE(igraph_array3) *a, - igraph_integer_t n1, igraph_integer_t n2, igraph_integer_t n3) { - - igraph_integer_t size, n1n2; - - IGRAPH_ASSERT(n1 >= 0 && n2 >= 0 && n3 >= 0); - - IGRAPH_SAFE_MULT(n1, n2, &n1n2); - IGRAPH_SAFE_MULT(n1n2, n3, &size); - - IGRAPH_CHECK(FUNCTION(igraph_vector, init)(&a->data, size)); - - a->n1 = n1; - a->n2 = n2; - a->n3 = n3; - a->n1n2 = n1n2; - - return IGRAPH_SUCCESS; -} - -void FUNCTION(igraph_array3, destroy)(TYPE(igraph_array3) *a) { - FUNCTION(igraph_vector, destroy)(&a->data); -} - -igraph_integer_t FUNCTION(igraph_array3, size)(const TYPE(igraph_array3) *a) { - return (a->n1n2) * (a->n3); -} - -igraph_integer_t FUNCTION(igraph_array3, n)(const TYPE(igraph_array3) *a, igraph_integer_t idx) { - switch (idx) { - case 1: return a->n1; - break; - case 2: return a->n2; - break; - case 3: return a->n3; - break; - } - return 0; -} - -igraph_error_t FUNCTION(igraph_array3, resize)( - TYPE(igraph_array3) *a, igraph_integer_t n1, igraph_integer_t n2, - igraph_integer_t n3) { - - igraph_integer_t size, n1n2; - - IGRAPH_ASSERT(n1 >= 0 && n2 >= 0 && n3 >= 0); - - IGRAPH_SAFE_MULT(n1, n2, &n1n2); - IGRAPH_SAFE_MULT(n1n2, n3, &size); - - IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(&a->data, size)); - - a->n1 = n1; - a->n2 = n2; - a->n3 = n3; - a->n1n2 = n1n2; - - return IGRAPH_SUCCESS; -} - -void FUNCTION(igraph_array3, null)(TYPE(igraph_array3) *a) { - FUNCTION(igraph_vector, null)(&a->data); -} - -BASE FUNCTION(igraph_array3, sum)(const TYPE(igraph_array3) *a) { - return FUNCTION(igraph_vector, sum)(&a->data); -} - -void FUNCTION(igraph_array3, scale)(TYPE(igraph_array3) *a, BASE by) { - FUNCTION(igraph_vector, scale)(&a->data, by); -} - -void FUNCTION(igraph_array3, fill)(TYPE(igraph_array3) *a, BASE e) { - FUNCTION(igraph_vector, fill)(&a->data, e); -} - -igraph_error_t FUNCTION(igraph_array3, update)(TYPE(igraph_array3) *to, - const TYPE(igraph_array3) *from) { - IGRAPH_CHECK(FUNCTION(igraph_array3, resize)(to, from->n1, from->n2, from->n3)); - FUNCTION(igraph_vector, update)(&to->data, &from->data); - return IGRAPH_SUCCESS; -} diff --git a/src/vendor/cigraph/src/core/bitset.c b/src/vendor/cigraph/src/core/bitset.c index e21b02309d5..1ffe9020d2e 100644 --- a/src/vendor/cigraph/src/core/bitset.c +++ b/src/vendor/cigraph/src/core/bitset.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -21,12 +21,12 @@ #include "igraph_bitset.h" #include "igraph_memory.h" -igraph_integer_t igraph_i_ctz32(igraph_uint_t x) { +igraph_int_t igraph_i_ctz32(igraph_uint_t x) { #ifdef HAVE__BITSCANFORWARD unsigned long index; return _BitScanForward(&index, x) ? index : 32; #else - for (igraph_integer_t i = 0; i < 32; ++i) { + for (igraph_int_t i = 0; i < 32; ++i) { if (IGRAPH_BIT_MASK(i) & x) { return i; } @@ -35,12 +35,12 @@ igraph_integer_t igraph_i_ctz32(igraph_uint_t x) { #endif } -igraph_integer_t igraph_i_clz32(igraph_uint_t x) { +igraph_int_t igraph_i_clz32(igraph_uint_t x) { #ifdef HAVE_BITSCANREVERSE unsigned long index; return _BitScanReverse(&index, x) ? 31 - index : 32; #else - for (igraph_integer_t i = 31; i >= 0; --i) { + for (igraph_int_t i = 31; i >= 0; --i) { if (IGRAPH_BIT_MASK(i) & x) { return 31 - i; } @@ -49,8 +49,8 @@ igraph_integer_t igraph_i_clz32(igraph_uint_t x) { #endif } -igraph_integer_t igraph_i_popcnt(igraph_uint_t x) { - igraph_integer_t result = 0; +igraph_int_t igraph_i_popcnt(igraph_uint_t x) { + igraph_int_t result = 0; while (x) { result++; x = x & (x - 1); @@ -58,14 +58,14 @@ igraph_integer_t igraph_i_popcnt(igraph_uint_t x) { return result; } -/* Fallbacks for 64-bit word (and igraph_integer_t/igraph_uint_t) size */ +/* Fallbacks for 64-bit word (and igraph_int_t/igraph_uint_t) size */ #if IGRAPH_INTEGER_SIZE == 64 -igraph_integer_t igraph_i_ctz64(igraph_uint_t x) { +igraph_int_t igraph_i_ctz64(igraph_uint_t x) { #ifdef HAVE_BITSCANFORWARD64 unsigned long index; return _BitScanForward64(&index, x) ? index : 64; #else - for (igraph_integer_t i = 0; i < 64; ++i) { + for (igraph_int_t i = 0; i < 64; ++i) { if (IGRAPH_BIT_MASK(i) & x) { return i; } @@ -74,12 +74,12 @@ igraph_integer_t igraph_i_ctz64(igraph_uint_t x) { #endif } -igraph_integer_t igraph_i_clz64(igraph_uint_t x) { +igraph_int_t igraph_i_clz64(igraph_uint_t x) { #ifdef HAVE_BITSCANREVERSE64 unsigned long index; return _BitScanReverse64(&index, x) ? 63 - index : 64; #else - for (igraph_integer_t i = 63; i >= 0; --i) { + for (igraph_int_t i = 63; i >= 0; --i) { if (IGRAPH_BIT_MASK(i) & x) { return 63 - i; } @@ -99,7 +99,7 @@ igraph_integer_t igraph_i_clz64(igraph_uint_t x) { * difference being the C++ version's size is initialized at compile time. * * The \type igraph_bitset_t type and use O(n/w) space - * to store n elements, where w is the bit width of \type igraph_integer_t, + * to store n elements, where w is the bit width of \type igraph_int_t, * the integer type used throughout the library (either 32 or 64). * Sometimes they use more, this is because bitsets can * shrink, but even if they shrink, the current implementation does not free a @@ -146,8 +146,6 @@ igraph_integer_t igraph_i_clz64(igraph_uint_t x) { * \function igraph_bitset_init * \brief Initializes a bitset object (constructor). * - * \experimental - * * * Every bitset needs to be initialized before it can be used, and * there are a number of initialization functions or otherwise called @@ -172,8 +170,8 @@ igraph_integer_t igraph_i_clz64(igraph_uint_t x) { * w is the word size of the machine (32 or 64). */ -igraph_error_t igraph_bitset_init(igraph_bitset_t *bitset, igraph_integer_t size) { - igraph_integer_t alloc_size = IGRAPH_BIT_NSLOTS(size); +igraph_error_t igraph_bitset_init(igraph_bitset_t *bitset, igraph_int_t size) { + igraph_int_t alloc_size = IGRAPH_BIT_NSLOTS(size); bitset->stor_begin = IGRAPH_CALLOC(alloc_size, igraph_uint_t); IGRAPH_CHECK_OOM(bitset->stor_begin, "Cannot initialize bitset."); bitset->size = size; @@ -186,8 +184,6 @@ igraph_error_t igraph_bitset_init(igraph_bitset_t *bitset, igraph_integer_t size * \function igraph_bitset_destroy * \brief Destroys a bitset object. * - * \experimental - * * All bitsets initialized by \ref igraph_bitset_init() should be properly * destroyed by this function. A destroyed bitset needs to be * reinitialized by \ref igraph_bitset_init() or @@ -210,8 +206,6 @@ void igraph_bitset_destroy(igraph_bitset_t *bitset) { * \function igraph_bitset_init_copy * \brief Initializes a bitset from another bitset object (constructor). * - * \experimental - * * The contents of the existing bitset object will be copied to * the new one. * @@ -230,7 +224,7 @@ igraph_error_t igraph_bitset_init_copy(igraph_bitset_t *dest, const igraph_bitse IGRAPH_ASSERT(src != NULL); IGRAPH_ASSERT(src->stor_begin != NULL); IGRAPH_CHECK(igraph_bitset_init(dest, src->size)); - for (igraph_integer_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { + for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { VECTOR(*dest)[i] = VECTOR(*src)[i]; } return IGRAPH_SUCCESS; @@ -241,8 +235,6 @@ igraph_error_t igraph_bitset_init_copy(igraph_bitset_t *dest, const igraph_bitse * \function igraph_bitset_update * \brief Update a bitset from another one. * - * \experimental - * * The size and contents of \p dest will be identical to that of \p src. * * \param dest Pointer to an initialized bitset object. This will be updated. @@ -261,7 +253,7 @@ igraph_error_t igraph_bitset_update(igraph_bitset_t *dest, const igraph_bitset_t IGRAPH_ASSERT(src->stor_begin != NULL); IGRAPH_CHECK(igraph_bitset_reserve(dest, src->size)); dest->size = src->size; - for (igraph_integer_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { + for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { VECTOR(*dest)[i] = VECTOR(*src)[i]; } return IGRAPH_SUCCESS; @@ -272,8 +264,6 @@ igraph_error_t igraph_bitset_update(igraph_bitset_t *dest, const igraph_bitset_t * \function igraph_bitset_capacity * \brief Returns the allocated capacity of the bitset. * - * \experimental - * * Note that this might be different from the size of the bitset (as * queried by \ref igraph_bitset_size()), and specifies how many elements * the bitset can hold, without reallocation. @@ -287,7 +277,7 @@ igraph_error_t igraph_bitset_update(igraph_bitset_t *dest, const igraph_bitset_t * Time complexity: O(1). */ -igraph_integer_t igraph_bitset_capacity(const igraph_bitset_t *bitset) { +igraph_int_t igraph_bitset_capacity(const igraph_bitset_t *bitset) { return IGRAPH_INTEGER_SIZE * (bitset->stor_end - bitset->stor_begin); } @@ -296,15 +286,13 @@ igraph_integer_t igraph_bitset_capacity(const igraph_bitset_t *bitset) { * \function igraph_bitset_size * \brief Returns the length of the bitset. * - * \experimental - * * \param bitset The bitset object * \return The size of the bitset. * * Time complexity: O(1). */ -igraph_integer_t igraph_bitset_size(const igraph_bitset_t *bitset) { +igraph_int_t igraph_bitset_size(const igraph_bitset_t *bitset) { return bitset->size; } @@ -313,8 +301,6 @@ igraph_integer_t igraph_bitset_size(const igraph_bitset_t *bitset) { * \function igraph_bitset_reserve * \brief Reserves memory for a bitset. * - * \experimental - * * \a igraph bitsets are flexible, they can grow and * shrink. Growing * however occasionally needs the data in the bitset to be copied. @@ -339,8 +325,8 @@ igraph_integer_t igraph_bitset_size(const igraph_bitset_t *bitset) { * w is the word size of the machine (32 or 64). */ -igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_integer_t capacity) { - igraph_integer_t current_capacity; +igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_int_t capacity) { + igraph_int_t current_capacity; igraph_uint_t *tmp; IGRAPH_ASSERT(bitset != NULL); @@ -367,8 +353,6 @@ igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_integer_t c * \function igraph_bitset_resize * \brief Resizes the bitset. * - * \experimental - * * Note that this function does not free any memory, just sets the * size of the bitset to the given one. It may, on the other hand, * allocate more memory if the new size is larger than the previous @@ -392,13 +376,13 @@ igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_integer_t c * w is the word size of the machine (32 or 64). */ -igraph_error_t igraph_bitset_resize(igraph_bitset_t *bitset, igraph_integer_t new_size) { +igraph_error_t igraph_bitset_resize(igraph_bitset_t *bitset, igraph_int_t new_size) { IGRAPH_ASSERT(bitset != NULL); IGRAPH_ASSERT(bitset->stor_begin != NULL); IGRAPH_CHECK(igraph_bitset_reserve(bitset, new_size)); if (new_size > bitset->size) { - for (igraph_integer_t i = bitset->size; i % IGRAPH_INTEGER_SIZE != 0; ++i) { + for (igraph_int_t i = bitset->size; i % IGRAPH_INTEGER_SIZE != 0; ++i) { IGRAPH_BIT_CLEAR(*bitset, i); } memset(bitset->stor_begin + IGRAPH_BIT_NSLOTS(bitset->size), 0, @@ -414,8 +398,6 @@ igraph_error_t igraph_bitset_resize(igraph_bitset_t *bitset, igraph_integer_t ne * \function igraph_bitset_popcount * \brief The population count of the bitset. * - * \experimental - * * Returns the number of set bits, also called the population count, * of the bitset. * @@ -425,14 +407,14 @@ igraph_error_t igraph_bitset_resize(igraph_bitset_t *bitset, igraph_integer_t ne * Time complexity: O(n/w). */ -igraph_integer_t igraph_bitset_popcount(const igraph_bitset_t *bitset) { - const igraph_integer_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; - const igraph_integer_t slots = IGRAPH_BIT_NSLOTS(bitset->size); +igraph_int_t igraph_bitset_popcount(const igraph_bitset_t *bitset) { + const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; + const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size); const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */ const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? ~zero : ((one << final_block_size) - 1); - igraph_integer_t count = 0; + igraph_int_t count = 0; - for (igraph_integer_t i = 0; i + 1 < slots; ++i) { + for (igraph_int_t i = 0; i + 1 < slots; ++i) { count += IGRAPH_POPCOUNT(VECTOR(*bitset)[i]); } if (bitset->size) { @@ -447,8 +429,6 @@ igraph_integer_t igraph_bitset_popcount(const igraph_bitset_t *bitset) { * \function igraph_bitset_countl_zero * \brief The number of leading zeros in the bitset. * - * \experimental - * * Returns the number of leading (starting at the most significant bit) * zeros in the bitset before the first one is encountered. If the bitset * is all zeros, then its size is returned. @@ -459,17 +439,17 @@ igraph_integer_t igraph_bitset_popcount(const igraph_bitset_t *bitset) { * Time complexity: O(n/w). */ -igraph_integer_t igraph_bitset_countl_zero(const igraph_bitset_t *bitset) { - const igraph_integer_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; - const igraph_integer_t padding = IGRAPH_INTEGER_SIZE - final_block_size; - const igraph_integer_t slots = IGRAPH_BIT_NSLOTS(bitset->size); +igraph_int_t igraph_bitset_countl_zero(const igraph_bitset_t *bitset) { + const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; + const igraph_int_t padding = IGRAPH_INTEGER_SIZE - final_block_size; + const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size); const igraph_uint_t one = 1, zero = 0; const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? ~zero : ((one << final_block_size) - one); if (bitset->size && (mask & VECTOR(*bitset)[slots - 1]) != 0) { return IGRAPH_CLZ(mask & VECTOR(*bitset)[slots - 1]) - padding; } - for (igraph_integer_t i = 1; i < slots; ++i) { + for (igraph_int_t i = 1; i < slots; ++i) { if (VECTOR(*bitset)[slots - i - 1] != 0) { return IGRAPH_INTEGER_SIZE * i + IGRAPH_CLZ(VECTOR(*bitset)[slots - i - 1]) - padding; } @@ -483,8 +463,6 @@ igraph_integer_t igraph_bitset_countl_zero(const igraph_bitset_t *bitset) { * \function igraph_bitset_countl_one * \brief The number of leading ones in the bitset. * - * \experimental - * * Returns the number of leading ones (starting at the most significant bit) * in the bitset before the first zero is encountered. * If the bitset is all ones, then its size is returned. @@ -495,17 +473,17 @@ igraph_integer_t igraph_bitset_countl_zero(const igraph_bitset_t *bitset) { * Time complexity: O(n/w). */ -igraph_integer_t igraph_bitset_countl_one(const igraph_bitset_t *bitset) { - const igraph_integer_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; - const igraph_integer_t padding = IGRAPH_INTEGER_SIZE - final_block_size; - const igraph_integer_t slots = IGRAPH_BIT_NSLOTS(bitset->size); +igraph_int_t igraph_bitset_countl_one(const igraph_bitset_t *bitset) { + const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; + const igraph_int_t padding = IGRAPH_INTEGER_SIZE - final_block_size; + const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size); const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */ const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? zero : ~((one << final_block_size) - one); if (bitset->size && (mask | VECTOR(*bitset)[slots - 1]) != ~zero) { return IGRAPH_CLO(mask | VECTOR(*bitset)[slots - 1]) - padding; } - for (igraph_integer_t i = 1; i < slots; ++i) { + for (igraph_int_t i = 1; i < slots; ++i) { if (VECTOR(*bitset)[slots - i - 1] != ~zero) { return IGRAPH_INTEGER_SIZE * i + IGRAPH_CLO(VECTOR(*bitset)[slots - i - 1]) - padding; } @@ -519,8 +497,6 @@ igraph_integer_t igraph_bitset_countl_one(const igraph_bitset_t *bitset) { * \function igraph_bitset_countr_zero * \brief The number of trailing zeros in the bitset. * - * \experimental - * * Returns the number of trailing (starting at the least significant bit) * zeros in the bitset before the first one is encountered. * If the bitset is all zeros, then its size is returned. @@ -531,13 +507,13 @@ igraph_integer_t igraph_bitset_countl_one(const igraph_bitset_t *bitset) { * Time complexity: O(n/w). */ -igraph_integer_t igraph_bitset_countr_zero(const igraph_bitset_t *bitset) { - const igraph_integer_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; - const igraph_integer_t slots = IGRAPH_BIT_NSLOTS(bitset->size); +igraph_int_t igraph_bitset_countr_zero(const igraph_bitset_t *bitset) { + const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; + const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size); const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */ const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? ~zero : ((one << final_block_size) - one); - for (igraph_integer_t i = 0; i + 1 < slots; ++i) { + for (igraph_int_t i = 0; i + 1 < slots; ++i) { if (VECTOR(*bitset)[i] != zero) { return IGRAPH_INTEGER_SIZE * i + IGRAPH_CTZ(VECTOR(*bitset)[i]); } @@ -554,8 +530,6 @@ igraph_integer_t igraph_bitset_countr_zero(const igraph_bitset_t *bitset) { * \function igraph_bitset_countr_one * \brief The number of trailing ones in the bitset. * - * \experimental - * * Returns the number of trailing ones (starting at the least significant bit) * in the bitset before the first zero is encountered. * If the bitset is all ones, then its size is returned. @@ -566,13 +540,13 @@ igraph_integer_t igraph_bitset_countr_zero(const igraph_bitset_t *bitset) { * Time complexity: O(n/w). */ -igraph_integer_t igraph_bitset_countr_one(const igraph_bitset_t *bitset) { - const igraph_integer_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; - const igraph_integer_t slots = IGRAPH_BIT_NSLOTS(bitset->size); +igraph_int_t igraph_bitset_countr_one(const igraph_bitset_t *bitset) { + const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; + const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size); const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */ const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? zero : ~((one << final_block_size) - one); - for (igraph_integer_t i = 0; i + 1 < slots; ++i) { + for (igraph_int_t i = 0; i + 1 < slots; ++i) { if (VECTOR(*bitset)[i] != ~zero) { return IGRAPH_INTEGER_SIZE * i + IGRAPH_CTO(VECTOR(*bitset)[i]); } @@ -589,8 +563,6 @@ igraph_integer_t igraph_bitset_countr_one(const igraph_bitset_t *bitset) { * \function igraph_bitset_is_all_zero * \brief Are all bits zeros? * - * \experimental - * * \param bitset The bitset object to test. * \return True if none of the bits are set. * @@ -598,12 +570,12 @@ igraph_integer_t igraph_bitset_countr_one(const igraph_bitset_t *bitset) { */ igraph_bool_t igraph_bitset_is_all_zero(const igraph_bitset_t *bitset) { - const igraph_integer_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; - const igraph_integer_t slots = IGRAPH_BIT_NSLOTS(bitset->size); + const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; + const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size); const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */ const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? ~zero : ((one << final_block_size) - one); - for (igraph_integer_t i = 0; i < slots - 1; i++) { + for (igraph_int_t i = 0; i < slots - 1; i++) { if (VECTOR(*bitset)[i] != zero) { return false; } @@ -619,8 +591,6 @@ igraph_bool_t igraph_bitset_is_all_zero(const igraph_bitset_t *bitset) { * \function igraph_bitset_is_all_one * \brief Are all bits ones? * - * \experimental - * * \param bitset The bitset object to test. * \return True if all of the bits are set. * @@ -628,12 +598,12 @@ igraph_bool_t igraph_bitset_is_all_zero(const igraph_bitset_t *bitset) { */ igraph_bool_t igraph_bitset_is_all_one(const igraph_bitset_t *bitset) { - const igraph_integer_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; - const igraph_integer_t slots = IGRAPH_BIT_NSLOTS(bitset->size); + const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE; + const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size); const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */ const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? zero : ~((one << final_block_size) - one); - for (igraph_integer_t i = 0; i < slots - 1; i++) { + for (igraph_int_t i = 0; i < slots - 1; i++) { if (VECTOR(*bitset)[i] != ~zero) { return false; } @@ -649,8 +619,6 @@ igraph_bool_t igraph_bitset_is_all_one(const igraph_bitset_t *bitset) { * \function igraph_bitset_is_any_zero * \brief Are any bits zeros? * - * \experimental - * * \param bitset The bitset object to test. * \return True if at least one bit is zero. * @@ -666,8 +634,6 @@ igraph_bool_t igraph_bitset_is_any_zero(const igraph_bitset_t *bitset) { * \function igraph_bitset_is_any_one * \brief Are any bits ones? * - * \experimental - * * \param bitset The bitset object to test. * \return True if at least one bit is one. * @@ -683,8 +649,6 @@ igraph_bool_t igraph_bitset_is_any_one(const igraph_bitset_t *bitset) { * \function igraph_bitset_or * \brief Bitwise OR of two bitsets. * - * \experimental - * * Applies a bitwise or to the contents of two bitsets and stores it in an * already initialized bitset. The destination bitset may be equal to one * (or even both) of the sources. When working with bitsets, it is common @@ -701,7 +665,7 @@ igraph_bool_t igraph_bitset_is_any_one(const igraph_bitset_t *bitset) { void igraph_bitset_or(igraph_bitset_t *dest, const igraph_bitset_t *src1, const igraph_bitset_t *src2) { - for (igraph_integer_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { + for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { VECTOR(*dest)[i] = VECTOR(*src1)[i] | VECTOR(*src2)[i]; } } @@ -711,8 +675,6 @@ void igraph_bitset_or(igraph_bitset_t *dest, * \function igraph_bitset_and * \brief Bitwise AND of two bitsets. * - * \experimental - * * Applies a bitwise and to the contents of two bitsets and stores it in an * already initialized bitset. The destination bitset may be equal to one * (or even both) of the sources. When working with bitsets, it is common @@ -728,7 +690,7 @@ void igraph_bitset_or(igraph_bitset_t *dest, */ void igraph_bitset_and(igraph_bitset_t *dest, const igraph_bitset_t *src1, const igraph_bitset_t *src2) { - for (igraph_integer_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { + for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { VECTOR(*dest)[i] = VECTOR(*src1)[i] & VECTOR(*src2)[i]; } } @@ -738,8 +700,6 @@ void igraph_bitset_and(igraph_bitset_t *dest, const igraph_bitset_t *src1, const * \function igraph_bitset_xor * \brief Bitwise XOR of two bitsets. * - * \experimental - * * Applies a bitwise xor to the contents of two bitsets and stores it in * an already initialized bitset. The destination bitset may be equal to * one (or even both) of the sources. When working with bitsets, it is common @@ -756,7 +716,7 @@ void igraph_bitset_and(igraph_bitset_t *dest, const igraph_bitset_t *src1, const void igraph_bitset_xor(igraph_bitset_t *dest, const igraph_bitset_t *src1, const igraph_bitset_t *src2) { - for (igraph_integer_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { + for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { VECTOR(*dest)[i] = VECTOR(*src1)[i] ^ VECTOR(*src2)[i]; } } @@ -766,8 +726,6 @@ void igraph_bitset_xor(igraph_bitset_t *dest, * \function igraph_bitset_not * \brief Bitwise negation of a bitset. * - * \experimental - * * Applies a bitwise not to the contents of a bitset and stores it in an * already initialized bitset. The destination bitset may be equal to the * source. When working with bitsets, it is common that those created are @@ -781,7 +739,7 @@ void igraph_bitset_xor(igraph_bitset_t *dest, */ void igraph_bitset_not(igraph_bitset_t *dest, const igraph_bitset_t *src) { - for (igraph_integer_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { + for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { VECTOR(*dest)[i] = ~VECTOR(*src)[i]; } } @@ -791,8 +749,6 @@ void igraph_bitset_not(igraph_bitset_t *dest, const igraph_bitset_t *src) { * \function igraph_bitset_fill * \brief Fills a bitset with a constant value. * - * \experimental - * * Sets all bits of a bitset to the same value. * * \param bitset The bitset object to modify. @@ -814,8 +770,6 @@ void igraph_bitset_fill(igraph_bitset_t *bitset, igraph_bool_t value) { * \function igraph_bitset_null * \brief Clears all bits in a bitset. * - * \experimental - * * \param bitset The bitset object to clear all bits in. * * \sa \ref igraph_bitset_fill() @@ -832,8 +786,6 @@ void igraph_bitset_null(igraph_bitset_t *bitset) { * \function igraph_bitset_fprint * \brief Prints the bits of a bitset. * - * \experimental - * * Outputs the contents of a bitset to a file. * The bitset is written from index n-1 to index 0, left to right, * such that index 0 is the least significant bit and index n-1 is @@ -852,7 +804,7 @@ void igraph_bitset_null(igraph_bitset_t *bitset) { * Time complexity: O(n). */ igraph_error_t igraph_bitset_fprint(const igraph_bitset_t *bitset, FILE *file) { - for (igraph_integer_t i = bitset->size - 1; i >= 0; i--) { + for (igraph_int_t i = bitset->size - 1; i >= 0; i--) { fputc(IGRAPH_BIT_TEST(*bitset, i) ? '1' : '0', file); } return IGRAPH_SUCCESS; diff --git a/src/vendor/cigraph/src/core/bitset_list.c b/src/vendor/cigraph/src/core/bitset_list.c index 4b3ec576be6..c6dc79c25ac 100644 --- a/src/vendor/cigraph/src/core/bitset_list.c +++ b/src/vendor/cigraph/src/core/bitset_list.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2024 The igraph development team This program is free software; you can redistribute it and/or modify diff --git a/src/vendor/cigraph/src/core/buckets.c b/src/vendor/cigraph/src/core/buckets.c index d2204cd99e3..28330b3d2f3 100644 --- a/src/vendor/cigraph/src/core/buckets.c +++ b/src/vendor/cigraph/src/core/buckets.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -43,7 +42,7 @@ * _empty() and _popmax() operations. */ -igraph_error_t igraph_buckets_init(igraph_buckets_t *b, igraph_integer_t bsize, igraph_integer_t size) { +igraph_error_t igraph_buckets_init(igraph_buckets_t *b, igraph_int_t bsize, igraph_int_t size) { IGRAPH_VECTOR_INT_INIT_FINALLY(&b->bptr, bsize); IGRAPH_VECTOR_INT_INIT_FINALLY(&b->buckets, size); b->max = -1; b->no = 0; @@ -56,10 +55,10 @@ void igraph_buckets_destroy(igraph_buckets_t *b) { igraph_vector_int_destroy(&b->buckets); } -igraph_integer_t igraph_buckets_popmax(igraph_buckets_t *b) { +igraph_int_t igraph_buckets_popmax(igraph_buckets_t *b) { /* Precondition: there is at least a non-empty bucket */ /* Search for the highest bucket first */ - igraph_integer_t max; + igraph_int_t max; while ( (max = VECTOR(b->bptr)[b->max]) == 0) { b->max --; } @@ -69,8 +68,8 @@ igraph_integer_t igraph_buckets_popmax(igraph_buckets_t *b) { return max - 1; } -igraph_integer_t igraph_buckets_pop(igraph_buckets_t *b, igraph_integer_t bucket) { - igraph_integer_t ret = VECTOR(b->bptr)[bucket] - 1; +igraph_int_t igraph_buckets_pop(igraph_buckets_t *b, igraph_int_t bucket) { + igraph_int_t ret = VECTOR(b->bptr)[bucket] - 1; VECTOR(b->bptr)[bucket] = VECTOR(b->buckets)[ret]; b->no--; return ret; @@ -81,12 +80,12 @@ igraph_bool_t igraph_buckets_empty(const igraph_buckets_t *b) { } igraph_bool_t igraph_buckets_empty_bucket(const igraph_buckets_t *b, - igraph_integer_t bucket) { + igraph_int_t bucket) { return VECTOR(b->bptr)[bucket] == 0; } -void igraph_buckets_add(igraph_buckets_t *b, igraph_integer_t bucket, - igraph_integer_t elem) { +void igraph_buckets_add(igraph_buckets_t *b, igraph_int_t bucket, + igraph_int_t elem) { VECTOR(b->buckets)[elem] = VECTOR(b->bptr)[bucket]; VECTOR(b->bptr)[bucket] = elem + 1; @@ -103,7 +102,7 @@ void igraph_buckets_clear(igraph_buckets_t *b) { b->no = 0; } -igraph_error_t igraph_dbuckets_init(igraph_dbuckets_t *b, igraph_integer_t bsize, igraph_integer_t size) { +igraph_error_t igraph_dbuckets_init(igraph_dbuckets_t *b, igraph_int_t bsize, igraph_int_t size) { IGRAPH_VECTOR_INT_INIT_FINALLY(&b->bptr, bsize); IGRAPH_VECTOR_INT_INIT_FINALLY(&b->next, size); IGRAPH_VECTOR_INT_INIT_FINALLY(&b->prev, size); @@ -126,16 +125,16 @@ void igraph_dbuckets_clear(igraph_dbuckets_t *b) { b->no = 0; } -igraph_integer_t igraph_dbuckets_popmax(igraph_dbuckets_t *b) { +igraph_int_t igraph_dbuckets_popmax(igraph_dbuckets_t *b) { while ( VECTOR(b->bptr)[b->max] == 0) { b->max--; } return igraph_dbuckets_pop(b, b->max); } -igraph_integer_t igraph_dbuckets_pop(igraph_dbuckets_t *b, igraph_integer_t bucket) { - igraph_integer_t ret = VECTOR(b->bptr)[bucket] - 1; - igraph_integer_t next = VECTOR(b->next)[ret]; +igraph_int_t igraph_dbuckets_pop(igraph_dbuckets_t *b, igraph_int_t bucket) { + igraph_int_t ret = VECTOR(b->bptr)[bucket] - 1; + igraph_int_t next = VECTOR(b->next)[ret]; VECTOR(b->bptr)[bucket] = next; if (next != 0) { VECTOR(b->prev)[next - 1] = 0; @@ -150,13 +149,13 @@ igraph_bool_t igraph_dbuckets_empty(const igraph_dbuckets_t *b) { } igraph_bool_t igraph_dbuckets_empty_bucket(const igraph_dbuckets_t *b, - igraph_integer_t bucket) { + igraph_int_t bucket) { return VECTOR(b->bptr)[bucket] == 0; } -void igraph_dbuckets_add(igraph_dbuckets_t *b, igraph_integer_t bucket, - igraph_integer_t elem) { - igraph_integer_t oldfirst = VECTOR(b->bptr)[bucket]; +void igraph_dbuckets_add(igraph_dbuckets_t *b, igraph_int_t bucket, + igraph_int_t elem) { + igraph_int_t oldfirst = VECTOR(b->bptr)[bucket]; VECTOR(b->bptr)[bucket] = elem + 1; VECTOR(b->next)[elem] = oldfirst; if (oldfirst != 0) { @@ -170,18 +169,18 @@ void igraph_dbuckets_add(igraph_dbuckets_t *b, igraph_integer_t bucket, /* Remove an arbitrary element */ -void igraph_dbuckets_delete(igraph_dbuckets_t *b, igraph_integer_t bucket, - igraph_integer_t elem) { +void igraph_dbuckets_delete(igraph_dbuckets_t *b, igraph_int_t bucket, + igraph_int_t elem) { if (VECTOR(b->bptr)[bucket] == elem + 1) { /* First element in bucket */ - igraph_integer_t next = VECTOR(b->next)[elem]; + igraph_int_t next = VECTOR(b->next)[elem]; if (next != 0) { VECTOR(b->prev)[next - 1] = 0; } VECTOR(b->bptr)[bucket] = next; } else { - igraph_integer_t next = VECTOR(b->next)[elem]; - igraph_integer_t prev = VECTOR(b->prev)[elem]; + igraph_int_t next = VECTOR(b->next)[elem]; + igraph_int_t prev = VECTOR(b->prev)[elem]; if (next != 0) { VECTOR(b->prev)[next - 1] = prev; } diff --git a/src/vendor/cigraph/src/core/buckets.h b/src/vendor/cigraph/src/core/buckets.h index 176eddf5468..6b862593f60 100644 --- a/src/vendor/cigraph/src/core/buckets.h +++ b/src/vendor/cigraph/src/core/buckets.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2009-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -27,46 +26,46 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* Buckets, needed for the maximum flow algorithm */ typedef struct igraph_buckets_t { igraph_vector_int_t bptr; igraph_vector_int_t buckets; - igraph_integer_t max, no; + igraph_int_t max, no; } igraph_buckets_t; -igraph_error_t igraph_buckets_init(igraph_buckets_t *b, igraph_integer_t bsize, igraph_integer_t size); +igraph_error_t igraph_buckets_init(igraph_buckets_t *b, igraph_int_t bsize, igraph_int_t size); void igraph_buckets_destroy(igraph_buckets_t *b); void igraph_buckets_clear(igraph_buckets_t *b); -igraph_integer_t igraph_buckets_popmax(igraph_buckets_t *b); -igraph_integer_t igraph_buckets_pop(igraph_buckets_t *b, igraph_integer_t bucket); +igraph_int_t igraph_buckets_popmax(igraph_buckets_t *b); +igraph_int_t igraph_buckets_pop(igraph_buckets_t *b, igraph_int_t bucket); IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_buckets_empty(const igraph_buckets_t *b); IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_buckets_empty_bucket(const igraph_buckets_t *b, - igraph_integer_t bucket); -void igraph_buckets_add(igraph_buckets_t *b, igraph_integer_t bucket, - igraph_integer_t elem); + igraph_int_t bucket); +void igraph_buckets_add(igraph_buckets_t *b, igraph_int_t bucket, + igraph_int_t elem); typedef struct igraph_dbuckets_t { igraph_vector_int_t bptr; igraph_vector_int_t next, prev; - igraph_integer_t max, no; + igraph_int_t max, no; } igraph_dbuckets_t; -igraph_error_t igraph_dbuckets_init(igraph_dbuckets_t *b, igraph_integer_t bsize, igraph_integer_t size); +igraph_error_t igraph_dbuckets_init(igraph_dbuckets_t *b, igraph_int_t bsize, igraph_int_t size); void igraph_dbuckets_destroy(igraph_dbuckets_t *b); void igraph_dbuckets_clear(igraph_dbuckets_t *b); -igraph_integer_t igraph_dbuckets_popmax(igraph_dbuckets_t *b); -igraph_integer_t igraph_dbuckets_pop(igraph_dbuckets_t *b, igraph_integer_t bucket); +igraph_int_t igraph_dbuckets_popmax(igraph_dbuckets_t *b); +igraph_int_t igraph_dbuckets_pop(igraph_dbuckets_t *b, igraph_int_t bucket); IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_dbuckets_empty(const igraph_dbuckets_t *b); IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_dbuckets_empty_bucket(const igraph_dbuckets_t *b, - igraph_integer_t bucket); -void igraph_dbuckets_add(igraph_dbuckets_t *b, igraph_integer_t bucket, - igraph_integer_t elem); -void igraph_dbuckets_delete(igraph_dbuckets_t *b, igraph_integer_t bucket, - igraph_integer_t elem); + igraph_int_t bucket); +void igraph_dbuckets_add(igraph_dbuckets_t *b, igraph_int_t bucket, + igraph_int_t elem); +void igraph_dbuckets_delete(igraph_dbuckets_t *b, igraph_int_t bucket, + igraph_int_t elem); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/core/cutheap.c b/src/vendor/cigraph/src/core/cutheap.c index 96dd1be7367..29d15cd7c16 100644 --- a/src/vendor/cigraph/src/core/cutheap.c +++ b/src/vendor/cigraph/src/core/cutheap.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -32,10 +31,10 @@ #define INDEXINC 1 static void igraph_i_cutheap_switch(igraph_i_cutheap_t *ch, - igraph_integer_t hidx1, igraph_integer_t hidx2) { + igraph_int_t hidx1, igraph_int_t hidx2) { if (hidx1 != hidx2) { - igraph_integer_t idx1 = VECTOR(ch->index)[hidx1]; - igraph_integer_t idx2 = VECTOR(ch->index)[hidx2]; + igraph_int_t idx1 = VECTOR(ch->index)[hidx1]; + igraph_int_t idx2 = VECTOR(ch->index)[hidx2]; igraph_real_t tmp = VECTOR(ch->heap)[hidx1]; VECTOR(ch->heap)[hidx1] = VECTOR(ch->heap)[hidx2]; @@ -49,8 +48,8 @@ static void igraph_i_cutheap_switch(igraph_i_cutheap_t *ch, } } -static void igraph_i_cutheap_sink(igraph_i_cutheap_t *ch, igraph_integer_t hidx) { - igraph_integer_t size = igraph_vector_size(&ch->heap); +static void igraph_i_cutheap_sink(igraph_i_cutheap_t *ch, igraph_int_t hidx) { + igraph_int_t size = igraph_vector_size(&ch->heap); if (LEFTCHILD(hidx) >= size) { /* leaf node */ } else if (RIGHTCHILD(hidx) == size || @@ -70,7 +69,7 @@ static void igraph_i_cutheap_sink(igraph_i_cutheap_t *ch, igraph_integer_t hidx) } } -static void igraph_i_cutheap_shift_up(igraph_i_cutheap_t *ch, igraph_integer_t hidx) { +static void igraph_i_cutheap_shift_up(igraph_i_cutheap_t *ch, igraph_int_t hidx) { if (hidx == 0 || VECTOR(ch->heap)[hidx] < VECTOR(ch->heap)[PARENT(hidx)]) { /* at the top */ } else { @@ -79,7 +78,7 @@ static void igraph_i_cutheap_shift_up(igraph_i_cutheap_t *ch, igraph_integer_t h } } -igraph_error_t igraph_i_cutheap_init(igraph_i_cutheap_t *ch, igraph_integer_t nodes) { +igraph_error_t igraph_i_cutheap_init(igraph_i_cutheap_t *ch, igraph_int_t nodes) { ch->dnodes = nodes; IGRAPH_VECTOR_INIT_FINALLY(&ch->heap, nodes); /* all zero */ IGRAPH_CHECK(igraph_vector_int_init_range(&ch->index, 0, nodes)); @@ -101,13 +100,13 @@ igraph_bool_t igraph_i_cutheap_empty(igraph_i_cutheap_t *ch) { /* Number of active vertices */ -igraph_integer_t igraph_i_cutheap_active_size(igraph_i_cutheap_t *ch) { +igraph_int_t igraph_i_cutheap_active_size(igraph_i_cutheap_t *ch) { return igraph_vector_size(&ch->heap); } /* Number of all (defined) vertices */ -igraph_integer_t igraph_i_cutheap_size(igraph_i_cutheap_t *ch) { +igraph_int_t igraph_i_cutheap_size(igraph_i_cutheap_t *ch) { return ch->dnodes; } @@ -115,9 +114,9 @@ igraph_real_t igraph_i_cutheap_maxvalue(igraph_i_cutheap_t *ch) { return VECTOR(ch->heap)[0]; } -igraph_integer_t igraph_i_cutheap_popmax(igraph_i_cutheap_t *ch) { - igraph_integer_t size = igraph_vector_size(&ch->heap); - igraph_integer_t maxindex = VECTOR(ch->index)[0]; +igraph_int_t igraph_i_cutheap_popmax(igraph_i_cutheap_t *ch) { + igraph_int_t size = igraph_vector_size(&ch->heap); + igraph_int_t maxindex = VECTOR(ch->index)[0]; /* put the last element to the top */ igraph_i_cutheap_switch(ch, 0, size - 1); /* remove the last element */ @@ -132,10 +131,10 @@ igraph_integer_t igraph_i_cutheap_popmax(igraph_i_cutheap_t *ch) { /* Update the value of an active vertex, if not active it will be ignored */ void igraph_i_cutheap_update( - igraph_i_cutheap_t *ch, igraph_integer_t index, igraph_real_t add) { + igraph_i_cutheap_t *ch, igraph_int_t index, igraph_real_t add) { igraph_real_t hidx = VECTOR(ch->hptr)[index]; if (hidx != INACTIVE && hidx != UNDEFINED) { - igraph_integer_t hidx2 = (hidx - INDEXINC); + igraph_int_t hidx2 = (hidx - INDEXINC); /* printf("updating vertex %li, heap index %li\n", index, hidx2); */ VECTOR(ch->heap)[hidx2] += add; igraph_i_cutheap_sink(ch, hidx2); @@ -145,8 +144,8 @@ void igraph_i_cutheap_update( /* Reset the value of all vertices to zero and make them active */ -igraph_error_t igraph_i_cutheap_reset_undefine(igraph_i_cutheap_t *ch, igraph_integer_t vertex) { - igraph_integer_t i, j, n = igraph_vector_size(&ch->hptr); +igraph_error_t igraph_i_cutheap_reset_undefine(igraph_i_cutheap_t *ch, igraph_int_t vertex) { + igraph_int_t i, j, n = igraph_vector_size(&ch->hptr); /* undefine */ VECTOR(ch->hptr)[vertex] = UNDEFINED; ch->dnodes -= 1; diff --git a/src/vendor/cigraph/src/core/cutheap.h b/src/vendor/cigraph/src/core/cutheap.h index fcbb4cdcc39..30901d3e7fc 100644 --- a/src/vendor/cigraph/src/core/cutheap.h +++ b/src/vendor/cigraph/src/core/cutheap.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2009-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -27,7 +26,7 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* Special maximum heap, needed for the minimum cut algorithm */ @@ -35,19 +34,19 @@ typedef struct igraph_i_cutheap_t { igraph_vector_t heap; igraph_vector_int_t index; igraph_vector_t hptr; - igraph_integer_t dnodes; + igraph_int_t dnodes; } igraph_i_cutheap_t; -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_cutheap_init(igraph_i_cutheap_t *ch, igraph_integer_t nodes); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_cutheap_init(igraph_i_cutheap_t *ch, igraph_int_t nodes); IGRAPH_PRIVATE_EXPORT void igraph_i_cutheap_destroy(igraph_i_cutheap_t *ch); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_i_cutheap_empty(igraph_i_cutheap_t *ch); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_i_cutheap_active_size(igraph_i_cutheap_t *ch); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_i_cutheap_size(igraph_i_cutheap_t *ch); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_i_cutheap_active_size(igraph_i_cutheap_t *ch); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_i_cutheap_size(igraph_i_cutheap_t *ch); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t igraph_i_cutheap_maxvalue(igraph_i_cutheap_t *ch); -IGRAPH_PRIVATE_EXPORT igraph_integer_t igraph_i_cutheap_popmax(igraph_i_cutheap_t *ch); -IGRAPH_PRIVATE_EXPORT void igraph_i_cutheap_update(igraph_i_cutheap_t *ch, igraph_integer_t index, igraph_real_t add); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_cutheap_reset_undefine(igraph_i_cutheap_t *ch, igraph_integer_t vertex); +IGRAPH_PRIVATE_EXPORT igraph_int_t igraph_i_cutheap_popmax(igraph_i_cutheap_t *ch); +IGRAPH_PRIVATE_EXPORT void igraph_i_cutheap_update(igraph_i_cutheap_t *ch, igraph_int_t index, igraph_real_t add); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_cutheap_reset_undefine(igraph_i_cutheap_t *ch, igraph_int_t vertex); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/core/dqueue.c b/src/vendor/cigraph/src/core/dqueue.c index 20e8d953f8e..142f2bced0a 100644 --- a/src/vendor/cigraph/src/core/dqueue.c +++ b/src/vendor/cigraph/src/core/dqueue.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/core/dqueue.pmt b/src/vendor/cigraph/src/core/dqueue.pmt index eb0f4c47caa..e7803fc94ac 100644 --- a/src/vendor/cigraph/src/core/dqueue.pmt +++ b/src/vendor/cigraph/src/core/dqueue.pmt @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -73,7 +72,7 @@ * Time complexity: O(\p capacity). */ -igraph_error_t FUNCTION(igraph_dqueue, init)(TYPE(igraph_dqueue)* q, igraph_integer_t capacity) { +igraph_error_t FUNCTION(igraph_dqueue, init)(TYPE(igraph_dqueue)* q, igraph_int_t capacity) { IGRAPH_ASSERT(q != NULL); IGRAPH_ASSERT(capacity >= 0); @@ -169,7 +168,7 @@ igraph_bool_t FUNCTION(igraph_dqueue, full)(TYPE(igraph_dqueue)* q) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_dqueue, size)(const TYPE(igraph_dqueue)* q) { +igraph_int_t FUNCTION(igraph_dqueue, size)(const TYPE(igraph_dqueue)* q) { IGRAPH_ASSERT(q != NULL); IGRAPH_ASSERT(q->stor_begin != NULL); if (q->end == NULL) { @@ -322,8 +321,8 @@ igraph_error_t FUNCTION(igraph_dqueue, push)(TYPE(igraph_dqueue)* q, BASE elem) /* full, allocate more storage */ BASE *bigger = NULL, *old = q->stor_begin; - igraph_integer_t old_size = q->stor_end - q->stor_begin; - igraph_integer_t new_capacity = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; + igraph_int_t old_size = q->stor_end - q->stor_begin; + igraph_int_t new_capacity = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; if (old_size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot push to dqueue, already at maximum size.", IGRAPH_EOVERFLOW); @@ -414,7 +413,7 @@ igraph_error_t FUNCTION(igraph_dqueue, fprint)(const TYPE(igraph_dqueue)* q, FIL * Time complexity: O(1). */ -BASE FUNCTION(igraph_dqueue, get)(const TYPE(igraph_dqueue) *q, igraph_integer_t idx) { +BASE FUNCTION(igraph_dqueue, get)(const TYPE(igraph_dqueue) *q, igraph_int_t idx) { IGRAPH_ASSERT(idx >= 0); IGRAPH_ASSERT(idx < FUNCTION(igraph_dqueue, size)(q)); if ((q->begin + idx < q->end) || @@ -429,15 +428,3 @@ BASE FUNCTION(igraph_dqueue, get)(const TYPE(igraph_dqueue) *q, igraph_integer_t IGRAPH_FATAL("Out of bounds access in dqueue."); } } - -/** - * \ingroup dqueue - * \function igraph_dqueue_e - * \brief Access an element in a queue (deprecated alias). - * - * \deprecated-by igraph_dqueue_get 0.10.2 - */ - -BASE FUNCTION(igraph_dqueue, e)(const TYPE(igraph_dqueue) *q, igraph_integer_t idx) { - return FUNCTION(igraph_dqueue, get)(q, idx); -} diff --git a/src/vendor/cigraph/src/core/error.c b/src/vendor/cigraph/src/core/error.c index 6bd429aab28..27180adb5cb 100644 --- a/src/vendor/cigraph/src/core/error.c +++ b/src/vendor/cigraph/src/core/error.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -92,63 +91,70 @@ static const char *igraph_i_error_strings[] = { /* 3 */ "Parse error", /* 4 */ "Invalid value", /* 5 */ "Already exists", - /* 6 */ "Invalid edge vector", + /* 6 */ NULL, // "Invalid edge vector", /* removed in 1.0 */ /* 7 */ "Invalid vertex ID", - /* 8 */ "Non-square matrix", + /* 8 */ "Invalid edge ID", /* 9 */ "Invalid mode", /* 10 */ "File operation error", /* 11 */ "Unfold infinite iterator", /* 12 */ "Unimplemented function call", /* 13 */ "Interrupted", /* 14 */ "Numeric procedure did not converge", - /* 15 */ "Matrix-vector product failed", - /* 16 */ "N must be positive", - /* 17 */ "NEV must be positive", - /* 18 */ "NCV must be greater than NEV and less than or equal to N " - "(and for the non-symmetric solver NCV-NEV >=2 must also hold)", - /* 19 */ "Maximum number of iterations should be positive", - /* 20 */ "Invalid WHICH parameter", - /* 21 */ "Invalid BMAT parameter", - /* 22 */ "WORKL is too small", - /* 23 */ "LAPACK error in tridiagonal eigenvalue calculation", - /* 24 */ "Starting vector is zero", - /* 25 */ "MODE is invalid", - /* 26 */ "MODE and BMAT are not compatible", - /* 27 */ "ISHIFT must be 0 or 1", - /* 28 */ "NEV and WHICH='BE' are incompatible", - /* 29 */ "Could not build an Arnoldi factorization", - /* 30 */ "No eigenvalues to sufficient accuracy", - /* 31 */ "HOWMNY is invalid", - /* 32 */ "HOWMNY='S' is not implemented", - /* 33 */ "Different number of converged Ritz values", - /* 34 */ "Error from calculation of a real Schur form", - /* 35 */ "LAPACK (dtrevc) error for calculating eigenvectors", - /* 36 */ "Unknown ARPACK error", + + /* ARPACK error codes moved to igraph_arpack_error_t in arpack.c from version 1.0 */ + /* 15 */ "ARPACK error", // used to be "Matrix-vector product failed", + /* 16 */ NULL, // "N must be positive", + /* 17 */ NULL, // "NEV must be positive", + /* 18 */ NULL, // "NCV must be greater than NEV and less than or equal to N " + // "(and for the non-symmetric solver NCV-NEV >=2 must also hold)", + /* 19 */ NULL, // "Maximum number of iterations should be positive", + /* 20 */ NULL, // "Invalid WHICH parameter", + /* 21 */ NULL, // "Invalid BMAT parameter", + /* 22 */ NULL, // "WORKL is too small", + /* 23 */ NULL, // "LAPACK error in tridiagonal eigenvalue calculation", + /* 24 */ NULL, // "Starting vector is zero", + /* 25 */ NULL, // "MODE is invalid", + /* 26 */ NULL, // "MODE and BMAT are not compatible", + /* 27 */ NULL, // "ISHIFT must be 0 or 1", + /* 28 */ NULL, // "NEV and WHICH='BE' are incompatible", + /* 29 */ NULL, // "Could not build an Arnoldi factorization", + /* 30 */ NULL, // "No eigenvalues to sufficient accuracy", + /* 31 */ NULL, // "HOWMNY is invalid", + /* 32 */ NULL, // "HOWMNY='S' is not implemented", + /* 33 */ NULL, // "Different number of converged Ritz values", + /* 34 */ NULL, // "Error from calculation of a real Schur form", + /* 35 */ NULL, // "LAPACK (dtrevc) error for calculating eigenvectors", + /* 36 */ NULL, // "Unknown ARPACK error", + /* ARPACK error codes end here */ + /* 37 */ "Negative cycle detected while calculating shortest paths", /* 38 */ "Internal error, likely a bug in igraph", - /* 39 */ "Maximum number of iterations reached", - /* 40 */ "No shifts could be applied during a cycle of the " - "Implicitly restarted Arnoldi iteration. One possibility " - "is to increase the size of NCV relative to NEV", - /* 41 */ "The Schur form computed by LAPACK routine dlahqr " - "could not be reordered by LAPACK routine dtrsen.", - /* 42 */ "Big integer division by zero", - /* 43 */ "GLPK Error, GLP_EBOUND", - /* 44 */ "GLPK Error, GLP_EROOT", - /* 45 */ "GLPK Error, GLP_ENOPFS", - /* 46 */ "GLPK Error, GLP_ENODFS", - /* 47 */ "GLPK Error, GLP_EFAIL", - /* 48 */ "GLPK Error, GLP_EMIPGAP", - /* 49 */ "GLPK Error, GLP_ETMLIM", - /* 50 */ "GLPK Error, GLP_STOP", - /* 51 */ "Internal attribute handler error", + + /* More ARPACK error codes moved to igraph_arpack_error_t in arpack.c from version 1.0 */ + /* 39 */ NULL, // "Maximum number of iterations reached", + /* 40 */ NULL, // "No shifts could be applied during a cycle of the " + // "Implicitly restarted Arnoldi iteration. One possibility " + // "is to increase the size of NCV relative to NEV", + /* 41 */ NULL, // "The Schur form computed by LAPACK routine dlahqr " + // "could not be reordered by LAPACK routine dtrsen.", + /* ARPACK error codes end here */ + + /* 42 */ NULL, // "Big integer division by zero", /* removed in 1.0 */ + /* 43 */ NULL, // "GLPK Error, GLP_EBOUND", /* removed in 1.0 */ + /* 44 */ NULL, // "GLPK Error, GLP_EROOT", /* removed in 1.0 */ + /* 45 */ NULL, // "GLPK Error, GLP_ENOPFS", /* removed in 1.0 */ + /* 46 */ NULL, // "GLPK Error, GLP_ENODFS", /* removed in 1.0 */ + /* 47 */ NULL, // "GLPK Error, GLP_EFAIL", /* removed in 1.0 */ + /* 48 */ NULL, // "GLPK Error, GLP_EMIPGAP", /* removed in 1.0 */ + /* 49 */ NULL, // "GLPK Error, GLP_ETMLIM", /* removed in 1.0 */ + /* 50 */ NULL, // "GLPK Error, GLP_STOP", /* removed in 1.0 */ + /* 51 */ NULL, // "Internal attribute handler error", /* removed in 1.0 */ /* 52 */ "Unimplemented attribute combination for this type", - /* 53 */ "LAPACK call resulted in an error", - /* 54 */ "Internal DrL error; this error should never be visible to the user, " - "please report this error along with the steps to reproduce it.", + /* 53 */ NULL, // "LAPACK call resulted in an error", /* removed in 1.0 */ + /* 54 */ NULL, // "Internal DrL error", /* removed in 1.0 */ /* 55 */ "Integer or double overflow", - /* 56 */ "Internal GPLK error", - /* 57 */ "CPU time exceeded", + /* 56 */ NULL, // "Internal GPLK error", /* removed in 1.0 */ + /* 57 */ NULL, // "CPU time exceeded", /* removed in 1.0 */ /* 58 */ "Integer or double underflow", /* 59 */ "Random walk got stuck", /* 60 */ "Search stopped; this error should never be visible to the user, " @@ -174,7 +180,10 @@ const char *igraph_strerror(const igraph_error_t igraph_errno) { (int) igraph_errno >= sizeof(igraph_i_error_strings) / sizeof(igraph_i_error_strings[0])) { IGRAPH_FATALF("Invalid error code %d; no error string available.", (int) igraph_errno); } - return igraph_i_error_strings[igraph_errno]; + const char *msg = igraph_i_error_strings[igraph_errno]; + /* Messages removed in 1.0 were replaced by NULL and should not be used. */ + IGRAPH_ASSERT(msg != NULL); + return msg; } diff --git a/src/vendor/cigraph/src/core/estack.c b/src/vendor/cigraph/src/core/estack.c index 7c45a2a82ba..918b47a1f87 100644 --- a/src/vendor/cigraph/src/core/estack.c +++ b/src/vendor/cigraph/src/core/estack.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -23,8 +22,8 @@ #include "core/estack.h" -igraph_error_t igraph_estack_init(igraph_estack_t *s, igraph_integer_t setsize, - igraph_integer_t stacksize) { +igraph_error_t igraph_estack_init(igraph_estack_t *s, igraph_int_t setsize, + igraph_int_t stacksize) { IGRAPH_CHECK(igraph_bitset_init(&s->isin, setsize)); IGRAPH_FINALLY(igraph_bitset_destroy, &s->isin); IGRAPH_CHECK(igraph_stack_int_init(&s->stack, stacksize)); @@ -37,7 +36,7 @@ void igraph_estack_destroy(igraph_estack_t *s) { igraph_bitset_destroy(&s->isin); } -igraph_error_t igraph_estack_push(igraph_estack_t *s, igraph_integer_t elem) { +igraph_error_t igraph_estack_push(igraph_estack_t *s, igraph_int_t elem) { if ( !IGRAPH_BIT_TEST(s->isin, elem)) { IGRAPH_CHECK(igraph_stack_int_push(&s->stack, elem)); IGRAPH_BIT_SET(s->isin, elem); @@ -45,18 +44,18 @@ igraph_error_t igraph_estack_push(igraph_estack_t *s, igraph_integer_t elem) { return IGRAPH_SUCCESS; } -igraph_integer_t igraph_estack_pop(igraph_estack_t *s) { - igraph_integer_t elem = igraph_stack_int_pop(&s->stack); +igraph_int_t igraph_estack_pop(igraph_estack_t *s) { + igraph_int_t elem = igraph_stack_int_pop(&s->stack); IGRAPH_BIT_CLEAR(s->isin, elem); return elem; } igraph_bool_t igraph_estack_iselement(const igraph_estack_t *s, - igraph_integer_t elem) { + igraph_int_t elem) { return IGRAPH_BIT_TEST(s->isin, elem); } -igraph_integer_t igraph_estack_size(const igraph_estack_t *s) { +igraph_int_t igraph_estack_size(const igraph_estack_t *s) { return igraph_stack_int_size(&s->stack); } diff --git a/src/vendor/cigraph/src/core/estack.h b/src/vendor/cigraph/src/core/estack.h index 9a738a69733..8ffd1830940 100644 --- a/src/vendor/cigraph/src/core/estack.h +++ b/src/vendor/cigraph/src/core/estack.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -28,7 +27,7 @@ #include "igraph_bitset.h" #include "igraph_stack.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS typedef struct igraph_estack_t { igraph_stack_int_t stack; @@ -36,17 +35,17 @@ typedef struct igraph_estack_t { } igraph_estack_t; IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_estack_init( - igraph_estack_t *s, igraph_integer_t setsize, igraph_integer_t stacksize); + igraph_estack_t *s, igraph_int_t setsize, igraph_int_t stacksize); IGRAPH_PRIVATE_EXPORT void igraph_estack_destroy(igraph_estack_t *s); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_estack_push(igraph_estack_t *s, igraph_integer_t elem); -IGRAPH_PRIVATE_EXPORT igraph_integer_t igraph_estack_pop(igraph_estack_t *s); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_estack_push(igraph_estack_t *s, igraph_int_t elem); +IGRAPH_PRIVATE_EXPORT igraph_int_t igraph_estack_pop(igraph_estack_t *s); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_estack_iselement(const igraph_estack_t *s, - igraph_integer_t elem); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_estack_size(const igraph_estack_t *s); + igraph_int_t elem); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_estack_size(const igraph_estack_t *s); IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_estack_print(const igraph_estack_t *s); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/core/fixed_vectorlist.c b/src/vendor/cigraph/src/core/fixed_vectorlist.c index 8b247f75599..724c83ba7bf 100644 --- a/src/vendor/cigraph/src/core/fixed_vectorlist.c +++ b/src/vendor/cigraph/src/core/fixed_vectorlist.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -29,10 +28,10 @@ void igraph_fixed_vectorlist_destroy(igraph_fixed_vectorlist_t *l) { igraph_error_t igraph_fixed_vectorlist_convert( igraph_fixed_vectorlist_t *l, const igraph_vector_int_t *from, - igraph_integer_t size + igraph_int_t size ) { igraph_vector_int_t sizes; - igraph_integer_t i, no = igraph_vector_int_size(from), to; + igraph_int_t i, no = igraph_vector_int_size(from), to; IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(&l->vecs, size); IGRAPH_VECTOR_INT_INIT_FINALLY(&sizes, size); diff --git a/src/vendor/cigraph/src/core/fixed_vectorlist.h b/src/vendor/cigraph/src/core/fixed_vectorlist.h index 34e2437873a..2571a2d007f 100644 --- a/src/vendor/cigraph/src/core/fixed_vectorlist.h +++ b/src/vendor/cigraph/src/core/fixed_vectorlist.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2009-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -29,7 +28,7 @@ #include "igraph_vector.h" #include "igraph_vector_list.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Vectorlist, fixed length */ @@ -37,14 +36,14 @@ __BEGIN_DECLS typedef struct igraph_fixed_vectorlist_t { igraph_vector_int_list_t vecs; - igraph_integer_t length; + igraph_int_t length; } igraph_fixed_vectorlist_t; void igraph_fixed_vectorlist_destroy(igraph_fixed_vectorlist_t *l); igraph_error_t igraph_fixed_vectorlist_convert(igraph_fixed_vectorlist_t *l, const igraph_vector_int_t *from, - igraph_integer_t size); + igraph_int_t size); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/core/genheap.c b/src/vendor/cigraph/src/core/genheap.c index 1e4ec3f3fa9..c748c3ea2c6 100644 --- a/src/vendor/cigraph/src/core/genheap.c +++ b/src/vendor/cigraph/src/core/genheap.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -50,9 +50,9 @@ static void swapfunc(char * restrict a, char * restrict b, size_t es) { } static void igraph_i_gen2wheap_switch(igraph_gen2wheap_t *h, - igraph_integer_t e1, igraph_integer_t e2) { + igraph_int_t e1, igraph_int_t e2) { if (e1 != e2) { - igraph_integer_t tmp1, tmp2; + igraph_int_t tmp1, tmp2; swapfunc(ELEM(h, e1), ELEM(h, e2), h->item_size); @@ -68,7 +68,7 @@ static void igraph_i_gen2wheap_switch(igraph_gen2wheap_t *h, } static void igraph_i_gen2wheap_shift_up(igraph_gen2wheap_t *h, - igraph_integer_t elem) { + igraph_int_t elem) { if (elem == 0 || h->cmp(ELEM(h, elem), ELEM(h, PARENT(elem))) < 0) { /* at the top */ } else { @@ -78,8 +78,8 @@ static void igraph_i_gen2wheap_shift_up(igraph_gen2wheap_t *h, } static void igraph_i_gen2wheap_sink(igraph_gen2wheap_t *h, - igraph_integer_t head) { - igraph_integer_t size = igraph_gen2wheap_size(h); + igraph_int_t head) { + igraph_int_t size = igraph_gen2wheap_size(h); if (LEFTCHILD(head) >= size) { /* no subtrees */ } else if (RIGHTCHILD(head) == size || @@ -109,7 +109,7 @@ static void igraph_i_gen2wheap_sink(igraph_gen2wheap_t *h, igraph_error_t igraph_gen2wheap_init( igraph_gen2wheap_t *h, int (*cmp)(const void *, const void *), - size_t item_size, igraph_integer_t max_size + size_t item_size, igraph_int_t max_size ) { /* TODO: Currently, storage is allocated for the maximum number of elements * right from the start. This is sufficient for the only use case as of this @@ -142,7 +142,7 @@ void igraph_gen2wheap_destroy(igraph_gen2wheap_t *h) { /** * Returns the current number of elements in the two-way heap. */ -igraph_integer_t igraph_gen2wheap_size(const igraph_gen2wheap_t *h) { +igraph_int_t igraph_gen2wheap_size(const igraph_gen2wheap_t *h) { return igraph_vector_int_size(&h->index); } @@ -168,9 +168,9 @@ igraph_bool_t igraph_gen2wheap_empty(const igraph_gen2wheap_t *h) { * the same index. */ igraph_error_t igraph_gen2wheap_push_with_index(igraph_gen2wheap_t *h, - igraph_integer_t idx, const void *elem) { + igraph_int_t idx, const void *elem) { - igraph_integer_t size = igraph_vector_int_size(&h->index); + igraph_int_t size = igraph_vector_int_size(&h->index); if (size > IGRAPH_INTEGER_MAX - 2) { /* to allow size+2 below */ @@ -192,7 +192,7 @@ igraph_error_t igraph_gen2wheap_push_with_index(igraph_gen2wheap_t *h, * is also one larger than the maximum allowed index that can be passed to * \c igraph_gen2wheap_push_with_index . */ -igraph_integer_t igraph_gen2wheap_max_size(const igraph_gen2wheap_t *h) { +igraph_int_t igraph_gen2wheap_max_size(const igraph_gen2wheap_t *h) { return h->max_size; } @@ -207,7 +207,7 @@ const void *igraph_gen2wheap_max(const igraph_gen2wheap_t *h) { * Returns the index that was associated to the largest element in the heap * when it was pushed to the heap. */ -igraph_integer_t igraph_gen2wheap_max_index(const igraph_gen2wheap_t *h) { +igraph_int_t igraph_gen2wheap_max_index(const igraph_gen2wheap_t *h) { return VECTOR(h->index)[0]; } @@ -215,7 +215,7 @@ igraph_integer_t igraph_gen2wheap_max_index(const igraph_gen2wheap_t *h) { * Returns whether the heap contains an element with the given index, even if * it was deactivated earlier. */ -igraph_bool_t igraph_gen2wheap_has_elem(const igraph_gen2wheap_t *h, igraph_integer_t idx) { +igraph_bool_t igraph_gen2wheap_has_elem(const igraph_gen2wheap_t *h, igraph_int_t idx) { return VECTOR(h->index2)[idx] != 0; } @@ -223,15 +223,15 @@ igraph_bool_t igraph_gen2wheap_has_elem(const igraph_gen2wheap_t *h, igraph_inte * Returns whether the heap contains an element with the given index \em and it * has not been deactivated yet. */ -igraph_bool_t igraph_gen2wheap_has_active(const igraph_gen2wheap_t *h, igraph_integer_t idx) { +igraph_bool_t igraph_gen2wheap_has_active(const igraph_gen2wheap_t *h, igraph_int_t idx) { return VECTOR(h->index2)[idx] > 1; } /** * Returns a pointer to the item at the given index in the two-way heap. */ -const void *igraph_gen2wheap_get(const igraph_gen2wheap_t *h, igraph_integer_t idx) { - igraph_integer_t i = VECTOR(h->index2)[idx] - 2; +const void *igraph_gen2wheap_get(const igraph_gen2wheap_t *h, igraph_int_t idx) { + igraph_int_t i = VECTOR(h->index2)[idx] - 2; return ELEM(h, i); } @@ -242,7 +242,7 @@ const void *igraph_gen2wheap_get(const igraph_gen2wheap_t *h, igraph_integer_t i * that remain in the heap. */ void igraph_gen2wheap_delete_max(igraph_gen2wheap_t *h) { - igraph_integer_t tmpidx = VECTOR(h->index)[0]; + igraph_int_t tmpidx = VECTOR(h->index)[0]; igraph_i_gen2wheap_switch(h, 0, igraph_gen2wheap_size(h) - 1); igraph_vector_int_pop_back(&h->index); VECTOR(h->index2)[tmpidx] = 0; @@ -256,7 +256,7 @@ void igraph_gen2wheap_delete_max(igraph_gen2wheap_t *h) { * that remain in the heap. */ void igraph_gen2wheap_deactivate_max(igraph_gen2wheap_t *h) { - igraph_integer_t tmpidx = VECTOR(h->index)[0]; + igraph_int_t tmpidx = VECTOR(h->index)[0]; igraph_i_gen2wheap_switch(h, 0, igraph_gen2wheap_size(h) - 1); igraph_vector_int_pop_back(&h->index); VECTOR(h->index2)[tmpidx] = 1; @@ -266,9 +266,9 @@ void igraph_gen2wheap_deactivate_max(igraph_gen2wheap_t *h) { /** * Modifies the value associated to the given index in the two-way heap. */ -void igraph_gen2wheap_modify(igraph_gen2wheap_t *h, igraph_integer_t idx, const void *elem) { +void igraph_gen2wheap_modify(igraph_gen2wheap_t *h, igraph_int_t idx, const void *elem) { - igraph_integer_t pos = VECTOR(h->index2)[idx] - 2; + igraph_int_t pos = VECTOR(h->index2)[idx] - 2; memcpy(ELEM(h, pos), elem, h->item_size); igraph_i_gen2wheap_sink(h, pos); @@ -279,8 +279,8 @@ void igraph_gen2wheap_modify(igraph_gen2wheap_t *h, igraph_integer_t idx, const * Checks that the heap is in a consistent state */ igraph_error_t igraph_gen2wheap_check(const igraph_gen2wheap_t *h) { - igraph_integer_t size = igraph_gen2wheap_size(h); - igraph_integer_t i; + igraph_int_t size = igraph_gen2wheap_size(h); + igraph_int_t i; igraph_bool_t error = false; /* Check the heap property */ diff --git a/src/vendor/cigraph/src/core/genheap.h b/src/vendor/cigraph/src/core/genheap.h index e711b430fd8..c8b18ddfd56 100644 --- a/src/vendor/cigraph/src/core/genheap.h +++ b/src/vendor/cigraph/src/core/genheap.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -21,7 +21,7 @@ typedef struct igraph_gen2wheap_t { /** Maximum number of items in the heap */ - igraph_integer_t max_size; + igraph_int_t max_size; /** The size of an individual item */ size_t item_size; @@ -53,21 +53,21 @@ typedef struct igraph_gen2wheap_t { IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_gen2wheap_init( igraph_gen2wheap_t *h, int (*cmp)(const void *, const void *), - size_t item_size, igraph_integer_t max_size + size_t item_size, igraph_int_t max_size ); IGRAPH_PRIVATE_EXPORT void igraph_gen2wheap_destroy(igraph_gen2wheap_t *h); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_gen2wheap_size(const igraph_gen2wheap_t *h); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_gen2wheap_size(const igraph_gen2wheap_t *h); IGRAPH_PRIVATE_EXPORT void igraph_gen2wheap_clear(igraph_gen2wheap_t *h); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_gen2wheap_empty(const igraph_gen2wheap_t *h); IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_gen2wheap_push_with_index(igraph_gen2wheap_t *h, - igraph_integer_t idx, const void *elem); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_gen2wheap_max_size(const igraph_gen2wheap_t *h); + igraph_int_t idx, const void *elem); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_gen2wheap_max_size(const igraph_gen2wheap_t *h); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE const void *igraph_gen2wheap_max(const igraph_gen2wheap_t *h); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_gen2wheap_max_index(const igraph_gen2wheap_t *h); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_gen2wheap_has_elem(const igraph_gen2wheap_t *h, igraph_integer_t idx); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_gen2wheap_has_active(const igraph_gen2wheap_t *h, igraph_integer_t idx); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE const void *igraph_gen2wheap_get(const igraph_gen2wheap_t *h, igraph_integer_t idx); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_gen2wheap_max_index(const igraph_gen2wheap_t *h); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_gen2wheap_has_elem(const igraph_gen2wheap_t *h, igraph_int_t idx); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_gen2wheap_has_active(const igraph_gen2wheap_t *h, igraph_int_t idx); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE const void *igraph_gen2wheap_get(const igraph_gen2wheap_t *h, igraph_int_t idx); IGRAPH_PRIVATE_EXPORT void igraph_gen2wheap_delete_max(igraph_gen2wheap_t *h); IGRAPH_PRIVATE_EXPORT void igraph_gen2wheap_deactivate_max(igraph_gen2wheap_t *h); -IGRAPH_PRIVATE_EXPORT void igraph_gen2wheap_modify(igraph_gen2wheap_t *h, igraph_integer_t idx, const void *elem); +IGRAPH_PRIVATE_EXPORT void igraph_gen2wheap_modify(igraph_gen2wheap_t *h, igraph_int_t idx, const void *elem); IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_gen2wheap_check(const igraph_gen2wheap_t *h); diff --git a/src/vendor/cigraph/src/core/grid.c b/src/vendor/cigraph/src/core/grid.c index 1c620349b8d..d0d9102ad47 100644 --- a/src/vendor/cigraph/src/core/grid.c +++ b/src/vendor/cigraph/src/core/grid.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ static void igraph_i_2dgrid_which( igraph_2dgrid_t *grid, igraph_real_t xc, igraph_real_t yc, - igraph_integer_t *x, igraph_integer_t *y + igraph_int_t *x, igraph_int_t *y ) { if (xc <= grid->minx) { *x = 0; @@ -48,7 +48,7 @@ static void igraph_i_2dgrid_which( igraph_error_t igraph_2dgrid_init(igraph_2dgrid_t *grid, igraph_matrix_t *coords, igraph_real_t minx, igraph_real_t maxx, igraph_real_t deltax, igraph_real_t miny, igraph_real_t maxy, igraph_real_t deltay) { - igraph_integer_t no_of_points; + igraph_int_t no_of_points; IGRAPH_ASSERT(minx <= maxx); IGRAPH_ASSERT(miny <= maxy); @@ -91,10 +91,10 @@ void igraph_2dgrid_destroy(igraph_2dgrid_t *grid) { igraph_vector_int_destroy(&grid->prev); } -void igraph_2dgrid_add(igraph_2dgrid_t *grid, igraph_integer_t elem, +void igraph_2dgrid_add(igraph_2dgrid_t *grid, igraph_int_t elem, igraph_real_t xc, igraph_real_t yc) { - igraph_integer_t x, y; - igraph_integer_t first; + igraph_int_t x, y; + igraph_int_t first; MATRIX(*grid->coords, elem, 0) = xc; MATRIX(*grid->coords, elem, 1) = yc; @@ -114,9 +114,9 @@ void igraph_2dgrid_add(igraph_2dgrid_t *grid, igraph_integer_t elem, grid->vertices += 1; } -void igraph_2dgrid_add2(igraph_2dgrid_t *grid, igraph_integer_t elem) { - igraph_integer_t x, y; - igraph_integer_t first; +void igraph_2dgrid_add2(igraph_2dgrid_t *grid, igraph_int_t elem) { + igraph_int_t x, y; + igraph_int_t first; igraph_real_t xc, yc; xc = MATRIX(*grid->coords, elem, 0); @@ -137,13 +137,13 @@ void igraph_2dgrid_add2(igraph_2dgrid_t *grid, igraph_integer_t elem) { grid->vertices += 1; } -void igraph_2dgrid_move(igraph_2dgrid_t *grid, igraph_integer_t elem, +void igraph_2dgrid_move(igraph_2dgrid_t *grid, igraph_int_t elem, igraph_real_t xc, igraph_real_t yc) { - igraph_integer_t oldx, oldy; - igraph_integer_t newx, newy; + igraph_int_t oldx, oldy; + igraph_int_t newx, newy; igraph_real_t oldxc = MATRIX(*grid->coords, elem, 0); igraph_real_t oldyc = MATRIX(*grid->coords, elem, 1); - igraph_integer_t first; + igraph_int_t first; xc = oldxc + xc; yc = oldyc + yc; @@ -186,12 +186,12 @@ void igraph_2dgrid_getcenter(const igraph_2dgrid_t *grid, *massy = (grid->massy) / (grid->vertices); } -igraph_bool_t igraph_2dgrid_in(const igraph_2dgrid_t *grid, igraph_integer_t elem) { +igraph_bool_t igraph_2dgrid_in(const igraph_2dgrid_t *grid, igraph_int_t elem) { return VECTOR(grid->next)[elem] != -1; } igraph_real_t igraph_2dgrid_sq_dist(const igraph_2dgrid_t *grid, - igraph_integer_t e1, igraph_integer_t e2) { + igraph_int_t e1, igraph_int_t e2) { igraph_real_t x = MATRIX(*grid->coords, e1, 0) - MATRIX(*grid->coords, e2, 0); igraph_real_t y = MATRIX(*grid->coords, e1, 1) - MATRIX(*grid->coords, e2, 1); @@ -210,9 +210,9 @@ void igraph_2dgrid_reset(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it) { } } -igraph_integer_t igraph_2dgrid_next(igraph_2dgrid_t *grid, +igraph_int_t igraph_2dgrid_next(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it) { - igraph_integer_t ret = it->vid; + igraph_int_t ret = it->vid; if (ret == 0) { return 0; @@ -259,9 +259,9 @@ igraph_integer_t igraph_2dgrid_next(igraph_2dgrid_t *grid, return ret; } -igraph_integer_t igraph_2dgrid_next_nei(igraph_2dgrid_t *grid, +igraph_int_t igraph_2dgrid_next_nei(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it) { - igraph_integer_t ret = it->nei; + igraph_int_t ret = it->nei; if (it->nei != 0) { it->nei = VECTOR(grid->next) [ ret - 1 ]; diff --git a/src/vendor/cigraph/src/core/grid.h b/src/vendor/cigraph/src/core/grid.h index 3043359752e..65a41ff13d1 100644 --- a/src/vendor/cigraph/src/core/grid.h +++ b/src/vendor/cigraph/src/core/grid.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2009-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -28,7 +27,7 @@ #include "igraph_matrix.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * 2d grid containing points @@ -38,41 +37,41 @@ typedef struct igraph_2dgrid_t { igraph_matrix_t *coords; /* The current coordinates in the grid */ igraph_real_t minx, maxx, deltax; /* Minimum and maximum X coordinates and X spacing */ igraph_real_t miny, maxy, deltay; /* Minimum and maximum Y coordinates and Y spacing */ - igraph_integer_t stepsx, stepsy; /* Number of cells in the X and Y directions */ + igraph_int_t stepsx, stepsy; /* Number of cells in the X and Y directions */ igraph_matrix_int_t startidx; /* startidx[i, j] is the index of an arbitrary point in that grid cell, plus one; zero means "empty cell" */ igraph_vector_int_t next; /* next[i] is the index of the point following point i in the same cell, plus one; zero means "last point" */ igraph_vector_int_t prev; /* prev[i] is the index of the point preceding point i in the same cell, plus one; zero means "first point" */ igraph_real_t massx, massy; /* The sum of the coordinates */ - igraph_integer_t vertices; /* Number of active vertices */ + igraph_int_t vertices; /* Number of active vertices */ } igraph_2dgrid_t; igraph_error_t igraph_2dgrid_init(igraph_2dgrid_t *grid, igraph_matrix_t *coords, igraph_real_t minx, igraph_real_t maxx, igraph_real_t deltax, igraph_real_t miny, igraph_real_t maxy, igraph_real_t deltay); void igraph_2dgrid_destroy(igraph_2dgrid_t *grid); -void igraph_2dgrid_add(igraph_2dgrid_t *grid, igraph_integer_t elem, +void igraph_2dgrid_add(igraph_2dgrid_t *grid, igraph_int_t elem, igraph_real_t xc, igraph_real_t yc); -void igraph_2dgrid_add2(igraph_2dgrid_t *grid, igraph_integer_t elem); -void igraph_2dgrid_move(igraph_2dgrid_t *grid, igraph_integer_t elem, +void igraph_2dgrid_add2(igraph_2dgrid_t *grid, igraph_int_t elem); +void igraph_2dgrid_move(igraph_2dgrid_t *grid, igraph_int_t elem, igraph_real_t xc, igraph_real_t yc); void igraph_2dgrid_getcenter(const igraph_2dgrid_t *grid, igraph_real_t *massx, igraph_real_t *massy); -IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_2dgrid_in(const igraph_2dgrid_t *grid, igraph_integer_t elem); +IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_2dgrid_in(const igraph_2dgrid_t *grid, igraph_int_t elem); IGRAPH_FUNCATTR_PURE igraph_real_t igraph_2dgrid_sq_dist(const igraph_2dgrid_t *grid, - igraph_integer_t e1, igraph_integer_t e2); + igraph_int_t e1, igraph_int_t e2); typedef struct igraph_2dgrid_iterator_t { - igraph_integer_t vid, x, y; - igraph_integer_t nei; - igraph_integer_t nx[4], ny[4], ncells; + igraph_int_t vid, x, y; + igraph_int_t nei; + igraph_int_t nx[4], ny[4], ncells; } igraph_2dgrid_iterator_t; void igraph_2dgrid_reset(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it); -igraph_integer_t igraph_2dgrid_next(igraph_2dgrid_t *grid, +igraph_int_t igraph_2dgrid_next(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it); -igraph_integer_t igraph_2dgrid_next_nei(igraph_2dgrid_t *grid, +igraph_int_t igraph_2dgrid_next_nei(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/core/heap.c b/src/vendor/cigraph/src/core/heap.c index a202ea64a60..ac0523dc8c0 100644 --- a/src/vendor/cigraph/src/core/heap.c +++ b/src/vendor/cigraph/src/core/heap.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/core/heap.pmt b/src/vendor/cigraph/src/core/heap.pmt index 0aa14c97030..6b406c59556 100644 --- a/src/vendor/cigraph/src/core/heap.pmt +++ b/src/vendor/cigraph/src/core/heap.pmt @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -32,10 +31,10 @@ #define RIGHTCHILD(x) (((x)+1)*2) /* Declare internal functions */ -static void FUNCTION(igraph_heap, i_build)(BASE* arr, igraph_integer_t size, igraph_integer_t head); -static void FUNCTION(igraph_heap, i_shift_up)(BASE* arr, igraph_integer_t size, igraph_integer_t elem); -static void FUNCTION(igraph_heap, i_sink)(BASE* arr, igraph_integer_t size, igraph_integer_t head); -static void FUNCTION(igraph_heap, i_switch)(BASE* arr, igraph_integer_t e1, igraph_integer_t e2); +static void FUNCTION(igraph_heap, i_build)(BASE* arr, igraph_int_t size, igraph_int_t head); +static void FUNCTION(igraph_heap, i_shift_up)(BASE* arr, igraph_int_t size, igraph_int_t elem); +static void FUNCTION(igraph_heap, i_sink)(BASE* arr, igraph_int_t size, igraph_int_t head); +static void FUNCTION(igraph_heap, i_switch)(BASE* arr, igraph_int_t e1, igraph_int_t e2); /** * \ingroup heap @@ -53,7 +52,7 @@ static void FUNCTION(igraph_heap, i_switch)(BASE* arr, igraph_integer_t e1, igra * linear operation. */ -igraph_error_t FUNCTION(igraph_heap, init)(TYPE(igraph_heap)* h, igraph_integer_t capacity) { +igraph_error_t FUNCTION(igraph_heap, init)(TYPE(igraph_heap)* h, igraph_int_t capacity) { IGRAPH_ASSERT(capacity >= 0); if (capacity == 0 ) { capacity = 1; @@ -62,7 +61,6 @@ igraph_error_t FUNCTION(igraph_heap, init)(TYPE(igraph_heap)* h, igraph_integer_ IGRAPH_CHECK_OOM(h->stor_begin, "Cannot initialize heap."); h->stor_end = h->stor_begin + capacity; h->end = h->stor_begin; - h->destroy = true; return IGRAPH_SUCCESS; } @@ -83,12 +81,11 @@ igraph_error_t FUNCTION(igraph_heap, init)(TYPE(igraph_heap)* h, igraph_integer_ * Time complexity: O(n), the number of elements in the heap. */ -igraph_error_t FUNCTION(igraph_heap, init_array)(TYPE(igraph_heap) *h, const BASE *data, igraph_integer_t len) { +igraph_error_t FUNCTION(igraph_heap, init_array)(TYPE(igraph_heap) *h, const BASE *data, igraph_int_t len) { h->stor_begin = IGRAPH_CALLOC(len, BASE); IGRAPH_CHECK_OOM(h->stor_begin, "Cannot initialize heap from array."); h->stor_end = h->stor_begin + len; h->end = h->stor_end; - h->destroy = true; memcpy(h->stor_begin, data, (size_t) len * sizeof(BASE)); @@ -108,10 +105,8 @@ igraph_error_t FUNCTION(igraph_heap, init_array)(TYPE(igraph_heap) *h, const BAS */ void FUNCTION(igraph_heap, destroy)(TYPE(igraph_heap)* h) { - if (h->destroy) { - if (h->stor_begin != NULL) { - IGRAPH_FREE(h->stor_begin); /* sets to NULL */ - } + if (h->stor_begin != NULL) { + IGRAPH_FREE(h->stor_begin); /* sets to NULL */ } } @@ -174,8 +169,8 @@ igraph_error_t FUNCTION(igraph_heap, push)(TYPE(igraph_heap)* h, BASE elem) { /* full, allocate more storage */ if (h->stor_end == h->end) { - igraph_integer_t old_size = FUNCTION(igraph_heap, size)(h); - igraph_integer_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; + igraph_int_t old_size = FUNCTION(igraph_heap, size)(h); + igraph_int_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; if (old_size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot push to heap, already at maximum size.", IGRAPH_EOVERFLOW); } @@ -259,7 +254,7 @@ BASE FUNCTION(igraph_heap, delete_top)(TYPE(igraph_heap)* h) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_heap, size)(const TYPE(igraph_heap)* h) { +igraph_int_t FUNCTION(igraph_heap, size)(const TYPE(igraph_heap)* h) { IGRAPH_ASSERT(h != NULL); IGRAPH_ASSERT(h->stor_begin != NULL); return h->end - h->stor_begin; @@ -282,8 +277,8 @@ igraph_integer_t FUNCTION(igraph_heap, size)(const TYPE(igraph_heap)* h) { * number of elements. O(1) otherwise. */ -igraph_error_t FUNCTION(igraph_heap, reserve)(TYPE(igraph_heap)* h, igraph_integer_t capacity) { - igraph_integer_t actual_size = FUNCTION(igraph_heap, size)(h); +igraph_error_t FUNCTION(igraph_heap, reserve)(TYPE(igraph_heap)* h, igraph_int_t capacity) { + igraph_int_t actual_size = FUNCTION(igraph_heap, size)(h); BASE *tmp; IGRAPH_ASSERT(h != NULL); IGRAPH_ASSERT(h->stor_begin != NULL); @@ -309,7 +304,7 @@ igraph_error_t FUNCTION(igraph_heap, reserve)(TYPE(igraph_heap)* h, igraph_integ */ void FUNCTION(igraph_heap, i_build)(BASE* arr, - igraph_integer_t size, igraph_integer_t head) { + igraph_int_t size, igraph_int_t head) { if (RIGHTCHILD(head) < size) { /* both subtrees */ @@ -331,7 +326,7 @@ void FUNCTION(igraph_heap, i_build)(BASE* arr, * called directly. */ -void FUNCTION(igraph_heap, i_shift_up)(BASE* arr, igraph_integer_t size, igraph_integer_t elem) { +void FUNCTION(igraph_heap, i_shift_up)(BASE* arr, igraph_int_t size, igraph_int_t elem) { if (elem == 0 || arr[elem] HEAPLESS arr[PARENT(elem)]) { /* at the top */ @@ -347,7 +342,7 @@ void FUNCTION(igraph_heap, i_shift_up)(BASE* arr, igraph_integer_t size, igraph_ * called directly. */ -void FUNCTION(igraph_heap, i_sink)(BASE* arr, igraph_integer_t size, igraph_integer_t head) { +void FUNCTION(igraph_heap, i_sink)(BASE* arr, igraph_int_t size, igraph_int_t head) { if (LEFTCHILD(head) >= size) { /* no subtrees */ @@ -373,7 +368,7 @@ void FUNCTION(igraph_heap, i_sink)(BASE* arr, igraph_integer_t size, igraph_inte * called directly. */ -void FUNCTION(igraph_heap, i_switch)(BASE* arr, igraph_integer_t e1, igraph_integer_t e2) { +void FUNCTION(igraph_heap, i_switch)(BASE* arr, igraph_int_t e1, igraph_int_t e2) { if (e1 != e2) { BASE tmp = arr[e1]; arr[e1] = arr[e2]; diff --git a/src/vendor/cigraph/src/core/indheap.c b/src/vendor/cigraph/src/core/indheap.c index b4ee00e4b54..662041a4d14 100644 --- a/src/vendor/cigraph/src/core/indheap.c +++ b/src/vendor/cigraph/src/core/indheap.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -37,10 +36,10 @@ #define LEFTCHILD(x) (((x)+1)*2-1) #define RIGHTCHILD(x) (((x)+1)*2) -static void igraph_indheap_i_build(igraph_indheap_t* h, igraph_integer_t head); -static void igraph_indheap_i_shift_up(igraph_indheap_t* h, igraph_integer_t elem); -static void igraph_indheap_i_sink(igraph_indheap_t* h, igraph_integer_t head); -static void igraph_indheap_i_switch(igraph_indheap_t* h, igraph_integer_t e1, igraph_integer_t e2); +static void igraph_indheap_i_build(igraph_indheap_t* h, igraph_int_t head); +static void igraph_indheap_i_shift_up(igraph_indheap_t* h, igraph_int_t elem); +static void igraph_indheap_i_sink(igraph_indheap_t* h, igraph_int_t head); +static void igraph_indheap_i_switch(igraph_indheap_t* h, igraph_int_t e1, igraph_int_t e2); /** * \ingroup indheap @@ -50,7 +49,7 @@ static void igraph_indheap_i_switch(igraph_indheap_t* h, igraph_integer_t e1, ig * - IGRAPH_ENOMEM: out of memory */ -igraph_error_t igraph_indheap_init(igraph_indheap_t* h, igraph_integer_t alloc_size) { +igraph_error_t igraph_indheap_init(igraph_indheap_t* h, igraph_int_t alloc_size) { IGRAPH_ASSERT(alloc_size >= 0); if (alloc_size == 0 ) { alloc_size = 1; @@ -60,7 +59,7 @@ igraph_error_t igraph_indheap_init(igraph_indheap_t* h, igraph_integer_t alloc_s h->index_begin = NULL; IGRAPH_ERROR("indheap init failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } - h->index_begin = IGRAPH_CALLOC(alloc_size, igraph_integer_t); + h->index_begin = IGRAPH_CALLOC(alloc_size, igraph_int_t); if (! h->index_begin) { IGRAPH_FREE(h->stor_begin); h->stor_begin = NULL; @@ -69,7 +68,6 @@ igraph_error_t igraph_indheap_init(igraph_indheap_t* h, igraph_integer_t alloc_s h->stor_end = h->stor_begin + alloc_size; h->end = h->stor_begin; - h->destroy = true; return IGRAPH_SUCCESS; } @@ -86,9 +84,9 @@ void igraph_indheap_clear(igraph_indheap_t *h) { * - IGRAPH_ENOMEM: out of memory */ -igraph_error_t igraph_indheap_init_array(igraph_indheap_t *h, const igraph_real_t *data, igraph_integer_t len) { - igraph_integer_t i; - igraph_integer_t alloc_size; +igraph_error_t igraph_indheap_init_array(igraph_indheap_t *h, const igraph_real_t *data, igraph_int_t len) { + igraph_int_t i; + igraph_int_t alloc_size; IGRAPH_ASSERT(len >= 0); alloc_size = (len <= 0) ? 1 : len; @@ -98,7 +96,7 @@ igraph_error_t igraph_indheap_init_array(igraph_indheap_t *h, const igraph_real_ h->index_begin = 0; IGRAPH_ERROR("indheap init from array failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } - h->index_begin = IGRAPH_CALLOC(alloc_size, igraph_integer_t); + h->index_begin = IGRAPH_CALLOC(alloc_size, igraph_int_t); if (! h->index_begin) { IGRAPH_FREE(h->stor_begin); h->stor_begin = 0; @@ -106,7 +104,6 @@ igraph_error_t igraph_indheap_init_array(igraph_indheap_t *h, const igraph_real_ } h->stor_end = h->stor_begin + alloc_size; h->end = h->stor_begin + len; - h->destroy = true; memcpy(h->stor_begin, data, (size_t) len * sizeof(igraph_real_t)); for (i = 0; i < len; i++) { @@ -124,17 +121,13 @@ igraph_error_t igraph_indheap_init_array(igraph_indheap_t *h, const igraph_real_ */ void igraph_indheap_destroy(igraph_indheap_t* h) { - IGRAPH_ASSERT(h != 0); - if (h->destroy) { - if (h->stor_begin != 0) { - IGRAPH_FREE(h->stor_begin); - h->stor_begin = 0; - } - if (h->index_begin != 0) { - IGRAPH_FREE(h->index_begin); - h->index_begin = 0; - } - } + IGRAPH_ASSERT(h != NULL); + if (h->stor_begin != NULL) { + IGRAPH_FREE(h->stor_begin); + } + if (h->index_begin != NULL) { + IGRAPH_FREE(h->index_begin); + } } /** @@ -143,8 +136,8 @@ void igraph_indheap_destroy(igraph_indheap_t* h) { */ igraph_bool_t igraph_indheap_empty(const igraph_indheap_t *h) { - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); return h->stor_begin == h->end; } @@ -154,13 +147,13 @@ igraph_bool_t igraph_indheap_empty(const igraph_indheap_t *h) { */ igraph_error_t igraph_indheap_push(igraph_indheap_t* h, igraph_real_t elem) { - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); /* full, allocate more storage */ if (h->stor_end == h->end) { - igraph_integer_t old_size = igraph_indheap_size(h); - igraph_integer_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; + igraph_int_t old_size = igraph_indheap_size(h); + igraph_int_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; if (old_size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot push to indheap, already at maximum size.", IGRAPH_EOVERFLOW); } @@ -185,14 +178,14 @@ igraph_error_t igraph_indheap_push(igraph_indheap_t* h, igraph_real_t elem) { * \brief Adds an element to an indexed heap with a given index. */ -igraph_error_t igraph_indheap_push_with_index(igraph_indheap_t* h, igraph_integer_t idx, igraph_real_t elem) { - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); +igraph_error_t igraph_indheap_push_with_index(igraph_indheap_t* h, igraph_int_t idx, igraph_real_t elem) { + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); /* full, allocate more storage */ if (h->stor_end == h->end) { - igraph_integer_t old_size = igraph_indheap_size(h); - igraph_integer_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; + igraph_int_t old_size = igraph_indheap_size(h); + igraph_int_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; if (old_size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot push to indheap, already at maximum size.", IGRAPH_EOVERFLOW); } @@ -217,11 +210,11 @@ igraph_error_t igraph_indheap_push_with_index(igraph_indheap_t* h, igraph_intege * \brief Modifies an element in an indexed heap. */ -void igraph_indheap_modify(igraph_indheap_t* h, igraph_integer_t idx, igraph_real_t elem) { - igraph_integer_t i, n; +void igraph_indheap_modify(igraph_indheap_t* h, igraph_int_t idx, igraph_real_t elem) { + igraph_int_t i, n; - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); n = igraph_indheap_size(h); for (i = 0; i < n; i++) @@ -275,9 +268,9 @@ igraph_real_t igraph_indheap_delete_max(igraph_indheap_t* h) { * \brief Gives the number of elements in an indexed heap. */ -igraph_integer_t igraph_indheap_size(const igraph_indheap_t* h) { - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); +igraph_int_t igraph_indheap_size(const igraph_indheap_t* h) { + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); return h->end - h->stor_begin; } @@ -289,12 +282,12 @@ igraph_integer_t igraph_indheap_size(const igraph_indheap_t* h) { * - IGRAPH_ENOMEM: out of memory */ -igraph_error_t igraph_indheap_reserve(igraph_indheap_t* h, igraph_integer_t size) { - igraph_integer_t actual_size = igraph_indheap_size(h); +igraph_error_t igraph_indheap_reserve(igraph_indheap_t* h, igraph_int_t size) { + igraph_int_t actual_size = igraph_indheap_size(h); igraph_real_t *tmp1; - igraph_integer_t *tmp2; - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); + igraph_int_t *tmp2; + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); if (size <= actual_size) { return IGRAPH_SUCCESS; @@ -305,13 +298,13 @@ igraph_error_t igraph_indheap_reserve(igraph_indheap_t* h, igraph_integer_t size IGRAPH_ERROR("indheap reserve failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } IGRAPH_FINALLY(igraph_free, tmp1); - tmp2 = IGRAPH_CALLOC(size, igraph_integer_t); + tmp2 = IGRAPH_CALLOC(size, igraph_int_t); if (tmp2 == 0) { IGRAPH_ERROR("indheap reserve failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } IGRAPH_FINALLY(igraph_free, tmp2); memcpy(tmp1, h->stor_begin, (size_t) actual_size * sizeof(igraph_real_t)); - memcpy(tmp2, h->index_begin, (size_t) actual_size * sizeof(igraph_integer_t)); + memcpy(tmp2, h->index_begin, (size_t) actual_size * sizeof(igraph_int_t)); IGRAPH_FREE(h->stor_begin); IGRAPH_FREE(h->index_begin); @@ -329,9 +322,9 @@ igraph_error_t igraph_indheap_reserve(igraph_indheap_t* h, igraph_integer_t size * \brief Returns the index of the largest element in an indexed heap. */ -igraph_integer_t igraph_indheap_max_index(const igraph_indheap_t *h) { - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); +igraph_int_t igraph_indheap_max_index(const igraph_indheap_t *h) { + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); return h->index_begin[0]; } @@ -341,9 +334,9 @@ igraph_integer_t igraph_indheap_max_index(const igraph_indheap_t *h) { * directly. */ -static void igraph_indheap_i_build(igraph_indheap_t* h, igraph_integer_t head) { +static void igraph_indheap_i_build(igraph_indheap_t* h, igraph_int_t head) { - igraph_integer_t size = igraph_indheap_size(h); + igraph_int_t size = igraph_indheap_size(h); if (RIGHTCHILD(head) < size) { /* both subtrees */ igraph_indheap_i_build(h, LEFTCHILD(head) ); @@ -364,7 +357,7 @@ static void igraph_indheap_i_build(igraph_indheap_t* h, igraph_integer_t head) { * directly. */ -static void igraph_indheap_i_shift_up(igraph_indheap_t *h, igraph_integer_t elem) { +static void igraph_indheap_i_shift_up(igraph_indheap_t *h, igraph_int_t elem) { if (elem == 0 || h->stor_begin[elem] < h->stor_begin[PARENT(elem)]) { /* at the top */ @@ -380,9 +373,9 @@ static void igraph_indheap_i_shift_up(igraph_indheap_t *h, igraph_integer_t elem * directly. */ -static void igraph_indheap_i_sink(igraph_indheap_t* h, igraph_integer_t head) { +static void igraph_indheap_i_sink(igraph_indheap_t* h, igraph_int_t head) { - igraph_integer_t size = igraph_indheap_size(h); + igraph_int_t size = igraph_indheap_size(h); if (LEFTCHILD(head) >= size) { /* no subtrees */ } else if (RIGHTCHILD(head) == size || @@ -407,7 +400,7 @@ static void igraph_indheap_i_sink(igraph_indheap_t* h, igraph_integer_t head) { * directly. */ -static void igraph_indheap_i_switch(igraph_indheap_t* h, igraph_integer_t e1, igraph_integer_t e2) { +static void igraph_indheap_i_switch(igraph_indheap_t* h, igraph_int_t e1, igraph_int_t e2) { if (e1 != e2) { igraph_real_t tmp = h->stor_begin[e1]; h->stor_begin[e1] = h->stor_begin[e2]; @@ -425,10 +418,10 @@ static void igraph_indheap_i_switch(igraph_indheap_t* h, igraph_integer_t e1, ig /* Doubly indexed heap */ /* -------------------------------------------------- */ -/* static void igraph_d_indheap_i_build(igraph_d_indheap_t* h, igraph_integer_t head); */ /* Unused function */ -static void igraph_d_indheap_i_shift_up(igraph_d_indheap_t* h, igraph_integer_t elem); -static void igraph_d_indheap_i_sink(igraph_d_indheap_t* h, igraph_integer_t head); -static void igraph_d_indheap_i_switch(igraph_d_indheap_t* h, igraph_integer_t e1, igraph_integer_t e2); +/* static void igraph_d_indheap_i_build(igraph_d_indheap_t* h, igraph_int_t head); */ /* Unused function */ +static void igraph_d_indheap_i_shift_up(igraph_d_indheap_t* h, igraph_int_t elem); +static void igraph_d_indheap_i_sink(igraph_d_indheap_t* h, igraph_int_t head); +static void igraph_d_indheap_i_switch(igraph_d_indheap_t* h, igraph_int_t e1, igraph_int_t e2); /** * \ingroup doubleindheap @@ -438,33 +431,32 @@ static void igraph_d_indheap_i_switch(igraph_d_indheap_t* h, igraph_integer_t e1 * - IGRAPH_ENOMEM: out of memory */ -igraph_error_t igraph_d_indheap_init(igraph_d_indheap_t* h, igraph_integer_t alloc_size) { +igraph_error_t igraph_d_indheap_init(igraph_d_indheap_t* h, igraph_int_t alloc_size) { IGRAPH_ASSERT(alloc_size >= 0); if (alloc_size == 0 ) { alloc_size = 1; } h->stor_begin = IGRAPH_CALLOC(alloc_size, igraph_real_t); - if (h->stor_begin == 0) { - h->index_begin = 0; - h->index2_begin = 0; + if (h->stor_begin == NULL) { + h->index_begin = NULL; + h->index2_begin = NULL; IGRAPH_ERROR("d_indheap init failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } h->stor_end = h->stor_begin + alloc_size; h->end = h->stor_begin; - h->destroy = true; - h->index_begin = IGRAPH_CALLOC(alloc_size, igraph_integer_t); - if (h->index_begin == 0) { + h->index_begin = IGRAPH_CALLOC(alloc_size, igraph_int_t); + if (h->index_begin == NULL) { IGRAPH_FREE(h->stor_begin); - h->stor_begin = 0; - h->index2_begin = 0; + h->stor_begin = NULL; + h->index2_begin = NULL; IGRAPH_ERROR("d_indheap init failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } - h->index2_begin = IGRAPH_CALLOC(alloc_size, igraph_integer_t); - if (h->index2_begin == 0) { + h->index2_begin = IGRAPH_CALLOC(alloc_size, igraph_int_t); + if (h->index2_begin == NULL) { IGRAPH_FREE(h->stor_begin); IGRAPH_FREE(h->index_begin); - h->stor_begin = 0; - h->index_begin = 0; + h->stor_begin = NULL; + h->index_begin = NULL; IGRAPH_ERROR("d_indheap init failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } @@ -477,20 +469,15 @@ igraph_error_t igraph_d_indheap_init(igraph_d_indheap_t* h, igraph_integer_t all */ void igraph_d_indheap_destroy(igraph_d_indheap_t* h) { - IGRAPH_ASSERT(h != 0); - if (h->destroy) { - if (h->stor_begin != 0) { - IGRAPH_FREE(h->stor_begin); - h->stor_begin = 0; - } - if (h->index_begin != 0) { - IGRAPH_FREE(h->index_begin); - h->index_begin = 0; - } - if (h->index2_begin != 0) { - IGRAPH_FREE(h->index2_begin); - h->index2_begin = 0; - } + IGRAPH_ASSERT(h != NULL); + if (h->stor_begin != NULL) { + IGRAPH_FREE(h->stor_begin); + } + if (h->index_begin != NULL) { + IGRAPH_FREE(h->index_begin); + } + if (h->index2_begin != NULL) { + IGRAPH_FREE(h->index2_begin); } } @@ -500,8 +487,8 @@ void igraph_d_indheap_destroy(igraph_d_indheap_t* h) { */ igraph_bool_t igraph_d_indheap_empty(const igraph_d_indheap_t *h) { - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); return h->stor_begin == h->end; } @@ -511,14 +498,14 @@ igraph_bool_t igraph_d_indheap_empty(const igraph_d_indheap_t *h) { */ igraph_error_t igraph_d_indheap_push(igraph_d_indheap_t* h, igraph_real_t elem, - igraph_integer_t idx, igraph_integer_t idx2) { - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); + igraph_int_t idx, igraph_int_t idx2) { + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); /* full, allocate more storage */ if (h->stor_end == h->end) { - igraph_integer_t old_size = igraph_d_indheap_size(h); - igraph_integer_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; + igraph_int_t old_size = igraph_d_indheap_size(h); + igraph_int_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; if (old_size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot push to indheap, already at maximum size.", IGRAPH_EOVERFLOW); } @@ -576,9 +563,9 @@ igraph_real_t igraph_d_indheap_delete_max(igraph_d_indheap_t* h) { * \brief Gives the number of elements in the heap. */ -igraph_integer_t igraph_d_indheap_size(const igraph_d_indheap_t* h) { - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); +igraph_int_t igraph_d_indheap_size(const igraph_d_indheap_t* h) { + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); return h->end - h->stor_begin; } @@ -590,12 +577,12 @@ igraph_integer_t igraph_d_indheap_size(const igraph_d_indheap_t* h) { * - IGRAPH_ENOMEM: out of memory */ -igraph_error_t igraph_d_indheap_reserve(igraph_d_indheap_t* h, igraph_integer_t size) { - igraph_integer_t actual_size = igraph_d_indheap_size(h); +igraph_error_t igraph_d_indheap_reserve(igraph_d_indheap_t* h, igraph_int_t size) { + igraph_int_t actual_size = igraph_d_indheap_size(h); igraph_real_t *tmp1; - igraph_integer_t *tmp2, *tmp3; - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); + igraph_int_t *tmp2, *tmp3; + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); if (size <= actual_size) { return IGRAPH_SUCCESS; @@ -606,20 +593,20 @@ igraph_error_t igraph_d_indheap_reserve(igraph_d_indheap_t* h, igraph_integer_t IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } IGRAPH_FINALLY(igraph_free, tmp1); - tmp2 = IGRAPH_CALLOC(size, igraph_integer_t); + tmp2 = IGRAPH_CALLOC(size, igraph_int_t); if (tmp2 == 0) { IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } IGRAPH_FINALLY(igraph_free, tmp2); - tmp3 = IGRAPH_CALLOC(size, igraph_integer_t); + tmp3 = IGRAPH_CALLOC(size, igraph_int_t); if (tmp3 == 0) { IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } IGRAPH_FINALLY(igraph_free, tmp3); memcpy(tmp1, h->stor_begin, (size_t) actual_size * sizeof(igraph_real_t)); - memcpy(tmp2, h->index_begin, (size_t) actual_size * sizeof(igraph_integer_t)); - memcpy(tmp3, h->index2_begin, (size_t) actual_size * sizeof(igraph_integer_t)); + memcpy(tmp2, h->index_begin, (size_t) actual_size * sizeof(igraph_int_t)); + memcpy(tmp3, h->index2_begin, (size_t) actual_size * sizeof(igraph_int_t)); IGRAPH_FREE(h->stor_begin); IGRAPH_FREE(h->index_begin); IGRAPH_FREE(h->index2_begin); @@ -639,9 +626,9 @@ igraph_error_t igraph_d_indheap_reserve(igraph_d_indheap_t* h, igraph_integer_t * \brief Gives the indices of the maximal element in the heap. */ -void igraph_d_indheap_max_index(igraph_d_indheap_t *h, igraph_integer_t *idx, igraph_integer_t *idx2) { - IGRAPH_ASSERT(h != 0); - IGRAPH_ASSERT(h->stor_begin != 0); +void igraph_d_indheap_max_index(igraph_d_indheap_t *h, igraph_int_t *idx, igraph_int_t *idx2) { + IGRAPH_ASSERT(h != NULL); + IGRAPH_ASSERT(h->stor_begin != NULL); (*idx) = h->index_begin[0]; (*idx2) = h->index2_begin[0]; } @@ -653,9 +640,9 @@ void igraph_d_indheap_max_index(igraph_d_indheap_t *h, igraph_integer_t *idx, ig /* Unused function, temporarily disabled */ #if 0 -static void igraph_d_indheap_i_build(igraph_d_indheap_t* h, igraph_integer_t head) { +static void igraph_d_indheap_i_build(igraph_d_indheap_t* h, igraph_int_t head) { - igraph_integer_t size = igraph_d_indheap_size(h); + igraph_int_t size = igraph_d_indheap_size(h); if (RIGHTCHILD(head) < size) { /* both subtrees */ igraph_d_indheap_i_build(h, LEFTCHILD(head) ); @@ -676,7 +663,7 @@ static void igraph_d_indheap_i_build(igraph_d_indheap_t* h, igraph_integer_t hea * \brief Moves an element up in the heap, don't call it directly. */ -static void igraph_d_indheap_i_shift_up(igraph_d_indheap_t *h, igraph_integer_t elem) { +static void igraph_d_indheap_i_shift_up(igraph_d_indheap_t *h, igraph_int_t elem) { if (elem == 0 || h->stor_begin[elem] < h->stor_begin[PARENT(elem)]) { /* at the top */ @@ -691,9 +678,9 @@ static void igraph_d_indheap_i_shift_up(igraph_d_indheap_t *h, igraph_integer_t * \brief Moves an element down in the heap, don't call it directly. */ -static void igraph_d_indheap_i_sink(igraph_d_indheap_t* h, igraph_integer_t head) { +static void igraph_d_indheap_i_sink(igraph_d_indheap_t* h, igraph_int_t head) { - igraph_integer_t size = igraph_d_indheap_size(h); + igraph_int_t size = igraph_d_indheap_size(h); if (LEFTCHILD(head) >= size) { /* no subtrees */ } else if (RIGHTCHILD(head) == size || @@ -717,9 +704,9 @@ static void igraph_d_indheap_i_sink(igraph_d_indheap_t* h, igraph_integer_t head * \brief Switches two elements in the heap, don't call it directly. */ -static void igraph_d_indheap_i_switch(igraph_d_indheap_t* h, igraph_integer_t e1, igraph_integer_t e2) { +static void igraph_d_indheap_i_switch(igraph_d_indheap_t* h, igraph_int_t e1, igraph_int_t e2) { if (e1 != e2) { - igraph_integer_t tmpi; + igraph_int_t tmpi; igraph_real_t tmp = h->stor_begin[e1]; h->stor_begin[e1] = h->stor_begin[e2]; h->stor_begin[e2] = tmp; @@ -753,9 +740,9 @@ static void igraph_d_indheap_i_switch(igraph_d_indheap_t* h, igraph_integer_t e1 normal heap does this in O(n) time.... */ static void igraph_i_2wheap_switch(igraph_2wheap_t *h, - igraph_integer_t e1, igraph_integer_t e2) { + igraph_int_t e1, igraph_int_t e2) { if (e1 != e2) { - igraph_integer_t tmp1, tmp2; + igraph_int_t tmp1, tmp2; igraph_real_t tmp3 = VECTOR(h->data)[e1]; VECTOR(h->data)[e1] = VECTOR(h->data)[e2]; VECTOR(h->data)[e2] = tmp3; @@ -772,7 +759,7 @@ static void igraph_i_2wheap_switch(igraph_2wheap_t *h, } static void igraph_i_2wheap_shift_up(igraph_2wheap_t *h, - igraph_integer_t elem) { + igraph_int_t elem) { if (elem == 0 || VECTOR(h->data)[elem] < VECTOR(h->data)[PARENT(elem)]) { /* at the top */ } else { @@ -782,8 +769,8 @@ static void igraph_i_2wheap_shift_up(igraph_2wheap_t *h, } static void igraph_i_2wheap_sink(igraph_2wheap_t *h, - igraph_integer_t head) { - igraph_integer_t size = igraph_2wheap_size(h); + igraph_int_t head) { + igraph_int_t size = igraph_2wheap_size(h); if (LEFTCHILD(head) >= size) { /* no subtrees */ } else if (RIGHTCHILD(head) == size || @@ -810,7 +797,7 @@ static void igraph_i_2wheap_sink(igraph_2wheap_t *h, * Initializes a new two-way heap. The max_size parameter defines the maximum * number of items that the heap can hold. */ -igraph_error_t igraph_2wheap_init(igraph_2wheap_t *h, igraph_integer_t max_size) { +igraph_error_t igraph_2wheap_init(igraph_2wheap_t *h, igraph_int_t max_size) { h->max_size = max_size; /* We start with the biggest */ IGRAPH_VECTOR_INT_INIT_FINALLY(&h->index2, max_size); @@ -854,11 +841,11 @@ igraph_bool_t igraph_2wheap_empty(const igraph_2wheap_t *h) { * the same index. */ igraph_error_t igraph_2wheap_push_with_index(igraph_2wheap_t *h, - igraph_integer_t idx, igraph_real_t elem) { + igraph_int_t idx, igraph_real_t elem) { /* printf("-> %.2g [%li]\n", elem, idx); */ - igraph_integer_t size = igraph_vector_size(&h->data); + igraph_int_t size = igraph_vector_size(&h->data); if (size > IGRAPH_INTEGER_MAX - 2) { /* to allow size+2 below */ @@ -877,7 +864,7 @@ igraph_error_t igraph_2wheap_push_with_index(igraph_2wheap_t *h, /** * Returns the current number of elements in the two-way heap. */ -igraph_integer_t igraph_2wheap_size(const igraph_2wheap_t *h) { +igraph_int_t igraph_2wheap_size(const igraph_2wheap_t *h) { return igraph_vector_size(&h->data); } @@ -886,7 +873,7 @@ igraph_integer_t igraph_2wheap_size(const igraph_2wheap_t *h) { * is also one larger than the maximum allowed index that can be passed to * \c igraph_2wheap_push_with_index . */ -igraph_integer_t igraph_2wheap_max_size(const igraph_2wheap_t *h) { +igraph_int_t igraph_2wheap_max_size(const igraph_2wheap_t *h) { return h->max_size; } @@ -901,7 +888,7 @@ igraph_real_t igraph_2wheap_max(const igraph_2wheap_t *h) { * Returns the index that was associated to the largest element in the heap * when it was pushed to the heap. */ -igraph_integer_t igraph_2wheap_max_index(const igraph_2wheap_t *h) { +igraph_int_t igraph_2wheap_max_index(const igraph_2wheap_t *h) { return VECTOR(h->index)[0]; } @@ -909,23 +896,23 @@ igraph_integer_t igraph_2wheap_max_index(const igraph_2wheap_t *h) { * Returns whether the heap contains an element with the given index, even if * it was deactivated earlier. */ -igraph_bool_t igraph_2wheap_has_elem(const igraph_2wheap_t *h, igraph_integer_t idx) { - return VECTOR(h->index2)[idx] != 0; +igraph_bool_t igraph_2wheap_has_elem(const igraph_2wheap_t *h, igraph_int_t idx) { + return (VECTOR(h->index2)[idx] != 0); } /** * Returns whether the heap contains an element with the given index \em and it * has not been deactivated yet. */ -igraph_bool_t igraph_2wheap_has_active(const igraph_2wheap_t *h, igraph_integer_t idx) { +igraph_bool_t igraph_2wheap_has_active(const igraph_2wheap_t *h, igraph_int_t idx) { return VECTOR(h->index2)[idx] > 1; } /** * Returns the item at the given index in the two-way heap. */ -igraph_real_t igraph_2wheap_get(const igraph_2wheap_t *h, igraph_integer_t idx) { - igraph_integer_t i = VECTOR(h->index2)[idx] - 2; +igraph_real_t igraph_2wheap_get(const igraph_2wheap_t *h, igraph_int_t idx) { + igraph_int_t i = VECTOR(h->index2)[idx] - 2; return VECTOR(h->data)[i]; } @@ -938,7 +925,7 @@ igraph_real_t igraph_2wheap_get(const igraph_2wheap_t *h, igraph_integer_t idx) igraph_real_t igraph_2wheap_delete_max(igraph_2wheap_t *h) { igraph_real_t tmp = VECTOR(h->data)[0]; - igraph_integer_t tmpidx = VECTOR(h->index)[0]; + igraph_int_t tmpidx = VECTOR(h->index)[0]; igraph_i_2wheap_switch(h, 0, igraph_2wheap_size(h) - 1); igraph_vector_pop_back(&h->data); igraph_vector_int_pop_back(&h->index); @@ -959,7 +946,7 @@ igraph_real_t igraph_2wheap_delete_max(igraph_2wheap_t *h) { igraph_real_t igraph_2wheap_deactivate_max(igraph_2wheap_t *h) { igraph_real_t tmp = VECTOR(h->data)[0]; - igraph_integer_t tmpidx = VECTOR(h->index)[0]; + igraph_int_t tmpidx = VECTOR(h->index)[0]; igraph_i_2wheap_switch(h, 0, igraph_2wheap_size(h) - 1); igraph_vector_pop_back(&h->data); igraph_vector_int_pop_back(&h->index); @@ -976,10 +963,10 @@ igraph_real_t igraph_2wheap_deactivate_max(igraph_2wheap_t *h) { * This function does \em not change the indices associated to the elements * that remain in the heap. */ -igraph_real_t igraph_2wheap_delete_max_index(igraph_2wheap_t *h, igraph_integer_t *idx) { +igraph_real_t igraph_2wheap_delete_max_index(igraph_2wheap_t *h, igraph_int_t *idx) { igraph_real_t tmp = VECTOR(h->data)[0]; - igraph_integer_t tmpidx = VECTOR(h->index)[0]; + igraph_int_t tmpidx = VECTOR(h->index)[0]; igraph_i_2wheap_switch(h, 0, igraph_2wheap_size(h) - 1); igraph_vector_pop_back(&h->data); igraph_vector_int_pop_back(&h->index); @@ -995,9 +982,9 @@ igraph_real_t igraph_2wheap_delete_max_index(igraph_2wheap_t *h, igraph_integer_ /** * Modifies the value associated to the given index in the two-way heap. */ -void igraph_2wheap_modify(igraph_2wheap_t *h, igraph_integer_t idx, igraph_real_t elem) { +void igraph_2wheap_modify(igraph_2wheap_t *h, igraph_int_t idx, igraph_real_t elem) { - igraph_integer_t pos = VECTOR(h->index2)[idx] - 2; + igraph_int_t pos = VECTOR(h->index2)[idx] - 2; /* printf("-- %.2g -> %.2g\n", VECTOR(h->data)[pos], elem); */ @@ -1010,8 +997,8 @@ void igraph_2wheap_modify(igraph_2wheap_t *h, igraph_integer_t idx, igraph_real_ * Checks that the heap is in a consistent state */ igraph_error_t igraph_2wheap_check(const igraph_2wheap_t *h) { - igraph_integer_t size = igraph_2wheap_size(h); - igraph_integer_t i; + igraph_int_t size = igraph_2wheap_size(h); + igraph_int_t i; igraph_bool_t error = false; /* Check the heap property */ diff --git a/src/vendor/cigraph/src/core/indheap.h b/src/vendor/cigraph/src/core/indheap.h index 93194cbf7c7..a718b45e9bc 100644 --- a/src/vendor/cigraph/src/core/indheap.h +++ b/src/vendor/cigraph/src/core/indheap.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2009-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -27,7 +26,7 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Indexed heap */ @@ -42,25 +41,24 @@ typedef struct s_indheap { igraph_real_t* stor_begin; igraph_real_t* stor_end; igraph_real_t* end; - igraph_bool_t destroy; - igraph_integer_t* index_begin; + igraph_int_t* index_begin; } igraph_indheap_t; -#define IGRAPH_INDHEAP_NULL { 0,0,0,0,0 } +#define IGRAPH_INDHEAP_NULL { 0,0,0,0 } -igraph_error_t igraph_indheap_init(igraph_indheap_t* h, igraph_integer_t size); -igraph_error_t igraph_indheap_init_array(igraph_indheap_t *t, const igraph_real_t *data, igraph_integer_t len); +igraph_error_t igraph_indheap_init(igraph_indheap_t* h, igraph_int_t size); +igraph_error_t igraph_indheap_init_array(igraph_indheap_t *t, const igraph_real_t *data, igraph_int_t len); void igraph_indheap_destroy(igraph_indheap_t* h); void igraph_indheap_clear(igraph_indheap_t *h); IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_indheap_empty(const igraph_indheap_t* h); igraph_error_t igraph_indheap_push(igraph_indheap_t* h, igraph_real_t elem); -igraph_error_t igraph_indheap_push_with_index(igraph_indheap_t* h, igraph_integer_t idx, igraph_real_t elem); -void igraph_indheap_modify(igraph_indheap_t* h, igraph_integer_t idx, igraph_real_t elem); +igraph_error_t igraph_indheap_push_with_index(igraph_indheap_t* h, igraph_int_t idx, igraph_real_t elem); +void igraph_indheap_modify(igraph_indheap_t* h, igraph_int_t idx, igraph_real_t elem); IGRAPH_FUNCATTR_PURE igraph_real_t igraph_indheap_max(const igraph_indheap_t* h); igraph_real_t igraph_indheap_delete_max(igraph_indheap_t* h); -IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_indheap_size(const igraph_indheap_t *h); -igraph_error_t igraph_indheap_reserve(igraph_indheap_t* h, igraph_integer_t size); -IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_indheap_max_index(const igraph_indheap_t *h); +IGRAPH_FUNCATTR_PURE igraph_int_t igraph_indheap_size(const igraph_indheap_t *h); +igraph_error_t igraph_indheap_reserve(igraph_indheap_t* h, igraph_int_t size); +IGRAPH_FUNCATTR_PURE igraph_int_t igraph_indheap_max_index(const igraph_indheap_t *h); /* -------------------------------------------------- */ @@ -81,24 +79,23 @@ typedef struct s_indheap_d { igraph_real_t* stor_begin; igraph_real_t* stor_end; igraph_real_t* end; - igraph_bool_t destroy; - igraph_integer_t* index_begin; - igraph_integer_t* index2_begin; + igraph_int_t* index_begin; + igraph_int_t* index2_begin; } igraph_d_indheap_t; -#define IGRAPH_D_INDHEAP_NULL { 0,0,0,0,0,0 } +#define IGRAPH_D_INDHEAP_NULL { 0,0,0,0,0 } -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_d_indheap_init(igraph_d_indheap_t *h, igraph_integer_t size); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_d_indheap_init(igraph_d_indheap_t *h, igraph_int_t size); IGRAPH_PRIVATE_EXPORT void igraph_d_indheap_destroy(igraph_d_indheap_t *h); IGRAPH_PRIVATE_EXPORT igraph_bool_t igraph_d_indheap_empty(const igraph_d_indheap_t *h); IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_d_indheap_push(igraph_d_indheap_t *h, igraph_real_t elem, - igraph_integer_t idx, igraph_integer_t idx2); + igraph_int_t idx, igraph_int_t idx2); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t igraph_d_indheap_max(const igraph_d_indheap_t *h); IGRAPH_PRIVATE_EXPORT igraph_real_t igraph_d_indheap_delete_max(igraph_d_indheap_t *h); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_d_indheap_size(const igraph_d_indheap_t *h); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_d_indheap_reserve(igraph_d_indheap_t *h, igraph_integer_t size); -IGRAPH_PRIVATE_EXPORT void igraph_d_indheap_max_index(igraph_d_indheap_t *h, igraph_integer_t *idx, igraph_integer_t *idx2); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_d_indheap_size(const igraph_d_indheap_t *h); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_d_indheap_reserve(igraph_d_indheap_t *h, igraph_int_t size); +IGRAPH_PRIVATE_EXPORT void igraph_d_indheap_max_index(igraph_d_indheap_t *h, igraph_int_t *idx, igraph_int_t *idx2); /* -------------------------------------------------- */ /* Two-way indexed heap */ @@ -111,7 +108,7 @@ IGRAPH_PRIVATE_EXPORT void igraph_d_indheap_max_index(igraph_d_indheap_t *h, igr typedef struct igraph_2wheap_t { /** Number of items in the heap */ - igraph_integer_t max_size; + igraph_int_t max_size; /** The items themselves in the heap */ igraph_vector_t data; @@ -133,25 +130,25 @@ typedef struct igraph_2wheap_t { igraph_vector_int_t index2; } igraph_2wheap_t; -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_2wheap_init(igraph_2wheap_t *h, igraph_integer_t size); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_2wheap_init(igraph_2wheap_t *h, igraph_int_t size); IGRAPH_PRIVATE_EXPORT void igraph_2wheap_destroy(igraph_2wheap_t *h); IGRAPH_PRIVATE_EXPORT void igraph_2wheap_clear(igraph_2wheap_t *h); IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_2wheap_push_with_index(igraph_2wheap_t *h, - igraph_integer_t idx, igraph_real_t elem); + igraph_int_t idx, igraph_real_t elem); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_2wheap_empty(const igraph_2wheap_t *h); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_2wheap_size(const igraph_2wheap_t *h); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_2wheap_max_size(const igraph_2wheap_t *h); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_2wheap_size(const igraph_2wheap_t *h); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_2wheap_max_size(const igraph_2wheap_t *h); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t igraph_2wheap_max(const igraph_2wheap_t *h); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_2wheap_max_index(const igraph_2wheap_t *h); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_2wheap_max_index(const igraph_2wheap_t *h); IGRAPH_PRIVATE_EXPORT igraph_real_t igraph_2wheap_deactivate_max(igraph_2wheap_t *h); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_2wheap_has_elem(const igraph_2wheap_t *h, igraph_integer_t idx); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_2wheap_has_active(const igraph_2wheap_t *h, igraph_integer_t idx); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t igraph_2wheap_get(const igraph_2wheap_t *h, igraph_integer_t idx); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_2wheap_has_elem(const igraph_2wheap_t *h, igraph_int_t idx); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_2wheap_has_active(const igraph_2wheap_t *h, igraph_int_t idx); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_real_t igraph_2wheap_get(const igraph_2wheap_t *h, igraph_int_t idx); IGRAPH_PRIVATE_EXPORT igraph_real_t igraph_2wheap_delete_max(igraph_2wheap_t *h); -IGRAPH_PRIVATE_EXPORT igraph_real_t igraph_2wheap_delete_max_index(igraph_2wheap_t *h, igraph_integer_t *idx); -IGRAPH_PRIVATE_EXPORT void igraph_2wheap_modify(igraph_2wheap_t *h, igraph_integer_t idx, igraph_real_t elem); +IGRAPH_PRIVATE_EXPORT igraph_real_t igraph_2wheap_delete_max_index(igraph_2wheap_t *h, igraph_int_t *idx); +IGRAPH_PRIVATE_EXPORT void igraph_2wheap_modify(igraph_2wheap_t *h, igraph_int_t idx, igraph_real_t elem); IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_2wheap_check(const igraph_2wheap_t *h); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/core/interruption.c b/src/vendor/cigraph/src/core/interruption.c index 08aebf77d88..2c30c179b4b 100644 --- a/src/vendor/cigraph/src/core/interruption.c +++ b/src/vendor/cigraph/src/core/interruption.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -25,13 +24,13 @@ #include "config.h" /* IGRAPH_THREAD_LOCAL */ -IGRAPH_THREAD_LOCAL igraph_interruption_handler_t *igraph_i_interruption_handler = 0; +IGRAPH_THREAD_LOCAL igraph_interruption_handler_t *igraph_i_interruption_handler = NULL; -igraph_error_t igraph_allow_interruption(void *data) { +igraph_bool_t igraph_allow_interruption(void) { if (igraph_i_interruption_handler) { - return igraph_i_interruption_handler(data); + return igraph_i_interruption_handler(); } - return IGRAPH_SUCCESS; + return false; } igraph_interruption_handler_t *igraph_set_interruption_handler (igraph_interruption_handler_t *new_handler) { diff --git a/src/vendor/cigraph/src/core/interruption.h b/src/vendor/cigraph/src/core/interruption.h index a7866226d83..b05f6713ae4 100644 --- a/src/vendor/cigraph/src/core/interruption.h +++ b/src/vendor/cigraph/src/core/interruption.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -29,7 +28,7 @@ #include "config.h" /* IGRAPH_THREAD_LOCAL */ -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS extern IGRAPH_THREAD_LOCAL igraph_interruption_handler_t *igraph_i_interruption_handler; @@ -38,16 +37,15 @@ extern IGRAPH_THREAD_LOCAL igraph_interruption_handler_t *igraph_i_interruption_ * \brief * * This macro should be called when interruption is allowed. It calls - * \ref igraph_allow_interruption() with the proper parameters and if that returns - * anything but \c IGRAPH_SUCCESS then - * the macro returns the "calling" function as well, with the proper - * error code (\c IGRAPH_INTERRUPTED). + * \ref igraph_allow_interruption() and if that returns anything but + * \c IGRAPH_SUCCESS then the macro returns the "calling" function as well, + * with the proper error code (\c IGRAPH_INTERRUPTED). */ #define IGRAPH_ALLOW_INTERRUPTION() \ do { \ if (igraph_i_interruption_handler) { \ - if (igraph_allow_interruption(NULL) != IGRAPH_SUCCESS) { \ + if (igraph_allow_interruption()) { \ return IGRAPH_INTERRUPTED; \ } \ } \ @@ -63,7 +61,7 @@ extern IGRAPH_THREAD_LOCAL igraph_interruption_handler_t *igraph_i_interruption_ * and initialized to 0. Example: * * int myiter = 0; - * for (igraph_integer_t i=0; i < n; i++) { + * for (igraph_int_t i=0; i < n; i++) { * // Allow for interruption every 1000th iteration * IGRAPH_ALLOW_INTERRUPTION_LIMITED(myiter, 1000); * } @@ -77,6 +75,6 @@ extern IGRAPH_THREAD_LOCAL igraph_interruption_handler_t *igraph_i_interruption_ } \ } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/core/marked_queue.c b/src/vendor/cigraph/src/core/marked_queue.c index 29fe4116cba..7c8da9395e1 100644 --- a/src/vendor/cigraph/src/core/marked_queue.c +++ b/src/vendor/cigraph/src/core/marked_queue.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -26,7 +25,7 @@ #define BATCH_MARKER -1 igraph_error_t igraph_marked_queue_int_init(igraph_marked_queue_int_t *q, - igraph_integer_t size) { + igraph_int_t size) { IGRAPH_CHECK(igraph_dqueue_int_init(&q->Q, 0)); IGRAPH_FINALLY(igraph_dqueue_int_destroy, &q->Q); IGRAPH_CHECK(igraph_vector_int_init(&q->set, size)); @@ -55,16 +54,16 @@ igraph_bool_t igraph_marked_queue_int_empty(const igraph_marked_queue_int_t *q) return q->size == 0; } -igraph_integer_t igraph_marked_queue_int_size(const igraph_marked_queue_int_t *q) { +igraph_int_t igraph_marked_queue_int_size(const igraph_marked_queue_int_t *q) { return q->size; } igraph_bool_t igraph_marked_queue_int_iselement(const igraph_marked_queue_int_t *q, - igraph_integer_t elem) { + igraph_int_t elem) { return (VECTOR(q->set)[elem] == q->mark); } -igraph_error_t igraph_marked_queue_int_push(igraph_marked_queue_int_t *q, igraph_integer_t elem) { +igraph_error_t igraph_marked_queue_int_push(igraph_marked_queue_int_t *q, igraph_int_t elem) { if (VECTOR(q->set)[elem] != q->mark) { IGRAPH_CHECK(igraph_dqueue_int_push(&q->Q, elem)); VECTOR(q->set)[elem] = q->mark; @@ -79,8 +78,8 @@ igraph_error_t igraph_marked_queue_int_start_batch(igraph_marked_queue_int_t *q) } void igraph_marked_queue_int_pop_back_batch(igraph_marked_queue_int_t *q) { - igraph_integer_t size = igraph_dqueue_int_size(&q->Q); - igraph_integer_t elem; + igraph_int_t size = igraph_dqueue_int_size(&q->Q); + igraph_int_t elem; while (size > 0 && (elem = igraph_dqueue_int_pop_back(&q->Q)) != BATCH_MARKER) { VECTOR(q->set)[elem] = 0; @@ -103,10 +102,10 @@ igraph_error_t igraph_marked_queue_int_fprint(const igraph_marked_queue_int_t *q igraph_error_t igraph_marked_queue_int_as_vector(const igraph_marked_queue_int_t *q, igraph_vector_int_t *vec) { - igraph_integer_t i, p, n = igraph_dqueue_int_size(&q->Q); + igraph_int_t i, p, n = igraph_dqueue_int_size(&q->Q); IGRAPH_CHECK(igraph_vector_int_resize(vec, q->size)); for (i = 0, p = 0; i < n; i++) { - igraph_integer_t e = igraph_dqueue_int_get(&q->Q, i); + igraph_int_t e = igraph_dqueue_int_get(&q->Q, i); if (e != BATCH_MARKER) { VECTOR(*vec)[p++] = e; } diff --git a/src/vendor/cigraph/src/core/marked_queue.h b/src/vendor/cigraph/src/core/marked_queue.h index 70a2fdce5ed..93a9bfd21ac 100644 --- a/src/vendor/cigraph/src/core/marked_queue.h +++ b/src/vendor/cigraph/src/core/marked_queue.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -30,7 +29,7 @@ #include -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* This is essentially a double ended queue, with some extra features: (1) The is-element? operation is fast, O(1). This requires that we @@ -45,24 +44,24 @@ __BEGIN_DECLS typedef struct igraph_marked_queue_int_t { igraph_dqueue_int_t Q; igraph_vector_int_t set; - igraph_integer_t mark; - igraph_integer_t size; + igraph_int_t mark; + igraph_int_t size; } igraph_marked_queue_int_t; IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_marked_queue_int_init(igraph_marked_queue_int_t *q, - igraph_integer_t size); + igraph_int_t size); IGRAPH_PRIVATE_EXPORT void igraph_marked_queue_int_destroy(igraph_marked_queue_int_t *q); IGRAPH_PRIVATE_EXPORT void igraph_marked_queue_int_reset(igraph_marked_queue_int_t *q); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_marked_queue_int_empty(const igraph_marked_queue_int_t *q); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_marked_queue_int_size(const igraph_marked_queue_int_t *q); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_marked_queue_int_size(const igraph_marked_queue_int_t *q); IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_marked_queue_int_print(const igraph_marked_queue_int_t *q); IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_marked_queue_int_fprint(const igraph_marked_queue_int_t *q, FILE *file); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_marked_queue_int_iselement(const igraph_marked_queue_int_t *q, - igraph_integer_t elem); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_marked_queue_int_push(igraph_marked_queue_int_t *q, igraph_integer_t elem); + igraph_int_t elem); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_marked_queue_int_push(igraph_marked_queue_int_t *q, igraph_int_t elem); IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_marked_queue_int_start_batch(igraph_marked_queue_int_t *q); IGRAPH_PRIVATE_EXPORT void igraph_marked_queue_int_pop_back_batch(igraph_marked_queue_int_t *q); @@ -70,6 +69,6 @@ IGRAPH_PRIVATE_EXPORT void igraph_marked_queue_int_pop_back_batch(igraph_marked_ IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_marked_queue_int_as_vector(const igraph_marked_queue_int_t *q, igraph_vector_int_t *vec); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/core/math.h b/src/vendor/cigraph/src/core/math.h index 9c406c26fd9..c91c19a17e6 100644 --- a/src/vendor/cigraph/src/core/math.h +++ b/src/vendor/cigraph/src/core/math.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify diff --git a/src/vendor/cigraph/src/core/matrix.c b/src/vendor/cigraph/src/core/matrix.c index 62a1c3c2fde..643dd9883cc 100644 --- a/src/vendor/cigraph/src/core/matrix.c +++ b/src/vendor/cigraph/src/core/matrix.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -70,8 +69,8 @@ igraph_error_t igraph_matrix_complex_real(const igraph_matrix_complex_t *m, igraph_matrix_t *real) { - igraph_integer_t nrow = igraph_matrix_complex_nrow(m); - igraph_integer_t ncol = igraph_matrix_complex_ncol(m); + igraph_int_t nrow = igraph_matrix_complex_nrow(m); + igraph_int_t ncol = igraph_matrix_complex_ncol(m); IGRAPH_CHECK(igraph_matrix_resize(real, nrow, ncol)); IGRAPH_CHECK(igraph_vector_complex_real(&m->data, &real->data)); return IGRAPH_SUCCESS; @@ -93,8 +92,8 @@ igraph_error_t igraph_matrix_complex_real(const igraph_matrix_complex_t *m, igraph_error_t igraph_matrix_complex_imag(const igraph_matrix_complex_t *m, igraph_matrix_t *imag) { - igraph_integer_t nrow = igraph_matrix_complex_nrow(m); - igraph_integer_t ncol = igraph_matrix_complex_ncol(m); + igraph_int_t nrow = igraph_matrix_complex_nrow(m); + igraph_int_t ncol = igraph_matrix_complex_ncol(m); IGRAPH_CHECK(igraph_matrix_resize(imag, nrow, ncol)); IGRAPH_CHECK(igraph_vector_complex_imag(&m->data, &imag->data)); return IGRAPH_SUCCESS; @@ -118,8 +117,8 @@ igraph_error_t igraph_matrix_complex_imag(const igraph_matrix_complex_t *m, igraph_error_t igraph_matrix_complex_realimag(const igraph_matrix_complex_t *m, igraph_matrix_t *real, igraph_matrix_t *imag) { - igraph_integer_t nrow = igraph_matrix_complex_nrow(m); - igraph_integer_t ncol = igraph_matrix_complex_ncol(m); + igraph_int_t nrow = igraph_matrix_complex_nrow(m); + igraph_int_t ncol = igraph_matrix_complex_ncol(m); IGRAPH_CHECK(igraph_matrix_resize(real, nrow, ncol)); IGRAPH_CHECK(igraph_matrix_resize(imag, nrow, ncol)); IGRAPH_CHECK(igraph_vector_complex_realimag(&m->data, &real->data, @@ -145,10 +144,10 @@ igraph_error_t igraph_matrix_complex_realimag(const igraph_matrix_complex_t *m, igraph_error_t igraph_matrix_complex_create(igraph_matrix_complex_t *m, const igraph_matrix_t *real, const igraph_matrix_t *imag) { - igraph_integer_t nrowr = igraph_matrix_nrow(real); - igraph_integer_t ncolr = igraph_matrix_ncol(real); - igraph_integer_t nrowi = igraph_matrix_nrow(imag); - igraph_integer_t ncoli = igraph_matrix_ncol(imag); + igraph_int_t nrowr = igraph_matrix_nrow(real); + igraph_int_t ncolr = igraph_matrix_ncol(real); + igraph_int_t nrowi = igraph_matrix_nrow(imag); + igraph_int_t ncoli = igraph_matrix_ncol(imag); if (nrowr != nrowi || ncolr != ncoli) { IGRAPH_ERRORF("Dimensions of real (%" IGRAPH_PRId " by %" IGRAPH_PRId ") and " @@ -158,7 +157,7 @@ igraph_error_t igraph_matrix_complex_create(igraph_matrix_complex_t *m, IGRAPH_CHECK(igraph_matrix_complex_init(m, nrowr, ncolr)); - for (igraph_integer_t i = 0; i < nrowr * ncolr; i++) { + for (igraph_int_t i = 0; i < nrowr * ncolr; i++) { VECTOR(m->data)[i] = igraph_complex(VECTOR(real->data)[i], VECTOR(imag->data)[i]); } @@ -183,10 +182,10 @@ igraph_error_t igraph_matrix_complex_create(igraph_matrix_complex_t *m, igraph_error_t igraph_matrix_complex_create_polar(igraph_matrix_complex_t *m, const igraph_matrix_t *r, const igraph_matrix_t *theta) { - igraph_integer_t nrowr = igraph_matrix_nrow(r); - igraph_integer_t ncolr = igraph_matrix_ncol(r); - igraph_integer_t nrowt = igraph_matrix_nrow(theta); - igraph_integer_t ncolt = igraph_matrix_ncol(theta); + igraph_int_t nrowr = igraph_matrix_nrow(r); + igraph_int_t ncolr = igraph_matrix_ncol(r); + igraph_int_t nrowt = igraph_matrix_nrow(theta); + igraph_int_t ncolt = igraph_matrix_ncol(theta); if (nrowr != nrowt || ncolr != ncolt) { IGRAPH_ERRORF("Dimensions of magnitude (%" IGRAPH_PRId " by %" IGRAPH_PRId ") and " @@ -196,7 +195,7 @@ igraph_error_t igraph_matrix_complex_create_polar(igraph_matrix_complex_t *m, IGRAPH_CHECK(igraph_matrix_complex_init(m, nrowr, ncolr)); - for (igraph_integer_t i = 0; i < nrowr * ncolr; i++) { + for (igraph_int_t i = 0; i < nrowr * ncolr; i++) { VECTOR(m->data)[i] = igraph_complex_polar(VECTOR(r->data)[i], VECTOR(theta->data)[i]); } return IGRAPH_SUCCESS; @@ -221,19 +220,6 @@ igraph_bool_t igraph_matrix_complex_all_almost_e(igraph_matrix_complex_t *lhs, igraph_vector_complex_all_almost_e(&lhs->data, &rhs->data, eps); } -/** - * Deprecated in favour of \ref igraph_matrix_all_almost_e() which uses - * relative tolerances. Will be removed in 0.11. - * - * Checks if two matrices are equal within an absolute tolerance. - */ -igraph_bool_t igraph_matrix_all_e_tol(const igraph_matrix_t *lhs, - const igraph_matrix_t *rhs, - igraph_real_t tol) { - return lhs->ncol == rhs->ncol && lhs->nrow == rhs->nrow && - igraph_vector_e_tol(&lhs->data, &rhs->data, tol); -} - /** * \function igraph_matrix_all_almost_e diff --git a/src/vendor/cigraph/src/core/matrix.pmt b/src/vendor/cigraph/src/core/matrix.pmt index c437aeae899..c73b4ef16bb 100644 --- a/src/vendor/cigraph/src/core/matrix.pmt +++ b/src/vendor/cigraph/src/core/matrix.pmt @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -62,8 +61,8 @@ */ igraph_error_t FUNCTION(igraph_matrix, init)( - TYPE(igraph_matrix) *m, igraph_integer_t nrow, igraph_integer_t ncol) { - igraph_integer_t size; + TYPE(igraph_matrix) *m, igraph_int_t nrow, igraph_int_t ncol) { + igraph_int_t size; IGRAPH_ASSERT(nrow >= 0 && ncol >= 0); IGRAPH_SAFE_MULT(nrow, ncol, &size); IGRAPH_CHECK(FUNCTION(igraph_vector, init)(&m->data, size)); @@ -85,35 +84,33 @@ igraph_error_t FUNCTION(igraph_matrix, init)( * * * Since this function creates a view into an existing array, you must \em not - * destroy the \c igraph_matrix_t object when you are done with it. Similarly, + * destroy the \type igraph_matrix_t object when you are done with it. Similarly, * you must \em not call any function on it that may attempt to modify the size * of the matrix. Modifying an element in the matrix will modify the underlying * array as the two share the same memory block. * - * \param m Pointer to a not yet initialized matrix object where the view will - * be created. - * \param data The array that the matrix provides a view into. + * \param data The raw array that the matrix provides a view into. * \param nrow The number of rows in the matrix. * \param ncol The number of columns in the matrix. - * \return Pointer to the matrix object, the same as the \p m parameter, for - * convenience. + * \return The matrix object providing the view into the array. * * Time complexity: O(1). */ -const TYPE(igraph_matrix)* FUNCTION(igraph_matrix, view)( - const TYPE(igraph_matrix) *m, const BASE *data, - igraph_integer_t nrow, igraph_integer_t ncol) { +TYPE(igraph_matrix) FUNCTION(igraph_matrix, view)( + const BASE *data, + igraph_int_t nrow, igraph_int_t ncol) { + /* temporarily cast away the constness */ - TYPE(igraph_matrix) *m2 = (TYPE(igraph_matrix)*)m; + TYPE(igraph_matrix) m; /* No overflow checking, as this function does not return igraph_error_t. * It is the caller's resposibility to ensure that the size of 'data' * matches nrow*ncol, which also implies that nrow*ncol does not overflow. */ - FUNCTION(igraph_vector, view)(&m2->data, data, ncol * nrow); - m2->nrow = nrow; - m2->ncol = ncol; + m.data = FUNCTION(igraph_vector, view)(data, ncol * nrow); + m.nrow = nrow; + m.ncol = ncol; return m; } @@ -142,33 +139,24 @@ const TYPE(igraph_matrix)* FUNCTION(igraph_matrix, view)( * block of the vector, and the matrix view will not be informed about the * re-allocation so it will point to an invalid memory area afterwards. * - * \param m Pointer to a not yet initialized matrix object where the view will - * be created. * \param v The vector that the matrix will provide a view into. * \param nrow The number of rows in the matrix. The number of columns will be * derived implicitly from the size of the vector. If the number of * items in the vector is not divisible by the number of rows, the * last few elements of the vector will not be covered by the view. - * \return Error code. + * \return The matrix object providing the view into the vector. * * Time complexity: O(1). */ -const TYPE(igraph_matrix) *FUNCTION(igraph_matrix, view_from_vector)( - const TYPE(igraph_matrix) *m, const TYPE(igraph_vector) *v, - igraph_integer_t nrow +TYPE(igraph_matrix) FUNCTION(igraph_matrix, view_from_vector)( + const TYPE(igraph_vector) *v, + igraph_int_t nrow ) { - /* temporarily cast away the constness */ - TYPE(igraph_matrix) *m2 = (TYPE(igraph_matrix)*)m; - - igraph_integer_t size = FUNCTION(igraph_vector, size)(v); - igraph_integer_t ncol = nrow > 0 ? size / nrow : 0; - - FUNCTION(igraph_vector, view)(&m2->data, VECTOR(*v), ncol * nrow); - m2->nrow = nrow; - m2->ncol = ncol; + igraph_int_t size = FUNCTION(igraph_vector, size)(v); + igraph_int_t ncol = nrow > 0 ? size / nrow : 0; - return m; + return FUNCTION(igraph_matrix, view)(VECTOR(*v), nrow, ncol); } /** @@ -207,7 +195,7 @@ void FUNCTION(igraph_matrix, destroy)(TYPE(igraph_matrix) *m) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_matrix, capacity)(const TYPE(igraph_matrix) *m) { +igraph_int_t FUNCTION(igraph_matrix, capacity)(const TYPE(igraph_matrix) *m) { return FUNCTION(igraph_vector, capacity)(&m->data); } @@ -238,8 +226,8 @@ igraph_integer_t FUNCTION(igraph_matrix, capacity)(const TYPE(igraph_matrix) *m) * number of elements in the resized matrix. */ -igraph_error_t FUNCTION(igraph_matrix, resize)(TYPE(igraph_matrix) *m, igraph_integer_t nrow, igraph_integer_t ncol) { - igraph_integer_t size; +igraph_error_t FUNCTION(igraph_matrix, resize)(TYPE(igraph_matrix) *m, igraph_int_t nrow, igraph_int_t ncol) { + igraph_int_t size; IGRAPH_ASSERT(nrow >= 0 && ncol >= 0); IGRAPH_SAFE_MULT(nrow, ncol, &size); IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(&m->data, size)); @@ -279,7 +267,7 @@ void FUNCTION(igraph_matrix, resize_min)(TYPE(igraph_matrix) *m) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_matrix, size)(const TYPE(igraph_matrix) *m) { +igraph_int_t FUNCTION(igraph_matrix, size)(const TYPE(igraph_matrix) *m) { return (m->nrow) * (m->ncol); } @@ -294,7 +282,7 @@ igraph_integer_t FUNCTION(igraph_matrix, size)(const TYPE(igraph_matrix) *m) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_matrix, nrow)(const TYPE(igraph_matrix) *m) { +igraph_int_t FUNCTION(igraph_matrix, nrow)(const TYPE(igraph_matrix) *m) { return m->nrow; } @@ -309,31 +297,72 @@ igraph_integer_t FUNCTION(igraph_matrix, nrow)(const TYPE(igraph_matrix) *m) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_matrix, ncol)(const TYPE(igraph_matrix) *m) { +igraph_int_t FUNCTION(igraph_matrix, ncol)(const TYPE(igraph_matrix) *m) { return m->ncol; } +/** + * Copies matrix data stored contiguously while transposing. Applications include implementing + * matrix transposition as well as changing between row-major and column-major storage formats. + * + * \param dst Data will be copied into this vector. It must have length m-by-n. It will not be resized. + * \param src Vector containing the data to be copied. It is assumed to have length m-by-n. + * Must not be the same as \p dst . + * \param m The size of contiguous blocks. This is the number of columns when using column-major + * storage format, or the number of rows when using row-major format. + * \param n The number of blocks. This is the number of rows when using column-major format, + * or the number of columns when using row-major format. + */ +static void FUNCTION(igraph_i, transpose_copy)( + TYPE(igraph_vector) *dst, const TYPE(igraph_vector) *src, + size_t m, size_t n) { + + IGRAPH_ASSERT(dst != src); + + /* Block size of 4 was found to yield the best performance when benchmarking with: + * - Intel Core i7-7920HQ on macOS. + * - AMD Ryzen Threadripper 3990X on Linux. + */ + const size_t blocksize = 4; + for (size_t i=0; i < m; i += blocksize) { + for (size_t j=0; j < n; j++) { + for (size_t k=0; k < blocksize && i+k < m; k++) { + VECTOR(*dst)[j + (i+k)*n] = VECTOR(*src)[i+k + j*m]; + } + } + } +} + /** * \ingroup matrix * \function igraph_matrix_copy_to * \brief Copies a matrix to a regular C array. * * - * The matrix is copied columnwise, as this is the format most - * programs and languages use. * The C array should be of sufficient size; there are (of course) no * range checks. + * * \param m Pointer to an initialized matrix object. * \param to Pointer to a C array; the place to copy the data to. + * \param storage \c IGRAPH_ROW_MAJOR to write the data in row-major format, + * \c IGRAPH_COLUMN_MAJOR to write it in column-major format. Currently + * igraph uses column-major storage internally, thus \c IGRAPH_COLUMN_MAJOR + * is much faster. * \return Error code. * * Time complexity: O(n), * n is the number of * elements in the matrix. */ - -void FUNCTION(igraph_matrix, copy_to)(const TYPE(igraph_matrix) *m, BASE *to) { - FUNCTION(igraph_vector, copy_to)(&m->data, to); +void FUNCTION(igraph_matrix, copy_to)(const TYPE(igraph_matrix) *m, BASE *to, igraph_matrix_storage_t storage) { + if (storage == IGRAPH_ROW_MAJOR) { + TYPE(igraph_vector) dst = FUNCTION(igraph_vector, view)(to, m->nrow * m->ncol); + FUNCTION(igraph_i, transpose_copy)(&dst, &m->data, m->nrow, m->ncol); + } else if (storage == IGRAPH_COLUMN_MAJOR) { + FUNCTION(igraph_vector, copy_to)(&m->data, to); + } else { + IGRAPH_FATAL("Invalid matrix storage format."); + } } /** @@ -365,8 +394,8 @@ void FUNCTION(igraph_matrix, null)(TYPE(igraph_matrix) *m) { * resized matrix. */ -igraph_error_t FUNCTION(igraph_matrix, add_cols)(TYPE(igraph_matrix) *m, igraph_integer_t n) { - igraph_integer_t new_ncol; +igraph_error_t FUNCTION(igraph_matrix, add_cols)(TYPE(igraph_matrix) *m, igraph_int_t n) { + igraph_int_t new_ncol; IGRAPH_SAFE_ADD(m->ncol, n, &new_ncol); IGRAPH_CHECK(FUNCTION(igraph_matrix, resize)(m, m->nrow, new_ncol)); return IGRAPH_SUCCESS; @@ -385,12 +414,12 @@ igraph_error_t FUNCTION(igraph_matrix, add_cols)(TYPE(igraph_matrix) *m, igraph_ * resized matrix. */ -igraph_error_t FUNCTION(igraph_matrix, add_rows)(TYPE(igraph_matrix) *m, igraph_integer_t n) { - igraph_integer_t new_nrow, new_size; +igraph_error_t FUNCTION(igraph_matrix, add_rows)(TYPE(igraph_matrix) *m, igraph_int_t n) { + igraph_int_t new_nrow, new_size; IGRAPH_SAFE_ADD(m->nrow, n, &new_nrow); IGRAPH_SAFE_MULT(m->ncol, new_nrow, &new_size); IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(&m->data, new_size)); - for (igraph_integer_t i = m->ncol - 1; i >= 0; i--) { + for (igraph_int_t i = m->ncol - 1; i >= 0; i--) { FUNCTION(igraph_vector, move_interval)(&m->data, (m->nrow)*i, (m->nrow) * (i + 1), new_nrow * i); } @@ -411,7 +440,7 @@ igraph_error_t FUNCTION(igraph_matrix, add_rows)(TYPE(igraph_matrix) *m, igraph_ * resized matrix. */ -igraph_error_t FUNCTION(igraph_matrix, remove_col)(TYPE(igraph_matrix) *m, igraph_integer_t col) { +igraph_error_t FUNCTION(igraph_matrix, remove_col)(TYPE(igraph_matrix) *m, igraph_int_t col) { FUNCTION(igraph_vector, remove_section)(&m->data, (m->nrow)*col, (m->nrow) * (col + 1)); m->ncol--; return IGRAPH_SUCCESS; @@ -427,8 +456,8 @@ igraph_error_t FUNCTION(igraph_matrix, remove_col)(TYPE(igraph_matrix) *m, igrap */ igraph_error_t FUNCTION(igraph_matrix, permdelete_rows)( - TYPE(igraph_matrix) *m, igraph_integer_t *index, igraph_integer_t nremove) { - igraph_integer_t i, j; + TYPE(igraph_matrix) *m, igraph_int_t *index, igraph_int_t nremove) { + igraph_int_t i, j; for (j = 0; j < m->nrow; j++) { if (index[j] != 0) { for (i = 0; i < m->ncol; i++) { @@ -445,38 +474,6 @@ igraph_error_t FUNCTION(igraph_matrix, permdelete_rows)( return IGRAPH_SUCCESS; } -/** - * Copies matrix data stored contiguously while transposing. Applications include implementing - * matrix transposition as well as changing between row-major and column-major storage formats. - * - * \param dst Data will be copied into this vector. It must have size m-by-n. It will not be resized. - * \param src Vector containing the data to be copied. It is assumed to have size m-by-n. - * Must not be the same as \p dst . - * \param m The size of contiguous blocks. This is the number of columns when using column-major - * storage format, or the number of rows when using row-major format. - * \param n The number of blocks. The is the number of rows when using column-major format, - * or the number of column when using row-major format. - */ -static void FUNCTION(igraph_i, transpose_copy)( - TYPE(igraph_vector) *dst, const TYPE(igraph_vector) *src, - size_t m, size_t n) { - - IGRAPH_ASSERT(dst != src); - - /* Block size of 4 was found to yield the best performance when benchmarking with: - * - Intel Core i7-7920HQ on macOS. - * - AMD Ryzen Threadripper 3990X on Linux. - */ - const size_t blocksize = 4; - for (size_t i=0; i < m; i += blocksize) { - for (size_t j=0; j < n; j++) { - for (size_t k=0; k < blocksize && i+k < m; k++) { - VECTOR(*dst)[j + (i+k)*n] = VECTOR(*src)[i+k + j*m]; - } - } - } -} - /** * \ingroup matrix * \function igraph_matrix_init_array @@ -505,14 +502,14 @@ static void FUNCTION(igraph_i, transpose_copy)( igraph_error_t FUNCTION(igraph_matrix, init_array)( TYPE(igraph_matrix) *m, const BASE *data, - igraph_integer_t nrow, igraph_integer_t ncol, + igraph_int_t nrow, igraph_int_t ncol, igraph_matrix_storage_t storage) { - igraph_integer_t length; - TYPE(igraph_vector) v; + igraph_int_t length; IGRAPH_SAFE_MULT(nrow, ncol, &length); IGRAPH_CHECK(FUNCTION(igraph_matrix, init)(m, nrow, ncol)); - FUNCTION(igraph_vector, view)(&v, data, length); + const TYPE(igraph_vector) v = FUNCTION(igraph_vector, view)(data, length); + if (storage == IGRAPH_COLUMN_MAJOR) { IGRAPH_CHECK(FUNCTION(igraph_vector, update)(&m->data, &v)); } else if (storage == IGRAPH_ROW_MAJOR) { @@ -547,18 +544,6 @@ igraph_error_t FUNCTION(igraph_matrix, init_copy)(TYPE(igraph_matrix) *to, const return IGRAPH_SUCCESS; } -/** - * \ingroup matrix - * \function igraph_matrix_copy - * \brief Copies a matrix (deprecated alias). - * - * \deprecated-by igraph_matrix_init_copy 0.10 - */ - -igraph_error_t FUNCTION(igraph_matrix, copy)(TYPE(igraph_matrix) *to, const TYPE(igraph_matrix) *from) { - return FUNCTION(igraph_matrix, init_copy)(to, from); -} - #ifndef NOTORDERED /** @@ -618,8 +603,8 @@ void FUNCTION(igraph_matrix, scale)(TYPE(igraph_matrix) *m, BASE by) { igraph_error_t FUNCTION(igraph_matrix, select_rows)(const TYPE(igraph_matrix) *m, TYPE(igraph_matrix) *res, const igraph_vector_int_t *rows) { - igraph_integer_t norows = igraph_vector_int_size(rows); - igraph_integer_t i, j, ncols = FUNCTION(igraph_matrix, ncol)(m); + igraph_int_t norows = igraph_vector_int_size(rows); + igraph_int_t i, j, ncols = FUNCTION(igraph_matrix, ncol)(m); IGRAPH_CHECK(FUNCTION(igraph_matrix, resize)(res, norows, ncols)); /* Iterate in column-major order for better performance. */ @@ -656,9 +641,9 @@ igraph_error_t FUNCTION(igraph_matrix, select_rows_cols)(const TYPE(igraph_matri TYPE(igraph_matrix) *res, const igraph_vector_int_t *rows, const igraph_vector_int_t *cols) { - igraph_integer_t nrows = igraph_vector_int_size(rows); - igraph_integer_t ncols = igraph_vector_int_size(cols); - igraph_integer_t i, j; + igraph_int_t nrows = igraph_vector_int_size(rows); + igraph_int_t ncols = igraph_vector_int_size(cols); + igraph_int_t i, j; IGRAPH_CHECK(FUNCTION(igraph_matrix, resize)(res, nrows, ncols)); /* Iterate in column-major order for better performance. */ @@ -687,8 +672,8 @@ igraph_error_t FUNCTION(igraph_matrix, select_rows_cols)(const TYPE(igraph_matri igraph_error_t FUNCTION(igraph_matrix, get_col)(const TYPE(igraph_matrix) *m, TYPE(igraph_vector) *res, - igraph_integer_t index) { - igraph_integer_t nrow = FUNCTION(igraph_matrix, nrow)(m); + igraph_int_t index) { + igraph_int_t nrow = FUNCTION(igraph_matrix, nrow)(m); if (index >= m->ncol) { IGRAPH_ERROR("Index out of range for selecting matrix column", IGRAPH_EINVAL); @@ -904,7 +889,7 @@ igraph_error_t FUNCTION(igraph_matrix, transpose)(TYPE(igraph_matrix) *m) { } } - SWAP(igraph_integer_t, m->nrow, m->ncol); + SWAP(igraph_int_t, m->nrow, m->ncol); return IGRAPH_SUCCESS; } @@ -926,7 +911,7 @@ igraph_error_t FUNCTION(igraph_matrix, transpose)(TYPE(igraph_matrix) *m) { */ BASE FUNCTION(igraph_matrix, get)(const TYPE(igraph_matrix) *m, - igraph_integer_t row, igraph_integer_t col) { + igraph_int_t row, igraph_int_t col) { return MATRIX(*m, row, col); } @@ -945,34 +930,10 @@ BASE FUNCTION(igraph_matrix, get)(const TYPE(igraph_matrix) *m, */ BASE* FUNCTION(igraph_matrix, get_ptr)(const TYPE(igraph_matrix) *m, - igraph_integer_t row, igraph_integer_t col) { + igraph_int_t row, igraph_int_t col) { return &MATRIX(*m, row, col); } -/** - * \function igraph_matrix_e - * Extract an element from a matrix (deprecated alias). - * - * \deprecated-by igraph_matrix_get 0.10.0 - */ - -BASE FUNCTION(igraph_matrix, e)(const TYPE(igraph_matrix) *m, - igraph_integer_t row, igraph_integer_t col) { - return FUNCTION(igraph_matrix, get)(m, row, col); -} - -/** - * \function igraph_matrix_e_ptr - * Pointer to an element of a matrix. - * - * \deprecated-by igraph_matrix_get_ptr 0.10.0 - */ - -BASE* FUNCTION(igraph_matrix, e_ptr)(const TYPE(igraph_matrix) *m, - igraph_integer_t row, igraph_integer_t col) { - return FUNCTION(igraph_matrix, get_ptr)(m, row, col); -} - /** * \function igraph_matrix_set * Set an element. @@ -987,7 +948,7 @@ BASE* FUNCTION(igraph_matrix, e_ptr)(const TYPE(igraph_matrix) *m, */ void FUNCTION(igraph_matrix, set)( - TYPE(igraph_matrix)* m, igraph_integer_t row, igraph_integer_t col, + TYPE(igraph_matrix)* m, igraph_int_t row, igraph_int_t col, BASE value) { MATRIX(*m, row, col) = value; } @@ -1045,14 +1006,14 @@ igraph_error_t FUNCTION(igraph_matrix, update)(TYPE(igraph_matrix) *to, igraph_error_t FUNCTION(igraph_matrix, rbind)(TYPE(igraph_matrix) *to, const TYPE(igraph_matrix) *from) { - igraph_integer_t tocols = to->ncol, fromcols = from->ncol; - igraph_integer_t torows = to->nrow, fromrows = from->nrow; - igraph_integer_t offset, c, r, index, offset2; + igraph_int_t tocols = to->ncol, fromcols = from->ncol; + igraph_int_t torows = to->nrow, fromrows = from->nrow; + igraph_int_t offset, c, r, index, offset2; if (tocols != fromcols) { IGRAPH_ERROR("Cannot do rbind, number of columns do not match", IGRAPH_EINVAL); } - igraph_integer_t new_size; /* new_size = tocols * (fromrows + torows) */ + igraph_int_t new_size; /* new_size = tocols * (fromrows + torows) */ IGRAPH_SAFE_ADD(fromrows, torows, &new_size); IGRAPH_SAFE_MULT(tocols, new_size, &new_size); IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(&to->data, new_size)); @@ -1093,13 +1054,13 @@ igraph_error_t FUNCTION(igraph_matrix, rbind)(TYPE(igraph_matrix) *to, igraph_error_t FUNCTION(igraph_matrix, cbind)(TYPE(igraph_matrix) *to, const TYPE(igraph_matrix) *from) { - igraph_integer_t tocols = to->ncol, fromcols = from->ncol; - igraph_integer_t torows = to->nrow, fromrows = from->nrow; + igraph_int_t tocols = to->ncol, fromcols = from->ncol; + igraph_int_t torows = to->nrow, fromrows = from->nrow; if (torows != fromrows) { IGRAPH_ERROR("Cannot do rbind, number of rows do not match", IGRAPH_EINVAL); } - igraph_integer_t new_tocols; + igraph_int_t new_tocols; IGRAPH_SAFE_ADD(tocols, fromcols, &new_tocols); IGRAPH_CHECK(FUNCTION(igraph_matrix, resize)(to, torows, new_tocols)); @@ -1115,13 +1076,12 @@ igraph_error_t FUNCTION(igraph_matrix, cbind)(TYPE(igraph_matrix) *to, * The contents of the two matrices will be swapped. * \param m1 The first matrix. * \param m2 The second matrix. - * \return Error code. * * Time complexity: O(1). */ -igraph_error_t FUNCTION(igraph_matrix, swap)(TYPE(igraph_matrix) *m1, TYPE(igraph_matrix) *m2) { - igraph_integer_t tmp; +void FUNCTION(igraph_matrix, swap)(TYPE(igraph_matrix) *m1, TYPE(igraph_matrix) *m2) { + igraph_int_t tmp; tmp = m1->nrow; m1->nrow = m2->nrow; @@ -1131,9 +1091,7 @@ igraph_error_t FUNCTION(igraph_matrix, swap)(TYPE(igraph_matrix) *m1, TYPE(igrap m1->ncol = m2->ncol; m2->ncol = tmp; - IGRAPH_CHECK(FUNCTION(igraph_vector, swap)(&m1->data, &m2->data)); - - return IGRAPH_SUCCESS; + FUNCTION(igraph_vector, swap)(&m1->data, &m2->data); } /** @@ -1151,9 +1109,9 @@ igraph_error_t FUNCTION(igraph_matrix, swap)(TYPE(igraph_matrix) *m1, TYPE(igrap */ igraph_error_t FUNCTION(igraph_matrix, get_row)(const TYPE(igraph_matrix) *m, - TYPE(igraph_vector) *res, igraph_integer_t index) { - igraph_integer_t rows = m->nrow, cols = m->ncol; - igraph_integer_t i, j; + TYPE(igraph_vector) *res, igraph_int_t index) { + igraph_int_t rows = m->nrow, cols = m->ncol; + igraph_int_t i, j; if (index >= rows) { IGRAPH_ERROR("Index out of range for selecting matrix row", IGRAPH_EINVAL); @@ -1183,8 +1141,8 @@ igraph_error_t FUNCTION(igraph_matrix, get_row)(const TYPE(igraph_matrix) *m, */ igraph_error_t FUNCTION(igraph_matrix, set_row)(TYPE(igraph_matrix) *m, - const TYPE(igraph_vector) *v, igraph_integer_t index) { - const igraph_integer_t rows = m->nrow, cols = m->ncol; + const TYPE(igraph_vector) *v, igraph_int_t index) { + const igraph_int_t rows = m->nrow, cols = m->ncol; if (index >= rows) { IGRAPH_ERROR("Index out of range for selecting matrix row.", IGRAPH_EINVAL); @@ -1192,7 +1150,7 @@ igraph_error_t FUNCTION(igraph_matrix, set_row)(TYPE(igraph_matrix) *m, if (FUNCTION(igraph_vector, size)(v) != cols) { IGRAPH_ERROR("Cannot set matrix row, invalid vector length.", IGRAPH_EINVAL); } - for (igraph_integer_t i = index, j = 0; j < cols; i += rows, j++) { + for (igraph_int_t i = index, j = 0; j < cols; i += rows, j++) { VECTOR(m->data)[i] = VECTOR(*v)[j]; } return IGRAPH_SUCCESS; @@ -1215,8 +1173,8 @@ igraph_error_t FUNCTION(igraph_matrix, set_row)(TYPE(igraph_matrix) *m, */ igraph_error_t FUNCTION(igraph_matrix, set_col)(TYPE(igraph_matrix) *m, - const TYPE(igraph_vector) *v, igraph_integer_t index) { - const igraph_integer_t rows = m->nrow, cols = m->ncol; + const TYPE(igraph_vector) *v, igraph_int_t index) { + const igraph_int_t rows = m->nrow, cols = m->ncol; if (index >= cols) { IGRAPH_ERROR("Index out of range for setting matrix column.", IGRAPH_EINVAL); @@ -1224,7 +1182,7 @@ igraph_error_t FUNCTION(igraph_matrix, set_col)(TYPE(igraph_matrix) *m, if (FUNCTION(igraph_vector, size)(v) != rows) { IGRAPH_ERROR("Cannot set matrix column, invalid vector length.", IGRAPH_EINVAL); } - for (igraph_integer_t i = index * rows, j = 0; j < rows; i++, j++) { + for (igraph_int_t i = index * rows, j = 0; j < rows; i++, j++) { VECTOR(m->data)[i] = VECTOR(*v)[j]; } return IGRAPH_SUCCESS; @@ -1244,9 +1202,9 @@ igraph_error_t FUNCTION(igraph_matrix, set_col)(TYPE(igraph_matrix) *m, */ igraph_error_t FUNCTION(igraph_matrix, swap_rows)(TYPE(igraph_matrix) *m, - igraph_integer_t i, igraph_integer_t j) { - const igraph_integer_t ncol = m->ncol, nrow = m->nrow; - const igraph_integer_t n = nrow * ncol; + igraph_int_t i, igraph_int_t j) { + const igraph_int_t ncol = m->ncol, nrow = m->nrow; + const igraph_int_t n = nrow * ncol; if (i >= nrow || j >= nrow) { IGRAPH_ERROR("Cannot swap rows, index out of range", IGRAPH_EINVAL); @@ -1254,7 +1212,7 @@ igraph_error_t FUNCTION(igraph_matrix, swap_rows)(TYPE(igraph_matrix) *m, if (i == j) { return IGRAPH_SUCCESS; } - for (igraph_integer_t index1 = i, index2 = j; index1 < n; index1 += nrow, index2 += nrow) { + for (igraph_int_t index1 = i, index2 = j; index1 < n; index1 += nrow, index2 += nrow) { BASE tmp; tmp = VECTOR(m->data)[index1]; VECTOR(m->data)[index1] = VECTOR(m->data)[index2]; @@ -1277,8 +1235,8 @@ igraph_error_t FUNCTION(igraph_matrix, swap_rows)(TYPE(igraph_matrix) *m, */ igraph_error_t FUNCTION(igraph_matrix, swap_cols)(TYPE(igraph_matrix) *m, - igraph_integer_t i, igraph_integer_t j) { - const igraph_integer_t ncol = m->ncol, nrow = m->nrow; + igraph_int_t i, igraph_int_t j) { + const igraph_int_t ncol = m->ncol, nrow = m->nrow; if (i >= ncol || j >= ncol) { IGRAPH_ERROR("Cannot swap columns, index out of range.", IGRAPH_EINVAL); @@ -1286,7 +1244,7 @@ igraph_error_t FUNCTION(igraph_matrix, swap_cols)(TYPE(igraph_matrix) *m, if (i == j) { return IGRAPH_SUCCESS; } - for (igraph_integer_t index1 = i * nrow, index2 = j * nrow, k = 0; k < nrow; k++, index1++, index2++) { + for (igraph_int_t index1 = i * nrow, index2 = j * nrow, k = 0; k < nrow; k++, index1++, index2++) { BASE tmp = VECTOR(m->data)[index1]; VECTOR(m->data)[index1] = VECTOR(m->data)[index2]; VECTOR(m->data)[index2] = tmp; @@ -1420,17 +1378,17 @@ igraph_real_t FUNCTION(igraph_matrix, min)(const TYPE(igraph_matrix) *m) { * NaN values, the indices of the first NaN value are returned. * * \param m The matrix. - * \param i Pointer to an igraph_integer_t. The row index of the + * \param i Pointer to an igraph_int_t. The row index of the * minimum is stored here. - * \param j Pointer to an igraph_integer_t. The column index of + * \param j Pointer to an igraph_int_t. The column index of * the minimum is stored here. * * Time complexity: O(mn), the number of elements. */ void FUNCTION(igraph_matrix, which_min)( - const TYPE(igraph_matrix) *m, igraph_integer_t *i, igraph_integer_t *j) { - igraph_integer_t vmin = FUNCTION(igraph_vector, which_min)(&m->data); + const TYPE(igraph_matrix) *m, igraph_int_t *i, igraph_int_t *j) { + igraph_int_t vmin = FUNCTION(igraph_vector, which_min)(&m->data); *i = vmin % m->nrow; *j = vmin / m->nrow; } @@ -1444,17 +1402,17 @@ void FUNCTION(igraph_matrix, which_min)( * NaN values, the indices of the first NaN value are returned. * * \param m The matrix. - * \param i Pointer to an igraph_integer_t. The row index of the + * \param i Pointer to an igraph_int_t. The row index of the * maximum is stored here. - * \param j Pointer to an igraph_integer_t. The column index of + * \param j Pointer to an igraph_int_t. The column index of * the maximum is stored here. * * Time complexity: O(mn), the number of elements. */ void FUNCTION(igraph_matrix, which_max)( - const TYPE(igraph_matrix) *m, igraph_integer_t *i, igraph_integer_t *j) { - igraph_integer_t vmax = FUNCTION(igraph_vector, which_max)(&m->data); + const TYPE(igraph_matrix) *m, igraph_int_t *i, igraph_int_t *j) { + igraph_int_t vmax = FUNCTION(igraph_vector, which_max)(&m->data); *i = vmax % m->nrow; *j = vmax / m->nrow; } @@ -1491,22 +1449,22 @@ void FUNCTION(igraph_matrix, minmax)(const TYPE(igraph_matrix) *m, * will point to the first NaN value. * * \param m The input matrix. - * \param imin Pointer to an igraph_integer_t, the row index of + * \param imin Pointer to an igraph_int_t, the row index of * the minimum is stored here. - * \param jmin Pointer to an igraph_integer_t, the column index of + * \param jmin Pointer to an igraph_int_t, the column index of * the minimum is stored here. - * \param imax Pointer to an igraph_integer_t, the row index of + * \param imax Pointer to an igraph_int_t, the row index of * the maximum is stored here. - * \param jmax Pointer to an igraph_integer_t, the column index of + * \param jmax Pointer to an igraph_int_t, the column index of * the maximum is stored here. * * Time complexity: O(mn), the number of elements. */ void FUNCTION(igraph_matrix, which_minmax)(const TYPE(igraph_matrix) *m, - igraph_integer_t *imin, igraph_integer_t *jmin, - igraph_integer_t *imax, igraph_integer_t *jmax) { - igraph_integer_t vmin, vmax; + igraph_int_t *imin, igraph_int_t *jmin, + igraph_int_t *imax, igraph_int_t *jmax) { + igraph_int_t vmin, vmax; FUNCTION(igraph_vector, which_minmax)(&m->data, &vmin, &vmax); *imin = vmin % m->nrow; *jmin = vmin / m->nrow; @@ -1567,12 +1525,12 @@ igraph_bool_t FUNCTION(igraph_matrix, empty)(const TYPE(igraph_matrix) *m) { igraph_bool_t FUNCTION(igraph_matrix, is_symmetric)(const TYPE(igraph_matrix) *m) { - const igraph_integer_t n = m->nrow; + const igraph_int_t n = m->nrow; if (m->ncol != n) { return false; } - for (igraph_integer_t r = 1; r < n; r++) { - for (igraph_integer_t c = 0; c < r; c++) { + for (igraph_int_t r = 1; r < n; r++) { + for (igraph_int_t c = 0; c < r; c++) { BASE a1 = MATRIX(*m, r, c); BASE a2 = MATRIX(*m, c, r); #ifdef EQ @@ -1622,12 +1580,12 @@ BASE FUNCTION(igraph_matrix, prod)(const TYPE(igraph_matrix) *m) { igraph_error_t FUNCTION(igraph_matrix, rowsum)(const TYPE(igraph_matrix) *m, TYPE(igraph_vector) *res) { - const igraph_integer_t nrow = m->nrow, ncol = m->ncol; + const igraph_int_t nrow = m->nrow, ncol = m->ncol; IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(res, nrow)); FUNCTION(igraph_vector, null)(res); /* Iterate in column-major order for better performance. */ - for (igraph_integer_t c = 0; c < ncol; c++) { - for (igraph_integer_t r = 0; r < nrow; r++) { + for (igraph_int_t c = 0; c < ncol; c++) { + for (igraph_int_t r = 0; r < nrow; r++) { #ifdef SUM SUM(VECTOR(*res)[r], VECTOR(*res)[r], MATRIX(*m, r, c)); #else @@ -1654,11 +1612,11 @@ igraph_error_t FUNCTION(igraph_matrix, rowsum)(const TYPE(igraph_matrix) *m, igraph_error_t FUNCTION(igraph_matrix, colsum)(const TYPE(igraph_matrix) *m, TYPE(igraph_vector) *res) { - const igraph_integer_t nrow = m->nrow, ncol = m->ncol; + const igraph_int_t nrow = m->nrow, ncol = m->ncol; IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(res, ncol)); - for (igraph_integer_t c = 0; c < ncol; c++) { + for (igraph_int_t c = 0; c < ncol; c++) { BASE sum = ZERO; - for (igraph_integer_t r = 0; r < nrow; r++) { + for (igraph_int_t r = 0; r < nrow; r++) { #ifdef SUM SUM(sum, sum, MATRIX(*m, r, c)); #else @@ -1698,11 +1656,11 @@ igraph_bool_t FUNCTION(igraph_matrix, contains)(const TYPE(igraph_matrix) *m, * \param from The position to search from, the positions are * enumerated columnwise. * \param what The element to search for. - * \param pos Pointer to an igraph_integer_t. If the element is + * \param pos Pointer to an igraph_int_t. If the element is * found, then this is set to the position of its first appearance. - * \param row Pointer to an igraph_integer_t. If the element is + * \param row Pointer to an igraph_int_t. If the element is * found, then this is set to its row index. - * \param col Pointer to an igraph_integer_t. If the element is + * \param col Pointer to an igraph_int_t. If the element is * found, then this is set to its column index. * \return Boolean, \c true if the element is found, \c false * otherwise. @@ -1711,8 +1669,8 @@ igraph_bool_t FUNCTION(igraph_matrix, contains)(const TYPE(igraph_matrix) *m, */ igraph_bool_t FUNCTION(igraph_matrix, search)(const TYPE(igraph_matrix) *m, - igraph_integer_t from, BASE what, igraph_integer_t *pos, - igraph_integer_t *row, igraph_integer_t *col) { + igraph_int_t from, BASE what, igraph_int_t *pos, + igraph_int_t *row, igraph_int_t *col) { igraph_bool_t find = FUNCTION(igraph_vector, search)(&m->data, from, what, pos); if (find) { *row = *pos % m->nrow; @@ -1733,9 +1691,9 @@ igraph_bool_t FUNCTION(igraph_matrix, search)(const TYPE(igraph_matrix) *m, * Time complexity: O(mn), the number of elements in the matrix. */ -igraph_error_t FUNCTION(igraph_matrix, remove_row)(TYPE(igraph_matrix) *m, igraph_integer_t row) { +igraph_error_t FUNCTION(igraph_matrix, remove_row)(TYPE(igraph_matrix) *m, igraph_int_t row) { - igraph_integer_t c, r, index = row + 1, leap = 1, n = m->nrow * m->ncol; + igraph_int_t c, r, index = row + 1, leap = 1, n = m->nrow * m->ncol; if (row >= m->nrow) { IGRAPH_ERROR("Cannot remove row, index out of range", IGRAPH_EINVAL); } @@ -1774,9 +1732,9 @@ igraph_error_t FUNCTION(igraph_matrix, remove_row)(TYPE(igraph_matrix) *m, igrap igraph_error_t FUNCTION(igraph_matrix, select_cols)(const TYPE(igraph_matrix) *m, TYPE(igraph_matrix) *res, const igraph_vector_int_t *cols) { - igraph_integer_t ncols = igraph_vector_int_size(cols); - igraph_integer_t nrows = m->nrow; - igraph_integer_t i, j; + igraph_int_t ncols = igraph_vector_int_size(cols); + igraph_int_t nrows = m->nrow; + igraph_int_t i, j; IGRAPH_CHECK(FUNCTION(igraph_matrix, resize)(res, nrows, ncols)); /* Iterate in column-major order for better performance. */ @@ -1792,9 +1750,9 @@ igraph_error_t FUNCTION(igraph_matrix, select_cols)(const TYPE(igraph_matrix) *m #ifndef USING_R igraph_error_t FUNCTION(igraph_matrix, printf)(const TYPE(igraph_matrix) *m, const char *format) { - igraph_integer_t nr = FUNCTION(igraph_matrix, nrow)(m); - igraph_integer_t nc = FUNCTION(igraph_matrix, ncol)(m); - igraph_integer_t i, j; + igraph_int_t nr = FUNCTION(igraph_matrix, nrow)(m); + igraph_int_t nc = FUNCTION(igraph_matrix, ncol)(m); + igraph_int_t i, j; for (i = 0; i < nr; i++) { for (j = 0; j < nc; j++) { @@ -1822,9 +1780,9 @@ igraph_error_t FUNCTION(igraph_matrix, print)(const TYPE(igraph_matrix) *m) { #endif /* USING_R */ igraph_error_t FUNCTION(igraph_matrix, fprint)(const TYPE(igraph_matrix) *m, FILE *file) { - igraph_integer_t nr = FUNCTION(igraph_matrix, nrow)(m); - igraph_integer_t nc = FUNCTION(igraph_matrix, ncol)(m); - igraph_integer_t i, j; + igraph_int_t nr = FUNCTION(igraph_matrix, nrow)(m); + igraph_int_t nc = FUNCTION(igraph_matrix, ncol)(m); + igraph_int_t i, j; igraph_vector_int_t column_width; #ifdef OUT_FORMAT diff --git a/src/vendor/cigraph/src/core/matrix_list.c b/src/vendor/cigraph/src/core/matrix_list.c index f00e5d7d1c5..5d6b295f8a2 100644 --- a/src/vendor/cigraph/src/core/matrix_list.c +++ b/src/vendor/cigraph/src/core/matrix_list.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify diff --git a/src/vendor/cigraph/src/core/memory.c b/src/vendor/cigraph/src/core/memory.c index b3e244c0592..f6164f793f0 100644 --- a/src/vendor/cigraph/src/core/memory.c +++ b/src/vendor/cigraph/src/core/memory.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2003-2024 The igraph development team This program is free software; you can redistribute it and/or modify diff --git a/src/vendor/cigraph/src/core/printing.c b/src/vendor/cigraph/src/core/printing.c index 85635f581b8..8c82ae84b23 100644 --- a/src/vendor/cigraph/src/core/printing.c +++ b/src/vendor/cigraph/src/core/printing.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/core/progress.c b/src/vendor/cigraph/src/core/progress.c index b5021e05f75..11725f1a8ab 100644 --- a/src/vendor/cigraph/src/core/progress.c +++ b/src/vendor/cigraph/src/core/progress.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -30,7 +29,7 @@ static IGRAPH_THREAD_LOCAL char igraph_i_progressmsg_buffer[1000]; /** * \function igraph_progress - * Report progress + * \brief Report the progress of a calculation from an igraph function. * * Note that the usual way to report progress is the \ref IGRAPH_PROGRESS * macro, as that takes care of the return value of the progress @@ -45,25 +44,22 @@ static IGRAPH_THREAD_LOCAL char igraph_i_progressmsg_buffer[1000]; * report progress pass a null pointer here. Users can * write their own progress handlers and functions with progress * reporting, and then pass some meaningfull context here. - * \return If there is a progress handler installed and - * it does not return \c IGRAPH_SUCCESS, then \c IGRAPH_INTERRUPTED - * is returned. + * \return Error code from the progress handler function, or \c IGRAPH_SUCCESS + * if no progress handler function was registered. * * Time complexity: O(1). */ igraph_error_t igraph_progress(const char *message, igraph_real_t percent, void *data) { if (igraph_i_progress_handler) { - if (igraph_i_progress_handler(message, percent, data) != IGRAPH_SUCCESS) { - return IGRAPH_INTERRUPTED; - } + return igraph_i_progress_handler(message, percent, data); } return IGRAPH_SUCCESS; } /** * \function igraph_progressf - * Report progress, printf-like version + * \brief Report the progress of a calculation from an igraph function, printf-like. * * This is a more flexible version of \ref igraph_progress(), with * a printf-like template string. First the template string @@ -84,9 +80,8 @@ igraph_error_t igraph_progress(const char *message, igraph_real_t percent, void * reporting, and then pass some meaningfull context here. * \param ... Additional argument that were specified in the * \p message argument. - * \return If there is a progress handler installed and - * it does not return \c IGRAPH_SUCCESS, then \c IGRAPH_INTERRUPTED - * is returned. + * \return Error code from the progress handler function, or \c IGRAPH_SUCCESS + * if no progress handler function was registered. * \return */ diff --git a/src/vendor/cigraph/src/core/psumtree.c b/src/vendor/cigraph/src/core/psumtree.c index f0bfc73720e..5d9384149fb 100644 --- a/src/vendor/cigraph/src/core/psumtree.c +++ b/src/vendor/cigraph/src/core/psumtree.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA Copyright (C) 2006 Elliot Paquette @@ -87,8 +86,8 @@ * * Time complexity: O(n) for a tree containing n elements */ -igraph_error_t igraph_psumtree_init(igraph_psumtree_t *t, igraph_integer_t size) { - igraph_integer_t vecsize; +igraph_error_t igraph_psumtree_init(igraph_psumtree_t *t, igraph_int_t size) { + igraph_int_t vecsize; IGRAPH_ASSERT(size > 0); @@ -146,7 +145,7 @@ void igraph_psumtree_destroy(igraph_psumtree_t *t) { * * Time complexity: O(1) */ -igraph_real_t igraph_psumtree_get(const igraph_psumtree_t *t, igraph_integer_t idx) { +igraph_real_t igraph_psumtree_get(const igraph_psumtree_t *t, igraph_int_t idx) { const igraph_vector_t *tree = &t->v; return VECTOR(*tree)[t->offset + idx]; } @@ -177,11 +176,11 @@ igraph_real_t igraph_psumtree_get(const igraph_psumtree_t *t, igraph_integer_t i * * Time complexity: O(log n), where n is the number of items in the tree. */ -igraph_error_t igraph_psumtree_search(const igraph_psumtree_t *t, igraph_integer_t *idx, +igraph_error_t igraph_psumtree_search(const igraph_psumtree_t *t, igraph_int_t *idx, igraph_real_t search) { const igraph_vector_t *tree = &t->v; - igraph_integer_t i = 1; - igraph_integer_t size = igraph_vector_size(tree); + igraph_int_t i = 1; + igraph_int_t size = igraph_vector_size(tree); IGRAPH_ASSERT(search >= 0); IGRAPH_ASSERT(search < igraph_psumtree_sum(t)); @@ -216,7 +215,7 @@ igraph_error_t igraph_psumtree_search(const igraph_psumtree_t *t, igraph_integer * * Time complexity: O(log n), where n is the number of items in the tree. */ -igraph_error_t igraph_psumtree_update(igraph_psumtree_t *t, igraph_integer_t idx, +igraph_error_t igraph_psumtree_update(igraph_psumtree_t *t, igraph_int_t idx, igraph_real_t new_value) { const igraph_vector_t *tree = &t->v; igraph_real_t difference; @@ -249,7 +248,7 @@ igraph_error_t igraph_psumtree_update(igraph_psumtree_t *t, igraph_integer_t idx * * Time complexity: O(1). */ -igraph_integer_t igraph_psumtree_size(const igraph_psumtree_t *t) { +igraph_int_t igraph_psumtree_size(const igraph_psumtree_t *t) { return t->size; } diff --git a/src/vendor/cigraph/src/core/set.c b/src/vendor/cigraph/src/core/set.c index a6be5a0964e..5bcfc52aba0 100644 --- a/src/vendor/cigraph/src/core/set.c +++ b/src/vendor/cigraph/src/core/set.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -42,12 +42,12 @@ * Time complexity: operating system dependent, should be around * O(n), n is the expected size of the set. */ -igraph_error_t igraph_set_init(igraph_set_t *set, igraph_integer_t capacity) { - igraph_integer_t alloc_size; +igraph_error_t igraph_set_init(igraph_set_t *set, igraph_int_t capacity) { + igraph_int_t alloc_size; IGRAPH_ASSERT(capacity >= 0); alloc_size = capacity > 0 ? capacity : 1; - set->stor_begin = IGRAPH_CALLOC(alloc_size, igraph_integer_t); + set->stor_begin = IGRAPH_CALLOC(alloc_size, igraph_int_t); if (! set->stor_begin) { IGRAPH_ERROR("Cannot initialize set.", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } @@ -105,16 +105,16 @@ igraph_bool_t igraph_set_inited(igraph_set_t *set) { * Time complexity: operating system dependent, should be around * O(n), n is the new allocated size of the set. */ -igraph_error_t igraph_set_reserve(igraph_set_t *set, igraph_integer_t capacity) { - igraph_integer_t actual_size = igraph_set_size(set); - igraph_integer_t *tmp; +igraph_error_t igraph_set_reserve(igraph_set_t *set, igraph_int_t capacity) { + igraph_int_t actual_size = igraph_set_size(set); + igraph_int_t *tmp; IGRAPH_ASSERT(set != NULL); IGRAPH_ASSERT(set->stor_begin != NULL); if (capacity <= actual_size) { return IGRAPH_SUCCESS; } - tmp = IGRAPH_REALLOC(set->stor_begin, capacity, igraph_integer_t); + tmp = IGRAPH_REALLOC(set->stor_begin, capacity, igraph_int_t); IGRAPH_CHECK_OOM(tmp, "Cannot reserve space for set."); set->stor_begin = tmp; @@ -174,7 +174,7 @@ void igraph_set_clear(igraph_set_t *set) { * Time complexity: O(1). */ -igraph_integer_t igraph_set_size(const igraph_set_t *set) { +igraph_int_t igraph_set_size(const igraph_set_t *set) { IGRAPH_ASSERT(set != NULL); IGRAPH_ASSERT(set->stor_begin != NULL); return set->end - set->stor_begin; @@ -193,9 +193,9 @@ igraph_integer_t igraph_set_size(const igraph_set_t *set) { * * Time complexity: O(log(n)), n is the number of elements in \p set. */ -igraph_error_t igraph_set_add(igraph_set_t *set, igraph_integer_t e) { - igraph_integer_t left, right, middle; - igraph_integer_t size; +igraph_error_t igraph_set_add(igraph_set_t *set, igraph_int_t e) { + igraph_int_t left, right, middle; + igraph_int_t size; IGRAPH_ASSERT(set != NULL); IGRAPH_ASSERT(set->stor_begin != NULL); @@ -226,7 +226,7 @@ igraph_error_t igraph_set_add(igraph_set_t *set, igraph_integer_t e) { if (left >= size || set->stor_begin[left] != e) { /* full, allocate more storage */ if (set->stor_end == set->end) { - igraph_integer_t new_size = size < IGRAPH_INTEGER_MAX/2 ? size * 2 : IGRAPH_INTEGER_MAX; + igraph_int_t new_size = size < IGRAPH_INTEGER_MAX/2 ? size * 2 : IGRAPH_INTEGER_MAX; if (size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot add to set, already at maximum size.", IGRAPH_EOVERFLOW); } @@ -259,8 +259,8 @@ igraph_error_t igraph_set_add(igraph_set_t *set, igraph_integer_t e) { * * Time complexity: O(log(n)), n is the number of elements in \p set. */ -igraph_bool_t igraph_set_contains(const igraph_set_t *set, igraph_integer_t e) { - igraph_integer_t left, right, middle; +igraph_bool_t igraph_set_contains(const igraph_set_t *set, igraph_int_t e) { + igraph_int_t left, right, middle; IGRAPH_ASSERT(set != NULL); IGRAPH_ASSERT(set->stor_begin != NULL); @@ -296,7 +296,7 @@ igraph_bool_t igraph_set_contains(const igraph_set_t *set, igraph_integer_t e) { * * \param set The set object. * \param state Internal state of the iteration. - * This should be a pointer to a \type igraph_integer_t variable + * This should be a pointer to a \type igraph_int_t variable * which must be zero for the first invocation. * The object must not be adjusted and its value should * not be used for anything during the iteration. @@ -305,8 +305,8 @@ igraph_bool_t igraph_set_contains(const igraph_set_t *set, igraph_integer_t e) { * * \return True if there are more elements, false otherwise. */ -igraph_bool_t igraph_set_iterate(const igraph_set_t *set, igraph_integer_t *state, - igraph_integer_t *element) { +igraph_bool_t igraph_set_iterate(const igraph_set_t *set, igraph_int_t *state, + igraph_int_t *element) { IGRAPH_ASSERT(set != 0); IGRAPH_ASSERT(set->stor_begin != 0); IGRAPH_ASSERT(state != 0); diff --git a/src/vendor/cigraph/src/core/set.h b/src/vendor/cigraph/src/core/set.h index cd6c8540d1c..5ac0cdac7cc 100644 --- a/src/vendor/cigraph/src/core/set.h +++ b/src/vendor/cigraph/src/core/set.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2009-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -23,7 +23,7 @@ #include "igraph_error.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* -------------------------------------------------- */ /* Flexible set */ @@ -35,9 +35,9 @@ __BEGIN_DECLS */ typedef struct s_set { - igraph_integer_t* stor_begin; - igraph_integer_t* stor_end; - igraph_integer_t* end; + igraph_int_t* stor_begin; + igraph_int_t* stor_end; + igraph_int_t* end; } igraph_set_t; #define IGRAPH_SET_NULL { 0,0,0 } @@ -45,19 +45,19 @@ typedef struct s_set { do { IGRAPH_CHECK(igraph_set_init(v, size)); \ IGRAPH_FINALLY(igraph_set_destroy, v); } while (0) -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_init(igraph_set_t *set, igraph_integer_t capacity); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_init(igraph_set_t *set, igraph_int_t capacity); IGRAPH_PRIVATE_EXPORT void igraph_set_destroy(igraph_set_t *set); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_set_inited(igraph_set_t *set); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_reserve(igraph_set_t *set, igraph_integer_t capacity); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_reserve(igraph_set_t *set, igraph_int_t capacity); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_set_empty(const igraph_set_t *set); IGRAPH_PRIVATE_EXPORT void igraph_set_clear(igraph_set_t *set); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_set_size(const igraph_set_t *set); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_add(igraph_set_t *set, igraph_integer_t e); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_set_contains(const igraph_set_t *set, igraph_integer_t e); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_set_size(const igraph_set_t *set); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_add(igraph_set_t *set, igraph_int_t e); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_set_contains(const igraph_set_t *set, igraph_int_t e); IGRAPH_PRIVATE_EXPORT igraph_bool_t igraph_set_iterate(const igraph_set_t *set, - igraph_integer_t *state, - igraph_integer_t *element); + igraph_int_t *state, + igraph_int_t *element); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/core/setup.c b/src/vendor/cigraph/src/core/setup.c new file mode 100644 index 00000000000..bef69f0d2f9 --- /dev/null +++ b/src/vendor/cigraph/src/core/setup.c @@ -0,0 +1,67 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "igraph_setup.h" +#include "igraph_random.h" + +#include "random/random_internal.h" + +/** + * \ingroup setup + * \function setup_rng + * \brief Initializes the random number generator. + * + * This function initializes the igraph library by setting up a random seed + * for its internal random number generator. It should be called before + * using any igraph functions that may use random numbers. + * + * \return Error code; currently always \c IGRAPH_SUCCESS. + */ +static igraph_error_t setup_rng(void) { + igraph_rng_t *rng = igraph_rng_default(); + + if (!rng->is_seeded) { + igraph_rng_seed(rng, igraph_i_get_random_seed()); + rng->is_seeded = true; + }; + + return IGRAPH_SUCCESS; +} + +/** + * \ingroup setup + * \function igraph_setup + * \brief Initializes the igraph library. + * + * This function is a convenience function to call all setup functions that are + * provided by the igraph library. + * + * + * Most of the library functions will work even if this function is not called, + * but it is recommended to call it before using any igraph functions that may + * use random numbers, such as graph generators or random sampling functions. + * This function initializes the random number generator with a seed based on + * the current time, ensuring that the random numbers generated by igraph are + * different each time the program is run. + * + * \return Error code; currently always \c IGRAPH_SUCCESS. + */ +igraph_error_t igraph_setup(void) { + IGRAPH_CHECK(setup_rng()); + return IGRAPH_SUCCESS; +} diff --git a/src/vendor/cigraph/src/core/sparsemat.c b/src/vendor/cigraph/src/core/sparsemat.c index ad7457bb00a..f946467ca87 100644 --- a/src/vendor/cigraph/src/core/sparsemat.c +++ b/src/vendor/cigraph/src/core/sparsemat.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2009-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -23,12 +22,8 @@ #include "igraph_sparsemat.h" -#include "igraph_attributes.h" -#include "igraph_constructors.h" -#include "igraph_interface.h" #include "igraph_memory.h" #include "igraph_types.h" -#include "igraph_vector_ptr.h" #include "internal/hacks.h" /* IGRAPH_STATIC_ASSERT */ @@ -110,9 +105,9 @@ static CS_INT igraph_i_sparsemat_count_elements(const igraph_sparsemat_t* A) { * Time complexity: TODO. */ -igraph_error_t igraph_sparsemat_init(igraph_sparsemat_t *A, igraph_integer_t rows, - igraph_integer_t cols, igraph_integer_t nzmax) { - IGRAPH_STATIC_ASSERT(sizeof(igraph_integer_t) == sizeof(CS_INT)); +igraph_error_t igraph_sparsemat_init(igraph_sparsemat_t *A, igraph_int_t rows, + igraph_int_t cols, igraph_int_t nzmax) { + IGRAPH_STATIC_ASSERT(sizeof(igraph_int_t) == sizeof(CS_INT)); IGRAPH_STATIC_ASSERT(sizeof(igraph_real_t) == sizeof(CS_ENTRY)); if (rows < 0) { @@ -172,19 +167,6 @@ igraph_error_t igraph_sparsemat_init_copy( return IGRAPH_SUCCESS; } -/** - * \function igraph_sparsemat_copy - * \brief Copies a sparse matrix (deprecated alias). - * - * \deprecated-by igraph_sparsemat_init_copy 0.10 - */ - -igraph_error_t igraph_sparsemat_copy( - igraph_sparsemat_t *to, const igraph_sparsemat_t *from -) { - return igraph_sparsemat_init_copy(to, from); -} - /** * \function igraph_sparsemat_destroy * \brief Deallocates memory used by a sparse matrix. @@ -216,7 +198,7 @@ void igraph_sparsemat_destroy(igraph_sparsemat_t *A) { * Time complexity: TODO. */ -igraph_error_t igraph_sparsemat_realloc(igraph_sparsemat_t *A, igraph_integer_t nzmax) { +igraph_error_t igraph_sparsemat_realloc(igraph_sparsemat_t *A, igraph_int_t nzmax) { if (!cs_sprealloc(A->cs, nzmax)) { IGRAPH_ERROR("Could not allocate more memory for sparse matrix.", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } @@ -233,7 +215,7 @@ igraph_error_t igraph_sparsemat_realloc(igraph_sparsemat_t *A, igraph_integer_t * Time complexity: O(1). */ -igraph_integer_t igraph_sparsemat_nrow(const igraph_sparsemat_t *A) { +igraph_int_t igraph_sparsemat_nrow(const igraph_sparsemat_t *A) { return A->cs->m; } @@ -247,7 +229,7 @@ igraph_integer_t igraph_sparsemat_nrow(const igraph_sparsemat_t *A) { * Time complexity: O(1). */ -igraph_integer_t igraph_sparsemat_ncol(const igraph_sparsemat_t *A) { +igraph_int_t igraph_sparsemat_ncol(const igraph_sparsemat_t *A) { return A->cs->n; } @@ -360,8 +342,8 @@ static igraph_error_t igraph_i_sparsemat_index_rows(const igraph_sparsemat_t *A, igraph_sparsemat_t II, II2; CS_INT nrow = A->cs->m; - igraph_integer_t idx_rows = igraph_vector_int_size(p); - igraph_integer_t k; + igraph_int_t idx_rows = igraph_vector_int_size(p); + igraph_int_t k; /* Create index matrix */ IGRAPH_CHECK(igraph_sparsemat_init(&II2, idx_rows, nrow, idx_rows)); @@ -397,8 +379,8 @@ static igraph_error_t igraph_i_sparsemat_index_cols(const igraph_sparsemat_t *A, igraph_sparsemat_t JJ, JJ2; CS_INT ncol = A->cs->n; - igraph_integer_t idx_cols = igraph_vector_int_size(q); - igraph_integer_t k; + igraph_int_t idx_cols = igraph_vector_int_size(q); + igraph_int_t k; /* Create index matrix */ IGRAPH_CHECK(igraph_sparsemat_init(&JJ2, ncol, idx_cols, idx_cols)); @@ -463,9 +445,9 @@ igraph_error_t igraph_sparsemat_index(const igraph_sparsemat_t *A, igraph_sparsemat_t II, JJ, II2, JJ2, tmp; CS_INT nrow = A->cs->m; CS_INT ncol = A->cs->n; - igraph_integer_t idx_rows = p ? igraph_vector_int_size(p) : -1; - igraph_integer_t idx_cols = q ? igraph_vector_int_size(q) : -1; - igraph_integer_t k; + igraph_int_t idx_rows = p ? igraph_vector_int_size(p) : -1; + igraph_int_t idx_cols = q ? igraph_vector_int_size(q) : -1; + igraph_int_t k; igraph_sparsemat_t *myres = res, mres; @@ -555,7 +537,7 @@ igraph_error_t igraph_sparsemat_index(const igraph_sparsemat_t *A, */ igraph_error_t igraph_sparsemat_entry(igraph_sparsemat_t *A, - igraph_integer_t row, igraph_integer_t col, igraph_real_t elem) { + igraph_int_t row, igraph_int_t col, igraph_real_t elem) { if (!igraph_sparsemat_is_triplet(A)) { IGRAPH_ERROR("Entries can only be added to sparse matrices that are in triplet format.", IGRAPH_EINVAL); @@ -600,7 +582,7 @@ igraph_error_t igraph_sparsemat_compress(const igraph_sparsemat_t *A, } static igraph_real_t igraph_i_sparsemat_get_cc( - const igraph_sparsemat_t *A, igraph_integer_t row, igraph_integer_t col + const igraph_sparsemat_t *A, igraph_int_t row, igraph_int_t col ) { /* elements in column 'col' are at indices * A->cs->p[col] .. A->cs->p[col+1] (open from right) in @@ -625,7 +607,7 @@ static igraph_real_t igraph_i_sparsemat_get_cc( } static igraph_real_t igraph_i_sparsemat_get_triplet( - const igraph_sparsemat_t *A, igraph_integer_t row, igraph_integer_t col + const igraph_sparsemat_t *A, igraph_int_t row, igraph_int_t col ) { igraph_sparsemat_iterator_t it; igraph_real_t result = 0.0; @@ -657,7 +639,7 @@ static igraph_real_t igraph_i_sparsemat_get_triplet( * Time complexity: TODO. */ igraph_real_t igraph_sparsemat_get( - const igraph_sparsemat_t *A, igraph_integer_t row, igraph_integer_t col + const igraph_sparsemat_t *A, igraph_int_t row, igraph_int_t col ) { if (row < 0 || col < 0 || row >= A->cs->m || col >= A->cs->n) { return 0.0; @@ -704,7 +686,7 @@ igraph_error_t igraph_sparsemat_transpose( static igraph_error_t igraph_i_sparsemat_is_symmetric_cc(const igraph_sparsemat_t *A, igraph_bool_t *result) { igraph_sparsemat_t t, tt; igraph_bool_t res; - igraph_integer_t nz; + igraph_int_t nz; IGRAPH_CHECK(igraph_sparsemat_transpose(A, &t)); IGRAPH_FINALLY(igraph_sparsemat_destroy, &t); @@ -792,7 +774,7 @@ igraph_error_t igraph_sparsemat_dupl(igraph_sparsemat_t *A) { } struct fkeep_wrapper_data { - igraph_integer_t (*fkeep) (igraph_integer_t, igraph_integer_t, igraph_real_t, void*); + igraph_int_t (*fkeep) (igraph_int_t, igraph_int_t, igraph_real_t, void*); void* data; }; @@ -813,8 +795,8 @@ static CS_INT fkeep_wrapper(CS_INT row, CS_INT col, double value, void* data) { * * \param A The input matrix, in column-compressed format. * \param fkeep The filter function. It must take four arguments: the - * first is an \c igraph_integer_t, the row index of the entry, the second is - * another \c igraph_integer_t, the column index. The third is \c igraph_real_t, + * first is an \c igraph_int_t, the row index of the entry, the second is + * another \c igraph_int_t, the column index. The third is \c igraph_real_t, * the value of the entry. The fourth element is a \c void pointer, * the \p other argument is passed here. The function must return * an \c int. If this is zero, then the entry is deleted, otherwise @@ -828,7 +810,7 @@ static CS_INT fkeep_wrapper(CS_INT row, CS_INT col, double value, void* data) { igraph_error_t igraph_sparsemat_fkeep( igraph_sparsemat_t *A, - igraph_integer_t (*fkeep)(igraph_integer_t, igraph_integer_t, igraph_real_t, void*), + igraph_int_t (*fkeep)(igraph_int_t, igraph_int_t, igraph_real_t, void*), void *other ) { struct fkeep_wrapper_data wrapper_data = { @@ -1010,7 +992,7 @@ igraph_error_t igraph_sparsemat_lsolve(const igraph_sparsemat_t *L, igraph_vector_t *res) { if (L->cs->m != L->cs->n) { - IGRAPH_ERROR("Cannot perform lower triangular solve", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Cannot perform lower triangular solve on non-square matrix.", IGRAPH_EINVAL); } if (res != b) { @@ -1018,7 +1000,7 @@ igraph_error_t igraph_sparsemat_lsolve(const igraph_sparsemat_t *L, } if (! cs_lsolve(L->cs, VECTOR(*res))) { - IGRAPH_ERROR("Cannot perform lower triangular solve", IGRAPH_FAILURE); + IGRAPH_ERROR("Cannot perform lower triangular solve.", IGRAPH_FAILURE); } return IGRAPH_SUCCESS; @@ -1044,8 +1026,10 @@ igraph_error_t igraph_sparsemat_ltsolve(const igraph_sparsemat_t *L, igraph_vector_t *res) { if (L->cs->m != L->cs->n) { - IGRAPH_ERROR("Cannot perform transposed lower triangular solve", - IGRAPH_NONSQUARE); + IGRAPH_ERROR( + "Cannot perform transposed lower triangular solve on non-square matrix.", + IGRAPH_EINVAL + ); } if (res != b) { @@ -1053,7 +1037,7 @@ igraph_error_t igraph_sparsemat_ltsolve(const igraph_sparsemat_t *L, } if (!cs_ltsolve(L->cs, VECTOR(*res))) { - IGRAPH_ERROR("Cannot perform lower triangular solve", IGRAPH_FAILURE); + IGRAPH_ERROR("Cannot perform lower triangular solve.", IGRAPH_FAILURE); } return IGRAPH_SUCCESS; @@ -1078,7 +1062,10 @@ igraph_error_t igraph_sparsemat_usolve(const igraph_sparsemat_t *U, igraph_vector_t *res) { if (U->cs->m != U->cs->n) { - IGRAPH_ERROR("Cannot perform upper triangular solve", IGRAPH_NONSQUARE); + IGRAPH_ERROR( + "Cannot perform upper triangular solve on non-square matrix.", + IGRAPH_EINVAL + ); } if (res != b) { @@ -1086,7 +1073,7 @@ igraph_error_t igraph_sparsemat_usolve(const igraph_sparsemat_t *U, } if (! cs_usolve(U->cs, VECTOR(*res))) { - IGRAPH_ERROR("Cannot perform upper triangular solve", IGRAPH_FAILURE); + IGRAPH_ERROR("Cannot perform upper triangular solve.", IGRAPH_FAILURE); } return IGRAPH_SUCCESS; @@ -1112,8 +1099,10 @@ igraph_error_t igraph_sparsemat_utsolve(const igraph_sparsemat_t *U, igraph_vector_t *res) { if (U->cs->m != U->cs->n) { - IGRAPH_ERROR("Cannot perform transposed upper triangular solve", - IGRAPH_NONSQUARE); + IGRAPH_ERROR( + "Cannot perform transposed upper triangular solve on non-square matrix.", + IGRAPH_EINVAL + ); } if (res != b) { @@ -1121,7 +1110,7 @@ igraph_error_t igraph_sparsemat_utsolve(const igraph_sparsemat_t *U, } if (!cs_utsolve(U->cs, VECTOR(*res))) { - IGRAPH_ERROR("Cannot perform transposed upper triangular solve", + IGRAPH_ERROR("Cannot perform transposed upper triangular solve.", IGRAPH_FAILURE); } @@ -1148,11 +1137,13 @@ igraph_error_t igraph_sparsemat_utsolve(const igraph_sparsemat_t *U, igraph_error_t igraph_sparsemat_cholsol(const igraph_sparsemat_t *A, const igraph_vector_t *b, igraph_vector_t *res, - igraph_integer_t order) { + igraph_int_t order) { if (A->cs->m != A->cs->n) { - IGRAPH_ERROR("Cannot perform sparse symmetric solve", - IGRAPH_NONSQUARE); + IGRAPH_ERROR( + "Cannot perform sparse symmetric solve on non-square matrix.", + IGRAPH_EINVAL + ); } if (res != b) { @@ -1160,7 +1151,7 @@ igraph_error_t igraph_sparsemat_cholsol(const igraph_sparsemat_t *A, } if (! cs_cholsol(order, A->cs, VECTOR(*res))) { - IGRAPH_ERROR("Cannot perform sparse symmetric solve", IGRAPH_FAILURE); + IGRAPH_ERROR("Cannot perform sparse symmetric solve.", IGRAPH_FAILURE); } return IGRAPH_SUCCESS; @@ -1189,12 +1180,11 @@ igraph_error_t igraph_sparsemat_cholsol(const igraph_sparsemat_t *A, igraph_error_t igraph_sparsemat_lusol(const igraph_sparsemat_t *A, const igraph_vector_t *b, igraph_vector_t *res, - igraph_integer_t order, + igraph_int_t order, igraph_real_t tol) { if (A->cs->m != A->cs->n) { - IGRAPH_ERROR("Cannot perform LU solve", - IGRAPH_NONSQUARE); + IGRAPH_ERROR("Cannot perform LU solve on non-square matrix.", IGRAPH_EINVAL); } if (res != b) { @@ -1202,218 +1192,12 @@ igraph_error_t igraph_sparsemat_lusol(const igraph_sparsemat_t *A, } if (! cs_lusol(order, A->cs, VECTOR(*res), tol)) { - IGRAPH_ERROR("Cannot perform LU solve", IGRAPH_FAILURE); + IGRAPH_ERROR("Cannot perform LU solve.", IGRAPH_FAILURE); } return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_sparsemat_cc(igraph_t *graph, const igraph_sparsemat_t *A, - igraph_bool_t directed) { - - igraph_vector_int_t edges; - CS_INT no_of_nodes = A->cs->m; - CS_INT no_of_edges = A->cs->p[A->cs->n]; - CS_INT *p = A->cs->p; - CS_INT *i = A->cs->i; - igraph_integer_t from = 0; - igraph_integer_t to = 0; - igraph_integer_t e = 0; - - if (no_of_nodes != A->cs->n) { - IGRAPH_ERROR("Cannot create graph object", IGRAPH_NONSQUARE); - } - - IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges * 2); - - while (*p < no_of_edges) { - while (to < * (p + 1)) { - if (directed || from >= *i) { - VECTOR(edges)[e++] = from; - VECTOR(edges)[e++] = (*i); - } - to++; - i++; - } - from++; - p++; - } - igraph_vector_int_resize(&edges, e); - - IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed)); - igraph_vector_int_destroy(&edges); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} - -static igraph_error_t igraph_i_sparsemat_triplet(igraph_t *graph, const igraph_sparsemat_t *A, - igraph_bool_t directed) { - - igraph_vector_int_t edges; - CS_INT no_of_nodes = A->cs->m; - CS_INT no_of_edges = A->cs->nz; - CS_INT *i = A->cs->p; - CS_INT *j = A->cs->i; - igraph_integer_t e; - - if (no_of_nodes != A->cs->n) { - IGRAPH_ERROR("Cannot create graph object", IGRAPH_NONSQUARE); - } - - IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges * 2); - - for (e = 0; e < 2 * no_of_edges; i++, j++) { - if (directed || *i >= *j) { - VECTOR(edges)[e++] = (*i); - VECTOR(edges)[e++] = (*j); - } - } - igraph_vector_int_resize(&edges, e); - - IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed)); - igraph_vector_int_destroy(&edges); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} - -/** - * \function igraph_sparsemat - * \brief Creates an igraph graph from a sparse matrix. - * - * One edge is created for each non-zero entry in the matrix. If you - * have a symmetric matrix, and want to create an undirected graph, - * then delete the entries in the upper diagonal first, or call \ref - * igraph_simplify() on the result graph to eliminate the multiple - * edges. - * - * \param graph Pointer to an uninitialized igraph_t object, the - * graphs is stored here. - * \param A The input matrix, in triplet or column-compressed format. - * \param directed Whether to create a directed graph. - * \return Error code. - * - * Time complexity: TODO. - */ - -igraph_error_t igraph_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A, - igraph_bool_t directed) { - - if (igraph_sparsemat_is_cc(A)) { - return (igraph_i_sparsemat_cc(graph, A, directed)); - } else { - return (igraph_i_sparsemat_triplet(graph, A, directed)); - } -} - -static igraph_error_t igraph_i_weighted_sparsemat_cc(const igraph_sparsemat_t *A, - igraph_bool_t directed, const char *attr, - igraph_bool_t loops, - igraph_vector_int_t *edges, - igraph_vector_t *weights) { - - CS_INT no_of_edges = A->cs->p[A->cs->n]; - CS_INT *p = A->cs->p; - CS_INT *i = A->cs->i; - CS_ENTRY *x = A->cs->x; - igraph_integer_t from = 0; - igraph_integer_t to = 0; - igraph_integer_t e = 0, w = 0; - - IGRAPH_UNUSED(attr); - - IGRAPH_CHECK(igraph_vector_int_resize(edges, no_of_edges * 2)); - IGRAPH_CHECK(igraph_vector_resize(weights, no_of_edges)); - - while (*p < no_of_edges) { - while (to < * (p + 1)) { - if ( (loops || from != *i) && (directed || from >= *i) && *x != 0) { - VECTOR(*edges)[e++] = (*i); - VECTOR(*edges)[e++] = from; - VECTOR(*weights)[w++] = (*x); - } - to++; - i++; - x++; - } - from++; - p++; - } - - igraph_vector_int_resize(edges, e); /* shrinks */ - igraph_vector_resize(weights, w); /* shrinks */ - - return IGRAPH_SUCCESS; -} - -static igraph_error_t igraph_i_weighted_sparsemat_triplet(const igraph_sparsemat_t *A, - igraph_bool_t directed, - const char *attr, - igraph_bool_t loops, - igraph_vector_int_t *edges, - igraph_vector_t *weights) { - - IGRAPH_UNUSED(A); IGRAPH_UNUSED(directed); IGRAPH_UNUSED(attr); - IGRAPH_UNUSED(loops); IGRAPH_UNUSED(edges); IGRAPH_UNUSED(weights); - - /* TODO */ - IGRAPH_ERROR("Triplet matrices are not implemented", - IGRAPH_UNIMPLEMENTED); -} - -igraph_error_t igraph_weighted_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A, - igraph_bool_t directed, const char *attr, - igraph_bool_t loops) { - - igraph_vector_int_t edges; - igraph_vector_t weights; - CS_INT pot_edges = igraph_i_sparsemat_count_elements(A); - const char* default_attr = "weight"; - igraph_vector_ptr_t attr_vec; - igraph_attribute_record_t attr_rec; - CS_INT no_of_nodes = A->cs->m; - - if (no_of_nodes != A->cs->n) { - IGRAPH_ERROR("Cannot create graph object", IGRAPH_NONSQUARE); - } - - IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, pot_edges * 2); - IGRAPH_VECTOR_INIT_FINALLY(&weights, pot_edges); - IGRAPH_VECTOR_PTR_INIT_FINALLY(&attr_vec, 1); - - if (igraph_sparsemat_is_cc(A)) { - IGRAPH_CHECK(igraph_i_weighted_sparsemat_cc(A, directed, attr, loops, - &edges, &weights)); - } else { - IGRAPH_CHECK(igraph_i_weighted_sparsemat_triplet(A, directed, attr, - loops, &edges, - &weights)); - } - - /* Prepare attribute record */ - attr_rec.name = attr ? attr : default_attr; - attr_rec.type = IGRAPH_ATTRIBUTE_NUMERIC; - attr_rec.value = &weights; - VECTOR(attr_vec)[0] = &attr_rec; - - /* Create graph */ - IGRAPH_CHECK(igraph_empty(graph, no_of_nodes, directed)); - IGRAPH_FINALLY(igraph_destroy, graph); - if (igraph_vector_int_size(&edges) > 0) { - IGRAPH_CHECK(igraph_add_edges(graph, &edges, &attr_vec)); - } - IGRAPH_FINALLY_CLEAN(1); - - /* Cleanup */ - igraph_vector_int_destroy(&edges); - igraph_vector_destroy(&weights); - igraph_vector_ptr_destroy(&attr_vec); - IGRAPH_FINALLY_CLEAN(3); - - return IGRAPH_SUCCESS; -} - #define CHECK(x) if ((x)<0) { IGRAPH_ERROR("Cannot write to file", IGRAPH_EFILE); } /** @@ -1461,10 +1245,10 @@ igraph_error_t igraph_sparsemat_print(const igraph_sparsemat_t *A, #undef CHECK static igraph_error_t igraph_i_sparsemat_eye_triplet( - igraph_sparsemat_t *A, igraph_integer_t n, igraph_integer_t nzmax, + igraph_sparsemat_t *A, igraph_int_t n, igraph_int_t nzmax, igraph_real_t value ) { - igraph_integer_t i; + igraph_int_t i; IGRAPH_CHECK(igraph_sparsemat_init(A, n, n, nzmax)); @@ -1476,9 +1260,9 @@ static igraph_error_t igraph_i_sparsemat_eye_triplet( } static igraph_error_t igraph_i_sparsemat_eye_cc( - igraph_sparsemat_t *A, igraph_integer_t n, igraph_real_t value + igraph_sparsemat_t *A, igraph_int_t n, igraph_real_t value ) { - igraph_integer_t i; + igraph_int_t i; A->cs = cs_spalloc(n, n, n, /*values=*/ 1, /*triplet=*/ 0); if (!A->cs) { @@ -1514,7 +1298,7 @@ static igraph_error_t igraph_i_sparsemat_eye_cc( */ igraph_error_t igraph_sparsemat_init_eye( - igraph_sparsemat_t *A, igraph_integer_t n, igraph_integer_t nzmax, + igraph_sparsemat_t *A, igraph_int_t n, igraph_int_t nzmax, igraph_real_t value, igraph_bool_t compress ) { if (compress) { @@ -1524,22 +1308,8 @@ igraph_error_t igraph_sparsemat_init_eye( } } -/** - * \function igraph_sparsemat_eye - * \brief Creates a sparse identity matrix (deprecated alias). - * - * \deprecated-by igraph_sparsemat_init_eye 0.10 - */ - -igraph_error_t igraph_sparsemat_eye( - igraph_sparsemat_t *A, igraph_integer_t n, igraph_integer_t nzmax, - igraph_real_t value, igraph_bool_t compress -) { - return igraph_sparsemat_init_eye(A, n, nzmax, value, compress); -} - static igraph_error_t igraph_i_sparsemat_init_diag_triplet( - igraph_sparsemat_t *A, igraph_integer_t nzmax, const igraph_vector_t *values + igraph_sparsemat_t *A, igraph_int_t nzmax, const igraph_vector_t *values ) { CS_INT i, n = igraph_vector_size(values); @@ -1594,7 +1364,7 @@ static igraph_error_t igraph_i_sparsemat_init_diag_cc(igraph_sparsemat_t *A, */ igraph_error_t igraph_sparsemat_init_diag( - igraph_sparsemat_t *A, igraph_integer_t nzmax, const igraph_vector_t *values, + igraph_sparsemat_t *A, igraph_int_t nzmax, const igraph_vector_t *values, igraph_bool_t compress ) { if (compress) { @@ -1604,30 +1374,17 @@ igraph_error_t igraph_sparsemat_init_diag( } } -/** - * \function igraph_sparsemat_diag - * \brief Creates a sparse diagonal matrix (deprecated alias). - * - * \deprecated-by igraph_sparsemat_init_diag 0.10 - */ - -igraph_error_t igraph_sparsemat_diag( - igraph_sparsemat_t *A, igraph_integer_t nzmax, const igraph_vector_t *values, - igraph_bool_t compress -) { - return igraph_sparsemat_init_diag(A, nzmax, values, compress); -} - static igraph_error_t igraph_i_sparsemat_arpack_multiply(igraph_real_t *to, const igraph_real_t *from, int n, void *extra) { igraph_sparsemat_t *A = extra; - igraph_vector_t vto, vfrom; - igraph_vector_view(&vto, to, n); - igraph_vector_view(&vfrom, from, n); + const igraph_vector_t vfrom = igraph_vector_view(from, n); + igraph_vector_t vto = igraph_vector_view(to, n); + igraph_vector_null(&vto); IGRAPH_CHECK(igraph_sparsemat_gaxpy(A, &vfrom, &vto)); + return IGRAPH_SUCCESS; } @@ -1644,10 +1401,8 @@ static igraph_error_t igraph_i_sparsemat_arpack_solve(igraph_real_t *to, void *extra) { igraph_i_sparsemat_arpack_rssolve_data_t *data = extra; - igraph_vector_t vfrom, vto; - - igraph_vector_view(&vfrom, from, n); - igraph_vector_view(&vto, to, n); + const igraph_vector_t vfrom = igraph_vector_view(from, n); + igraph_vector_t vto = igraph_vector_view(to, n); if (data->method == IGRAPH_SPARSEMAT_SOLVE_LU) { IGRAPH_CHECK(igraph_sparsemat_luresol(data->dis, data->din, &vfrom, @@ -1699,14 +1454,14 @@ igraph_error_t igraph_sparsemat_arpack_rssolve(const igraph_sparsemat_t *A, igraph_matrix_t *vectors, igraph_sparsemat_solve_t solvemethod) { - igraph_integer_t n = igraph_sparsemat_nrow(A); + igraph_int_t n = igraph_sparsemat_nrow(A); if (n != igraph_sparsemat_ncol(A)) { - IGRAPH_ERROR("Non-square matrix for ARPACK", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Non-square matrix for ARPACK.", IGRAPH_EINVAL); } if (n > INT_MAX) { - IGRAPH_ERROR("Matrix too large for ARPACK", IGRAPH_EOVERFLOW); + IGRAPH_ERROR("Matrix too large for ARPACK.", IGRAPH_EOVERFLOW); } if (options == 0) { @@ -1803,14 +1558,14 @@ igraph_error_t igraph_sparsemat_arpack_rnsolve(const igraph_sparsemat_t *A, igraph_matrix_t *values, igraph_matrix_t *vectors) { - igraph_integer_t n = igraph_sparsemat_nrow(A); + igraph_int_t n = igraph_sparsemat_nrow(A); if (n > INT_MAX) { - IGRAPH_ERROR("Matrix too large for ARPACK", IGRAPH_EOVERFLOW); + IGRAPH_ERROR("Matrix too large for ARPACK.", IGRAPH_EOVERFLOW); } if (n != igraph_sparsemat_ncol(A)) { - IGRAPH_ERROR("Non-square matrix for ARPACK", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Non-square matrix for ARPACK.", IGRAPH_EINVAL); } if (options == 0) { @@ -1845,7 +1600,7 @@ igraph_error_t igraph_sparsemat_arpack_rnsolve(const igraph_sparsemat_t *A, * Time complexity: TODO. */ -igraph_error_t igraph_sparsemat_symbqr(igraph_integer_t order, const igraph_sparsemat_t *A, +igraph_error_t igraph_sparsemat_symbqr(igraph_int_t order, const igraph_sparsemat_t *A, igraph_sparsemat_symbolic_t *dis) { dis->symbolic = cs_sqr(order, A->cs, /*qr=*/ 1); @@ -1876,7 +1631,7 @@ igraph_error_t igraph_sparsemat_symbqr(igraph_integer_t order, const igraph_spar * Time complexity: TODO. */ -igraph_error_t igraph_sparsemat_symblu(igraph_integer_t order, const igraph_sparsemat_t *A, +igraph_error_t igraph_sparsemat_symblu(igraph_int_t order, const igraph_sparsemat_t *A, igraph_sparsemat_symbolic_t *dis) { dis->symbolic = cs_sqr(order, A->cs, /*qr=*/ 0); @@ -1970,7 +1725,7 @@ igraph_error_t igraph_sparsemat_luresol(const igraph_sparsemat_symbolic_t *dis, const igraph_sparsemat_numeric_t *din, const igraph_vector_t *b, igraph_vector_t *res) { - igraph_integer_t n = din->numeric->L->n; + igraph_int_t n = din->numeric->L->n; igraph_real_t *workspace; if (res != b) { @@ -2026,9 +1781,9 @@ igraph_error_t igraph_sparsemat_qrresol(const igraph_sparsemat_symbolic_t *dis, const igraph_sparsemat_numeric_t *din, const igraph_vector_t *b, igraph_vector_t *res) { - igraph_integer_t n = din->numeric->L->n; + igraph_int_t n = din->numeric->L->n; igraph_real_t *workspace; - igraph_integer_t k; + igraph_int_t k; if (res != b) { IGRAPH_CHECK(igraph_vector_update(res, b)); @@ -2117,9 +1872,9 @@ void igraph_sparsemat_numeric_destroy(igraph_sparsemat_numeric_t *din) { igraph_error_t igraph_matrix_as_sparsemat(igraph_sparsemat_t *res, const igraph_matrix_t *mat, igraph_real_t tol) { - igraph_integer_t nrow = igraph_matrix_nrow(mat); - igraph_integer_t ncol = igraph_matrix_ncol(mat); - igraph_integer_t i, j, nzmax = 0; + igraph_int_t nrow = igraph_matrix_nrow(mat); + igraph_int_t ncol = igraph_matrix_ncol(mat); + igraph_int_t i, j, nzmax = 0; for (i = 0; i < nrow; i++) { for (j = 0; j < ncol; j++) { @@ -2145,8 +1900,8 @@ igraph_error_t igraph_matrix_as_sparsemat(igraph_sparsemat_t *res, static igraph_error_t igraph_i_sparsemat_as_matrix_cc(igraph_matrix_t *res, const igraph_sparsemat_t *spmat) { - igraph_integer_t nrow = igraph_sparsemat_nrow(spmat); - igraph_integer_t ncol = igraph_sparsemat_ncol(spmat); + igraph_int_t nrow = igraph_sparsemat_nrow(spmat); + igraph_int_t ncol = igraph_sparsemat_ncol(spmat); CS_INT from = 0, to = 0; CS_INT *p = spmat->cs->p; CS_INT *i = spmat->cs->i; @@ -2172,8 +1927,8 @@ static igraph_error_t igraph_i_sparsemat_as_matrix_cc(igraph_matrix_t *res, static igraph_error_t igraph_i_sparsemat_as_matrix_triplet(igraph_matrix_t *res, const igraph_sparsemat_t *spmat) { - igraph_integer_t nrow = igraph_sparsemat_nrow(spmat); - igraph_integer_t ncol = igraph_sparsemat_ncol(spmat); + igraph_int_t nrow = igraph_sparsemat_nrow(spmat); + igraph_int_t ncol = igraph_sparsemat_ncol(spmat); CS_INT *i = spmat->cs->p; CS_INT *j = spmat->cs->i; CS_ENTRY *x = spmat->cs->x; @@ -2333,10 +2088,10 @@ igraph_error_t igraph_sparsemat_minmax(igraph_sparsemat_t *A, * Time complexity: TODO. */ -igraph_integer_t igraph_sparsemat_count_nonzero(igraph_sparsemat_t *A) { +igraph_int_t igraph_sparsemat_count_nonzero(igraph_sparsemat_t *A) { CS_INT i, n; CS_ENTRY *ptr; - igraph_integer_t res = 0; + igraph_int_t res = 0; IGRAPH_CHECK(igraph_sparsemat_dupl(A)); @@ -2366,11 +2121,11 @@ igraph_integer_t igraph_sparsemat_count_nonzero(igraph_sparsemat_t *A) { * Time complexity: TODO. */ -igraph_integer_t igraph_sparsemat_count_nonzerotol(igraph_sparsemat_t *A, +igraph_int_t igraph_sparsemat_count_nonzerotol(igraph_sparsemat_t *A, igraph_real_t tol) { CS_INT i, n; CS_ENTRY *ptr; - igraph_integer_t res = 0; + igraph_int_t res = 0; IGRAPH_CHECK(igraph_sparsemat_dupl(A)); @@ -2685,7 +2440,7 @@ static igraph_error_t igraph_i_sparsemat_which_min_rows_cc(igraph_sparsemat_t *A CS_ENTRY *px; CS_INT *pp; CS_INT *pi; - igraph_integer_t j; + igraph_int_t j; IGRAPH_CHECK(igraph_sparsemat_dupl(A)); @@ -2751,7 +2506,7 @@ static igraph_error_t igraph_i_sparsemat_which_min_cols_cc(igraph_sparsemat_t *A CS_INT n, j, p; CS_ENTRY *px; double *pr; - igraph_integer_t *ppos; + igraph_int_t *ppos; IGRAPH_CHECK(igraph_sparsemat_dupl(A)); @@ -2884,7 +2639,7 @@ igraph_error_t igraph_sparsemat_scale(igraph_sparsemat_t *A, igraph_real_t by) { * Time complexity: O(1). */ -igraph_error_t igraph_sparsemat_add_rows(igraph_sparsemat_t *A, igraph_integer_t n) { +igraph_error_t igraph_sparsemat_add_rows(igraph_sparsemat_t *A, igraph_int_t n) { A->cs->m += n; return IGRAPH_SUCCESS; } @@ -2902,7 +2657,7 @@ igraph_error_t igraph_sparsemat_add_rows(igraph_sparsemat_t *A, igraph_integer_t * Time complexity: TODO. */ -igraph_error_t igraph_sparsemat_add_cols(igraph_sparsemat_t *A, igraph_integer_t n) { +igraph_error_t igraph_sparsemat_add_cols(igraph_sparsemat_t *A, igraph_int_t n) { if (igraph_sparsemat_is_triplet(A)) { A->cs->n += n; } else { @@ -2938,8 +2693,8 @@ igraph_error_t igraph_sparsemat_add_cols(igraph_sparsemat_t *A, igraph_integer_t * Time complexity: O(nzmax), the maximum number of non-zero elements. */ -igraph_error_t igraph_sparsemat_resize(igraph_sparsemat_t *A, igraph_integer_t nrow, - igraph_integer_t ncol, igraph_integer_t nzmax) { +igraph_error_t igraph_sparsemat_resize(igraph_sparsemat_t *A, igraph_int_t nrow, + igraph_int_t ncol, igraph_int_t nzmax) { if (igraph_sparsemat_is_cc(A)) { igraph_sparsemat_t tmp; @@ -2971,7 +2726,7 @@ igraph_error_t igraph_sparsemat_resize(igraph_sparsemat_t *A, igraph_integer_t n * Time complexity: O(1). */ -igraph_integer_t igraph_sparsemat_nonzero_storage(const igraph_sparsemat_t *A) { +igraph_int_t igraph_sparsemat_nonzero_storage(const igraph_sparsemat_t *A) { return igraph_i_sparsemat_count_elements(A); } @@ -3089,10 +2844,10 @@ igraph_error_t igraph_sparsemat_multiply_by_dense(const igraph_sparsemat_t *A, const igraph_matrix_t *B, igraph_matrix_t *res) { - igraph_integer_t m = igraph_sparsemat_nrow(A); - igraph_integer_t n = igraph_sparsemat_ncol(A); - igraph_integer_t p = igraph_matrix_ncol(B); - igraph_integer_t i; + igraph_int_t m = igraph_sparsemat_nrow(A); + igraph_int_t n = igraph_sparsemat_ncol(A); + igraph_int_t p = igraph_matrix_ncol(B); + igraph_int_t i; if (igraph_matrix_nrow(B) != n) { IGRAPH_ERROR("Invalid dimensions in sparse-dense matrix product", @@ -3115,10 +2870,10 @@ igraph_error_t igraph_sparsemat_multiply_by_dense(const igraph_sparsemat_t *A, igraph_error_t igraph_sparsemat_dense_multiply(const igraph_matrix_t *A, const igraph_sparsemat_t *B, igraph_matrix_t *res) { - igraph_integer_t m = igraph_matrix_nrow(A); - igraph_integer_t n = igraph_matrix_ncol(A); - igraph_integer_t p = igraph_sparsemat_ncol(B); - igraph_integer_t r, c; + igraph_int_t m = igraph_matrix_nrow(A); + igraph_int_t n = igraph_matrix_ncol(A); + igraph_int_t p = igraph_sparsemat_ncol(B); + igraph_int_t r, c; CS_INT *Bp = B->cs->p; if (igraph_sparsemat_nrow(B) != n) { @@ -3136,7 +2891,7 @@ igraph_error_t igraph_sparsemat_dense_multiply(const igraph_matrix_t *A, for (c = 0; c < p; c++) { for (r = 0; r < m; r++) { - igraph_integer_t idx = *Bp; + igraph_int_t idx = *Bp; while (idx < * (Bp + 1)) { MATRIX(*res, r, c) += MATRIX(*A, r, B->cs->i[idx]) * B->cs->x[idx]; idx++; @@ -3148,74 +2903,6 @@ igraph_error_t igraph_sparsemat_dense_multiply(const igraph_matrix_t *A, return IGRAPH_SUCCESS; } -/** - * \function igraph_sparsemat_view - * \brief Initialize a sparse matrix and set all parameters. - * - * This function can be used to temporarily handle existing sparse matrix data, - * usually created by another software library, as an \c igraph_sparsemat_t object, - * and thus avoid unnecessary copying. It supports data stored in either the - * compressed sparse column format, or the (i, j, x) triplet format - * where \c i and \c j are the matrix indices of a non-zero element, and \c x - * is its value. - * - * - * The compressed sparse column (or row) format is commonly used to represent - * sparse matrix data. It consists of three vectors, the \p p column pointers, the - * \p i row indices, and the \p x values. p[k] is the number - * of non-zero entires in matrix columns k-1 and lower. - * p[0] is always zero and p[n] is always the total - * number of non-zero entires in the matrix. i[l] is the row index - * of the \c l-th stored element, while x[l] is its value. - * If a matrix element with indices (j, k) is explicitly stored, - * it must be located between positions p[k] and p[k+1] - 1 - * (inclusive) in the \p i and \p x vectors. - * - * - * Do not call \ref igraph_sparsemat_destroy() on a sparse matrix created with - * this function. Instead, \ref igraph_free() must be called on the \c cs - * field of \p A to free the storage allocated by this function. - * - * - * Warning: Matrices created with this function must not be used with functions - * that may reallocate the underlying storage, such as \ref igraph_sparsemat_entry(). - * - * \param A The non-initialized sparse matrix. - * \param nzmax The maximum number of entries, typically the actual number of entries. - * \param m The number of matrix rows. - * \param n The number of matrix columns. - * \param p For a compressed matrix, this is the column pointer vector, and - * must be of size n+1. For a triplet format matrix, it - * is a vector of column indices and must be of size \p nzmax. - * \param i The row vector. This should contain the row indices of the - * elements in \p x. It must be of size \p nzmax. - * \param x The values of the non-zero elements of the sparse matrix. - * It must be of size \p nzmax. - * \param nz For a compressed matrix, is must be -1. For a triplet format - * matrix, is must contain the number of entries. - * \return Error code. - * - * Time complexity: O(1). - */ - -igraph_error_t igraph_sparsemat_view(igraph_sparsemat_t *A, igraph_integer_t nzmax, igraph_integer_t m, igraph_integer_t n, - igraph_integer_t *p, igraph_integer_t *i, igraph_real_t *x, igraph_integer_t nz) { - - A->cs = IGRAPH_CALLOC(1, cs_igraph); - - IGRAPH_CHECK_OOM(A->cs, "Insufficient memory to create sparsemat view."); - - A->cs->nzmax = nzmax; - A->cs->m = m; - A->cs->n = n; - A->cs->p = (CS_INT*) p; - A->cs->i = (CS_INT*) i; - A->cs->x = x; - A->cs->nz = nz; - - return IGRAPH_SUCCESS; -} - /** * \function igraph_sparsemat_sort @@ -3335,7 +3022,7 @@ igraph_error_t igraph_sparsemat_getelements_sorted(const igraph_sparsemat_t *A, return IGRAPH_SUCCESS; } -igraph_integer_t igraph_sparsemat_nzmax(const igraph_sparsemat_t *A) { +igraph_int_t igraph_sparsemat_nzmax(const igraph_sparsemat_t *A) { return A->cs->nzmax; } @@ -3367,12 +3054,12 @@ igraph_error_t igraph_sparsemat_normalize_cols( igraph_sparsemat_t *sparsemat, igraph_bool_t allow_zeros ) { igraph_vector_t sum; - const igraph_integer_t no_of_nodes = igraph_sparsemat_nrow(sparsemat); + const igraph_int_t no_of_nodes = igraph_sparsemat_nrow(sparsemat); IGRAPH_VECTOR_INIT_FINALLY(&sum, no_of_nodes); IGRAPH_CHECK(igraph_sparsemat_colsums(sparsemat, &sum)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(sum)[i] != 0.0) { VECTOR(sum)[i] = 1.0 / VECTOR(sum)[i]; } else if (!allow_zeros) { @@ -3403,12 +3090,12 @@ igraph_error_t igraph_sparsemat_normalize_rows( igraph_sparsemat_t *sparsemat, igraph_bool_t allow_zeros ) { igraph_vector_t sum; - const igraph_integer_t no_of_nodes = igraph_sparsemat_nrow(sparsemat); + const igraph_int_t no_of_nodes = igraph_sparsemat_nrow(sparsemat); IGRAPH_VECTOR_INIT_FINALLY(&sum, no_of_nodes); IGRAPH_CHECK(igraph_sparsemat_rowsums(sparsemat, &sum)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(sum)[i] != 0.0) { VECTOR(sum)[i] = 1.0 / VECTOR(sum)[i]; } else if (!allow_zeros) { @@ -3493,7 +3180,7 @@ igraph_sparsemat_iterator_end(const igraph_sparsemat_iterator_t *it) { * Time complexity: O(1). */ -igraph_integer_t igraph_sparsemat_iterator_row(const igraph_sparsemat_iterator_t *it) { +igraph_int_t igraph_sparsemat_iterator_row(const igraph_sparsemat_iterator_t *it) { return it->mat->cs->i[it->pos]; } @@ -3507,7 +3194,7 @@ igraph_integer_t igraph_sparsemat_iterator_row(const igraph_sparsemat_iterator_t * Time complexity: O(1). */ -igraph_integer_t igraph_sparsemat_iterator_col(const igraph_sparsemat_iterator_t *it) { +igraph_int_t igraph_sparsemat_iterator_col(const igraph_sparsemat_iterator_t *it) { if (igraph_sparsemat_is_triplet(it->mat)) { return it->mat->cs->p[it->pos]; } else { @@ -3540,7 +3227,7 @@ igraph_sparsemat_iterator_get(const igraph_sparsemat_iterator_t *it) { * Time complexity: O(n), the number of columns of the sparse matrix. */ -igraph_integer_t igraph_sparsemat_iterator_next(igraph_sparsemat_iterator_t *it) { +igraph_int_t igraph_sparsemat_iterator_next(igraph_sparsemat_iterator_t *it) { it->pos += 1; while (it->col < it->mat->cs->n && it->mat->cs->p[it->col + 1] == it->pos) { @@ -3559,6 +3246,6 @@ igraph_integer_t igraph_sparsemat_iterator_next(igraph_sparsemat_iterator_t *it) * Time complexity: O(1). */ -igraph_integer_t igraph_sparsemat_iterator_idx(const igraph_sparsemat_iterator_t *it) { +igraph_int_t igraph_sparsemat_iterator_idx(const igraph_sparsemat_iterator_t *it) { return it->pos; } diff --git a/src/vendor/cigraph/src/core/stack.c b/src/vendor/cigraph/src/core/stack.c index 69b3b3efef9..0f567d4f200 100644 --- a/src/vendor/cigraph/src/core/stack.c +++ b/src/vendor/cigraph/src/core/stack.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/core/stack.pmt b/src/vendor/cigraph/src/core/stack.pmt index 4be8cff534d..cfc7bed3793 100644 --- a/src/vendor/cigraph/src/core/stack.pmt +++ b/src/vendor/cigraph/src/core/stack.pmt @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -42,8 +41,8 @@ * Time complexity: O(\p size). */ -igraph_error_t FUNCTION(igraph_stack, init)(TYPE(igraph_stack)* s, igraph_integer_t capacity) { - igraph_integer_t alloc_size; +igraph_error_t FUNCTION(igraph_stack, init)(TYPE(igraph_stack)* s, igraph_int_t capacity) { + igraph_int_t alloc_size; IGRAPH_ASSERT(capacity >= 0); alloc_size = capacity > 0 ? capacity : 1; IGRAPH_ASSERT(s != NULL); @@ -96,7 +95,7 @@ void FUNCTION(igraph_stack, destroy) (TYPE(igraph_stack)* s) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_stack, capacity)(const TYPE(igraph_stack) *s) { +igraph_int_t FUNCTION(igraph_stack, capacity)(const TYPE(igraph_stack) *s) { return s->stor_end - s->stor_begin; } @@ -116,8 +115,8 @@ igraph_integer_t FUNCTION(igraph_stack, capacity)(const TYPE(igraph_stack) *s) { * the stack. */ -igraph_error_t FUNCTION(igraph_stack, reserve)(TYPE(igraph_stack)* s, igraph_integer_t capacity) { - igraph_integer_t current_capacity; +igraph_error_t FUNCTION(igraph_stack, reserve)(TYPE(igraph_stack)* s, igraph_int_t capacity) { + igraph_int_t current_capacity; BASE *tmp; IGRAPH_ASSERT(s != NULL); @@ -169,7 +168,7 @@ igraph_bool_t FUNCTION(igraph_stack, empty)(TYPE(igraph_stack)* s) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_stack, size)(const TYPE(igraph_stack)* s) { +igraph_int_t FUNCTION(igraph_stack, size)(const TYPE(igraph_stack)* s) { IGRAPH_ASSERT(s != NULL); IGRAPH_ASSERT(s->stor_begin != NULL); return s->end - s->stor_begin; @@ -212,8 +211,8 @@ igraph_error_t FUNCTION(igraph_stack, push)(TYPE(igraph_stack)* s, BASE elem) { if (s->stor_end == s->end) { /* full, allocate more storage */ - igraph_integer_t old_size = FUNCTION(igraph_stack, size)(s); - igraph_integer_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; + igraph_int_t old_size = FUNCTION(igraph_stack, size)(s); + igraph_int_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; if (old_size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot push to stack, already at maximum size.", IGRAPH_EOVERFLOW); } @@ -284,7 +283,7 @@ igraph_error_t FUNCTION(igraph_stack, print)(const TYPE(igraph_stack) *s) { #endif /* USING_R */ igraph_error_t FUNCTION(igraph_stack, fprint)(const TYPE(igraph_stack) *s, FILE *file) { - igraph_integer_t i, n = FUNCTION(igraph_stack, size)(s); + igraph_int_t i, n = FUNCTION(igraph_stack, size)(s); if (n != 0) { #ifdef FPRINTFUNC FPRINTFUNC(file, s->stor_begin[0]); diff --git a/src/vendor/cigraph/src/core/statusbar.c b/src/vendor/cigraph/src/core/statusbar.c index 503bb34e44e..b56e113b528 100644 --- a/src/vendor/cigraph/src/core/statusbar.c +++ b/src/vendor/cigraph/src/core/statusbar.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -39,26 +38,24 @@ static IGRAPH_THREAD_LOCAL igraph_status_handler_t *igraph_i_status_handler = 0; * one. Otherwise it does nothing. Note that the standard way to * report the status from an igraph function is the * \ref IGRAPH_STATUS or \ref IGRAPH_STATUSF macro, as these - * take care of the termination of the calling function if the - * status handler returns with \c IGRAPH_INTERRUPTED. + * take care of cleaning up allocated memory from the calling + * function if the status handler returns with an error code. * * \param message The status message. * \param data Additional context, with user-defined semantics. * Existing igraph functions pass a null pointer here. - * \return Error code. If a status handler function was called - * and it did not return with \c IGRAPH_SUCCESS, then - * \c IGRAPH_INTERRUPTED is returned by \c igraph_status(). + * \return Error code from the status handler function, or \c IGRAPH_SUCCESS + * if no status handler function was registered. * * Time complexity: O(1). */ igraph_error_t igraph_status(const char *message, void *data) { if (igraph_i_status_handler) { - if (igraph_i_status_handler(message, data) != IGRAPH_SUCCESS) { - return IGRAPH_INTERRUPTED; - } + return igraph_i_status_handler(message, data); + } else { + return IGRAPH_SUCCESS; } - return IGRAPH_SUCCESS; } /** @@ -69,15 +66,15 @@ igraph_error_t igraph_status(const char *message, void *data) { * that has a syntax similar to the \c printf standard C library function. * It substitutes the values of the additional arguments into the * \p message template string and calls \ref igraph_status(). + * * \param message Status message template string, the syntax is the same * as for the \c printf function. * \param data Additional context, with user-defined semantics. * Existing igraph functions pass a null pointer here. * \param ... The additional arguments to fill the template given in the * \p message argument. - * \return Error code. If a status handler function was called - * and it did not return with \c IGRAPH_SUCCESS, then - * \c IGRAPH_INTERRUPTED is returned by \ref igraph_status(). + * \return Error code from the status handler function, or \c IGRAPH_SUCCESS + * if no status handler function was registered. */ igraph_error_t igraph_statusf(const char *message, void *data, ...) { diff --git a/src/vendor/cigraph/src/core/strvector.c b/src/vendor/cigraph/src/core/strvector.c index 94293ee7632..84e6a6d3758 100644 --- a/src/vendor/cigraph/src/core/strvector.c +++ b/src/vendor/cigraph/src/core/strvector.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -21,8 +20,9 @@ */ -#include "igraph_types.h" #include "igraph_strvector.h" + +#include "igraph_types.h" #include "igraph_memory.h" #include "igraph_error.h" @@ -68,9 +68,9 @@ * Time complexity: O(\p len). */ -igraph_error_t igraph_strvector_init(igraph_strvector_t *sv, igraph_integer_t size) { +igraph_error_t igraph_strvector_init(igraph_strvector_t *sv, igraph_int_t size) { - sv->stor_begin = IGRAPH_CALLOC(size, char*); + sv->stor_begin = IGRAPH_CALLOC(size, const char *); IGRAPH_CHECK_OOM(sv->stor_begin, "Cannot initialize string vector."); sv->stor_end = sv->stor_begin + size; @@ -93,10 +93,9 @@ igraph_error_t igraph_strvector_init(igraph_strvector_t *sv, igraph_integer_t si */ void igraph_strvector_destroy(igraph_strvector_t *sv) { - char **ptr; IGRAPH_ASSERT(sv != NULL); IGRAPH_ASSERT(sv->stor_begin != NULL); - for (ptr = sv->stor_begin; ptr < sv->end; ptr++) { + for (const char **ptr = sv->stor_begin; ptr < sv->end; ptr++) { IGRAPH_FREE(*ptr); } IGRAPH_FREE(sv->stor_begin); @@ -115,7 +114,7 @@ void igraph_strvector_destroy(igraph_strvector_t *sv) { * Time complexity: O(1). */ -const char *igraph_strvector_get(const igraph_strvector_t *sv, igraph_integer_t idx) { +const char *igraph_strvector_get(const igraph_strvector_t *sv, igraph_int_t idx) { IGRAPH_ASSERT(sv != NULL); IGRAPH_ASSERT(sv->stor_begin != NULL); return sv->stor_begin[idx] ? sv->stor_begin[idx] : ""; @@ -138,7 +137,7 @@ const char *igraph_strvector_get(const igraph_strvector_t *sv, igraph_integer_t * depending on the memory management, if reallocation is needed. */ -igraph_error_t igraph_strvector_set(igraph_strvector_t *sv, igraph_integer_t idx, +igraph_error_t igraph_strvector_set(igraph_strvector_t *sv, igraph_int_t idx, const char *value) { return igraph_strvector_set_len(sv, idx, value, strlen(value)); } @@ -160,7 +159,7 @@ igraph_error_t igraph_strvector_set(igraph_strvector_t *sv, igraph_integer_t idx * Time complexity: O(l), the length of the new string. Maybe more, * depending on the memory management, if reallocation is needed. */ -igraph_error_t igraph_strvector_set_len(igraph_strvector_t *sv, igraph_integer_t idx, +igraph_error_t igraph_strvector_set_len(igraph_strvector_t *sv, igraph_int_t idx, const char *value, size_t len) { IGRAPH_ASSERT(sv != NULL); IGRAPH_ASSERT(sv->stor_begin != NULL); @@ -172,9 +171,9 @@ igraph_error_t igraph_strvector_set_len(igraph_strvector_t *sv, igraph_integer_t char *tmp = IGRAPH_REALLOC(sv->stor_begin[idx], len + 1, char); IGRAPH_CHECK_OOM(tmp, "Cannot reserve space for new item in string vector."); + memcpy(tmp, value, len * sizeof(char)); + tmp[len] = '\0'; sv->stor_begin[idx] = tmp; - memcpy(sv->stor_begin[idx], value, len * sizeof(char)); - sv->stor_begin[idx][len] = '\0'; } return IGRAPH_SUCCESS; @@ -193,9 +192,9 @@ igraph_error_t igraph_strvector_set_len(igraph_strvector_t *sv, igraph_integer_t */ void igraph_strvector_remove_section( - igraph_strvector_t *sv, igraph_integer_t from, igraph_integer_t to) { - igraph_integer_t size = igraph_strvector_size(sv); - igraph_integer_t i; + igraph_strvector_t *sv, igraph_int_t from, igraph_int_t to) { + igraph_int_t size = igraph_strvector_size(sv); + igraph_int_t i; if (from < 0) { from = 0; @@ -228,7 +227,7 @@ void igraph_strvector_remove_section( * Time complexity: O(n), the length of the string. */ -void igraph_strvector_remove(igraph_strvector_t *sv, igraph_integer_t elem) { +void igraph_strvector_remove(igraph_strvector_t *sv, igraph_int_t elem) { igraph_strvector_remove_section(sv, elem, elem + 1); } @@ -248,12 +247,12 @@ void igraph_strvector_remove(igraph_strvector_t *sv, igraph_integer_t elem) { igraph_error_t igraph_strvector_init_copy(igraph_strvector_t *to, const igraph_strvector_t *from) { - igraph_integer_t from_size = igraph_strvector_size(from); + igraph_int_t from_size = igraph_strvector_size(from); - to->stor_begin = IGRAPH_CALLOC(from_size, char*); + to->stor_begin = IGRAPH_CALLOC(from_size, const char *); IGRAPH_CHECK_OOM(to->stor_begin, "Cannot copy string vector."); - for (igraph_integer_t i = 0; i < from_size; i++) { + for (igraph_int_t i = 0; i < from_size; i++) { /* If the string in the 'from' vector is empty, we represent it as NULL. * The NULL value was already set by IGRAPH_CALLOC(). */ if (from->stor_begin[i] == NULL || from->stor_begin[i][0] == '\0') { @@ -262,7 +261,7 @@ igraph_error_t igraph_strvector_init_copy(igraph_strvector_t *to, to->stor_begin[i] = strdup(from->stor_begin[i]); if (to->stor_begin[i] == NULL) { /* LCOV_EXCL_START */ - for (igraph_integer_t j = 0; j < i; j++) { + for (igraph_int_t j = 0; j < i; j++) { IGRAPH_FREE(to->stor_begin[j]); } IGRAPH_FREE(to->stor_begin); @@ -277,18 +276,6 @@ igraph_error_t igraph_strvector_init_copy(igraph_strvector_t *to, return IGRAPH_SUCCESS; } -/** - * \ingroup strvector - * \function igraph_strvector_copy - * \brief Initialization by copying (deprecated alias). - * - * \deprecated-by igraph_strvector_init_copy 0.10.0 - */ - -igraph_error_t igraph_strvector_copy(igraph_strvector_t *to, - const igraph_strvector_t *from) { - return igraph_strvector_init_copy(to, from); -} /** * \function igraph_strvector_append @@ -310,16 +297,25 @@ igraph_error_t igraph_strvector_copy(igraph_strvector_t *to, */ igraph_error_t igraph_strvector_append(igraph_strvector_t *to, - const igraph_strvector_t *from) { - igraph_integer_t len1 = igraph_strvector_size(to), len2 = igraph_strvector_size(from); - igraph_integer_t newlen; + const igraph_strvector_t *from) { + const igraph_int_t to_size = igraph_strvector_size(to); + const igraph_int_t from_size = igraph_strvector_size(from); + const igraph_int_t to_capacity = igraph_strvector_capacity(to); + igraph_int_t new_to_size; igraph_bool_t error = false; - char *tmp; + const char *tmp; - IGRAPH_SAFE_ADD(len1, len2, &newlen); - IGRAPH_CHECK(igraph_strvector_reserve(to, newlen)); + IGRAPH_SAFE_ADD(to_size, from_size, &new_to_size); - for (igraph_integer_t i = 0; i < len2; i++) { + if (to_capacity < new_to_size) { + igraph_int_t new_to_capacity = to_capacity < IGRAPH_INTEGER_MAX/2 ? to_capacity * 2 : IGRAPH_INTEGER_MAX; + if (new_to_capacity < new_to_size) { + new_to_capacity = new_to_size; + } + IGRAPH_CHECK(igraph_strvector_reserve(to, new_to_capacity)); + } + + for (igraph_int_t i = 0; i < from_size; i++) { if (from->stor_begin[i] == NULL || from->stor_begin[i][0] == '\0') { /* Represent empty strings as NULL. */ tmp = NULL; @@ -335,7 +331,7 @@ igraph_error_t igraph_strvector_append(igraph_strvector_t *to, } if (error) { - igraph_strvector_resize(to, len1); /* always shrinks */ + igraph_strvector_resize(to, to_size); /* always shrinks */ IGRAPH_ERROR("Cannot append string vector.", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } @@ -362,8 +358,8 @@ igraph_error_t igraph_strvector_append(igraph_strvector_t *to, * where l1 and l2 are the lengths of \p to and \from respectively. */ igraph_error_t igraph_strvector_merge(igraph_strvector_t *to, igraph_strvector_t *from) { - char **p1, **p2, **pe; - igraph_integer_t newlen; + const char **p1, **p2, **pe; + igraph_int_t newlen; IGRAPH_SAFE_ADD(igraph_strvector_size(to), igraph_strvector_size(from), &newlen); IGRAPH_CHECK(igraph_strvector_reserve(to, newlen)); @@ -395,9 +391,9 @@ igraph_error_t igraph_strvector_merge(igraph_strvector_t *to, igraph_strvector_t */ void igraph_strvector_clear(igraph_strvector_t *sv) { - igraph_integer_t n = igraph_strvector_size(sv); + igraph_int_t n = igraph_strvector_size(sv); - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { IGRAPH_FREE(sv->stor_begin[i]); } sv->end = sv->stor_begin; @@ -420,18 +416,18 @@ void igraph_strvector_clear(igraph_strvector_t *sv) { * smaller, maybe less, depending on memory management. */ -igraph_error_t igraph_strvector_resize(igraph_strvector_t *sv, igraph_integer_t newsize) { - igraph_integer_t toadd = newsize - igraph_strvector_size(sv); - igraph_integer_t oldsize = igraph_strvector_size(sv); +igraph_error_t igraph_strvector_resize(igraph_strvector_t *sv, igraph_int_t newsize) { + igraph_int_t toadd = newsize - igraph_strvector_size(sv); + igraph_int_t oldsize = igraph_strvector_size(sv); if (newsize < oldsize) { - for (igraph_integer_t i = newsize; i < oldsize; i++) { + for (igraph_int_t i = newsize; i < oldsize; i++) { IGRAPH_FREE(sv->stor_begin[i]); } sv->end = sv->stor_begin + newsize; } else if (newsize > oldsize) { IGRAPH_CHECK(igraph_strvector_reserve(sv, newsize)); - memset(sv->stor_begin + oldsize, 0, toadd * sizeof(char *)); + memset(sv->stor_begin + oldsize, 0, toadd * sizeof(const char *)); sv->end = sv->stor_begin + newsize; } @@ -449,7 +445,7 @@ igraph_error_t igraph_strvector_resize(igraph_strvector_t *sv, igraph_integer_t * Time complexity: O(1). */ -igraph_integer_t igraph_strvector_capacity(const igraph_strvector_t *sv) { +igraph_int_t igraph_strvector_capacity(const igraph_strvector_t *sv) { IGRAPH_ASSERT(sv != NULL); IGRAPH_ASSERT(sv->stor_begin != NULL); return sv->stor_end - sv->stor_begin; @@ -482,15 +478,14 @@ igraph_integer_t igraph_strvector_capacity(const igraph_strvector_t *sv) { * O(n), n is the new allocated size of the vector. */ -igraph_error_t igraph_strvector_reserve(igraph_strvector_t *sv, igraph_integer_t capacity) { - igraph_integer_t current_capacity = igraph_strvector_capacity(sv); - char **tmp; +igraph_error_t igraph_strvector_reserve(igraph_strvector_t *sv, igraph_int_t capacity) { + igraph_int_t current_capacity = igraph_strvector_capacity(sv); if (capacity <= current_capacity) { return IGRAPH_SUCCESS; } - tmp = IGRAPH_REALLOC(sv->stor_begin, capacity, char *); + const char **tmp = IGRAPH_REALLOC(sv->stor_begin, capacity, const char *); IGRAPH_CHECK_OOM(tmp, "Cannot reserve space for new items in string vector."); sv->end = tmp + (sv->end - sv->stor_begin); @@ -516,14 +511,12 @@ igraph_error_t igraph_strvector_reserve(igraph_strvector_t *sv, igraph_integer_t */ void igraph_strvector_resize_min(igraph_strvector_t *sv) { - igraph_integer_t size; - char **tmp; if (sv->stor_end == sv->end) { return; } - size = (sv->end - sv->stor_begin); - tmp = IGRAPH_REALLOC(sv->stor_begin, size, char *); + const igraph_int_t size = (sv->end - sv->stor_begin); + const char **tmp = IGRAPH_REALLOC(sv->stor_begin, size, const char *); if (tmp != NULL) { sv->stor_begin = tmp; @@ -542,7 +535,7 @@ void igraph_strvector_resize_min(igraph_strvector_t *sv) { * Time complexity: O(1). */ -igraph_integer_t igraph_strvector_size(const igraph_strvector_t *sv) { +igraph_int_t igraph_strvector_size(const igraph_strvector_t *sv) { IGRAPH_ASSERT(sv != NULL); IGRAPH_ASSERT(sv->stor_begin != NULL); return sv->end - sv->stor_begin; @@ -552,13 +545,13 @@ igraph_integer_t igraph_strvector_size(const igraph_strvector_t *sv) { * Ensures that the vector has at least one extra slot at the end of its * allocated storage area. */ -static igraph_error_t igraph_i_strvector_expand_if_full(igraph_strvector_t *sv) { +static igraph_error_t strvector_expand_if_full(igraph_strvector_t *sv) { IGRAPH_ASSERT(sv != NULL); IGRAPH_ASSERT(sv->stor_begin != NULL); if (sv->stor_end == sv->end) { - igraph_integer_t old_size = igraph_strvector_size(sv); - igraph_integer_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; + igraph_int_t old_size = igraph_strvector_size(sv); + igraph_int_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; if (old_size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot add new item to string vector, already at maximum size.", IGRAPH_EOVERFLOW); } @@ -585,8 +578,8 @@ static igraph_error_t igraph_i_strvector_expand_if_full(igraph_strvector_t *sv) */ igraph_error_t igraph_strvector_push_back(igraph_strvector_t *sv, const char *value) { - IGRAPH_CHECK(igraph_i_strvector_expand_if_full(sv)); - char *tmp = strdup(value); + IGRAPH_CHECK(strvector_expand_if_full(sv)); + const char *tmp = strdup(value); IGRAPH_CHECK_OOM(tmp, "Cannot push new string to string vector."); *sv->end = tmp; sv->end++; @@ -610,68 +603,57 @@ igraph_error_t igraph_strvector_push_back(igraph_strvector_t *sv, const char *va igraph_error_t igraph_strvector_push_back_len( igraph_strvector_t *sv, - const char *value, igraph_integer_t len) { + const char *value, size_t len) { - IGRAPH_CHECK(igraph_i_strvector_expand_if_full(sv)); - char *tmp = strndup(value, len); - if (! tmp) { - IGRAPH_ERROR("Cannot add string to string vector.", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } + IGRAPH_CHECK(strvector_expand_if_full(sv)); + const char *tmp = strndup(value, len); + IGRAPH_CHECK_OOM(tmp, "Insufficient memory to push to string vector."); *sv->end = tmp; sv->end++; return IGRAPH_SUCCESS; } -/** - * \ingroup strvector - * \function igraph_strvector_add - * \brief Adds an element to the back of a string vector (deprecated alias). - * - * \deprecated-by igraph_strvector_push_back 0.10.0 - */ - -igraph_error_t igraph_strvector_add(igraph_strvector_t *sv, const char *value) { - return igraph_strvector_push_back(sv, value); -} - -/** - * \ingroup strvector - * \function igraph_strvector_set2 - * \brief Sets an element of the string vector given a buffer and its size (deprecated alias). - * - * \deprecated-by igraph_strvector_set_len 0.10.0 - */ - -igraph_error_t igraph_strvector_set2( - igraph_strvector_t *sv, igraph_integer_t idx, const char *value, size_t len -) { - return igraph_strvector_set_len(sv, idx, value, len); -} /** * \ingroup strvector * \function igraph_strvector_print - * \brief Prints a string vector. + * \brief Prints a string vector to a file. * * \param sv The string vector. * \param file The file to write to. * \param sep The separator to print between strings. * \return Error code. */ -igraph_error_t igraph_strvector_print(const igraph_strvector_t *sv, FILE *file, - const char *sep) { +igraph_error_t igraph_strvector_fprint(const igraph_strvector_t *sv, FILE *file, + const char *sep) { - igraph_integer_t n = igraph_strvector_size(sv); + const igraph_int_t n = igraph_strvector_size(sv); if (n != 0) { fprintf(file, "%s", igraph_strvector_get(sv, 0)); } - for (igraph_integer_t i = 1; i < n; i++) { + for (igraph_int_t i = 1; i < n; i++) { fprintf(file, "%s%s", sep, igraph_strvector_get(sv, i)); } return IGRAPH_SUCCESS; } +/** + * \ingroup strvector + * \function igraph_strvector_print + * \brief Prints a string vector. + * + * \param sv The string vector. + * \param sep The separator to print between strings. + * \return Error code. + */ +#ifndef USING_R +igraph_error_t igraph_strvector_print(const igraph_strvector_t *sv, + const char *sep) { + return igraph_strvector_fprint(sv, stdout, sep); +} +#endif + /** * \ingroup strvector * \function igraph_strvector_index @@ -686,11 +668,11 @@ igraph_error_t igraph_strvector_index(const igraph_strvector_t *sv, igraph_strvector_t *newv, const igraph_vector_int_t *idx) { - igraph_integer_t newlen = igraph_vector_int_size(idx); + igraph_int_t newlen = igraph_vector_int_size(idx); IGRAPH_CHECK(igraph_strvector_resize(newv, newlen)); - for (igraph_integer_t i = 0; i < newlen; i++) { - igraph_integer_t j = VECTOR(*idx)[i]; + for (igraph_int_t i = 0; i < newlen; i++) { + igraph_int_t j = VECTOR(*idx)[i]; const char *str = igraph_strvector_get(sv, j); IGRAPH_CHECK(igraph_strvector_set(newv, i, str)); } @@ -698,6 +680,45 @@ igraph_error_t igraph_strvector_index(const igraph_strvector_t *sv, return IGRAPH_SUCCESS; } +/** + * \ingroup strvector + * \function igraph_strvector_update + * \brief Updates a string vector from another one. + * + * After this operation the contents of \p to will be exactly the same + * as that of \p from. The vector \p to will be resized if it was originally + * shorter or longer than \p from. + * + * \param to The string vector to update. + * \param from The string vector to update from. + * \return Error code. + */ +igraph_error_t igraph_strvector_update( + igraph_strvector_t *to, const igraph_strvector_t *from +) { + igraph_strvector_clear(to); + IGRAPH_CHECK(igraph_strvector_append(to, from)); + return IGRAPH_SUCCESS; +} + +/** + * \ingroup strvector + * \function igraph_strvector_swap + * \brief Swaps all elements of two string vectors. + * + * \param v1 The first string vector. + * \param v2 The second string vector. + * + * Time complexity: O(1). + */ +void igraph_strvector_swap(igraph_strvector_t *v1, igraph_strvector_t *v2) { + igraph_strvector_t tmp; + + tmp = *v1; + *v1 = *v2; + *v2 = tmp; +} + /** * \function igraph_strvector_swap_elements * \brief Swap two elements in a string vector. @@ -710,8 +731,8 @@ igraph_error_t igraph_strvector_index(const igraph_strvector_t *sv, * * Time complexity: O(1). */ -void igraph_strvector_swap_elements(igraph_strvector_t *sv, igraph_integer_t i, igraph_integer_t j) { - char *tmp = sv->stor_begin[i]; +void igraph_strvector_swap_elements(igraph_strvector_t *sv, igraph_int_t i, igraph_int_t j) { + const char *tmp = sv->stor_begin[i]; sv->stor_begin[i] = sv->stor_begin[j]; sv->stor_begin[j] = tmp; } diff --git a/src/vendor/cigraph/src/core/trie.c b/src/vendor/cigraph/src/core/trie.c index 2c129bba3f8..99cc6ab1d9b 100644 --- a/src/vendor/cigraph/src/core/trie.c +++ b/src/vendor/cigraph/src/core/trie.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -74,8 +73,8 @@ igraph_error_t igraph_trie_init(igraph_trie_t *t, igraph_bool_t storekeys) { static void igraph_i_trie_destroy_node_helper(igraph_trie_node_t *t, igraph_bool_t sfree) { igraph_strvector_destroy(&t->strs); - igraph_integer_t children_size = igraph_vector_ptr_size(&t->children); - for (igraph_integer_t i = 0; i < children_size; i++) { + igraph_int_t children_size = igraph_vector_ptr_size(&t->children); + for (igraph_int_t i = 0; i < children_size; i++) { igraph_trie_node_t *child = VECTOR(t->children)[i]; if (child != NULL) { igraph_i_trie_destroy_node_helper(child, true); @@ -125,8 +124,8 @@ static size_t igraph_i_strdiff(const char *str, const char *key) { */ static igraph_error_t igraph_i_trie_get_node( - igraph_trie_node_t *t, const char *key, igraph_integer_t newvalue, - igraph_integer_t *id + igraph_trie_node_t *t, const char *key, igraph_int_t newvalue, + igraph_int_t *id ) { assert(key != NULL); @@ -134,8 +133,8 @@ static igraph_error_t igraph_i_trie_get_node( * for its existence */ igraph_bool_t add = (newvalue >= 0); - igraph_integer_t strs_size = igraph_strvector_size(&t->strs); - for (igraph_integer_t i = 0; i < strs_size; i++) { + igraph_int_t strs_size = igraph_strvector_size(&t->strs); + for (igraph_int_t i = 0; i < strs_size; i++) { size_t diff; const char *str = igraph_strvector_get(&t->strs, i); diff = igraph_i_strdiff(str, key); @@ -296,7 +295,7 @@ static igraph_error_t igraph_i_trie_get_node( * \return Error code, usually \c IGRAPH_ENOMEM. */ -igraph_error_t igraph_trie_get(igraph_trie_t *t, const char *key, igraph_integer_t *id) { +igraph_error_t igraph_trie_get(igraph_trie_t *t, const char *key, igraph_int_t *id) { assert(key != NULL); if (*key == '\0') { @@ -354,8 +353,8 @@ igraph_error_t igraph_trie_get(igraph_trie_t *t, const char *key, igraph_integer igraph_error_t igraph_trie_get_len( igraph_trie_t *t, const char *key, - igraph_integer_t length, - igraph_integer_t *id) { + igraph_int_t length, + igraph_int_t *id) { char *tmp = strndup(key, length); IGRAPH_CHECK_OOM(tmp, "Cannot get from trie."); @@ -381,7 +380,7 @@ igraph_error_t igraph_trie_get_len( * \return Error code. */ -igraph_error_t igraph_trie_check(igraph_trie_t *t, const char *key, igraph_integer_t *id) { +igraph_error_t igraph_trie_check(igraph_trie_t *t, const char *key, igraph_int_t *id) { IGRAPH_CHECK(igraph_i_trie_get_node(&t->node, key, -1, id)); return IGRAPH_SUCCESS; } @@ -396,7 +395,7 @@ igraph_error_t igraph_trie_check(igraph_trie_t *t, const char *key, igraph_integ * reverse lookup, \c NULL is returned. */ -const char* igraph_trie_idx(igraph_trie_t *t, igraph_integer_t idx) { +const char* igraph_trie_idx(igraph_trie_t *t, igraph_int_t idx) { if (! t->storekeys) { return NULL; } @@ -411,7 +410,7 @@ const char* igraph_trie_idx(igraph_trie_t *t, igraph_integer_t idx) { * \return The size of the trie, i.e. one larger than the maximum index. */ -igraph_integer_t igraph_trie_size(igraph_trie_t *t) { +igraph_int_t igraph_trie_size(igraph_trie_t *t) { return t->maxvalue + 1; } diff --git a/src/vendor/cigraph/src/core/trie.h b/src/vendor/cigraph/src/core/trie.h index 3bfcb47ba85..84a8daa59ea 100644 --- a/src/vendor/cigraph/src/core/trie.h +++ b/src/vendor/cigraph/src/core/trie.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2009-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -29,7 +28,7 @@ #include "igraph_vector.h" #include "igraph_vector_ptr.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /** * Trie data type @@ -44,7 +43,7 @@ typedef struct s_igraph_trie_node { typedef struct s_igraph_trie { igraph_trie_node_t node; - igraph_integer_t maxvalue; + igraph_int_t maxvalue; igraph_bool_t storekeys; igraph_strvector_t keys; } igraph_trie_t; @@ -58,15 +57,15 @@ typedef struct s_igraph_trie { IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_trie_init(igraph_trie_t *t, igraph_bool_t storekeys); IGRAPH_PRIVATE_EXPORT void igraph_trie_destroy(igraph_trie_t *t); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_trie_get(igraph_trie_t *t, const char *key, igraph_integer_t *id); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_trie_check(igraph_trie_t *t, const char *key, igraph_integer_t *id); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_trie_get_len(igraph_trie_t *t, const char *key, igraph_integer_t length, - igraph_integer_t *id); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE const char* igraph_trie_idx(igraph_trie_t *t, igraph_integer_t idx); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_trie_size(igraph_trie_t *t); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_trie_get(igraph_trie_t *t, const char *key, igraph_int_t *id); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_trie_check(igraph_trie_t *t, const char *key, igraph_int_t *id); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_trie_get_len(igraph_trie_t *t, const char *key, igraph_int_t length, + igraph_int_t *id); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE const char* igraph_trie_idx(igraph_trie_t *t, igraph_int_t idx); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_trie_size(igraph_trie_t *t); const igraph_strvector_t* igraph_i_trie_borrow_keys(igraph_trie_t *t); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/core/typed_list.pmt b/src/vendor/cigraph/src/core/typed_list.pmt index 979af44deb9..4f23915e81b 100644 --- a/src/vendor/cigraph/src/core/typed_list.pmt +++ b/src/vendor/cigraph/src/core/typed_list.pmt @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -65,6 +64,8 @@ * _item_ in the vector */ #if defined(BASE_GRAPH) #define ITEM_FUNCTION(f) CONCAT2x(igraph,f) + #elif defined(BASE_ATTRIBUTE_RECORD) + #define ITEM_FUNCTION(f) CONCAT2x(igraph_attribute_record,f) #endif #if defined(BASE_BITSET) #define ITEM_FUNCTION(f) CONCAT2x(igraph_bitset,f) @@ -105,8 +106,8 @@ static int INTERNAL_FUNCTION(sort_ind_cmp)(void *thunk, const void *p1, const vo * n is the number of elements. */ -igraph_error_t FUNCTION(init)(TYPE *v, igraph_integer_t size) { - igraph_integer_t alloc_size = size > 0 ? size : 1; +igraph_error_t FUNCTION(init)(TYPE *v, igraph_int_t size) { + igraph_int_t alloc_size = size > 0 ? size : 1; IGRAPH_ASSERT(size >= 0); v->stor_begin = IGRAPH_CALLOC(alloc_size, ITEM_TYPE); if (v->stor_begin == 0) { @@ -120,6 +121,38 @@ igraph_error_t FUNCTION(init)(TYPE *v, igraph_integer_t size) { return IGRAPH_SUCCESS; } +/** + * \ingroup vector_list + * \function igraph_vector_list_init_copy + * \brief Initializes a list of vectors from another list of vectors (constructor). + * + * + * The contents of the existing list will be copied to the new one. + * \param to Pointer to a not yet initialized list of vectors. + * \param from The original list of vectors to copy. + * \return Error code: + * \c IGRAPH_ENOMEM if there is not enough memory. + * + * Time complexity: operating system dependent, usually O(nm), n is the size of + * the list, m is the size of each element in the list, assuming that copying a + * single item takes O(m) time. + */ + +igraph_error_t FUNCTION(init_copy)(TYPE* to, const TYPE* from) { + igraph_int_t i, size = FUNCTION(size)(from); + + IGRAPH_CHECK(FUNCTION(init)(to, 0)); + IGRAPH_FINALLY(FUNCTION(destroy), to); + + for (i = 0; i < size; i++) { + IGRAPH_CHECK(FUNCTION(push_back_copy)(to, FUNCTION(get_ptr)(from, i))); + } + + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} + /** * \ingroup vector_list * \function igraph_vector_list_destroy @@ -167,7 +200,7 @@ void FUNCTION(destroy)(TYPE *v) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(capacity)(const TYPE *v) { +igraph_int_t FUNCTION(capacity)(const TYPE *v) { return v->stor_end - v->stor_begin; } @@ -197,8 +230,8 @@ igraph_integer_t FUNCTION(capacity)(const TYPE *v) { * O(n), n is the new allocated size of the list. */ -igraph_error_t FUNCTION(reserve)(TYPE *v, igraph_integer_t capacity) { - igraph_integer_t current_capacity; +igraph_error_t FUNCTION(reserve)(TYPE *v, igraph_int_t capacity) { + igraph_int_t current_capacity; ITEM_TYPE *tmp; IGRAPH_ASSERT(v != NULL); @@ -251,7 +284,7 @@ igraph_bool_t FUNCTION(empty)(const TYPE *v) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(size)(const TYPE *v) { +igraph_int_t FUNCTION(size)(const TYPE *v) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return v->end - v->stor_begin; @@ -288,8 +321,8 @@ igraph_integer_t FUNCTION(size)(const TYPE *v) { * size is larger. In the latter case it is usually around O(n), where n is the * new size of the vector. */ -igraph_error_t FUNCTION(resize)(TYPE *v, igraph_integer_t new_size) { - igraph_integer_t old_size; +igraph_error_t FUNCTION(resize)(TYPE *v, igraph_int_t new_size) { + igraph_int_t old_size; IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); @@ -341,7 +374,7 @@ void FUNCTION(clear)(TYPE *v) { * * Time complexity: O(1). */ -ITEM_TYPE *FUNCTION(get_ptr)(const TYPE *v, igraph_integer_t pos) { +ITEM_TYPE *FUNCTION(get_ptr)(const TYPE *v, igraph_int_t pos) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return v->stor_begin + pos; @@ -366,7 +399,7 @@ ITEM_TYPE *FUNCTION(get_ptr)(const TYPE *v, igraph_integer_t pos) { * * Time complexity: O(1). */ -void FUNCTION(set)(TYPE *v, igraph_integer_t pos, ITEM_TYPE *e) { +void FUNCTION(set)(TYPE *v, igraph_int_t pos, ITEM_TYPE *e) { INTERNAL_FUNCTION(destroy_item)(v->stor_begin + pos); v->stor_begin[pos] = *e; } @@ -391,7 +424,7 @@ void FUNCTION(set)(TYPE *v, igraph_integer_t pos, ITEM_TYPE *e) { * * Time complexity: O(1). */ -void FUNCTION(replace)(TYPE *v, igraph_integer_t pos, ITEM_TYPE *e) { +void FUNCTION(replace)(TYPE *v, igraph_int_t pos, ITEM_TYPE *e) { ITEM_TYPE old_value = *(FUNCTION(get_ptr)(v, pos)); v->stor_begin[pos] = *e; *e = old_value; @@ -408,14 +441,12 @@ void FUNCTION(replace)(TYPE *v, igraph_integer_t pos, ITEM_TYPE *e) { * Time complexity: O(1). */ -igraph_error_t FUNCTION(swap)(TYPE *v1, TYPE *v2) { +void FUNCTION(swap)(TYPE *v1, TYPE *v2) { TYPE tmp; tmp = *v1; *v1 = *v2; *v2 = tmp; - - return IGRAPH_SUCCESS; } /** @@ -433,11 +464,10 @@ igraph_error_t FUNCTION(swap)(TYPE *v1, TYPE *v2) { * Time complexity: O(1). */ -igraph_error_t FUNCTION(swap_elements)(TYPE *v1, igraph_integer_t i, igraph_integer_t j) { +void FUNCTION(swap_elements)(TYPE *v1, igraph_int_t i, igraph_int_t j) { ITEM_TYPE tmp = v1->stor_begin[i]; v1->stor_begin[i] = v1->stor_begin[j]; v1->stor_begin[j] = tmp; - return IGRAPH_SUCCESS; } /** @@ -452,7 +482,7 @@ igraph_error_t FUNCTION(swap_elements)(TYPE *v1, igraph_integer_t i, igraph_inte * Time complexity: O(1). */ ITEM_TYPE *FUNCTION(tail_ptr)(const TYPE *v) { - igraph_integer_t size = FUNCTION(size)(v); + igraph_int_t size = FUNCTION(size)(v); return size > 0 ? FUNCTION(get_ptr)(v, size - 1) : 0; } @@ -473,8 +503,8 @@ ITEM_TYPE *FUNCTION(tail_ptr)(const TYPE *v) { * * Time complexity: O(n), where n is the number of items in the list. */ -void FUNCTION(discard)(TYPE *v, igraph_integer_t index) { - igraph_integer_t size = FUNCTION(size)(v); +void FUNCTION(discard)(TYPE *v, igraph_int_t index) { + igraph_int_t size = FUNCTION(size)(v); if (size > 0) { INTERNAL_FUNCTION(destroy_item)(v->stor_begin + index); @@ -495,7 +525,7 @@ void FUNCTION(discard)(TYPE *v, igraph_integer_t index) { * Time complexity: O(1). */ void FUNCTION(discard_back)(TYPE *v) { - igraph_integer_t size = FUNCTION(size)(v); + igraph_int_t size = FUNCTION(size)(v); if (size > 0) { INTERNAL_FUNCTION(destroy_item)(v->end - 1); v->end -= 1; @@ -519,8 +549,8 @@ void FUNCTION(discard_back)(TYPE *v) { * * Time complexity: O(1). */ -void FUNCTION(discard_fast)(TYPE *v, igraph_integer_t index) { - igraph_integer_t size = FUNCTION(size)(v); +void FUNCTION(discard_fast)(TYPE *v, igraph_int_t index) { + igraph_int_t size = FUNCTION(size)(v); if (size > 0) { INTERNAL_FUNCTION(destroy_item)(v->stor_begin + index); @@ -636,8 +666,8 @@ igraph_error_t FUNCTION(push_back_new)(TYPE *v, ITEM_TYPE** e) { * * Time complexity: O(n). */ -igraph_error_t FUNCTION(insert)(TYPE *v, igraph_integer_t pos, ITEM_TYPE *e) { - igraph_integer_t size = FUNCTION(size)(v); +igraph_error_t FUNCTION(insert)(TYPE *v, igraph_int_t pos, ITEM_TYPE *e) { + igraph_int_t size = FUNCTION(size)(v); IGRAPH_ASSERT(0 <= pos && pos <= size); IGRAPH_CHECK(INTERNAL_FUNCTION(expand_if_full)(v)); if (pos < size) { @@ -667,7 +697,7 @@ igraph_error_t FUNCTION(insert)(TYPE *v, igraph_integer_t pos, ITEM_TYPE *e) { * Time complexity: same as \ref igraph_vector_list_insert() plus the time * needed to copy the vector (which is O(n) for n elements in the vector). */ -igraph_error_t FUNCTION(insert_copy)(TYPE *v, igraph_integer_t pos, const ITEM_TYPE *e) { +igraph_error_t FUNCTION(insert_copy)(TYPE *v, igraph_int_t pos, const ITEM_TYPE *e) { ITEM_TYPE copy; IGRAPH_CHECK(INTERNAL_FUNCTION(copy_item)(©, e)); IGRAPH_FINALLY(INTERNAL_FUNCTION(destroy_item), ©); @@ -696,7 +726,7 @@ igraph_error_t FUNCTION(insert_copy)(TYPE *v, igraph_integer_t pos, const ITEM_T * * Time complexity: same as \ref igraph_vector_list_push_back(). */ -igraph_error_t FUNCTION(insert_new)(TYPE *v, igraph_integer_t pos, ITEM_TYPE** e) { +igraph_error_t FUNCTION(insert_new)(TYPE *v, igraph_int_t pos, ITEM_TYPE** e) { ITEM_TYPE copy; IGRAPH_CHECK(INTERNAL_FUNCTION(init_item)(v, ©)); IGRAPH_FINALLY(INTERNAL_FUNCTION(destroy_item), ©); @@ -730,8 +760,8 @@ igraph_error_t FUNCTION(insert_new)(TYPE *v, igraph_integer_t pos, ITEM_TYPE** e * * Time complexity: O(n), where n is the number of items in the list. */ -igraph_error_t FUNCTION(remove)(TYPE *v, igraph_integer_t index, ITEM_TYPE *result) { - igraph_integer_t size = FUNCTION(size)(v); +igraph_error_t FUNCTION(remove)(TYPE *v, igraph_int_t index, ITEM_TYPE *result) { + igraph_int_t size = FUNCTION(size)(v); IGRAPH_ASSERT(result != 0); @@ -795,8 +825,8 @@ ITEM_TYPE FUNCTION(pop_back)(TYPE *v) { * * Time complexity: O(1). */ -igraph_error_t FUNCTION(remove_fast)(TYPE *v, igraph_integer_t index, ITEM_TYPE *result) { - igraph_integer_t size = FUNCTION(size)(v); +igraph_error_t FUNCTION(remove_fast)(TYPE *v, igraph_int_t index, ITEM_TYPE *result) { + igraph_int_t size = FUNCTION(size)(v); IGRAPH_ASSERT(result != 0); @@ -842,7 +872,7 @@ igraph_error_t FUNCTION(remove_fast)(TYPE *v, igraph_integer_t index, ITEM_TYPE */ igraph_error_t FUNCTION(permute)(TYPE *v, const igraph_vector_int_t* index) { ITEM_TYPE *work; - igraph_integer_t i, size; + igraph_int_t i, size; IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); @@ -916,7 +946,7 @@ igraph_error_t FUNCTION(sort_ind)( TYPE *v, igraph_vector_int_t *inds, int (*cmp)(const ITEM_TYPE*, const ITEM_TYPE*) ) { - igraph_integer_t i, n = FUNCTION(size)(v); + igraph_int_t i, n = FUNCTION(size)(v); ITEM_TYPE **vind, *first; IGRAPH_CHECK(igraph_vector_int_resize(inds, n)); @@ -972,7 +1002,7 @@ igraph_error_t FUNCTION(sort_ind)( void FUNCTION(remove_consecutive_duplicates)( TYPE *v, igraph_bool_t (*eq)(const ITEM_TYPE*, const ITEM_TYPE*) ) { - igraph_integer_t i, j, n = FUNCTION(size)(v); + igraph_int_t i, j, n = FUNCTION(size)(v); ITEM_TYPE *p = v->stor_begin; if (n < 2) { @@ -1003,8 +1033,8 @@ void FUNCTION(remove_consecutive_duplicates)( * Time complexity: O(n), the number of elements. */ igraph_error_t FUNCTION(reverse)(TYPE *v) { - igraph_integer_t n = FUNCTION(size)(v), n2 = n / 2; - igraph_integer_t i, j; + igraph_int_t n = FUNCTION(size)(v), n2 = n / 2; + igraph_int_t i, j; for (i = 0, j = n - 1; i < n2; i++, j--) { ITEM_TYPE tmp; tmp = VECTOR(*v)[i]; @@ -1066,8 +1096,8 @@ static igraph_error_t INTERNAL_FUNCTION(expand_if_full)(TYPE *v) { IGRAPH_ASSERT(v->stor_begin != NULL); if (v->stor_end == v->end) { - igraph_integer_t old_size = FUNCTION(size)(v); - igraph_integer_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; + igraph_int_t old_size = FUNCTION(size)(v); + igraph_int_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; if (old_size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot add new item to list, already at maximum size.", IGRAPH_EOVERFLOW); } diff --git a/src/vendor/cigraph/src/core/vector.c b/src/vendor/cigraph/src/core/vector.c index dcc4a077d1f..86d58d0b8a2 100644 --- a/src/vendor/cigraph/src/core/vector.c +++ b/src/vendor/cigraph/src/core/vector.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -59,8 +58,6 @@ #include "igraph_pmt_off.h" #undef BASE_COMPLEX -#include "core/indheap.h" - /** * \ingroup vector * \function igraph_vector_floor @@ -76,10 +73,10 @@ * Time complexity: O(n), where n is the number of elements in the vector. */ igraph_error_t igraph_vector_floor(const igraph_vector_t *from, igraph_vector_int_t *to) { - const igraph_integer_t n = igraph_vector_size(from); + const igraph_int_t n = igraph_vector_size(from); IGRAPH_CHECK(igraph_vector_int_resize(to, n)); - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { VECTOR(*to)[i] = floor(VECTOR(*from)[i]); } @@ -87,33 +84,16 @@ igraph_error_t igraph_vector_floor(const igraph_vector_t *from, igraph_vector_in } igraph_error_t igraph_vector_round(const igraph_vector_t *from, igraph_vector_int_t *to) { - const igraph_integer_t n = igraph_vector_size(from); + const igraph_int_t n = igraph_vector_size(from); IGRAPH_CHECK(igraph_vector_int_resize(to, n)); - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { VECTOR(*to)[i] = round(VECTOR(*from)[i]); } return IGRAPH_SUCCESS; } -igraph_error_t igraph_vector_order2(igraph_vector_t *v) { - igraph_indheap_t heap; - - IGRAPH_CHECK(igraph_indheap_init_array(&heap, VECTOR(*v), igraph_vector_size(v))); - IGRAPH_FINALLY(igraph_indheap_destroy, &heap); - - igraph_vector_clear(v); - while (!igraph_indheap_empty(&heap)) { - IGRAPH_CHECK(igraph_vector_push_back(v, igraph_indheap_max_index(&heap) - 1)); - igraph_indheap_delete_max(&heap); - } - - igraph_indheap_destroy(&heap); - IGRAPH_FINALLY_CLEAN(1); - return IGRAPH_SUCCESS; -} - /** * \ingroup vector * \function igraph_vector_int_pair_order @@ -136,11 +116,11 @@ igraph_error_t igraph_vector_order2(igraph_vector_t *v) { igraph_error_t igraph_vector_int_pair_order(const igraph_vector_int_t* v, const igraph_vector_int_t* v2, - igraph_vector_int_t* res, igraph_integer_t nodes) { - igraph_integer_t edges = igraph_vector_int_size(v); + igraph_vector_int_t* res, igraph_int_t nodes) { + igraph_int_t edges = igraph_vector_int_size(v); igraph_vector_int_t ptr; igraph_vector_int_t rad; - igraph_integer_t i, j; + igraph_int_t i, j; IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); @@ -150,7 +130,7 @@ igraph_error_t igraph_vector_int_pair_order(const igraph_vector_int_t* v, IGRAPH_CHECK(igraph_vector_int_resize(res, edges)); for (i = 0; i < edges; i++) { - igraph_integer_t radix = VECTOR(*v2)[i]; + igraph_int_t radix = VECTOR(*v2)[i]; if (VECTOR(ptr)[radix] != 0) { VECTOR(rad)[i] = VECTOR(ptr)[radix]; } @@ -160,7 +140,7 @@ igraph_error_t igraph_vector_int_pair_order(const igraph_vector_int_t* v, j = 0; for (i = 0; i < nodes + 1; i++) { if (VECTOR(ptr)[i] != 0) { - igraph_integer_t next = VECTOR(ptr)[i] - 1; + igraph_int_t next = VECTOR(ptr)[i] - 1; VECTOR(*res)[j++] = next; while (VECTOR(rad)[next] != 0) { next = VECTOR(rad)[next] - 1; @@ -173,8 +153,8 @@ igraph_error_t igraph_vector_int_pair_order(const igraph_vector_int_t* v, igraph_vector_int_null(&rad); for (i = 0; i < edges; i++) { - igraph_integer_t edge = VECTOR(*res)[edges - i - 1]; - igraph_integer_t radix = VECTOR(*v)[edge]; + igraph_int_t edge = VECTOR(*res)[edges - i - 1]; + igraph_int_t radix = VECTOR(*v)[edge]; if (VECTOR(ptr)[radix] != 0) { VECTOR(rad)[edge] = VECTOR(ptr)[radix]; } @@ -184,7 +164,7 @@ igraph_error_t igraph_vector_int_pair_order(const igraph_vector_int_t* v, j = 0; for (i = 0; i < nodes + 1; i++) { if (VECTOR(ptr)[i] != 0) { - igraph_integer_t next = VECTOR(ptr)[i] - 1; + igraph_int_t next = VECTOR(ptr)[i] - 1; VECTOR(*res)[j++] = next; while (VECTOR(rad)[next] != 0) { next = VECTOR(rad)[next] - 1; @@ -200,23 +180,36 @@ igraph_error_t igraph_vector_int_pair_order(const igraph_vector_int_t* v, return IGRAPH_SUCCESS; } -igraph_error_t igraph_vector_int_order1(const igraph_vector_int_t* v, - igraph_vector_int_t* res, - igraph_integer_t nodes) { - igraph_integer_t edges = igraph_vector_int_size(v); +/** + * \function igraph_i_vector_int_order + * + * \param v Integer vector with non-negative entries. + * \param res The indices of the elements of \p v will be written here + * in sorted order. + * \param maxval The largest value in \p v must be provided here. + * \return Error code. + * + * Time complexity: O(maxval). + */ +igraph_error_t igraph_i_vector_int_order( + const igraph_vector_int_t *v, + igraph_vector_int_t *res, + igraph_int_t maxval) { + + const igraph_int_t size = igraph_vector_int_size(v); igraph_vector_int_t ptr; igraph_vector_int_t rad; - igraph_integer_t i, j; + igraph_int_t j; IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); - IGRAPH_VECTOR_INT_INIT_FINALLY(&ptr, nodes + 1); - IGRAPH_VECTOR_INT_INIT_FINALLY(&rad, edges); - IGRAPH_CHECK(igraph_vector_int_resize(res, edges)); + IGRAPH_VECTOR_INT_INIT_FINALLY(&ptr, maxval + 1); + IGRAPH_VECTOR_INT_INIT_FINALLY(&rad, size); + IGRAPH_CHECK(igraph_vector_int_resize(res, size)); - for (i = 0; i < edges; i++) { - igraph_integer_t radix = v->stor_begin[i]; + for (igraph_int_t i = 0; i < size; i++) { + igraph_int_t radix = VECTOR(*v)[i]; if (VECTOR(ptr)[radix] != 0) { VECTOR(rad)[i] = VECTOR(ptr)[radix]; } @@ -224,13 +217,13 @@ igraph_error_t igraph_vector_int_order1(const igraph_vector_int_t* v, } j = 0; - for (i = 0; i < nodes + 1; i++) { + for (igraph_int_t i = 0; i < maxval + 1; i++) { if (VECTOR(ptr)[i] != 0) { - igraph_integer_t next = VECTOR(ptr)[i] - 1; - res->stor_begin[j++] = next; + igraph_int_t next = VECTOR(ptr)[i] - 1; + VECTOR(*res)[j++] = next; while (VECTOR(rad)[next] != 0) { next = VECTOR(rad)[next] - 1; - res->stor_begin[j++] = next; + VECTOR(*res)[j++] = next; } } } @@ -242,26 +235,39 @@ igraph_error_t igraph_vector_int_order1(const igraph_vector_int_t* v, return IGRAPH_SUCCESS; } -igraph_error_t igraph_vector_rank( - const igraph_vector_t *v, igraph_vector_int_t *res, igraph_integer_t nodes) { +/** + * \function igraph_i_vector_int_rank + * + * \param v Integer vector with non-negative entries. + * \param res The zero-based rank of the elements of \p v will be written here + * from smallest to largest. + * \param maxval The largest value in \p v must be provided here. + * \return Error code. + * + * Time complexity: O(maxval). + */ +igraph_error_t igraph_i_vector_int_rank( + const igraph_vector_int_t *v, + igraph_vector_int_t *res, + igraph_int_t maxval) { + const igraph_int_t size = igraph_vector_int_size(v); igraph_vector_int_t rad; igraph_vector_int_t ptr; - igraph_integer_t edges = igraph_vector_size(v); - igraph_integer_t i, c = 0; + igraph_int_t c = 0; - IGRAPH_VECTOR_INT_INIT_FINALLY(&rad, nodes); - IGRAPH_VECTOR_INT_INIT_FINALLY(&ptr, edges); - IGRAPH_CHECK(igraph_vector_int_resize(res, edges)); + IGRAPH_VECTOR_INT_INIT_FINALLY(&rad, maxval); + IGRAPH_VECTOR_INT_INIT_FINALLY(&ptr, size); + IGRAPH_CHECK(igraph_vector_int_resize(res, size)); - for (i = 0; i < edges; i++) { - igraph_integer_t elem = VECTOR(*v)[i]; + for (igraph_int_t i = 0; i < size; i++) { + igraph_int_t elem = VECTOR(*v)[i]; VECTOR(ptr)[i] = VECTOR(rad)[elem]; VECTOR(rad)[elem] = i + 1; } - for (i = 0; i < nodes; i++) { - igraph_integer_t p = VECTOR(rad)[i]; + for (igraph_int_t i = 0; i < maxval; i++) { + igraph_int_t p = VECTOR(rad)[i]; while (p != 0) { VECTOR(*res)[p - 1] = c++; p = VECTOR(ptr)[p - 1]; @@ -271,38 +277,7 @@ igraph_error_t igraph_vector_rank( igraph_vector_int_destroy(&ptr); igraph_vector_int_destroy(&rad); IGRAPH_FINALLY_CLEAN(2); - return IGRAPH_SUCCESS; -} -igraph_error_t igraph_vector_int_rank( - const igraph_vector_int_t *v, igraph_vector_int_t *res, igraph_integer_t nodes) { - - igraph_vector_int_t rad; - igraph_vector_int_t ptr; - igraph_integer_t edges = igraph_vector_int_size(v); - igraph_integer_t i, c = 0; - - IGRAPH_VECTOR_INT_INIT_FINALLY(&rad, nodes); - IGRAPH_VECTOR_INT_INIT_FINALLY(&ptr, edges); - IGRAPH_CHECK(igraph_vector_int_resize(res, edges)); - - for (i = 0; i < edges; i++) { - igraph_integer_t elem = VECTOR(*v)[i]; - VECTOR(ptr)[i] = VECTOR(rad)[elem]; - VECTOR(rad)[elem] = i + 1; - } - - for (i = 0; i < nodes; i++) { - igraph_integer_t p = VECTOR(rad)[i]; - while (p != 0) { - VECTOR(*res)[p - 1] = c++; - p = VECTOR(ptr)[p - 1]; - } - } - - igraph_vector_int_destroy(&ptr); - igraph_vector_int_destroy(&rad); - IGRAPH_FINALLY_CLEAN(2); return IGRAPH_SUCCESS; } @@ -320,7 +295,7 @@ igraph_error_t igraph_vector_int_rank( igraph_error_t igraph_vector_complex_real(const igraph_vector_complex_t *v, igraph_vector_t *real) { - igraph_integer_t i, n = igraph_vector_complex_size(v); + igraph_int_t i, n = igraph_vector_complex_size(v); IGRAPH_CHECK(igraph_vector_resize(real, n)); for (i = 0; i < n; i++) { VECTOR(*real)[i] = IGRAPH_REAL(VECTOR(*v)[i]); @@ -343,7 +318,7 @@ igraph_error_t igraph_vector_complex_real(const igraph_vector_complex_t *v, igraph_error_t igraph_vector_complex_imag(const igraph_vector_complex_t *v, igraph_vector_t *imag) { - igraph_integer_t i, n = igraph_vector_complex_size(v); + igraph_int_t i, n = igraph_vector_complex_size(v); IGRAPH_CHECK(igraph_vector_resize(imag, n)); for (i = 0; i < n; i++) { VECTOR(*imag)[i] = IGRAPH_IMAG(VECTOR(*v)[i]); @@ -368,7 +343,7 @@ igraph_error_t igraph_vector_complex_imag(const igraph_vector_complex_t *v, igraph_error_t igraph_vector_complex_realimag(const igraph_vector_complex_t *v, igraph_vector_t *real, igraph_vector_t *imag) { - igraph_integer_t i, n = igraph_vector_complex_size(v); + igraph_int_t i, n = igraph_vector_complex_size(v); IGRAPH_CHECK(igraph_vector_resize(real, n)); IGRAPH_CHECK(igraph_vector_resize(imag, n)); for (i = 0; i < n; i++) { @@ -396,7 +371,7 @@ igraph_error_t igraph_vector_complex_realimag(const igraph_vector_complex_t *v, igraph_error_t igraph_vector_complex_create(igraph_vector_complex_t *v, const igraph_vector_t *real, const igraph_vector_t *imag) { - igraph_integer_t i, n = igraph_vector_size(real); + igraph_int_t i, n = igraph_vector_size(real); if (n != igraph_vector_size(imag)) { IGRAPH_ERROR("Real and imag vector sizes don't match", IGRAPH_EINVAL); } @@ -427,7 +402,7 @@ igraph_error_t igraph_vector_complex_create(igraph_vector_complex_t *v, igraph_error_t igraph_vector_complex_create_polar(igraph_vector_complex_t *v, const igraph_vector_t *r, const igraph_vector_t *theta) { - igraph_integer_t i, n = igraph_vector_size(r); + igraph_int_t i, n = igraph_vector_size(r); if (n != igraph_vector_size(theta)) { IGRAPH_ERROR("'r' and 'theta' vector sizes don't match", IGRAPH_EINVAL); } @@ -458,7 +433,7 @@ igraph_bool_t igraph_vector_complex_all_almost_e(const igraph_vector_complex_t * const igraph_vector_complex_t *rhs, igraph_real_t eps) { - igraph_integer_t n = igraph_vector_complex_size(lhs); + igraph_int_t n = igraph_vector_complex_size(lhs); if (lhs == rhs) { return true; @@ -468,7 +443,7 @@ igraph_bool_t igraph_vector_complex_all_almost_e(const igraph_vector_complex_t * return false; } - for (igraph_integer_t i=0; i < n; i++) { + for (igraph_int_t i=0; i < n; i++) { if (! igraph_complex_almost_equals(VECTOR(*lhs)[i], VECTOR(*rhs)[i], eps)) return false; } @@ -476,38 +451,6 @@ igraph_bool_t igraph_vector_complex_all_almost_e(const igraph_vector_complex_t * return true; } -/** - * Deprecated in favour of \ref igraph_vector_all_almost_e() which uses - * relative tolerances. Will be removed in 0.11. - * - * Checks if two vectors are equal within an absolute tolerance. - */ -igraph_bool_t igraph_vector_e_tol(const igraph_vector_t *lhs, - const igraph_vector_t *rhs, - igraph_real_t tol) { - igraph_integer_t i, s; - IGRAPH_ASSERT(lhs != 0); - IGRAPH_ASSERT(rhs != 0); - IGRAPH_ASSERT(lhs->stor_begin != 0); - IGRAPH_ASSERT(rhs->stor_begin != 0); - - s = igraph_vector_size(lhs); - if (s != igraph_vector_size(rhs)) { - return false; - } else { - if (tol == 0) { - tol = DBL_EPSILON; - } - for (i = 0; i < s; i++) { - igraph_real_t l = VECTOR(*lhs)[i]; - igraph_real_t r = VECTOR(*rhs)[i]; - if (l < r - tol || l > r + tol) { - return false; - } - } - return true; - } -} /** * \function igraph_vector_all_almost_e @@ -525,7 +468,7 @@ igraph_bool_t igraph_vector_all_almost_e(const igraph_vector_t *lhs, const igraph_vector_t *rhs, igraph_real_t eps) { - igraph_integer_t n = igraph_vector_size(lhs); + igraph_int_t n = igraph_vector_size(lhs); if (lhs == rhs) { return true; @@ -535,7 +478,7 @@ igraph_bool_t igraph_vector_all_almost_e(const igraph_vector_t *lhs, return false; } - for (igraph_integer_t i=0; i < n; i++) { + for (igraph_int_t i=0; i < n; i++) { if (! igraph_almost_equals(VECTOR(*lhs)[i], VECTOR(*rhs)[i], eps)) return false; } @@ -562,7 +505,7 @@ igraph_bool_t igraph_vector_all_almost_e(const igraph_vector_t *lhs, * perform comparisons with relative tolerances. */ igraph_error_t igraph_vector_zapsmall(igraph_vector_t *v, igraph_real_t tol) { - igraph_integer_t i, n = igraph_vector_size(v); + igraph_int_t i, n = igraph_vector_size(v); if (tol < 0.0) { IGRAPH_ERROR("Tolerance must be positive or zero.", IGRAPH_EINVAL); } @@ -601,7 +544,7 @@ igraph_error_t igraph_vector_zapsmall(igraph_vector_t *v, igraph_real_t tol) { * tolerances. */ igraph_error_t igraph_vector_complex_zapsmall(igraph_vector_complex_t *v, igraph_real_t tol) { - igraph_integer_t i, n = igraph_vector_complex_size(v); + igraph_int_t i, n = igraph_vector_complex_size(v); if (tol < 0.0) { IGRAPH_ERROR("Tolerance must be positive or zero.", IGRAPH_EINVAL); } diff --git a/src/vendor/cigraph/src/core/vector.pmt b/src/vendor/cigraph/src/core/vector.pmt index 00544b1a74c..15c34f94806 100644 --- a/src/vendor/cigraph/src/core/vector.pmt +++ b/src/vendor/cigraph/src/core/vector.pmt @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -43,7 +42,7 @@ * * There are multiple variants of \type igraph_vector_t; the basic variant * stores doubles, but there is also \type igraph_vector_int_t for integers (of - * type \type igraph_integer_t), \c igraph_vector_bool_t for booleans (of type + * type \type igraph_int_t), \c igraph_vector_bool_t for booleans (of type * \type igraph_bool_t) and so on. Vectors are used extensively in \a igraph; all * functions that expect or return a list of numbers use \type igraph_vector_t or * \type igraph_vector_int_t to achieve this. Integer vectors are typically used @@ -132,8 +131,8 @@ * n is the number of elements. */ -igraph_error_t FUNCTION(igraph_vector, init)(TYPE(igraph_vector) *v, igraph_integer_t size) { - igraph_integer_t alloc_size; +igraph_error_t FUNCTION(igraph_vector, init)(TYPE(igraph_vector) *v, igraph_int_t size) { + igraph_int_t alloc_size; IGRAPH_ASSERT(size >= 0); alloc_size = size > 0 ? size : 1; @@ -156,25 +155,36 @@ igraph_error_t FUNCTION(igraph_vector, init)(TYPE(igraph_vector) *v, igraph_inte * \function igraph_vector_view * \brief Handle a regular C array as a \type igraph_vector_t. * + * This function lets you treat an existing C array as an \ref igraph_vector_t. + * * - * This is a special \type igraph_vector_t constructor. It allows to - * handle a regular C array as a \type igraph_vector_t temporarily. - * Be sure that you \em don't ever call the destructor (\ref - * igraph_vector_destroy()) on objects created by this constructor. - * \param v Pointer to an uninitialized \type igraph_vector_t object. - * \param data Pointer, the C array. It may not be \c NULL, except - * when \p length is zero. + * Since this function creates a view into an existing array, you must \em not + * destroy the \c igraph_vector_t object when you are done with it. Similarly, + * you must \em not call any function on it that may attempt to modify the size + * of the vector. Modifying an element in the vector will modify the underlying + * array as the two share the same memory block. + * + * + * Typical usage pattern: + * + * + * igraph_real_t array[] = { 1.0, 1.5, 2.0 }; + * const igraph_vector_t v = igraph_vector_view(array, sizeof(array) / sizeof(array[0])); + * printf("The sum of vector elements is %g.\n", igraph_vector_sum(&v)); + * + * + * \param data The raw array that the vector provides a view into. * \param length The length of the C array. - * \return Pointer to the vector object, the same as the - * \p v parameter, for convenience. + * \return The vector object providing the view into the array. * * Time complexity: O(1) */ -const TYPE(igraph_vector)* FUNCTION(igraph_vector, view)(const TYPE(igraph_vector) *v, - const BASE *data, igraph_integer_t length) { +TYPE(igraph_vector) FUNCTION(igraph_vector, view)( + const BASE *data, igraph_int_t length) { + static const BASE dummy = ZERO; - TYPE(igraph_vector) *v2 = (TYPE(igraph_vector)*)v; + TYPE(igraph_vector) v; /* When the length is zero, we allow 'data' to be NULL. * An igraph_vector_t may never contain a NULL pointer, @@ -185,9 +195,9 @@ const TYPE(igraph_vector)* FUNCTION(igraph_vector, view)(const TYPE(igraph_vecto IGRAPH_ASSERT(data != NULL); } - v2->stor_begin = (BASE*)data; - v2->stor_end = (BASE*)data + length; - v2->end = v2->stor_end; + v.stor_begin = (BASE*)data; + v.stor_end = (BASE*)data + length; + v.end = v.stor_end; return v; } @@ -425,7 +435,7 @@ void FUNCTION(igraph_vector, destroy)(TYPE(igraph_vector) *v) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_vector, capacity)(const TYPE(igraph_vector) *v) { +igraph_int_t FUNCTION(igraph_vector, capacity)(const TYPE(igraph_vector) *v) { return v->stor_end - v->stor_begin; } @@ -457,8 +467,8 @@ igraph_integer_t FUNCTION(igraph_vector, capacity)(const TYPE(igraph_vector) *v) * is the new allocated size of the vector. */ -igraph_error_t FUNCTION(igraph_vector, reserve)(TYPE(igraph_vector) *v, igraph_integer_t capacity) { - igraph_integer_t current_capacity; +igraph_error_t FUNCTION(igraph_vector, reserve)(TYPE(igraph_vector) *v, igraph_int_t capacity) { + igraph_int_t current_capacity; BASE *tmp; IGRAPH_ASSERT(v != NULL); @@ -511,7 +521,7 @@ igraph_bool_t FUNCTION(igraph_vector, empty)(const TYPE(igraph_vector) *v) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_vector, size)(const TYPE(igraph_vector) *v) { +igraph_int_t FUNCTION(igraph_vector, size)(const TYPE(igraph_vector) *v) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return v->end - v->stor_begin; @@ -568,8 +578,8 @@ igraph_error_t FUNCTION(igraph_vector, push_back)(TYPE(igraph_vector) *v, BASE e if (v->stor_end == v->end) { /* full, allocate more storage */ - igraph_integer_t old_size = FUNCTION(igraph_vector, size)(v); - igraph_integer_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; + igraph_int_t old_size = FUNCTION(igraph_vector, size)(v); + igraph_int_t new_size = old_size < IGRAPH_INTEGER_MAX/2 ? old_size * 2 : IGRAPH_INTEGER_MAX; if (old_size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot push to vector, already at maximum size.", IGRAPH_EOVERFLOW); } @@ -600,8 +610,8 @@ igraph_error_t FUNCTION(igraph_vector, push_back)(TYPE(igraph_vector) *v, BASE e * \param value The new element to be inserted. */ igraph_error_t FUNCTION(igraph_vector, insert)( - TYPE(igraph_vector) *v, igraph_integer_t pos, BASE value) { - igraph_integer_t size = FUNCTION(igraph_vector, size)(v); + TYPE(igraph_vector) *v, igraph_int_t pos, BASE value) { + igraph_int_t size = FUNCTION(igraph_vector, size)(v); IGRAPH_ASSERT(0 <= pos && pos <= size); if (size == IGRAPH_INTEGER_MAX) { IGRAPH_ERROR("Cannot insert to vector, already at maximum size.", IGRAPH_EOVERFLOW); @@ -648,7 +658,7 @@ igraph_error_t FUNCTION(igraph_vector, insert)( * Time complexity: O(1). */ -BASE FUNCTION(igraph_vector, get)(const TYPE(igraph_vector) *v, igraph_integer_t pos) { +BASE FUNCTION(igraph_vector, get)(const TYPE(igraph_vector) *v, igraph_int_t pos) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return * (v->stor_begin + pos); @@ -671,42 +681,12 @@ BASE FUNCTION(igraph_vector, get)(const TYPE(igraph_vector) *v, igraph_integer_t * Time complexity: O(1). */ -BASE* FUNCTION(igraph_vector, get_ptr)(const TYPE(igraph_vector) *v, igraph_integer_t pos) { +BASE* FUNCTION(igraph_vector, get_ptr)(const TYPE(igraph_vector) *v, igraph_int_t pos) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return v->stor_begin + pos; } -/** - * \ingroup vector - * \function igraph_vector_e - * \brief Access an element of a vector (deprecated alias). - * - * \deprecated-by igraph_vector_get 0.10.0 - */ - -BASE FUNCTION(igraph_vector, e)(const TYPE(igraph_vector) *v, igraph_integer_t pos) { - return FUNCTION(igraph_vector, get)(v, pos); -} - -/** - * \ingroup vector - * \function igraph_vector_e_ptr - * \brief Get the address of an element of a vector. - * - * \param v The \type igraph_vector_t object. - * \param pos The position of the element, the position of the first - * element is zero. - * \return Pointer to the desired element. - * \sa \ref igraph_vector_get() and the \ref VECTOR macro. - * - * Time complexity: O(1). - */ - -BASE* FUNCTION(igraph_vector, e_ptr)(const TYPE(igraph_vector) *v, igraph_integer_t pos) { - return FUNCTION(igraph_vector, get_ptr)(v, pos); -} - /** * \ingroup vector * \function igraph_vector_set @@ -721,7 +701,7 @@ BASE* FUNCTION(igraph_vector, e_ptr)(const TYPE(igraph_vector) *v, igraph_intege * \sa \ref igraph_vector_get(). */ -void FUNCTION(igraph_vector, set)(TYPE(igraph_vector) *v, igraph_integer_t pos, BASE value) { +void FUNCTION(igraph_vector, set)(TYPE(igraph_vector) *v, igraph_int_t pos, BASE value) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); *(v->stor_begin + pos) = value; @@ -913,7 +893,7 @@ igraph_error_t FUNCTION(igraph_vector, permute)(TYPE(igraph_vector) *v, const ig TYPE(igraph_vector) v_copy; BASE *v_ptr; - igraph_integer_t *ind_ptr; + igraph_int_t *ind_ptr; /* There is a more space-efficient algorithm that needs O(1) space only, * but it messes up the index vector, which we don't want */ @@ -1066,7 +1046,7 @@ igraph_error_t FUNCTION(igraph_vector, sort_ind)( igraph_vector_int_t *inds, igraph_order_t order) { - igraph_integer_t i, n = FUNCTION(igraph_vector, size)(v); + igraph_int_t i, n = FUNCTION(igraph_vector, size)(v); BASE **vind, *first; IGRAPH_CHECK(igraph_vector_int_resize(inds, n)); if (n == 0) { @@ -1092,17 +1072,6 @@ igraph_error_t FUNCTION(igraph_vector, sort_ind)( return IGRAPH_SUCCESS; } -/** - * \function igraph_vector_qsort_ind - * \brief Returns a permutation of indices that sorts a vector (deprecated alias). - * - * \deprecated-by igraph_vector_sort_ind 0.10.14 - */ -igraph_error_t FUNCTION(igraph_vector, qsort_ind)(const TYPE(igraph_vector) *v, - igraph_vector_int_t *inds, igraph_order_t order) { - return FUNCTION(igraph_vector, sort_ind)(v, inds, order); -} - /** * \function igraph_vector_lex_cmp * \brief Lexicographical comparison of two vectors (type-safe variant). @@ -1128,7 +1097,7 @@ igraph_error_t FUNCTION(igraph_vector, qsort_ind)(const TYPE(igraph_vector) *v, int FUNCTION(igraph_vector, lex_cmp)( const TYPE(igraph_vector) *lhs, const TYPE(igraph_vector) *rhs ) { - igraph_integer_t i, sa, sb; + igraph_int_t i, sa, sb; const TYPE(igraph_vector) *a = lhs, *b = rhs; sa = FUNCTION(igraph_vector, size)(a); @@ -1208,7 +1177,7 @@ int FUNCTION(igraph_vector, lex_cmp_untyped)(const void *lhs, const void *rhs) { int FUNCTION(igraph_vector, colex_cmp)( const TYPE(igraph_vector) *lhs, const TYPE(igraph_vector) *rhs ) { - igraph_integer_t i, sa, sb, rai, rbi; + igraph_int_t i, sa, sb, rai, rbi; const TYPE(igraph_vector) *a = lhs, *b = rhs; sa = FUNCTION(igraph_vector, size)(a); @@ -1296,7 +1265,7 @@ int FUNCTION(igraph_vector, colex_cmp_untyped)(const void *lhs, const void *rhs) * n is the new size of the vector. */ -igraph_error_t FUNCTION(igraph_vector, resize)(TYPE(igraph_vector)* v, igraph_integer_t new_size) { +igraph_error_t FUNCTION(igraph_vector, resize)(TYPE(igraph_vector)* v, igraph_int_t new_size) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); IGRAPH_CHECK(FUNCTION(igraph_vector, reserve)(v, new_size)); @@ -1322,7 +1291,7 @@ igraph_error_t FUNCTION(igraph_vector, resize)(TYPE(igraph_vector)* v, igraph_in */ void FUNCTION(igraph_vector, resize_min)(TYPE(igraph_vector) *v) { - igraph_integer_t size; + igraph_int_t size; BASE *tmp; if (v->stor_end == v->end) { return; @@ -1397,7 +1366,7 @@ BASE FUNCTION(igraph_vector, max)(const TYPE(igraph_vector) *v) { * * Time complexity: O(n), n is the size of the vector. */ -igraph_integer_t FUNCTION(igraph_vector, which_max)(const TYPE(igraph_vector) *v) { +igraph_int_t FUNCTION(igraph_vector, which_max)(const TYPE(igraph_vector) *v) { BASE *max; BASE *ptr; IGRAPH_ASSERT(!FUNCTION(igraph_vector, empty)(v)); @@ -1470,7 +1439,7 @@ BASE FUNCTION(igraph_vector, min)(const TYPE(igraph_vector) *v) { * * Time complexity: O(n), the number of elements. */ -igraph_integer_t FUNCTION(igraph_vector, which_min)(const TYPE(igraph_vector)* v) { +igraph_int_t FUNCTION(igraph_vector, which_min)(const TYPE(igraph_vector)* v) { BASE *min; BASE *ptr; IGRAPH_ASSERT(!FUNCTION(igraph_vector, empty)(v)); @@ -1515,7 +1484,7 @@ igraph_integer_t FUNCTION(igraph_vector, which_min)(const TYPE(igraph_vector)* v */ igraph_error_t FUNCTION(igraph_vector, init_array)( - TYPE(igraph_vector) *v, const BASE *data, igraph_integer_t length) { + TYPE(igraph_vector) *v, const BASE *data, igraph_int_t length) { IGRAPH_CHECK(FUNCTION(igraph_vector, init)(v, length)); @@ -1571,7 +1540,7 @@ void FUNCTION(igraph_vector, copy_to)(const TYPE(igraph_vector) *v, BASE *to) { igraph_error_t FUNCTION(igraph_vector, init_copy)( TYPE(igraph_vector) *to, const TYPE(igraph_vector) *from ) { - igraph_integer_t from_size; + igraph_int_t from_size; IGRAPH_ASSERT(from != NULL); IGRAPH_ASSERT(from->stor_begin != NULL); @@ -1584,19 +1553,6 @@ igraph_error_t FUNCTION(igraph_vector, init_copy)( return IGRAPH_SUCCESS; } -/** - * \ingroup vector - * \function igraph_vector_copy - * \brief Initializes a vector from another vector object (deprecated alias). - * - * \deprecated-by igraph_vector_init_copy 0.10 - */ - -igraph_error_t FUNCTION(igraph_vector, copy)(TYPE(igraph_vector) *to, - const TYPE(igraph_vector) *from) { - return FUNCTION(igraph_vector, init_copy)(to, from); -} - /** * \ingroup vector * \function igraph_vector_sum @@ -1712,38 +1668,6 @@ igraph_error_t FUNCTION(igraph_vector, cumsum)(TYPE(igraph_vector) *to, #ifndef NOTORDERED -/** - * \ingroup vector - * \function igraph_vector_init_seq - * \brief Initializes a vector with a sequence, inclusive endpoints (deprecated). - * - * - * The vector will contain the numbers \p from, \p from+1, ..., \p to. Note that - * both endpoints are \em inclusive, contrary to typical usage of ranges in C. - * - * \deprecated-by igraph_vector_init_range 0.10.0 - * - * \param v Pointer to an uninitialized vector object. - * \param from The lower limit in the sequence (inclusive). - * \param to The upper limit in the sequence (inclusive). - * \return Error code: - * \c IGRAPH_ENOMEM: out of memory. - * - * Time complexity: O(n), the number - * of elements in the vector. - */ - -igraph_error_t FUNCTION(igraph_vector, init_seq)(TYPE(igraph_vector) *v, BASE from, BASE to) { - BASE *p; - IGRAPH_CHECK(FUNCTION(igraph_vector, init)(v, (to - from + 1))); - - for (p = v->stor_begin; p < v->end; p++) { - *p = from++; - } - - return IGRAPH_SUCCESS; -} - /** * \ingroup vector * \function igraph_vector_init_range @@ -1793,8 +1717,8 @@ igraph_error_t FUNCTION(igraph_vector, init_range)(TYPE(igraph_vector) *v, BASE */ void FUNCTION(igraph_vector, remove_section)( - TYPE(igraph_vector) *v, igraph_integer_t from, igraph_integer_t to) { - igraph_integer_t size = FUNCTION(igraph_vector, size)(v); + TYPE(igraph_vector) *v, igraph_int_t from, igraph_int_t to) { + igraph_int_t size = FUNCTION(igraph_vector, size)(v); IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); @@ -1828,7 +1752,7 @@ void FUNCTION(igraph_vector, remove_section)( * vector. */ -void FUNCTION(igraph_vector, remove)(TYPE(igraph_vector) *v, igraph_integer_t elem) { +void FUNCTION(igraph_vector, remove)(TYPE(igraph_vector) *v, igraph_int_t elem) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); FUNCTION(igraph_vector, remove_section)(v, elem, elem + 1); @@ -1853,11 +1777,11 @@ void FUNCTION(igraph_vector, remove)(TYPE(igraph_vector) *v, igraph_integer_t el * Time complexity: O(1). */ -void FUNCTION(igraph_vector, remove_fast)(TYPE(igraph_vector) *v, igraph_integer_t elem) { +void FUNCTION(igraph_vector, remove_fast)(TYPE(igraph_vector) *v, igraph_int_t elem) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); - igraph_integer_t len = FUNCTION(igraph_vector, size)(v); + igraph_int_t len = FUNCTION(igraph_vector, size)(v); VECTOR(*v)[elem] = VECTOR(*v)[len - 1]; FUNCTION(igraph_vector, pop_back)(v); } @@ -1881,7 +1805,7 @@ void FUNCTION(igraph_vector, remove_fast)(TYPE(igraph_vector) *v, igraph_integer */ igraph_error_t FUNCTION(igraph_vector, move_interval)(TYPE(igraph_vector) *v, - igraph_integer_t begin, igraph_integer_t end, igraph_integer_t to) { + igraph_int_t begin, igraph_int_t end, igraph_int_t to) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); memmove(v->stor_begin + to, v->stor_begin + begin, @@ -1890,14 +1814,6 @@ igraph_error_t FUNCTION(igraph_vector, move_interval)(TYPE(igraph_vector) *v, return IGRAPH_SUCCESS; } -/** - * \deprecated-by igraph_vector_move_interval 0.10.0 - */ -igraph_error_t FUNCTION(igraph_vector, move_interval2)(TYPE(igraph_vector) *v, - igraph_integer_t begin, igraph_integer_t end, igraph_integer_t to) { - return FUNCTION(igraph_vector, move_interval)(v, begin, end, to); -} - #ifndef NOTORDERED /** @@ -1978,7 +1894,7 @@ igraph_bool_t FUNCTION(igraph_vector, any_smaller)(const TYPE(igraph_vector) *v, igraph_bool_t FUNCTION(igraph_vector, all_e)(const TYPE(igraph_vector) *lhs, const TYPE(igraph_vector) *rhs) { - igraph_integer_t i, s; + igraph_int_t i, s; IGRAPH_ASSERT(lhs != 0); IGRAPH_ASSERT(rhs != 0); IGRAPH_ASSERT(lhs->stor_begin != 0); @@ -2043,7 +1959,7 @@ igraph_bool_t FUNCTION(igraph_vector, is_equal)(const TYPE(igraph_vector) *lhs, igraph_bool_t FUNCTION(igraph_vector, all_l)(const TYPE(igraph_vector) *lhs, const TYPE(igraph_vector) *rhs) { - igraph_integer_t i, s; + igraph_int_t i, s; IGRAPH_ASSERT(lhs != 0); IGRAPH_ASSERT(rhs != 0); IGRAPH_ASSERT(lhs->stor_begin != 0); @@ -2082,7 +1998,7 @@ igraph_bool_t FUNCTION(igraph_vector, all_l)(const TYPE(igraph_vector) *lhs, igraph_bool_t FUNCTION(igraph_vector, all_g)(const TYPE(igraph_vector) *lhs, const TYPE(igraph_vector) *rhs) { - igraph_integer_t i, s; + igraph_int_t i, s; IGRAPH_ASSERT(lhs != 0); IGRAPH_ASSERT(rhs != 0); IGRAPH_ASSERT(lhs->stor_begin != 0); @@ -2120,7 +2036,7 @@ igraph_bool_t FUNCTION(igraph_vector, all_g)(const TYPE(igraph_vector) *lhs, igraph_bool_t FUNCTION(igraph_vector, all_le)(const TYPE(igraph_vector) *lhs, const TYPE(igraph_vector) *rhs) { - igraph_integer_t i, s; + igraph_int_t i, s; IGRAPH_ASSERT(lhs != 0); IGRAPH_ASSERT(rhs != 0); IGRAPH_ASSERT(lhs->stor_begin != 0); @@ -2158,7 +2074,7 @@ igraph_bool_t FUNCTION(igraph_vector, all_le)(const TYPE(igraph_vector) *lhs, igraph_bool_t FUNCTION(igraph_vector, all_ge)(const TYPE(igraph_vector) *lhs, const TYPE(igraph_vector) *rhs) { - igraph_integer_t i, s; + igraph_int_t i, s; IGRAPH_ASSERT(lhs != 0); IGRAPH_ASSERT(rhs != 0); IGRAPH_ASSERT(lhs->stor_begin != 0); @@ -2185,7 +2101,7 @@ igraph_bool_t FUNCTION(igraph_vector, all_ge)(const TYPE(igraph_vector) *lhs, #ifndef NOTORDERED static igraph_bool_t FUNCTION(igraph_i_vector, binsearch_slice)(const TYPE(igraph_vector) *v, - BASE what, igraph_integer_t *pos, igraph_integer_t start, igraph_integer_t end); + BASE what, igraph_int_t *pos, igraph_int_t start, igraph_int_t end); /** * \ingroup vector @@ -2201,12 +2117,12 @@ static igraph_bool_t FUNCTION(igraph_i_vector, binsearch_slice)(const TYPE(igrap * * \param v The \type igraph_vector_t object. * \param what The element to search for. - * \param pos Pointer to an \type igraph_integer_t. This is set to the + * \param pos Pointer to an \type igraph_int_t. This is set to the * position of an instance of \p what in the * vector if it is present. If \p v does not * contain \p what then * \p pos is set to the position to which it - * should be inserted (to keep the the vector sorted of course). + * should be inserted (to keep the vector sorted of course). * \return True if \p what is found in the vector, false otherwise. * * Time complexity: O(log(n)), @@ -2215,7 +2131,7 @@ static igraph_bool_t FUNCTION(igraph_i_vector, binsearch_slice)(const TYPE(igrap */ igraph_bool_t FUNCTION(igraph_vector, binsearch)(const TYPE(igraph_vector) *v, - BASE what, igraph_integer_t *pos) { + BASE what, igraph_int_t *pos) { return FUNCTION(igraph_i_vector, binsearch_slice)(v, what, pos, 0, FUNCTION(igraph_vector, size)(v)); } @@ -2237,10 +2153,10 @@ igraph_bool_t FUNCTION(igraph_vector, binsearch)(const TYPE(igraph_vector) *v, * * \param v The \type igraph_vector_t object. * \param what The element to search for. - * \param pos Pointer to an \type igraph_integer_t. This is set to the position of an + * \param pos Pointer to an \type igraph_int_t. This is set to the position of an * instance of \p what in the slice of the vector if it is present. If \p * v does not contain \p what then \p pos is set to the position to which - * it should be inserted (to keep the the vector sorted). + * it should be inserted (to keep the vector sorted). * \param start The start position of the slice to search (inclusive). * \param end The end position of the slice to search (exclusive). * \return True if \p what is found in the vector, false otherwise. @@ -2250,9 +2166,9 @@ igraph_bool_t FUNCTION(igraph_vector, binsearch)(const TYPE(igraph_vector) *v, */ igraph_bool_t FUNCTION(igraph_vector, binsearch_slice)(const TYPE(igraph_vector) *v, - BASE what, igraph_integer_t *pos, igraph_integer_t start, igraph_integer_t end) { - igraph_integer_t left = start; - igraph_integer_t right = end - 1; + BASE what, igraph_int_t *pos, igraph_int_t start, igraph_int_t end) { + igraph_int_t left = start; + igraph_int_t right = end - 1; if (left < 0) IGRAPH_ERROR("Invalid start position.", IGRAPH_EINVAL); @@ -2268,13 +2184,13 @@ igraph_bool_t FUNCTION(igraph_vector, binsearch_slice)(const TYPE(igraph_vector) } static igraph_bool_t FUNCTION(igraph_i_vector, binsearch_slice)(const TYPE(igraph_vector) *v, - BASE what, igraph_integer_t *pos, igraph_integer_t start, igraph_integer_t end) { - igraph_integer_t left = start; - igraph_integer_t right = end - 1; + BASE what, igraph_int_t *pos, igraph_int_t start, igraph_int_t end) { + igraph_int_t left = start; + igraph_int_t right = end - 1; while (left <= right) { /* (right + left) / 2 could theoretically overflow for long vectors */ - igraph_integer_t middle = left + ((right - left) >> 1); + igraph_int_t middle = left + ((right - left) >> 1); if (VECTOR(*v)[middle] > what) { right = middle - 1; } else if (VECTOR(*v)[middle] < what) { @@ -2310,12 +2226,12 @@ static igraph_bool_t FUNCTION(igraph_i_vector, binsearch_slice)(const TYPE(igrap */ igraph_bool_t FUNCTION(igraph_vector, contains_sorted)(const TYPE(igraph_vector) *v, BASE what) { - igraph_integer_t left = 0; - igraph_integer_t right = FUNCTION(igraph_vector, size)(v) - 1; + igraph_int_t left = 0; + igraph_int_t right = FUNCTION(igraph_vector, size)(v) - 1; while (left <= right) { /* (right + left) / 2 could theoretically overflow for long vectors */ - igraph_integer_t middle = left + ((right - left) >> 1); + igraph_int_t middle = left + ((right - left) >> 1); if (what < VECTOR(*v)[middle]) { right = middle - 1; } else if (what > VECTOR(*v)[middle]) { @@ -2328,18 +2244,6 @@ igraph_bool_t FUNCTION(igraph_vector, contains_sorted)(const TYPE(igraph_vector) return false; } -/** - * \ingroup vector - * \function igraph_vector_binsearch2 - * \brief Binary search, without returning the index. - * - * \deprecated-by igraph_vector_contains_sorted 0.10.14 - */ -igraph_bool_t FUNCTION(igraph_vector, binsearch2)(const TYPE(igraph_vector) *v, - BASE what) { - return FUNCTION(igraph_vector, contains_sorted)(v, what); -} - #endif /** @@ -2356,7 +2260,7 @@ igraph_bool_t FUNCTION(igraph_vector, binsearch2)(const TYPE(igraph_vector) *v, */ void FUNCTION(igraph_vector, scale)(TYPE(igraph_vector) *v, BASE by) { - const igraph_integer_t n = FUNCTION(igraph_vector, size)(v); + const igraph_int_t n = FUNCTION(igraph_vector, size)(v); #ifdef EQ const BASE one = ONE; if (EQ(by, one)) { @@ -2367,7 +2271,7 @@ void FUNCTION(igraph_vector, scale)(TYPE(igraph_vector) *v, BASE by) { return; } #endif - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { #ifdef PROD PROD(VECTOR(*v)[i], VECTOR(*v)[i], by); #else @@ -2389,7 +2293,7 @@ void FUNCTION(igraph_vector, scale)(TYPE(igraph_vector) *v, BASE by) { */ void FUNCTION(igraph_vector, add_constant)(TYPE(igraph_vector) *v, BASE plus) { - const igraph_integer_t n = FUNCTION(igraph_vector, size)(v); + const igraph_int_t n = FUNCTION(igraph_vector, size)(v); #ifdef EQ const BASE zero = ZERO; if (EQ(plus, zero)) { @@ -2400,7 +2304,7 @@ void FUNCTION(igraph_vector, add_constant)(TYPE(igraph_vector) *v, BASE plus) { return; } #endif - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { #ifdef SUM SUM(VECTOR(*v)[i], VECTOR(*v)[i], plus); #else @@ -2461,8 +2365,8 @@ igraph_bool_t FUNCTION(igraph_vector, contains)(const TYPE(igraph_vector) *v, */ igraph_bool_t FUNCTION(igraph_vector, search)(const TYPE(igraph_vector) *v, - igraph_integer_t from, BASE what, igraph_integer_t *pos) { - igraph_integer_t i, n = FUNCTION(igraph_vector, size)(v); + igraph_int_t from, BASE what, igraph_int_t *pos) { + igraph_int_t i, n = FUNCTION(igraph_vector, size)(v); for (i = from; i < n; i++) { #ifdef EQ if (EQ(VECTOR(*v)[i], what)) { @@ -2494,8 +2398,8 @@ igraph_bool_t FUNCTION(igraph_vector, search)(const TYPE(igraph_vector) *v, igraph_error_t FUNCTION(igraph_vector, filter_smaller)(TYPE(igraph_vector) *v, BASE elem) { - igraph_integer_t i = 0, n = FUNCTION(igraph_vector, size)(v); - igraph_integer_t s; + igraph_int_t i = 0, n = FUNCTION(igraph_vector, size)(v); + igraph_int_t s; while (i < n && VECTOR(*v)[i] < elem) { i++; } @@ -2524,17 +2428,28 @@ igraph_error_t FUNCTION(igraph_vector, filter_smaller)(TYPE(igraph_vector) *v, */ igraph_error_t FUNCTION(igraph_vector, append)(TYPE(igraph_vector) *to, - const TYPE(igraph_vector) *from) { - igraph_integer_t tosize, fromsize; - igraph_integer_t newsize; + const TYPE(igraph_vector) *from) { + IGRAPH_ASSERT(to != NULL); + IGRAPH_ASSERT(to->stor_begin != NULL); + + const igraph_int_t to_size = FUNCTION(igraph_vector, size)(to); + const igraph_int_t from_size = FUNCTION(igraph_vector, size)(from); + const igraph_int_t to_capacity = FUNCTION(igraph_vector, capacity)(to); + igraph_int_t new_to_size; - tosize = FUNCTION(igraph_vector, size)(to); - fromsize = FUNCTION(igraph_vector, size)(from); - IGRAPH_SAFE_ADD(tosize, fromsize, &newsize); - IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(to, newsize)); - memcpy(to->stor_begin + tosize, from->stor_begin, - sizeof(BASE) * fromsize); - to->end = to->stor_begin + tosize + fromsize; + IGRAPH_SAFE_ADD(to_size, from_size, &new_to_size); + + if (to_capacity < new_to_size) { + igraph_int_t new_to_capacity = to_capacity < IGRAPH_INTEGER_MAX/2 ? to_capacity * 2 : IGRAPH_INTEGER_MAX; + if (new_to_capacity < new_to_size) { + new_to_capacity = new_to_size; + } + IGRAPH_CHECK(FUNCTION(igraph_vector, reserve)(to, new_to_capacity)); + } + + memcpy(to->stor_begin + to_size, from->stor_begin, + sizeof(BASE) * from_size); + to->end = to->stor_begin + new_to_size; return IGRAPH_SUCCESS; } @@ -2544,7 +2459,7 @@ igraph_error_t FUNCTION(igraph_vector, append)(TYPE(igraph_vector) *to, */ igraph_error_t FUNCTION(igraph_vector, get_interval)(const TYPE(igraph_vector) *v, - TYPE(igraph_vector) *res, igraph_integer_t from, igraph_integer_t to) { + TYPE(igraph_vector) *res, igraph_int_t from, igraph_int_t to) { IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(res, to - from)); memcpy(res->stor_begin, v->stor_begin + from, (to - from) * sizeof(BASE)); @@ -2571,10 +2486,10 @@ igraph_error_t FUNCTION(igraph_vector, get_interval)(const TYPE(igraph_vector) * igraph_real_t FUNCTION(igraph_vector, maxdifference)(const TYPE(igraph_vector) *m1, const TYPE(igraph_vector) *m2) { - igraph_integer_t n1 = FUNCTION(igraph_vector, size)(m1); - igraph_integer_t n2 = FUNCTION(igraph_vector, size)(m2); - igraph_integer_t n = n1 < n2 ? n1 : n2; - igraph_integer_t i; + igraph_int_t n1 = FUNCTION(igraph_vector, size)(m1); + igraph_int_t n2 = FUNCTION(igraph_vector, size)(m2); + igraph_int_t n = n1 < n2 ? n1 : n2; + igraph_int_t i; igraph_real_t diff = 0.0; for (i = 0; i < n; i++) { @@ -2611,7 +2526,7 @@ igraph_real_t FUNCTION(igraph_vector, maxdifference)(const TYPE(igraph_vector) * igraph_error_t FUNCTION(igraph_vector, update)(TYPE(igraph_vector) *to, const TYPE(igraph_vector) *from) { - igraph_integer_t n = FUNCTION(igraph_vector, size)(from); + igraph_int_t n = FUNCTION(igraph_vector, size)(from); IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(to, n)); memcpy(to->stor_begin, from->stor_begin, sizeof(BASE)*n); return IGRAPH_SUCCESS; @@ -2623,20 +2538,17 @@ igraph_error_t FUNCTION(igraph_vector, update)(TYPE(igraph_vector) *to, * * \param v1 The first vector. * \param v2 The second vector. - * \return Error code. * * Time complexity: O(1). */ -igraph_error_t FUNCTION(igraph_vector, swap)(TYPE(igraph_vector) *v1, TYPE(igraph_vector) *v2) { +void FUNCTION(igraph_vector, swap)(TYPE(igraph_vector) *v1, TYPE(igraph_vector) *v2) { TYPE(igraph_vector) tmp; tmp = *v1; *v1 = *v2; *v2 = tmp; - - return IGRAPH_SUCCESS; } /** @@ -2644,22 +2556,19 @@ igraph_error_t FUNCTION(igraph_vector, swap)(TYPE(igraph_vector) *v1, TYPE(igrap * \brief Swap two elements in a vector. * * Note that currently no range checking is performed. + * * \param v The input vector. * \param i Index of the first element. - * \param j Index of the second element (may be the same as the - * first one). - * \return Error code, currently always \c IGRAPH_SUCCESS. + * \param j Index of the second element (may be the same as the first one). * * Time complexity: O(1). */ -igraph_error_t FUNCTION(igraph_vector, swap_elements)(TYPE(igraph_vector) *v, - igraph_integer_t i, igraph_integer_t j) { +void FUNCTION(igraph_vector, swap_elements)(TYPE(igraph_vector) *v, + igraph_int_t i, igraph_int_t j) { BASE tmp = VECTOR(*v)[i]; VECTOR(*v)[i] = VECTOR(*v)[j]; VECTOR(*v)[j] = tmp; - - return IGRAPH_SUCCESS; } /** @@ -2675,9 +2584,9 @@ igraph_error_t FUNCTION(igraph_vector, swap_elements)(TYPE(igraph_vector) *v, * Time complexity: O(to - from), the number of elements to reverse. */ -void FUNCTION(igraph_vector, reverse_section)(TYPE(igraph_vector) *v, igraph_integer_t from, igraph_integer_t to) { - const igraph_integer_t mid = (from + to) / 2; - for (igraph_integer_t i = from, j = to - 1; i < mid; i++, j--) { +void FUNCTION(igraph_vector, reverse_section)(TYPE(igraph_vector) *v, igraph_int_t from, igraph_int_t to) { + const igraph_int_t mid = (from + to) / 2; + for (igraph_int_t i = from, j = to - 1; i < mid; i++, j--) { BASE tmp = VECTOR(*v)[i]; VECTOR(*v)[i] = VECTOR(*v)[j]; VECTOR(*v)[j] = tmp; @@ -2692,16 +2601,14 @@ void FUNCTION(igraph_vector, reverse_section)(TYPE(igraph_vector) *v, igraph_int * first, etc. * * \param v The input vector. - * \return Error code, currently always \c IGRAPH_SUCCESS. * * \sa igraph_vector_reverse_section() to reverse only a section of a vector. * * Time complexity: O(n), the number of elements. */ -igraph_error_t FUNCTION(igraph_vector, reverse)(TYPE(igraph_vector) *v) { +void FUNCTION(igraph_vector, reverse)(TYPE(igraph_vector) *v) { FUNCTION(igraph_vector, reverse_section)(v, 0, FUNCTION(igraph_vector, size)(v)); - return IGRAPH_SUCCESS; } /** @@ -2720,8 +2627,8 @@ igraph_error_t FUNCTION(igraph_vector, reverse)(TYPE(igraph_vector) *v) { * Time complexity: O(n), the number of elements. */ -void FUNCTION(igraph_vector, rotate_left)(TYPE(igraph_vector) *v, igraph_integer_t n) { - const igraph_integer_t size = FUNCTION(igraph_vector, size)(v); +void FUNCTION(igraph_vector, rotate_left)(TYPE(igraph_vector) *v, igraph_int_t n) { + const igraph_int_t size = FUNCTION(igraph_vector, size)(v); n = n % size; if (n < 0) n += size; if (n == 0) return; @@ -2742,7 +2649,6 @@ void FUNCTION(igraph_vector, rotate_left)(TYPE(igraph_vector) *v, igraph_integer * these generators is less than the number of possible permutations * of the vector if the vector is long enough. * \param v The vector object. - * \return Error code, currently always \c IGRAPH_SUCCESS. * * Time complexity: O(n), * n is the number of elements in the @@ -2763,12 +2669,11 @@ void FUNCTION(igraph_vector, rotate_left)(TYPE(igraph_vector) *v, igraph_integer * \example examples/simple/igraph_fisher_yates_shuffle.c */ -igraph_error_t FUNCTION(igraph_vector, shuffle)(TYPE(igraph_vector) *v) { - igraph_integer_t n = FUNCTION(igraph_vector, size)(v); - igraph_integer_t k; +void FUNCTION(igraph_vector, shuffle)(TYPE(igraph_vector) *v) { + igraph_int_t n = FUNCTION(igraph_vector, size)(v); + igraph_int_t k; BASE dummy; - RNG_BEGIN(); while (n > 1) { k = RNG_INTEGER(0, n - 1); n--; @@ -2776,9 +2681,6 @@ igraph_error_t FUNCTION(igraph_vector, shuffle)(TYPE(igraph_vector) *v) { VECTOR(*v)[n] = VECTOR(*v)[k]; VECTOR(*v)[k] = dummy; } - RNG_END(); - - return IGRAPH_SUCCESS; } /** @@ -2797,9 +2699,9 @@ igraph_error_t FUNCTION(igraph_vector, shuffle)(TYPE(igraph_vector) *v) { igraph_error_t FUNCTION(igraph_vector, add)(TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2) { - igraph_integer_t n1 = FUNCTION(igraph_vector, size)(v1); - igraph_integer_t n2 = FUNCTION(igraph_vector, size)(v2); - igraph_integer_t i; + igraph_int_t n1 = FUNCTION(igraph_vector, size)(v1); + igraph_int_t n2 = FUNCTION(igraph_vector, size)(v2); + igraph_int_t i; if (n1 != n2) { IGRAPH_ERROR("Vectors to be added must have the same sizes.", IGRAPH_EINVAL); @@ -2833,9 +2735,9 @@ igraph_error_t FUNCTION(igraph_vector, add)(TYPE(igraph_vector) *v1, igraph_error_t FUNCTION(igraph_vector, sub)(TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2) { - igraph_integer_t n1 = FUNCTION(igraph_vector, size)(v1); - igraph_integer_t n2 = FUNCTION(igraph_vector, size)(v2); - igraph_integer_t i; + igraph_int_t n1 = FUNCTION(igraph_vector, size)(v1); + igraph_int_t n2 = FUNCTION(igraph_vector, size)(v2); + igraph_int_t i; if (n1 != n2) { IGRAPH_ERROR("Vectors to be subtracted must have the same sizes.", IGRAPH_EINVAL); @@ -2868,9 +2770,9 @@ igraph_error_t FUNCTION(igraph_vector, sub)(TYPE(igraph_vector) *v1, igraph_error_t FUNCTION(igraph_vector, mul)(TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2) { - igraph_integer_t n1 = FUNCTION(igraph_vector, size)(v1); - igraph_integer_t n2 = FUNCTION(igraph_vector, size)(v2); - igraph_integer_t i; + igraph_int_t n1 = FUNCTION(igraph_vector, size)(v1); + igraph_int_t n2 = FUNCTION(igraph_vector, size)(v2); + igraph_int_t i; if (n1 != n2) { IGRAPH_ERROR("Vectors to be multiplied must have the same sizes.", IGRAPH_EINVAL); @@ -2905,9 +2807,9 @@ igraph_error_t FUNCTION(igraph_vector, mul)(TYPE(igraph_vector) *v1, igraph_error_t FUNCTION(igraph_vector, div)(TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2) { - igraph_integer_t n1 = FUNCTION(igraph_vector, size)(v1); - igraph_integer_t n2 = FUNCTION(igraph_vector, size)(v2); - igraph_integer_t i; + igraph_int_t n1 = FUNCTION(igraph_vector, size)(v1); + igraph_int_t n2 = FUNCTION(igraph_vector, size)(v2); + igraph_int_t i; if (n1 != n2) { IGRAPH_ERROR("Vectors to be divided must have the same sizes.", IGRAPH_EINVAL); @@ -2931,7 +2833,7 @@ igraph_error_t FUNCTION(igraph_vector, abs)(TYPE(igraph_vector) *v) { /* Nothing do to, unsigned type */ IGRAPH_UNUSED(v); #else - igraph_integer_t i, n = FUNCTION(igraph_vector, size)(v); + igraph_int_t i, n = FUNCTION(igraph_vector, size)(v); for (i = 0; i < n; i++) { VECTOR(*v)[i] = VECTOR(*v)[i] >= 0 ? VECTOR(*v)[i] : -VECTOR(*v)[i]; } @@ -3005,7 +2907,7 @@ void FUNCTION(igraph_vector, minmax)(const TYPE(igraph_vector) *v, */ void FUNCTION(igraph_vector, which_minmax)(const TYPE(igraph_vector) *v, - igraph_integer_t *which_min, igraph_integer_t *which_max) { + igraph_int_t *which_min, igraph_int_t *which_max) { BASE *min, *max; BASE *ptr; IGRAPH_ASSERT(!FUNCTION(igraph_vector, empty)(v)); @@ -3051,8 +2953,8 @@ void FUNCTION(igraph_vector, which_minmax)(const TYPE(igraph_vector) *v, igraph_bool_t FUNCTION(igraph_vector, isnull)(const TYPE(igraph_vector) *v) { - igraph_integer_t n = FUNCTION(igraph_vector, size)(v); - igraph_integer_t i = 0; + igraph_int_t n = FUNCTION(igraph_vector, size)(v); + igraph_int_t i = 0; #ifdef EQ while (i < n && EQ(VECTOR(*v)[i], (BASE) ZERO)) { @@ -3074,10 +2976,10 @@ igraph_bool_t FUNCTION(igraph_vector, isnull)(const TYPE(igraph_vector) *v) { /* Recursive Baeza-Yates intersection algorithm for sorted vector intersection. */ static igraph_error_t FUNCTION(igraph_i_vector, intersect_sorted)( - const TYPE(igraph_vector) *v1, igraph_integer_t begin1, igraph_integer_t end1, - const TYPE(igraph_vector) *v2, igraph_integer_t begin2, igraph_integer_t end2, + const TYPE(igraph_vector) *v1, igraph_int_t begin1, igraph_int_t end1, + const TYPE(igraph_vector) *v2, igraph_int_t begin2, igraph_int_t end2, TYPE(igraph_vector) *result) { - igraph_integer_t size1, size2, probe1, probe2; + igraph_int_t size1, size2, probe1, probe2; if (begin1 == end1 || begin2 == end2) { return IGRAPH_SUCCESS; @@ -3154,7 +3056,7 @@ static igraph_error_t FUNCTION(igraph_i_vector, intersect_sorted)( */ igraph_error_t FUNCTION(igraph_vector, intersect_sorted)(const TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2, TYPE(igraph_vector) *result) { - igraph_integer_t size1, size2; + igraph_int_t size1, size2; igraph_real_t r; size1 = FUNCTION(igraph_vector, size)(v1); @@ -3171,7 +3073,7 @@ igraph_error_t FUNCTION(igraph_vector, intersect_sorted)(const TYPE(igraph_vecto /* When the set size ratio is small, use a simple linear scan. See comments in * igraph_vector_intersection_size_sorted() for the justification of this r threshold. */ if (r < 10) { - igraph_integer_t i1 = 0, i2 = 0; + igraph_int_t i1 = 0, i2 = 0; while (i1 < size1 && i2 < size2) { BASE e1 = VECTOR(*v1)[i1], e2 = VECTOR(*v2)[i2]; if (e1 < e2) { @@ -3192,11 +3094,11 @@ igraph_error_t FUNCTION(igraph_vector, intersect_sorted)(const TYPE(igraph_vecto /* Recursive Baeza-Yates intersection algorithm for sorted vector intersection size. */ static void FUNCTION(igraph_i_vector, intersection_size_sorted)( - const TYPE(igraph_vector) *v1, igraph_integer_t begin1, igraph_integer_t end1, - const TYPE(igraph_vector) *v2, igraph_integer_t begin2, igraph_integer_t end2, - igraph_integer_t *result) { + const TYPE(igraph_vector) *v1, igraph_int_t begin1, igraph_int_t end1, + const TYPE(igraph_vector) *v2, igraph_int_t begin2, igraph_int_t end2, + igraph_int_t *result) { - igraph_integer_t size1, size2, probe1, probe2; + igraph_int_t size1, size2, probe1, probe2; if (begin1 == end1 || begin2 == end2) { return; @@ -3238,8 +3140,6 @@ static void FUNCTION(igraph_i_vector, intersection_size_sorted)( * \function igraph_vector_intersection_size_sorted * \brief Intersection size of two sorted vectors. * - * \experimental - * * Counts elements that are present in both vectors. This is particularly * useful for counting common neighbours of two vertices. * @@ -3271,11 +3171,11 @@ static void FUNCTION(igraph_i_vector, intersection_size_sorted)( * and n is the size of the larger one. */ -igraph_integer_t FUNCTION(igraph_vector, intersection_size_sorted)( +igraph_int_t FUNCTION(igraph_vector, intersection_size_sorted)( const TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2) { - igraph_integer_t size1, size2, count; + igraph_int_t size1, size2, count; igraph_real_t r; size1 = FUNCTION(igraph_vector, size)(v1); @@ -3297,10 +3197,10 @@ igraph_integer_t FUNCTION(igraph_vector, intersection_size_sorted)( if (r < 10) { /* This is a fast branchless implementation that uses arithmetic * instead of conditionals. */ - igraph_integer_t i1 = 0, i2 = 0; + igraph_int_t i1 = 0, i2 = 0; while (i1 < size1 && i2 < size2) { BASE e1 = VECTOR(*v1)[i1], e2 = VECTOR(*v2)[i2]; - igraph_integer_t d1 = (e1 <= e2), d2 = (e1 >= e2); + igraph_int_t d1 = (e1 <= e2), d2 = (e1 >= e2); i1 += d1; i2 += d2; count += (d1 == d2); } @@ -3319,65 +3219,147 @@ igraph_integer_t FUNCTION(igraph_vector, intersection_size_sorted)( * The elements that are contained in only the first vector but not the second are * stored in the result vector. All three vectors must be initialized. * + * + * The algorithm keeps the multiplicities of the elements: if an element appears + * \c k1 times in the first vector and \c k2 times in the second, the result + * will include that element max(0, k1-k2) times. + * * \param v1 the first vector * \param v2 the second vector * \param result the result vector */ igraph_error_t FUNCTION(igraph_vector, difference_sorted)(const TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2, TYPE(igraph_vector) *result) { - igraph_integer_t i, j, i0, j0; + return FUNCTION(igraph_vector, difference_and_intersection_sorted)( + v1, v2, result, NULL, NULL + ); +} + +/** + * \function igraph_vector_difference_and_intersection_sorted + * \brief Simultaneous difference and intersection of two sorted vectors. + * + * This function iterates over all the elements of the two input vectors and + * sorts them into three other vectors: elements that are in the first vector + * but not in the second, elements that are in the second vector but not in the + * first, and the intersection of the two vectors. The input vectors must be + * initialized. The output arguments can be \c NULL, but they must be initialized + * if they are not \c NULL and will be resized accordingly. + * + * + * The multiplicities of the individual elements are treated consistently with + * \ref igraph_vector_difference_sorted() and \ref igraph_vector_intersect_sorted(): + * The algorithm keeps the multiplicities of the elements: if an element appears + * \c k1 times in the first vector and \c k2 times in the second, the intersection + * vector will include that element min(k1, k2) times, while the + * difference vectors will include that element max(0, k1-k2) and + * max(0, k2-k1) times, respectively. + * + * \param v1 the first vector + * \param v2 the second vector + * \param vdiff12 output vector containing the elements that are in the first + * vector but not the second one, or \c NULL if not needed + * \param vdiff21 output vector containing the elements that are in the second + * vector but not the first one, or \c NULL if not needed + * \param vint output vector containing the intersection, or \c NULL if not + * needed + */ +igraph_error_t FUNCTION(igraph_vector, difference_and_intersection_sorted)( + const TYPE(igraph_vector) *v1, const TYPE(igraph_vector) *v2, + TYPE(igraph_vector) *vdiff12, TYPE(igraph_vector)*vdiff21, + TYPE(igraph_vector)*vint) { + igraph_int_t i, j, i0, j0, oldsize; i0 = FUNCTION(igraph_vector, size)(v1); j0 = FUNCTION(igraph_vector, size)(v2); i = j = 0; + if (!vdiff12 && !vdiff21 && !vint) { + /* nothing to compute */ + return IGRAPH_SUCCESS; + } + + if (vdiff12) { + FUNCTION(igraph_vector, clear)(vdiff12); + } + if (vdiff21) { + FUNCTION(igraph_vector, clear)(vdiff21); + } + if (vint) { + FUNCTION(igraph_vector, clear)(vint); + } + if (i0 == 0) { /* v1 is empty, this is easy */ - FUNCTION(igraph_vector, clear)(result); + if (vdiff21) { + IGRAPH_CHECK(FUNCTION(igraph_vector, update)(vdiff21, v2)); + } return IGRAPH_SUCCESS; } if (j0 == 0) { /* v2 is empty, this is easy */ - IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(result, i0)); - memcpy(result->stor_begin, v1->stor_begin, sizeof(BASE) * i0); + if (vdiff12) { + IGRAPH_CHECK(FUNCTION(igraph_vector, update)(vdiff12, v1)); + } return IGRAPH_SUCCESS; } - FUNCTION(igraph_vector, clear)(result); - /* Copy the part of v1 that is less than the first element of v2 */ while (i < i0 && VECTOR(*v1)[i] < VECTOR(*v2)[j]) { i++; } - if (i > 0) { - IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(result, i)); - memcpy(result->stor_begin, v1->stor_begin, sizeof(BASE) * i); + if (vdiff12 && i > 0) { + IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(vdiff12, i)); + memcpy(vdiff12->stor_begin, v1->stor_begin, sizeof(BASE) * i); + } + + /* Copy the part of v2 that is less than the first element of v1 */ + while (j < j0 && VECTOR(*v2)[j] < VECTOR(*v1)[i]) { + j++; + } + if (vdiff21 && j > 0) { + IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(vdiff21, j)); + memcpy(vdiff21->stor_begin, v2->stor_begin, sizeof(BASE) * j); } + /* Now process the common segments */ while (i < i0 && j < j0) { - BASE element = VECTOR(*v1)[i]; - if (element == VECTOR(*v2)[j]) { + BASE element1 = VECTOR(*v1)[i]; + BASE element2 = VECTOR(*v2)[j]; + if (element1 == element2) { i++; j++; - while (i < i0 && VECTOR(*v1)[i] == element) { - i++; + if (vint) { + IGRAPH_CHECK(FUNCTION(igraph_vector, push_back)(vint, element1)); } - while (j < j0 && VECTOR(*v2)[j] == element) { - j++; + } else if (element1 < element2) { + if (vdiff12) { + IGRAPH_CHECK(FUNCTION(igraph_vector, push_back)(vdiff12, element1)); } - } else if (element < VECTOR(*v2)[j]) { - IGRAPH_CHECK(FUNCTION(igraph_vector, push_back)(result, element)); i++; } else { + if (vdiff21) { + IGRAPH_CHECK(FUNCTION(igraph_vector, push_back)(vdiff21, element2)); + } j++; } } - if (i < i0) { - igraph_integer_t oldsize = FUNCTION(igraph_vector, size)(result); - IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(result, oldsize + i0 - i)); - memcpy(result->stor_begin + oldsize, v1->stor_begin + i, + + /* Copy the part of v1 that is greater than the last element of v2 */ + if (vdiff12 && i < i0) { + oldsize = FUNCTION(igraph_vector, size)(vdiff12); + IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(vdiff12, oldsize + i0 - i)); + memcpy(vdiff12->stor_begin + oldsize, v1->stor_begin + i, sizeof(BASE) * (i0 - i)); } + /* Copy the part of v2 that is greater than the last element of v1 */ + if (vdiff21 && j < j0) { + oldsize = FUNCTION(igraph_vector, size)(vdiff21); + IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(vdiff21, oldsize + j0 - j)); + memcpy(vdiff21->stor_begin + oldsize, v2->stor_begin + j, + sizeof(BASE) * (j0 - j)); + } + return IGRAPH_SUCCESS; } @@ -3386,7 +3368,7 @@ igraph_error_t FUNCTION(igraph_vector, difference_sorted)(const TYPE(igraph_vect #ifdef OUT_FORMAT #ifndef USING_R igraph_error_t FUNCTION(igraph_vector, printf)(const TYPE(igraph_vector) *v, const char *format) { - igraph_integer_t i, n = FUNCTION(igraph_vector, size)(v); + igraph_int_t i, n = FUNCTION(igraph_vector, size)(v); if (n != 0) { printf(format, VECTOR(*v)[0]); } @@ -3408,7 +3390,7 @@ igraph_error_t FUNCTION(igraph_vector, print)(const TYPE(igraph_vector) *v) { #endif igraph_error_t FUNCTION(igraph_vector, fprint)(const TYPE(igraph_vector) *v, FILE *file) { - igraph_integer_t i, n = FUNCTION(igraph_vector, size)(v); + igraph_int_t i, n = FUNCTION(igraph_vector, size)(v); if (n != 0) { #ifdef FPRINTFUNC FPRINTFUNC(file, VECTOR(*v)[0]); @@ -3429,11 +3411,22 @@ igraph_error_t FUNCTION(igraph_vector, fprint)(const TYPE(igraph_vector) *v, FIL #endif /* defined(OUT_FORMAT) || defined(FPRINTFUNC) */ +/** + * \function igraph_vector_index + * \brief Extract elements from a vector at specific indices. + * + * \param v the vector to extract elements from + * \param newv the result vector + * \param idx vector containing the indices of the elements to extract + * + * \sa \ref igraph_vector_index_in_place for the in-place variant + */ + igraph_error_t FUNCTION(igraph_vector, index)(const TYPE(igraph_vector) *v, TYPE(igraph_vector) *newv, const igraph_vector_int_t *idx) { - igraph_integer_t i, j, newlen = igraph_vector_int_size(idx); + igraph_int_t i, j, newlen = igraph_vector_int_size(idx); IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(newv, newlen)); for (i = 0; i < newlen; i++) { @@ -3444,10 +3437,21 @@ igraph_error_t FUNCTION(igraph_vector, index)(const TYPE(igraph_vector) *v, return IGRAPH_SUCCESS; } -igraph_error_t FUNCTION(igraph_vector, index_int)(TYPE(igraph_vector) *v, +/** + * \function igraph_vector_index_in_place + * \brief Extract elements from a vector at specific indices in-place. + * + * \param v the vector to extract elements from. This will be modified in-place. + * \param idx vector containing the indices of the elements to extract + * + * \sa \ref igraph_vector_index for a function that does not modify the original + * vector + */ + +igraph_error_t FUNCTION(igraph_vector, index_in_place)(TYPE(igraph_vector) *v, const igraph_vector_int_t *idx) { BASE *tmp; - igraph_integer_t i, n = igraph_vector_int_size(idx); + igraph_int_t i, n = igraph_vector_int_size(idx); tmp = IGRAPH_CALLOC(n, BASE); if (!tmp) { diff --git a/src/vendor/cigraph/src/core/vector_list.c b/src/vendor/cigraph/src/core/vector_list.c index 5f761b11530..93455d2af51 100644 --- a/src/vendor/cigraph/src/core/vector_list.c +++ b/src/vendor/cigraph/src/core/vector_list.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify diff --git a/src/vendor/cigraph/src/core/vector_ptr.c b/src/vendor/cigraph/src/core/vector_ptr.c index ce063fd69da..f451713cd39 100644 --- a/src/vendor/cigraph/src/core/vector_ptr.c +++ b/src/vendor/cigraph/src/core/vector_ptr.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -27,6 +26,8 @@ #include "igraph_memory.h" #include "igraph_qsort.h" +#include "math/safe_intop.h" + #include /* memcpy & co. */ #include /* uintptr_t */ #include @@ -82,8 +83,8 @@ * time \endquote required to allocate \p size elements. */ -igraph_error_t igraph_vector_ptr_init(igraph_vector_ptr_t* v, igraph_integer_t size) { - igraph_integer_t alloc_size = size > 0 ? size : 1; +igraph_error_t igraph_vector_ptr_init(igraph_vector_ptr_t* v, igraph_int_t size) { + igraph_int_t alloc_size = size > 0 ? size : 1; IGRAPH_ASSERT(v != NULL); if (size < 0) { size = 0; @@ -102,14 +103,14 @@ igraph_error_t igraph_vector_ptr_init(igraph_vector_ptr_t* v, igraph_integer_t s /** */ -const igraph_vector_ptr_t *igraph_vector_ptr_view( - const igraph_vector_ptr_t *v, void *const *data, igraph_integer_t length +igraph_vector_ptr_t igraph_vector_ptr_view( + void *const *data, igraph_int_t length ) { - igraph_vector_ptr_t *v2 = (igraph_vector_ptr_t*) v; - v2->stor_begin = (void **)data; - v2->stor_end = (void**)data + length; - v2->end = v2->stor_end; - v2->item_destructor = 0; + igraph_vector_ptr_t v; + v.stor_begin = (void **)data; + v.stor_end = (void**)data + length; + v.end = v.stor_end; + v.item_destructor = 0; return v; } @@ -205,14 +206,14 @@ void igraph_vector_ptr_destroy_all(igraph_vector_ptr_t* v) { /** * \ingroup vectorptr + * \function igraph_vector_ptr_reserve * \brief Reserves memory for a pointer vector for later use. * - * @return Error code: - * - IGRAPH_ENOMEM: out of memory + * \return Error code. */ -igraph_error_t igraph_vector_ptr_reserve(igraph_vector_ptr_t* v, igraph_integer_t capacity) { - igraph_integer_t actual_size = igraph_vector_ptr_size(v); +igraph_error_t igraph_vector_ptr_reserve(igraph_vector_ptr_t* v, igraph_int_t capacity) { + igraph_int_t actual_size = igraph_vector_ptr_size(v); void **tmp; IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); @@ -232,6 +233,39 @@ igraph_error_t igraph_vector_ptr_reserve(igraph_vector_ptr_t* v, igraph_integer_ return IGRAPH_SUCCESS; } +/** + * \ingroup vectorptr + * \function igraph_vector_ptr_resize_min + * \brief Deallocate the unused memory of a pointer vector. + * + * This function attempts to deallocate the unused reserved storage + * of a pointer vector. If it succeeds, \ref igraph_vector_ptr_size() and + * \ref igraph_vector_ptr_capacity() will be the same. The data in the + * pointer vector is always preserved, even if deallocation is not successful. + * + * \param v Pointer to an initialized pointer vector. + * + * \sa \ref igraph_vector_ptr_resize(), \ref igraph_vector_ptr_reserve(). + * + * Time complexity: operating system dependent, O(n) at worst. + */ + +void igraph_vector_ptr_resize_min(igraph_vector_ptr_t* v) { + igraph_int_t size; + void **tmp; + if (v->stor_end == v->end) { + return; + } + + size = (v->end - v->stor_begin); + tmp = IGRAPH_REALLOC(v->stor_begin, size, void *); + + if (tmp != NULL) { + v->stor_begin = tmp; + v->stor_end = v->end = v->stor_begin + size; + } +} + /** * \ingroup vectorptr * \brief Decides whether the pointer vector is empty. @@ -254,12 +288,29 @@ igraph_bool_t igraph_vector_ptr_empty(const igraph_vector_ptr_t* v) { * Time complexity: O(1). */ -igraph_integer_t igraph_vector_ptr_size(const igraph_vector_ptr_t* v) { +igraph_int_t igraph_vector_ptr_size(const igraph_vector_ptr_t* v) { IGRAPH_ASSERT(v != NULL); - /* IGRAPH_ASSERT(v->stor_begin != NULL); */ /* TODO */ + IGRAPH_ASSERT(v->stor_begin != NULL); return v->end - v->stor_begin; } +/** + * \ingroup vectorptr + * \function igraph_vector_ptr_capacity + * \brief Returns the allocated capacity of the pointer vector. + * + * \param v The pointer vector object. + * \return The allocated capacity. + * + * Time complexity: O(1). + */ + +igraph_int_t igraph_vector_ptr_capacity(const igraph_vector_ptr_t* v) { + IGRAPH_ASSERT(v != NULL); + IGRAPH_ASSERT(v->stor_begin != NULL); + return v->stor_end - v->stor_begin; +} + /** * \ingroup vectorptr * \function igraph_vector_ptr_clear @@ -312,7 +363,7 @@ igraph_error_t igraph_vector_ptr_push_back(igraph_vector_ptr_t* v, void* e) { /* full, allocate more storage */ if (v->stor_end == v->end) { - igraph_integer_t new_size = igraph_vector_ptr_size(v) * 2; + igraph_int_t new_size = igraph_vector_ptr_size(v) * 2; if (new_size == 0) { new_size = 1; } @@ -362,8 +413,8 @@ void *igraph_vector_ptr_pop_back(igraph_vector_ptr_t *v) { * \param pos The position where the new element is inserted. * \param e The inserted element */ -igraph_error_t igraph_vector_ptr_insert(igraph_vector_ptr_t* v, igraph_integer_t pos, void* e) { - igraph_integer_t size = igraph_vector_ptr_size(v); +igraph_error_t igraph_vector_ptr_insert(igraph_vector_ptr_t* v, igraph_int_t pos, void* e) { + igraph_int_t size = igraph_vector_ptr_size(v); IGRAPH_CHECK(igraph_vector_ptr_resize(v, size + 1)); if (pos < size) { memmove(v->stor_begin + pos + 1, v->stor_begin + pos, @@ -385,24 +436,12 @@ igraph_error_t igraph_vector_ptr_insert(igraph_vector_ptr_t* v, igraph_integer_t * Time complexity: O(1). */ -void *igraph_vector_ptr_get(const igraph_vector_ptr_t* v, igraph_integer_t pos) { +void *igraph_vector_ptr_get(const igraph_vector_ptr_t* v, igraph_int_t pos) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return *(v->stor_begin + pos); } -/** - * \ingroup vectorptr - * \function igraph_vector_ptr_e - * \brief Access an element of a pointer vector (deprecated alias). - * - * \deprecated-by igraph_vector_ptr_get 0.10.0 - */ - -void *igraph_vector_ptr_e(const igraph_vector_ptr_t* v, igraph_integer_t pos) { - return igraph_vector_ptr_get(v, pos); -} - /** * \ingroup vectorptr * \function igraph_vector_ptr_set @@ -415,7 +454,7 @@ void *igraph_vector_ptr_e(const igraph_vector_ptr_t* v, igraph_integer_t pos) { * Time complexity: O(1). */ -void igraph_vector_ptr_set(igraph_vector_ptr_t* v, igraph_integer_t pos, void* value) { +void igraph_vector_ptr_set(igraph_vector_ptr_t* v, igraph_int_t pos, void* value) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); *(v->stor_begin + pos) = value; @@ -454,7 +493,7 @@ void igraph_vector_ptr_null(igraph_vector_ptr_t* v) { * needed to allocate the memory for the vector elements. */ -igraph_error_t igraph_vector_ptr_resize(igraph_vector_ptr_t* v, igraph_integer_t newsize) { +igraph_error_t igraph_vector_ptr_resize(igraph_vector_ptr_t* v, igraph_int_t newsize) { IGRAPH_CHECK(igraph_vector_ptr_reserve(v, newsize)); v->end = v->stor_begin + newsize; return IGRAPH_SUCCESS; @@ -473,7 +512,7 @@ igraph_error_t igraph_vector_ptr_resize(igraph_vector_ptr_t* v, igraph_integer_t * \c IGRAPH_ENOMEM if out of memory */ -igraph_error_t igraph_vector_ptr_init_array(igraph_vector_ptr_t *v, void *const *data, igraph_integer_t length) { +igraph_error_t igraph_vector_ptr_init_array(igraph_vector_ptr_t *v, void *const *data, igraph_int_t length) { v->stor_begin = IGRAPH_CALLOC(length, void*); if (v->stor_begin == 0) { IGRAPH_ERROR("Cannot initialize pointer vector from array", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ @@ -527,7 +566,7 @@ void igraph_vector_ptr_copy_to(const igraph_vector_ptr_t *v, void** to) { */ igraph_error_t igraph_vector_ptr_init_copy(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from) { - igraph_integer_t from_size; + igraph_int_t from_size; IGRAPH_ASSERT(from != NULL); /* IGRAPH_ASSERT(from->stor_begin != NULL); */ /* TODO */ @@ -547,24 +586,12 @@ igraph_error_t igraph_vector_ptr_init_copy(igraph_vector_ptr_t *to, const igraph return IGRAPH_SUCCESS; } -/** - * \ingroup vectorptr - * \function igraph_vector_ptr_copy - * \brief Initializes a pointer vector from another one (deprecated alias). - * - * \deprecated-by igraph_vector_ptr_init_copy 0.10 - */ - -igraph_error_t igraph_vector_ptr_copy(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from) { - return igraph_vector_ptr_init_copy(to, from); -} - /** * \ingroup vectorptr * \brief Remove an element from a pointer vector. */ -void igraph_vector_ptr_remove(igraph_vector_ptr_t *v, igraph_integer_t pos) { +void igraph_vector_ptr_remove(igraph_vector_ptr_t *v, igraph_int_t pos) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); if (pos + 1 < igraph_vector_ptr_size(v)) { /* No need to move data when removing the last element. */ @@ -601,15 +628,25 @@ void igraph_vector_ptr_sort(igraph_vector_ptr_t *v, int (*compar)(const void*, c } igraph_error_t igraph_vector_ptr_append(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from) { - igraph_integer_t origsize = igraph_vector_ptr_size(to); - igraph_integer_t othersize = igraph_vector_ptr_size(from); - igraph_integer_t i; + const igraph_int_t to_size = igraph_vector_ptr_size(to); + const igraph_int_t from_size = igraph_vector_ptr_size(from); + const igraph_int_t to_capacity = igraph_vector_ptr_capacity(to); + igraph_int_t new_to_size; - IGRAPH_CHECK(igraph_vector_ptr_resize(to, origsize + othersize)); - for (i = 0; i < othersize; i++, origsize++) { - to->stor_begin[origsize] = from->stor_begin[i]; + IGRAPH_SAFE_ADD(to_size, from_size, &new_to_size); + + if (to_capacity < new_to_size) { + igraph_int_t new_to_capacity = to_capacity < IGRAPH_INTEGER_MAX/2 ? to_capacity * 2 : IGRAPH_INTEGER_MAX; + if (new_to_capacity < new_to_size) { + new_to_capacity = new_to_size; + } + IGRAPH_CHECK(igraph_vector_ptr_reserve(to, new_to_capacity)); } + memcpy(to->stor_begin + to_size, from->stor_begin, + sizeof(void *) * from_size); + to->end = to->stor_begin + new_to_size; + return IGRAPH_SUCCESS; } @@ -701,9 +738,9 @@ static int igraph_vector_ptr_i_sort_ind_cmp(void *thunk, const void *p1, const v igraph_error_t igraph_vector_ptr_sort_ind(igraph_vector_ptr_t *v, igraph_vector_int_t *inds, cmp_t *cmp) { - igraph_integer_t i; + igraph_int_t i; uintptr_t *vind, first; - igraph_integer_t n = igraph_vector_ptr_size(v); + igraph_int_t n = igraph_vector_ptr_size(v); IGRAPH_CHECK(igraph_vector_int_resize(inds, n)); if (n == 0) { @@ -776,7 +813,7 @@ igraph_error_t igraph_vector_ptr_permute(igraph_vector_ptr_t* v, const igraph_ve igraph_vector_ptr_t v_copy; void** v_ptr; - igraph_integer_t *ind_ptr; + igraph_int_t *ind_ptr; /* There is a more space-efficient algorithm that needs O(1) space only, * but it messes up the index vector, which we don't want */ diff --git a/src/vendor/cigraph/src/misc/cycle_bases.c b/src/vendor/cigraph/src/cycles/cycle_bases.c similarity index 86% rename from src/vendor/cigraph/src/misc/cycle_bases.c rename to src/vendor/cigraph/src/cycles/cycle_bases.c index 01732a8163e..c81feab2f2d 100644 --- a/src/vendor/cigraph/src/misc/cycle_bases.c +++ b/src/vendor/cigraph/src/cycles/cycle_bases.c @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2021-2022 The igraph development team + igraph library. + Copyright (C) 2021-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ #include "igraph_interface.h" #include "core/interruption.h" -#include "misc/order_cycle.h" +#include "cycles/order_cycle.h" /**** Fundamental cycles *****/ @@ -46,13 +46,13 @@ static igraph_error_t igraph_i_fundamental_cycles_bfs( const igraph_t *graph, igraph_vector_int_list_t *result, - igraph_integer_t start_vid, - igraph_integer_t bfs_cutoff, + igraph_int_t start_vid, + igraph_int_t bfs_cutoff, const igraph_inclist_t *inclist, igraph_vector_int_t *visited, - igraph_integer_t mark /* mark used in 'visited' */) { + igraph_int_t mark /* mark used in 'visited' */) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_dqueue_int_t q; igraph_vector_int_t pred_edge; igraph_vector_int_t u_back, v_back; @@ -77,18 +77,18 @@ igraph_i_fundamental_cycles_bfs( VECTOR(pred_edge)[start_vid] = -1; /* non-valid predecessor edge id for root vertex */ while (! igraph_dqueue_int_empty(&q)) { - igraph_integer_t v = igraph_dqueue_int_pop(&q); - igraph_integer_t vdist = igraph_dqueue_int_pop(&q); + igraph_int_t v = igraph_dqueue_int_pop(&q); + igraph_int_t vdist = igraph_dqueue_int_pop(&q); igraph_vector_int_t *incs = igraph_inclist_get(inclist, v); - igraph_integer_t n = igraph_vector_int_size(incs); - igraph_integer_t i, j; + igraph_int_t n = igraph_vector_int_size(incs); + igraph_int_t i, j; IGRAPH_ALLOW_INTERRUPTION(); for (i=0; i < n; ++i) { - igraph_integer_t e = VECTOR(*incs)[i]; - igraph_integer_t u = IGRAPH_OTHER(graph, e, v); + igraph_int_t e = VECTOR(*incs)[i]; + igraph_int_t u = IGRAPH_OTHER(graph, e, v); if (e == VECTOR(pred_edge)[v]) { /* do not follow the edge through which we came to v */ @@ -106,13 +106,13 @@ igraph_i_fundamental_cycles_bfs( * that the distance of u from the start vertex is either the * same as that of v, or one greater. */ - igraph_integer_t up = u, vp = v; - igraph_integer_t u_back_len, v_back_len; + igraph_int_t up = u, vp = v; + igraph_int_t u_back_len, v_back_len; igraph_vector_int_t cycle; IGRAPH_CHECK(igraph_vector_int_push_back(&v_back, e)); for (;;) { - igraph_integer_t upe, vpe; + igraph_int_t upe, vpe; if (up == vp) { break; @@ -187,6 +187,7 @@ igraph_i_fundamental_cycles_bfs( * Edge directions are ignored. Multi-edges and self-loops are supported. * * \param graph The graph object. + * \param weights Currently unused. * \param result An initialized integer vector list. The result will be stored here, * each vector containing the edge IDs of a basis element. * \param start_vid If negative, a complete fundamental cycle basis is returned. @@ -196,23 +197,21 @@ igraph_i_fundamental_cycles_bfs( * \param bfs_cutoff If negative, a complete cycle basis is returned. Otherwise, only * cycles of length 2*bfs_cutoff + 1 or shorter are included. \p bfs_cutoff * is used to limit the depth of the BFS tree when searching for cycle edges. - * \param weights Currently unused. * \return Error code. * * \sa \ref igraph_minimum_cycle_basis() * * Time complexity: O(|V| + |E|). */ -igraph_error_t igraph_fundamental_cycles(const igraph_t *graph, - igraph_vector_int_list_t *result, - igraph_integer_t start_vid, - igraph_integer_t bfs_cutoff, - const igraph_vector_t *weights) { - - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t estimated_rank; - igraph_integer_t i; +igraph_error_t igraph_fundamental_cycles( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_int_list_t *result, + igraph_int_t start_vid, igraph_real_t bfs_cutoff) { + + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t estimated_rank; + igraph_int_t i; igraph_inclist_t inclist; igraph_vector_int_t visited; /* see comments before igraph_i_fundamental_cycles_bfs() */ @@ -264,7 +263,7 @@ igraph_error_t igraph_fundamental_cycles(const igraph_t *graph, * order for equal length ones. Lexicographic order helps keep row insertion into the reduced matrix * efficient during Gaussian elimination, by ensuring that insertions usually happen near the end. */ static int cycle_cmp(const igraph_vector_int_t *v1, const igraph_vector_int_t *v2) { - igraph_integer_t n1 = igraph_vector_int_size(v1), n2 = igraph_vector_int_size(v2); + igraph_int_t n1 = igraph_vector_int_size(v1), n2 = igraph_vector_int_size(v2); if (n1 < n2) { return -1; @@ -277,9 +276,9 @@ static int cycle_cmp(const igraph_vector_int_t *v1, const igraph_vector_int_t *v /* Adding cycle vectors produces the symmetric difference of the corresponding edge sets. */ static igraph_error_t cycle_add(const igraph_vector_int_t *a, const igraph_vector_int_t *b, igraph_vector_int_t *res) { - igraph_integer_t na = igraph_vector_int_size(a), nb = igraph_vector_int_size(b); - const igraph_integer_t *pa = VECTOR(*a), *pb = VECTOR(*b); - const igraph_integer_t *pa_end = pa + na, *pb_end = pb + nb; + igraph_int_t na = igraph_vector_int_size(a), nb = igraph_vector_int_size(b); + const igraph_int_t *pa = VECTOR(*a), *pb = VECTOR(*b); + const igraph_int_t *pa_end = pa + na, *pb_end = pb + nb; igraph_vector_int_clear(res); for (;;) { @@ -324,8 +323,8 @@ static igraph_error_t gaussian_elimination(igraph_vector_int_list_t *reduced_mat const igraph_vector_int_t *cycle, igraph_bool_t *independent) { - const igraph_integer_t nrow = igraph_vector_int_list_size(reduced_matrix); - igraph_integer_t i; + const igraph_int_t nrow = igraph_vector_int_list_size(reduced_matrix); + igraph_int_t i; igraph_vector_int_t work, tmp; @@ -348,7 +347,7 @@ static igraph_error_t gaussian_elimination(igraph_vector_int_list_t *reduced_mat IGRAPH_FINALLY_CLEAN(2); return IGRAPH_SUCCESS; } - IGRAPH_CHECK(igraph_vector_int_swap(&work, &tmp)); + igraph_vector_int_swap(&work, &tmp); } else { /* VECTOR(*row)[0] > VECTOR(work)[0] */ break; } @@ -390,6 +389,7 @@ static igraph_error_t gaussian_elimination(igraph_vector_int_list_t *reduced_mat * https://doi.org/10.1137%2F0216026 * * \param graph The graph object. + * \param weights Currently unused. * \param result An initialized integer vector list, the elements of the cycle * basis will be stored here as vectors of edge IDs. * \param bfs_cutoff If negative, an exact minimum cycle basis is returned. Otherwise @@ -407,23 +407,21 @@ static igraph_error_t gaussian_elimination(igraph_vector_int_list_t *reduced_mat * performance cost. If false, no guarantees are given about the ordering * of edge IDs within cycles. This parameter exists solely to control * performance tradeoffs. - * \param weights Currently unused. * \return Error code. * * \sa \ref igraph_fundamental_cycles() * * Time complexity: TODO. */ -igraph_error_t igraph_minimum_cycle_basis(const igraph_t *graph, - igraph_vector_int_list_t *result, - igraph_integer_t bfs_cutoff, - igraph_bool_t complete, - igraph_bool_t use_cycle_order, - const igraph_vector_t *weights) { - - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t rank; +igraph_error_t igraph_minimum_cycle_basis( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_vector_int_list_t *result, + igraph_real_t bfs_cutoff, + igraph_bool_t complete, igraph_bool_t use_cycle_order) { + + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t rank; igraph_vector_int_list_t candidates; IGRAPH_UNUSED(weights); @@ -433,8 +431,8 @@ igraph_error_t igraph_minimum_cycle_basis(const igraph_t *graph, igraph_inclist_t inclist; igraph_vector_int_t visited; /* visited[v] % 3 is zero for unvisited vertices, see igraph_i_fundamental_cycles_bfs() */ igraph_vector_int_t degrees; - igraph_integer_t no_of_comps; - igraph_integer_t mark; + igraph_int_t no_of_comps; + igraph_int_t mark; /* We use the degrees to avoid doing a BFS from vertices with d < 3, except in special cases. * Degrees cannot be computed from the inclist because there we use IGRAPH_LOOPS_ONCE. */ @@ -454,8 +452,8 @@ igraph_error_t igraph_minimum_cycle_basis(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_list_reserve(&candidates, rank)); mark = 0; - for (igraph_integer_t i=0; i < no_of_nodes; ++i) { - igraph_integer_t degree = VECTOR(degrees)[i]; + for (igraph_int_t i=0; i < no_of_nodes; ++i) { + igraph_int_t degree = VECTOR(degrees)[i]; igraph_bool_t vis = VECTOR(visited)[i] % 3 != 0; /* was vertex i visited already? */ /* Generally, we only need to run a BFS from vertices of degree 3 or greater. @@ -483,9 +481,9 @@ igraph_error_t igraph_minimum_cycle_basis(const igraph_t *graph, /* Sort candidates by size (= weight) and remove duplicates. */ { - igraph_integer_t cand_count = igraph_vector_int_list_size(&candidates); + igraph_int_t cand_count = igraph_vector_int_list_size(&candidates); - for (igraph_integer_t i=0; i < cand_count; ++i) { + for (igraph_int_t i=0; i < cand_count; ++i) { igraph_vector_int_sort(igraph_vector_int_list_get_ptr(&candidates, i)); } igraph_vector_int_list_sort(&candidates, &cycle_cmp); @@ -498,13 +496,13 @@ igraph_error_t igraph_minimum_cycle_basis(const igraph_t *graph, /* Find a complete basis, starting with smallest elements. */ /* This is typically the slowest part of the algorithm. */ { - igraph_integer_t cand_len = igraph_vector_int_list_size(&candidates); + igraph_int_t cand_len = igraph_vector_int_list_size(&candidates); igraph_vector_int_list_t reduced_matrix; igraph_bool_t independent; IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(&reduced_matrix, 0); - for (igraph_integer_t i=0; i < cand_len; ++i) { + for (igraph_int_t i=0; i < cand_len; ++i) { const igraph_vector_int_t *cycle = igraph_vector_int_list_get_ptr(&candidates, i); IGRAPH_ALLOW_INTERRUPTION(); @@ -528,10 +526,10 @@ igraph_error_t igraph_minimum_cycle_basis(const igraph_t *graph, IGRAPH_FINALLY_CLEAN(1); if (use_cycle_order) { - igraph_integer_t result_size = igraph_vector_int_list_size(result); + igraph_int_t result_size = igraph_vector_int_list_size(result); igraph_vector_int_t tmp; IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, 0); - for (igraph_integer_t i=0; i < result_size; ++i) { + for (igraph_int_t i=0; i < result_size; ++i) { igraph_vector_int_t *cycle = igraph_vector_int_list_get_ptr(result, i); IGRAPH_CHECK(igraph_vector_int_update(&tmp, cycle)); IGRAPH_CHECK(igraph_i_order_cycle(graph, &tmp, cycle)); diff --git a/src/vendor/cigraph/src/misc/feedback_arc_set.c b/src/vendor/cigraph/src/cycles/feedback_sets.c similarity index 91% rename from src/vendor/cigraph/src/misc/feedback_arc_set.c rename to src/vendor/cigraph/src/cycles/feedback_sets.c index 2bf8a0c2580..09f5c7aab76 100644 --- a/src/vendor/cigraph/src/misc/feedback_arc_set.c +++ b/src/vendor/cigraph/src/cycles/feedback_sets.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2011-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -16,17 +16,16 @@ along with this program. If not, see . */ -#include "igraph_structural.h" -#include "misc/feedback_arc_set.h" +#include "igraph_cycles.h" +#include "cycles/feedback_sets.h" #include "igraph_bitset.h" #include "igraph_components.h" -#include "igraph_cycles.h" #include "igraph_dqueue.h" #include "igraph_interface.h" #include "igraph_memory.h" #include "igraph_stack.h" -#include "igraph_topology.h" +#include "igraph_structural.h" #include "igraph_vector.h" #include "igraph_vector_list.h" #include "igraph_visitor.h" @@ -52,14 +51,14 @@ static igraph_error_t igraph_i_find_cycle(const igraph_t *graph, igraph_neimode_t mode, const igraph_bitset_t *removed) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_stack_int_t stack; igraph_vector_int_t inc; igraph_vector_int_t vpath, epath; igraph_vector_char_t seen; /* 0 = unseen, 1 = acestor of current, 2 = seen, non-ancestor */ - igraph_integer_t ea, va; - igraph_integer_t depth; + igraph_int_t ea, va; + igraph_int_t depth; if (vertices) { igraph_vector_int_clear(vertices); @@ -98,7 +97,7 @@ static igraph_error_t igraph_i_find_cycle(const igraph_t *graph, IGRAPH_VECTOR_CHAR_INIT_FINALLY(&seen, vcount); IGRAPH_STACK_INT_INIT_FINALLY(&stack, 200); - for (igraph_integer_t v=0; v < vcount; v++) { + for (igraph_int_t v=0; v < vcount; v++) { if (VECTOR(seen)[v]) { continue; } @@ -107,7 +106,7 @@ static igraph_error_t igraph_i_find_cycle(const igraph_t *graph, IGRAPH_CHECK(igraph_stack_int_push(&stack, v)); while (! igraph_stack_int_empty(&stack)) { - igraph_integer_t x = igraph_stack_int_pop(&stack); + igraph_int_t x = igraph_stack_int_pop(&stack); if (x == -1) { PATH_POP(); continue; @@ -125,11 +124,11 @@ static igraph_error_t igraph_i_find_cycle(const igraph_t *graph, PATH_PUSH(va, ea); IGRAPH_CHECK(igraph_stack_int_push(&stack, -1)); - IGRAPH_CHECK(igraph_incident(graph, &inc, va, mode)); - igraph_integer_t n = igraph_vector_int_size(&inc); - for (igraph_integer_t i=0; i < n; i++) { - igraph_integer_t eb = VECTOR(inc)[i]; - igraph_integer_t vb = IGRAPH_OTHER(graph, eb, va); + IGRAPH_CHECK(igraph_incident(graph, &inc, va, mode, IGRAPH_LOOPS)); + igraph_int_t n = igraph_vector_int_size(&inc); + for (igraph_int_t i=0; i < n; i++) { + igraph_int_t eb = VECTOR(inc)[i]; + igraph_int_t vb = IGRAPH_OTHER(graph, eb, va); if (eb == ea) continue; if (VECTOR(seen)[vb] == 2) continue; if (removed && IGRAPH_BIT_TEST(*removed, eb)) continue; @@ -150,7 +149,7 @@ static igraph_error_t igraph_i_find_cycle(const igraph_t *graph, depth = igraph_vector_int_size(&vpath); if (depth > 0) { - igraph_integer_t i = depth; + igraph_int_t i = depth; while (VECTOR(vpath)[i-1] != va) i--; for (; i < depth; i++) { if (vertices) { @@ -186,8 +185,6 @@ static igraph_error_t igraph_i_find_cycle(const igraph_t *graph, * \function igraph_find_cycle * \brief Finds a single cycle in the graph. * - * \experimental - * * This function returns a cycle of the graph, if there is one. If the graph * is acyclic, it returns empty vectors. * @@ -386,8 +383,6 @@ igraph_error_t igraph_feedback_arc_set( * \function igraph_feedback_vertex_set * \brief Feedback vertex set of a graph. * - * \experimental - * * A feedback vertex set is a set of vertices whose removal makes the graph * acyclic. Finding a \em minimum feedback vertex set is an NP-complete * problem, both on directed and undirected graphs. @@ -437,8 +432,8 @@ igraph_error_t igraph_feedback_vertex_set( igraph_error_t igraph_i_feedback_arc_set_undirected(const igraph_t *graph, igraph_vector_int_t *result, const igraph_vector_t *weights, igraph_vector_int_t *layering) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_int_t edges; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_nodes > 0 ? no_of_nodes - 1 : 0); @@ -449,12 +444,12 @@ igraph_error_t igraph_i_feedback_arc_set_undirected(const igraph_t *graph, igrap IGRAPH_CHECK(igraph_vector_init_copy(&vcopy, weights)); IGRAPH_FINALLY(igraph_vector_destroy, &vcopy); igraph_vector_scale(&vcopy, -1); - IGRAPH_CHECK(igraph_minimum_spanning_tree(graph, &edges, &vcopy)); + IGRAPH_CHECK(igraph_minimum_spanning_tree(graph, &edges, &vcopy, IGRAPH_MST_AUTOMATIC)); igraph_vector_destroy(&vcopy); IGRAPH_FINALLY_CLEAN(1); } else { /* Any spanning tree will do */ - IGRAPH_CHECK(igraph_minimum_spanning_tree(graph, &edges, 0)); + IGRAPH_CHECK(igraph_minimum_spanning_tree(graph, &edges, NULL, IGRAPH_MST_AUTOMATIC)); } /* Now we have a bunch of edges that constitute a spanning forest. We have @@ -465,7 +460,7 @@ igraph_error_t igraph_i_feedback_arc_set_undirected(const igraph_t *graph, igrap if (result) { igraph_vector_int_clear(result); - for (igraph_integer_t i = 0, j = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0, j = 0; i < no_of_edges; i++) { if (i == VECTOR(edges)[j]) { j++; continue; @@ -481,7 +476,7 @@ igraph_error_t igraph_i_feedback_arc_set_undirected(const igraph_t *graph, igrap IGRAPH_VECTOR_INIT_FINALLY(°rees, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&roots, no_of_nodes); IGRAPH_CHECK(igraph_strength(graph, °rees, igraph_vss_all(), - IGRAPH_ALL, /* loops */ false, weights)); + IGRAPH_ALL, IGRAPH_NO_LOOPS, weights)); IGRAPH_CHECK(igraph_vector_sort_ind(°rees, &roots, IGRAPH_DESCENDING)); IGRAPH_CHECK(igraph_bfs(graph, @@ -516,16 +511,16 @@ igraph_error_t igraph_i_feedback_arc_set_undirected(const igraph_t *graph, igrap */ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vector_int_t *result, const igraph_vector_t *weights, igraph_vector_int_t *layers) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t nodes_left; - igraph_integer_t neis_size; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t nodes_left; + igraph_int_t neis_size; igraph_dqueue_int_t sources, sinks; igraph_vector_int_t neis; igraph_vector_int_t indegrees, outdegrees; igraph_vector_t instrengths, outstrengths; igraph_vector_int_t ordering; - igraph_integer_t order_next_pos = 0, order_next_neg = -1; + igraph_int_t order_next_pos = 0, order_next_neg = -1; IGRAPH_VECTOR_INT_INIT_FINALLY(&ordering, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); @@ -537,14 +532,14 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec IGRAPH_VECTOR_INIT_FINALLY(&instrengths, no_of_nodes); IGRAPH_VECTOR_INIT_FINALLY(&outstrengths, no_of_nodes); - IGRAPH_CHECK(igraph_degree(graph, &indegrees, igraph_vss_all(), IGRAPH_IN, false)); - IGRAPH_CHECK(igraph_degree(graph, &outdegrees, igraph_vss_all(), IGRAPH_OUT, false)); + IGRAPH_CHECK(igraph_degree(graph, &indegrees, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS)); + IGRAPH_CHECK(igraph_degree(graph, &outdegrees, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS)); if (weights) { - IGRAPH_CHECK(igraph_strength(graph, &instrengths, igraph_vss_all(), IGRAPH_IN, false, weights)); - IGRAPH_CHECK(igraph_strength(graph, &outstrengths, igraph_vss_all(), IGRAPH_OUT, false, weights)); + IGRAPH_CHECK(igraph_strength(graph, &instrengths, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS, weights)); + IGRAPH_CHECK(igraph_strength(graph, &outstrengths, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS, weights)); } else { - for (igraph_integer_t u = 0; u < no_of_nodes; u++) { + for (igraph_int_t u = 0; u < no_of_nodes; u++) { VECTOR(instrengths)[u] = VECTOR(indegrees)[u]; VECTOR(outstrengths)[u] = VECTOR(outdegrees)[u]; } @@ -552,7 +547,7 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec /* Find initial sources and sinks */ nodes_left = no_of_nodes; - for (igraph_integer_t u = 0; u < no_of_nodes; u++) { + for (igraph_int_t u = 0; u < no_of_nodes; u++) { if (VECTOR(indegrees)[u] == 0) { if (VECTOR(outdegrees)[u] == 0) { /* Isolated vertex, we simply ignore it */ @@ -574,17 +569,17 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec /* (1) Remove the sources one by one */ while (!igraph_dqueue_int_empty(&sources)) { - const igraph_integer_t u = igraph_dqueue_int_pop(&sources); + const igraph_int_t u = igraph_dqueue_int_pop(&sources); /* Add the node to the ordering */ VECTOR(ordering)[u] = order_next_pos++; /* Exclude the node from further searches */ VECTOR(indegrees)[u] = VECTOR(outdegrees)[u] = -1; /* Get the neighbors and decrease their degrees */ - IGRAPH_CHECK(igraph_incident(graph, &neis, u, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(graph, &neis, u, IGRAPH_OUT, IGRAPH_LOOPS)); neis_size = igraph_vector_int_size(&neis); - for (igraph_integer_t i = 0; i < neis_size; i++) { - const igraph_integer_t eid = VECTOR(neis)[i]; - const igraph_integer_t w = IGRAPH_TO(graph, eid); + for (igraph_int_t i = 0; i < neis_size; i++) { + const igraph_int_t eid = VECTOR(neis)[i]; + const igraph_int_t w = IGRAPH_TO(graph, eid); if (VECTOR(indegrees)[w] <= 0) { /* Already removed, continue */ continue; @@ -600,7 +595,7 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec /* (2) Remove the sinks one by one */ while (!igraph_dqueue_int_empty(&sinks)) { - const igraph_integer_t u = igraph_dqueue_int_pop(&sinks); + const igraph_int_t u = igraph_dqueue_int_pop(&sinks); /* Maybe the vertex became sink and source at the same time, hence it * was already removed in the previous iteration. Check it. */ if (VECTOR(indegrees)[u] < 0) { @@ -611,11 +606,11 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec /* Exclude the node from further searches */ VECTOR(indegrees)[u] = VECTOR(outdegrees)[u] = -1; /* Get the neighbors and decrease their degrees */ - IGRAPH_CHECK(igraph_incident(graph, &neis, u, IGRAPH_IN)); + IGRAPH_CHECK(igraph_incident(graph, &neis, u, IGRAPH_IN, IGRAPH_LOOPS)); neis_size = igraph_vector_int_size(&neis); - for (igraph_integer_t i = 0; i < neis_size; i++) { - const igraph_integer_t eid = VECTOR(neis)[i]; - const igraph_integer_t w = IGRAPH_FROM(graph, eid); + for (igraph_int_t i = 0; i < neis_size; i++) { + const igraph_int_t eid = VECTOR(neis)[i]; + const igraph_int_t w = IGRAPH_FROM(graph, eid); if (VECTOR(outdegrees)[w] <= 0) { /* Already removed, continue */ continue; @@ -631,9 +626,9 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec /* (3) No more sources or sinks. Find the node with the largest * difference between its out-strength and in-strength */ - igraph_integer_t v = -1; + igraph_int_t v = -1; igraph_real_t maxdiff = -IGRAPH_INFINITY; - for (igraph_integer_t u = 0; u < no_of_nodes; u++) { + for (igraph_int_t u = 0; u < no_of_nodes; u++) { if (VECTOR(outdegrees)[u] < 0) { continue; } @@ -647,11 +642,11 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec /* Remove vertex v */ VECTOR(ordering)[v] = order_next_pos++; /* Remove outgoing edges */ - IGRAPH_CHECK(igraph_incident(graph, &neis, v, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(graph, &neis, v, IGRAPH_OUT, IGRAPH_LOOPS)); neis_size = igraph_vector_int_size(&neis); - for (igraph_integer_t i = 0; i < neis_size; i++) { - const igraph_integer_t eid = VECTOR(neis)[i]; - const igraph_integer_t w = IGRAPH_TO(graph, eid); + for (igraph_int_t i = 0; i < neis_size; i++) { + const igraph_int_t eid = VECTOR(neis)[i]; + const igraph_int_t w = IGRAPH_TO(graph, eid); if (VECTOR(indegrees)[w] <= 0) { /* Already removed, continue */ continue; @@ -663,11 +658,11 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec } } /* Remove incoming edges */ - IGRAPH_CHECK(igraph_incident(graph, &neis, v, IGRAPH_IN)); + IGRAPH_CHECK(igraph_incident(graph, &neis, v, IGRAPH_IN, IGRAPH_LOOPS)); neis_size = igraph_vector_int_size(&neis); - for (igraph_integer_t i = 0; i < neis_size; i++) { - const igraph_integer_t eid = VECTOR(neis)[i]; - const igraph_integer_t w = IGRAPH_FROM(graph, eid); + for (igraph_int_t i = 0; i < neis_size; i++) { + const igraph_int_t eid = VECTOR(neis)[i]; + const igraph_int_t w = IGRAPH_FROM(graph, eid); if (VECTOR(outdegrees)[w] <= 0) { /* Already removed, continue */ continue; @@ -694,7 +689,7 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec IGRAPH_FINALLY_CLEAN(6); /* Tidy up the ordering */ - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(ordering)[i] < 0) { VECTOR(ordering)[i] += no_of_nodes; } @@ -703,9 +698,9 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec /* Find the feedback edges based on the ordering */ if (result) { igraph_vector_int_clear(result); - for (igraph_integer_t eid = 0; eid < no_of_edges; eid++) { - igraph_integer_t from = IGRAPH_FROM(graph, eid); - igraph_integer_t to = IGRAPH_TO(graph, eid); + for (igraph_int_t eid = 0; eid < no_of_edges; eid++) { + igraph_int_t from = IGRAPH_FROM(graph, eid); + igraph_int_t to = IGRAPH_TO(graph, eid); if (from == to || VECTOR(ordering)[from] > VECTOR(ordering)[to]) { IGRAPH_CHECK(igraph_vector_int_push_back(result, eid)); } @@ -723,12 +718,14 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec IGRAPH_CHECK(igraph_vector_int_sort_ind(&ordering, &ranks, IGRAPH_ASCENDING)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t from = VECTOR(ranks)[i]; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, from, IGRAPH_OUT)); + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t from = VECTOR(ranks)[i]; + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, from, IGRAPH_OUT, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); neis_size = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < neis_size; j++) { - igraph_integer_t to = VECTOR(neis)[j]; + for (igraph_int_t j = 0; j < neis_size; j++) { + igraph_int_t to = VECTOR(neis)[j]; if (from == to) { continue; } @@ -765,13 +762,13 @@ igraph_error_t igraph_i_feedback_arc_set_ip_ti( IGRAPH_ERROR("GLPK is not available.", IGRAPH_UNIMPLEMENTED); #else - const igraph_integer_t no_of_vertices = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_components; + const igraph_int_t no_of_vertices = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_components; igraph_vector_int_t membership, *vec; igraph_vector_int_t ordering, vertex_remapping; igraph_vector_int_list_t vertices_by_components, edges_by_components; - igraph_integer_t i, j, k, l, m, n, from, to, no_of_rows, n_choose_2; + igraph_int_t i, j, k, l, m, n, from, to, no_of_rows, n_choose_2; igraph_real_t weight; glp_prob *ip; glp_iocp parm; @@ -892,8 +889,8 @@ igraph_error_t igraph_i_feedback_arc_set_ip_ti( */ /* res = n * (n - 1) * (n - 2) / 3 */ - igraph_integer_t mod = n % 3; - igraph_integer_t res = n / 3; /* same as (n - mod) / 3 */ + igraph_int_t mod = n % 3; + igraph_int_t res = n / 3; /* same as (n - mod) / 3 */ mod = (mod + 1) % 3; IGRAPH_SAFE_MULT(res, n - mod, &res); @@ -1087,7 +1084,7 @@ igraph_error_t igraph_i_feedback_arc_set_ip_cg( #ifndef HAVE_GLPK IGRAPH_ERROR("GLPK is not available.", IGRAPH_UNIMPLEMENTED); #else - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_bool_t is_dag; igraph_bitset_t removed; igraph_vector_int_t cycle; @@ -1178,7 +1175,7 @@ igraph_error_t igraph_i_feedback_arc_set_ip_cg( igraph_bitset_null(&removed); for (int j=1; j <= var_count; j++) { if (glp_mip_col_val(ip, j) > 0) { - igraph_integer_t i = VAR_TO_ID(j); + igraph_int_t i = VAR_TO_ID(j); IGRAPH_CHECK(igraph_vector_int_push_back(result, i)); IGRAPH_BIT_SET(removed, i); } @@ -1204,8 +1201,8 @@ igraph_error_t igraph_i_feedback_vertex_set_ip_cg( IGRAPH_ERROR("GLPK is not available.", IGRAPH_UNIMPLEMENTED); #else - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_bool_t is_acyclic; igraph_bitset_t removed; igraph_vector_int_t cycle; @@ -1273,10 +1270,10 @@ igraph_error_t igraph_i_feedback_vertex_set_ip_cg( /* Add as many vertex-disjoint cycles at once as possible. */ while (true) { for (int i=0; i < cycle_size; i++) { - IGRAPH_CHECK(igraph_incident(graph, &incident, VECTOR(cycle)[i], IGRAPH_ALL)); - const igraph_integer_t incident_size = igraph_vector_int_size(&incident); - for (igraph_integer_t j = 0; j < incident_size; j++) { - igraph_integer_t eid = VECTOR(incident)[j]; + IGRAPH_CHECK(igraph_incident(graph, &incident, VECTOR(cycle)[i], IGRAPH_ALL, IGRAPH_LOOPS)); + const igraph_int_t incident_size = igraph_vector_int_size(&incident); + for (igraph_int_t j = 0; j < incident_size; j++) { + igraph_int_t eid = VECTOR(incident)[j]; IGRAPH_BIT_SET(removed, eid); } } @@ -1300,14 +1297,14 @@ igraph_error_t igraph_i_feedback_vertex_set_ip_cg( for (int j=1; j <= var_count; j++) { if (glp_mip_col_val(ip, j) > 0) { - igraph_integer_t i = VAR_TO_ID(j); + igraph_int_t i = VAR_TO_ID(j); IGRAPH_CHECK(igraph_vector_int_push_back(result, i)); - IGRAPH_CHECK(igraph_incident(graph, &incident, i, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(graph, &incident, i, IGRAPH_ALL, IGRAPH_LOOPS)); - const igraph_integer_t incident_size = igraph_vector_int_size(&incident); - for (igraph_integer_t k = 0; k < incident_size; k++) { - igraph_integer_t eid = VECTOR(incident)[k]; + const igraph_int_t incident_size = igraph_vector_int_size(&incident); + for (igraph_int_t k = 0; k < incident_size; k++) { + igraph_int_t eid = VECTOR(incident)[k]; IGRAPH_BIT_SET(removed, eid); } } diff --git a/src/vendor/cigraph/src/misc/feedback_arc_set.h b/src/vendor/cigraph/src/cycles/feedback_sets.h similarity index 90% rename from src/vendor/cigraph/src/misc/feedback_arc_set.h rename to src/vendor/cigraph/src/cycles/feedback_sets.h index 447405cb81d..8218fe181f9 100644 --- a/src/vendor/cigraph/src/misc/feedback_arc_set.h +++ b/src/vendor/cigraph/src/cycles/feedback_sets.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2009-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -16,14 +16,14 @@ along with this program. If not, see . */ -#ifndef IGRAPH_FEEDBACK_ARC_SET_INTERNAL_H -#define IGRAPH_FEEDBACK_ARC_SET_INTERNAL_H +#ifndef IGRAPH_CYCLES_FEEDBACK_SETS_H +#define IGRAPH_CYCLES_FEEDBACK_SETS_H #include "igraph_decls.h" #include "igraph_datatype.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS igraph_error_t igraph_i_feedback_arc_set_eades( const igraph_t *graph, igraph_vector_int_t *result, @@ -47,6 +47,6 @@ igraph_error_t igraph_i_feedback_vertex_set_ip_cg( const igraph_t *graph, igraph_vector_int_t *result, const igraph_vector_t *weights); -__END_DECLS +IGRAPH_END_C_DECLS -#endif +#endif /* IGRAPH_CYCLES_FEEDBACK_SETS_H */ diff --git a/src/vendor/cigraph/src/misc/order_cycle.cpp b/src/vendor/cigraph/src/cycles/order_cycle.cpp similarity index 72% rename from src/vendor/cigraph/src/misc/order_cycle.cpp rename to src/vendor/cigraph/src/cycles/order_cycle.cpp index e977db593e3..5c15e05c0e5 100644 --- a/src/vendor/cigraph/src/misc/order_cycle.cpp +++ b/src/vendor/cigraph/src/cycles/order_cycle.cpp @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2022 The igraph development team + igraph library. + Copyright (C) 2022-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,7 +16,7 @@ along with this program. If not, see . */ -#include "misc/order_cycle.h" +#include "cycles/order_cycle.h" #include "igraph_interface.h" @@ -26,8 +26,8 @@ #include // Initialized to {-1, -1} -struct eid_pair_t : public std::pair { - eid_pair_t() : std::pair(-1, -1) { } +struct eid_pair_t : public std::pair { + eid_pair_t() : std::pair(-1, -1) { } }; /** @@ -45,15 +45,15 @@ igraph_error_t igraph_i_order_cycle( IGRAPH_HANDLE_EXCEPTIONS_BEGIN; - igraph_integer_t n = igraph_vector_int_size(cycle); + igraph_int_t n = igraph_vector_int_size(cycle); IGRAPH_ASSERT(n > 0); - std::map inclist; - for (igraph_integer_t i=0; i < n; ++i) { - igraph_integer_t eid = VECTOR(*cycle)[i]; + std::map inclist; + for (igraph_int_t i=0; i < n; ++i) { + igraph_int_t eid = VECTOR(*cycle)[i]; { - igraph_integer_t from = IGRAPH_FROM(graph, eid); + igraph_int_t from = IGRAPH_FROM(graph, eid); auto &p = inclist[from]; if (p.first < 0) { p.first = eid; @@ -64,7 +64,7 @@ igraph_error_t igraph_i_order_cycle( } { - igraph_integer_t to = IGRAPH_TO(graph, eid); + igraph_int_t to = IGRAPH_TO(graph, eid); auto &p = inclist[to]; if (p.first < 0) { p.first = eid; @@ -77,17 +77,17 @@ igraph_error_t igraph_i_order_cycle( igraph_vector_int_clear(res); IGRAPH_CHECK(igraph_vector_int_reserve(res, igraph_vector_int_size(cycle))); - igraph_integer_t current_e = VECTOR(*cycle)[0]; - igraph_integer_t current_v = IGRAPH_FROM(graph, current_e); - for (igraph_integer_t i=0; i < n; ++i) { + igraph_int_t current_e = VECTOR(*cycle)[0]; + igraph_int_t current_v = IGRAPH_FROM(graph, current_e); + for (igraph_int_t i=0; i < n; ++i) { const auto &p = inclist.at(current_v); igraph_vector_int_push_back(res, current_e); /* reserved */ - igraph_integer_t next_e = p.first; + igraph_int_t next_e = p.first; if (next_e == current_e) { next_e = p.second; } current_e = next_e; - igraph_integer_t next_v = IGRAPH_FROM(graph, current_e); + igraph_int_t next_v = IGRAPH_FROM(graph, current_e); if (next_v == current_v) { next_v = IGRAPH_TO(graph, current_e); } diff --git a/src/vendor/cigraph/src/misc/order_cycle.h b/src/vendor/cigraph/src/cycles/order_cycle.h similarity index 94% rename from src/vendor/cigraph/src/misc/order_cycle.h rename to src/vendor/cigraph/src/cycles/order_cycle.h index 2ed87f54ee2..291577b9d5f 100644 --- a/src/vendor/cigraph/src/misc/order_cycle.h +++ b/src/vendor/cigraph/src/cycles/order_cycle.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -23,13 +23,13 @@ #include "igraph_datatype.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS igraph_error_t igraph_i_order_cycle( const igraph_t *graph, const igraph_vector_int_t *cycle, igraph_vector_int_t *res); -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_ORDER_CYCLE_H */ diff --git a/src/vendor/cigraph/src/cycles/simple_cycles.c b/src/vendor/cigraph/src/cycles/simple_cycles.c index 788835ef8fe..1eb0c8502d4 100644 --- a/src/vendor/cigraph/src/cycles/simple_cycles.c +++ b/src/vendor/cigraph/src/cycles/simple_cycles.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2024-2025 The igraph development team This program is free software; you can redistribute it and/or modify @@ -41,7 +41,7 @@ */ typedef struct { /* Number of vertices in the graph */ - igraph_integer_t N; + igraph_int_t N; /* The incidence list of the graph */ igraph_inclist_t IK; @@ -80,6 +80,10 @@ typedef struct { igraph_vector_int_list_t *vertices; /* the edges in the cycle */ igraph_vector_int_list_t *edges; + /* number of cycles found so far */ + igraph_int_t cycle_count; + /* how many cycles to record at most? */ + igraph_int_t max_results; } simple_cycle_results_t; /** @@ -87,7 +91,7 @@ typedef struct { */ static igraph_error_t simple_cycles_unblock( simple_cycle_search_state_t *state, - igraph_integer_t u) { + igraph_int_t u) { // TODO: introduce stack for w & neis in order to reduce the number of // iterations. @@ -99,13 +103,13 @@ static igraph_error_t simple_cycles_unblock( while (igraph_stack_int_size(&u_stack) > 0) { igraph_bool_t recurse_deeper = false; - const igraph_integer_t current_u = igraph_stack_int_top(&u_stack); + const igraph_int_t current_u = igraph_stack_int_top(&u_stack); IGRAPH_BIT_CLEAR(state->v_blocked, current_u); neis = igraph_adjlist_get(&state->B, current_u); while (!igraph_vector_int_empty(neis) && !recurse_deeper) { - const igraph_integer_t w = igraph_vector_int_pop_back(neis); + const igraph_int_t w = igraph_vector_int_pop_back(neis); if (IGRAPH_BIT_TEST(state->v_blocked, w)) { IGRAPH_CHECK(igraph_stack_int_push(&u_stack, w)); recurse_deeper = true; @@ -135,17 +139,17 @@ static igraph_error_t simple_cycles_unblock( */ static igraph_error_t simple_cycles_circuit( simple_cycle_search_state_t *state, - igraph_integer_t V, - igraph_integer_t max_cycle_length, - igraph_integer_t min_cycle_length, + igraph_int_t V, + igraph_int_t max_cycle_length, + igraph_int_t min_cycle_length, igraph_cycle_handler_t *callback, void *arg) { const igraph_vector_int_t *neighbors; const igraph_vector_int_t *incident_edges; - igraph_integer_t num_neighbors; - igraph_integer_t S = V; // start - igraph_integer_t E = -1; // edge start + igraph_int_t num_neighbors; + igraph_int_t S = V; // start + igraph_int_t E = -1; // edge start igraph_bool_t local_found = false; igraph_bool_t loop_length_stop = false; @@ -171,7 +175,7 @@ static igraph_error_t simple_cycles_circuit( IGRAPH_ASSERT(igraph_stack_int_size(&v_stack) == igraph_stack_int_size(&e_stack)); - igraph_integer_t i0 = 0; + igraph_int_t i0 = 0; if (recurse_deeper) { // stack v & e IGRAPH_CHECK(igraph_vector_int_push_back(&state->vertex_stack, V)); @@ -196,9 +200,9 @@ static igraph_error_t simple_cycles_circuit( incident_edges = igraph_inclist_get(&state->IK, V); num_neighbors = igraph_vector_int_size(neighbors); IGRAPH_ASSERT(igraph_vector_int_size(incident_edges) == num_neighbors); - for (igraph_integer_t i = i0; i < num_neighbors; ++i) { - igraph_integer_t W = VECTOR(*neighbors)[i]; - igraph_integer_t WE = VECTOR(*incident_edges)[i]; + for (igraph_int_t i = i0; i < num_neighbors; ++i) { + igraph_int_t W = VECTOR(*neighbors)[i]; + igraph_int_t WE = VECTOR(*incident_edges)[i]; if (W == S) { igraph_error_t ret; @@ -267,8 +271,8 @@ static igraph_error_t simple_cycles_circuit( if (local_found || loop_length_stop) { IGRAPH_CHECK(simple_cycles_unblock(state, V)); } else { - for (igraph_integer_t i = 0; i < num_neighbors; ++i) { - const igraph_integer_t W = VECTOR(*neighbors)[i]; + for (igraph_int_t i = 0; i < num_neighbors; ++i) { + const igraph_int_t W = VECTOR(*neighbors)[i]; if (!igraph_vector_int_contains(igraph_adjlist_get(&state->B, W), V)) { IGRAPH_CHECK( igraph_vector_int_push_back(igraph_adjlist_get(&state->B, W), V)); @@ -395,8 +399,8 @@ static igraph_error_t append_simple_cycle_result( const igraph_vector_int_t *edges, void *arg) { - simple_cycle_results_t *res_list = - (simple_cycle_results_t *)arg; + simple_cycle_results_t *res_list = (simple_cycle_results_t *) arg; + if (res_list->vertices != NULL) { // copy output: from stack to vector. No need to reverse because // we were putting vertices in the stack in reverse order anyway. @@ -417,7 +421,13 @@ static igraph_error_t append_simple_cycle_result( IGRAPH_FINALLY_CLEAN(1); } - return IGRAPH_SUCCESS; + res_list->cycle_count++; + + if (res_list->max_results >= 0 && res_list->cycle_count == res_list->max_results) { + return IGRAPH_STOP; + } else { + return IGRAPH_SUCCESS; + } } /** @@ -440,14 +450,14 @@ static igraph_error_t append_simple_cycle_result( */ static igraph_error_t simple_cycles_search_callback_from_one_vertex( simple_cycle_search_state_t *state, - igraph_integer_t s, - igraph_integer_t min_cycle_length, - igraph_integer_t max_cycle_length, + igraph_int_t s, + igraph_int_t min_cycle_length, + igraph_int_t max_cycle_length, igraph_cycle_handler_t *callback, void *arg) { // L3: - for (igraph_integer_t i = s; i < state->N; ++i) { + for (igraph_int_t i = s; i < state->N; ++i) { IGRAPH_BIT_CLEAR(state->v_blocked, i); igraph_vector_int_clear(igraph_adjlist_get(&state->B, i)); } @@ -455,11 +465,11 @@ static igraph_error_t simple_cycles_search_callback_from_one_vertex( IGRAPH_CHECK(simple_cycles_circuit(state, s, max_cycle_length, min_cycle_length, callback, arg)); - for (igraph_integer_t i = 0; i < state->N; ++i) { + for (igraph_int_t i = 0; i < state->N; ++i) { // We want to remove the vertex with value s, not at position s. // It's fine to use binary search since we never add to, only remove from // an already sorted adjacency list. - igraph_integer_t pos; + igraph_int_t pos; if (igraph_vector_int_binsearch(igraph_adjlist_get(&state->AK, i), s, &pos)) { igraph_vector_int_remove(igraph_adjlist_get(&state->AK, i), pos); @@ -515,8 +525,8 @@ static igraph_error_t simple_cycles_search_callback_from_one_vertex( igraph_error_t igraph_simple_cycles_callback( const igraph_t *graph, igraph_neimode_t mode, - igraph_integer_t min_cycle_length, - igraph_integer_t max_cycle_length, + igraph_int_t min_cycle_length, + igraph_int_t max_cycle_length, igraph_cycle_handler_t *callback, void *arg) { @@ -538,13 +548,13 @@ igraph_error_t igraph_simple_cycles_callback( // // Thus, we iterate over the vertices, and check if they can be skipped as // a starting point according to the rules laid out above. - for (igraph_integer_t i = 0; i < state.N; i++) { + for (igraph_int_t i = 0; i < state.N; i++) { // Check if the vertex is a candidate for a cycle. // Note that we call igraph_degree_1() here instead of retrieving the // neighbor count from igraph_adjlist_get(&state.AK, i) because: // - we need to the undirected degree in all cases, and // - our algorithm modifies the adjlist state.AK - igraph_integer_t degree; + igraph_int_t degree; IGRAPH_CHECK(igraph_degree_1(graph, °ree, i, IGRAPH_ALL, true)); if (degree < 3 && IGRAPH_BIT_TEST(state.v_visited, i)) { continue; @@ -598,6 +608,8 @@ igraph_error_t igraph_simple_cycles_callback( * Pass a negative value to search for all cycles. * \param max_cycle_length Limit the maximum length of cycles to search for. * Pass a negative value to search for all cycles. + * \param max_results At most this many cycles will be recorded. If + * negative, or \ref IGRAPH_UNLIMITED, no limit is applied. * \return Error code. * * \sa \ref igraph_simple_cycles_callback() to call a function for each found @@ -609,15 +621,16 @@ igraph_error_t igraph_simple_cycles_callback( */ igraph_error_t igraph_simple_cycles( const igraph_t *graph, - igraph_vector_int_list_t *vertices, - igraph_vector_int_list_t *edges, + igraph_vector_int_list_t *vertices, igraph_vector_int_list_t *edges, igraph_neimode_t mode, - igraph_integer_t min_cycle_length, - igraph_integer_t max_cycle_length) { + igraph_int_t min_cycle_length, igraph_int_t max_cycle_length, + igraph_int_t max_results) { simple_cycle_results_t result_list; result_list.vertices = vertices; result_list.edges = edges; + result_list.cycle_count = 0; + result_list.max_results = max_results; if (vertices) { igraph_vector_int_list_clear(vertices); @@ -626,6 +639,10 @@ igraph_error_t igraph_simple_cycles( igraph_vector_int_list_clear(edges); } + if (max_results == 0) { + return IGRAPH_SUCCESS; + } + IGRAPH_CHECK(igraph_simple_cycles_callback(graph, mode, min_cycle_length, max_cycle_length, &append_simple_cycle_result, &result_list)); diff --git a/src/vendor/cigraph/src/f2c.h b/src/vendor/cigraph/src/f2c.h index ddb322575c4..120a29fa0f6 100644 --- a/src/vendor/cigraph/src/f2c.h +++ b/src/vendor/cigraph/src/f2c.h @@ -144,7 +144,7 @@ union Multitype { /* for multiple entry points */ typedef union Multitype Multitype; -/*typedef igraph_integer_t Long;*/ /* No longer used; formerly in Namelist */ +/*typedef igraph_int_t Long;*/ /* No longer used; formerly in Namelist */ struct Vardesc { /* for Namelist */ char *name; diff --git a/src/vendor/cigraph/src/flow/flow.c b/src/vendor/cigraph/src/flow/flow.c index 6a5cfd0f86d..fb6a376cd9c 100644 --- a/src/vendor/cigraph/src/flow/flow.c +++ b/src/vendor/cigraph/src/flow/flow.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -28,14 +27,13 @@ #include "igraph_conversion.h" #include "igraph_constants.h" #include "igraph_constructors.h" +#include "igraph_cycles.h" #include "igraph_dqueue.h" #include "igraph_error.h" #include "igraph_interface.h" -#include "igraph_memory.h" #include "igraph_progress.h" #include "igraph_operators.h" #include "igraph_structural.h" -#include "igraph_topology.h" #include "core/buckets.h" #include "core/cutheap.h" @@ -163,17 +161,17 @@ static igraph_error_t igraph_i_maxflow_undirected( igraph_vector_int_t *cut, igraph_vector_int_t *partition, igraph_vector_int_t *partition2, - igraph_integer_t source, - igraph_integer_t target, + igraph_int_t source, + igraph_int_t target, const igraph_vector_t *capacity, igraph_maxflow_stats_t *stats) { - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t edges; igraph_vector_t newcapacity; igraph_t newgraph; - igraph_integer_t size; + igraph_int_t size; /* We need to convert this to directed by hand, since we need to be sure that the edge IDs will be handled properly to build the new @@ -185,7 +183,7 @@ static igraph_error_t igraph_i_maxflow_undirected( IGRAPH_CHECK(igraph_vector_int_reserve(&edges, size)); IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); IGRAPH_CHECK(igraph_vector_int_resize(&edges, size)); - for (igraph_integer_t i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { VECTOR(edges)[no_of_edges * 2 + i * 2] = VECTOR(edges)[i * 2 + 1]; VECTOR(edges)[no_of_edges * 2 + i * 2 + 1] = VECTOR(edges)[i * 2]; VECTOR(newcapacity)[i] = VECTOR(newcapacity)[no_of_edges + i] = @@ -199,8 +197,8 @@ static igraph_error_t igraph_i_maxflow_undirected( partition2, source, target, &newcapacity, stats)); if (cut) { - igraph_integer_t cs = igraph_vector_int_size(cut); - for (igraph_integer_t i = 0; i < cs; i++) { + igraph_int_t cs = igraph_vector_int_size(cut); + for (igraph_int_t i = 0; i < cs; i++) { if (VECTOR(*cut)[i] >= no_of_edges) { VECTOR(*cut)[i] -= no_of_edges; } @@ -213,7 +211,7 @@ static igraph_error_t igraph_i_maxflow_undirected( from the bigger vertex ID to the smaller one. For positive values the direction is the opposite. */ if (flow) { - for (igraph_integer_t i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { VECTOR(*flow)[i] -= VECTOR(*flow)[i + no_of_edges]; } IGRAPH_CHECK(igraph_vector_resize(flow, no_of_edges)); @@ -255,33 +253,33 @@ static igraph_error_t igraph_i_maxflow_undirected( &first, ¤t, &to, &excess, \ &rescap, &rev)) -static void igraph_i_mf_gap(igraph_integer_t b, igraph_maxflow_stats_t *stats, +static void igraph_i_mf_gap(igraph_int_t b, igraph_maxflow_stats_t *stats, igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets, - igraph_integer_t no_of_nodes, + igraph_int_t no_of_nodes, igraph_vector_int_t *distance) { IGRAPH_UNUSED(buckets); - igraph_integer_t bo; + igraph_int_t bo; (stats->nogap)++; for (bo = b + 1; bo <= no_of_nodes; bo++) { while (!igraph_dbuckets_empty_bucket(ibuckets, bo)) { - igraph_integer_t n = igraph_dbuckets_pop(ibuckets, bo); + igraph_int_t n = igraph_dbuckets_pop(ibuckets, bo); (stats->nogapnodes)++; DIST(n) = no_of_nodes; } } } -static void igraph_i_mf_relabel(igraph_integer_t v, igraph_integer_t no_of_nodes, +static void igraph_i_mf_relabel(igraph_int_t v, igraph_int_t no_of_nodes, igraph_vector_int_t *distance, igraph_vector_int_t *first, igraph_vector_t *rescap, igraph_vector_int_t *to, igraph_vector_int_t *current, - igraph_maxflow_stats_t *stats, igraph_integer_t *nrelabelsince) { + igraph_maxflow_stats_t *stats, igraph_int_t *nrelabelsince) { - igraph_integer_t min = no_of_nodes; - igraph_integer_t k, l, min_edge = 0; + igraph_int_t min = no_of_nodes; + igraph_int_t k, l, min_edge = 0; (stats->norelabel)++; (*nrelabelsince)++; DIST(v) = no_of_nodes; for (k = FIRST(v), l = LAST(v); k < l; k++) { @@ -297,14 +295,14 @@ static void igraph_i_mf_relabel(igraph_integer_t v, igraph_integer_t no_of_nodes } } -static void igraph_i_mf_push(igraph_integer_t v, igraph_integer_t e, igraph_integer_t n, +static void igraph_i_mf_push(igraph_int_t v, igraph_int_t e, igraph_int_t n, igraph_vector_int_t *current, igraph_vector_t *rescap, igraph_vector_t *excess, - igraph_integer_t target, igraph_integer_t source, + igraph_int_t target, igraph_int_t source, igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets, igraph_vector_int_t *distance, igraph_vector_int_t *rev, igraph_maxflow_stats_t *stats, - igraph_integer_t *npushsince) { + igraph_int_t *npushsince) { IGRAPH_UNUSED(current); IGRAPH_UNUSED(source); @@ -322,27 +320,27 @@ static void igraph_i_mf_push(igraph_integer_t v, igraph_integer_t e, igraph_inte EXCESS(v) -= delta; } -static void igraph_i_mf_discharge(igraph_integer_t v, +static void igraph_i_mf_discharge(igraph_int_t v, igraph_vector_int_t *current, igraph_vector_int_t *first, igraph_vector_t *rescap, igraph_vector_int_t *to, igraph_vector_int_t *distance, igraph_vector_t *excess, - igraph_integer_t no_of_nodes, igraph_integer_t source, - igraph_integer_t target, igraph_buckets_t *buckets, + igraph_int_t no_of_nodes, igraph_int_t source, + igraph_int_t target, igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets, igraph_vector_int_t *rev, igraph_maxflow_stats_t *stats, - igraph_integer_t *npushsince, igraph_integer_t *nrelabelsince) { + igraph_int_t *npushsince, igraph_int_t *nrelabelsince) { do { - igraph_integer_t i; - igraph_integer_t start = CURRENT(v); - igraph_integer_t stop = LAST(v); + igraph_int_t i; + igraph_int_t start = CURRENT(v); + igraph_int_t stop = LAST(v); for (i = start; i < stop; i++) { if (RESCAP(i) > 0) { - igraph_integer_t nei = HEAD(i); + igraph_int_t nei = HEAD(i); if (DIST(v) == DIST(nei) + 1) { PUSH((v), i, nei); if (EXCESS(v) == 0) { @@ -352,7 +350,7 @@ static void igraph_i_mf_discharge(igraph_integer_t v, } } if (i == stop) { - igraph_integer_t origdist = DIST(v); + igraph_int_t origdist = DIST(v); RELABEL(v); if (igraph_buckets_empty_bucket(buckets, origdist) && igraph_dbuckets_empty_bucket(ibuckets, origdist)) { @@ -370,15 +368,15 @@ static void igraph_i_mf_discharge(igraph_integer_t v, } static igraph_error_t igraph_i_mf_bfs(igraph_dqueue_int_t *bfsq, - igraph_integer_t source, igraph_integer_t target, - igraph_integer_t no_of_nodes, igraph_buckets_t *buckets, + igraph_int_t source, igraph_int_t target, + igraph_int_t no_of_nodes, igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets, igraph_vector_int_t *distance, igraph_vector_int_t *first, igraph_vector_int_t *current, igraph_vector_int_t *to, igraph_vector_t *excess, igraph_vector_t *rescap, igraph_vector_int_t *rev) { - igraph_integer_t k, l; + igraph_int_t k, l; IGRAPH_UNUSED(source); @@ -389,11 +387,11 @@ static igraph_error_t igraph_i_mf_bfs(igraph_dqueue_int_t *bfsq, IGRAPH_CHECK(igraph_dqueue_int_push(bfsq, target)); while (!igraph_dqueue_int_empty(bfsq)) { - igraph_integer_t node = igraph_dqueue_int_pop(bfsq); - igraph_integer_t ndist = DIST(node) + 1; + igraph_int_t node = igraph_dqueue_int_pop(bfsq); + igraph_int_t ndist = DIST(node) + 1; for (k = FIRST(node), l = LAST(node); k < l; k++) { if (RESCAP(REV(k)) > 0) { - igraph_integer_t nei = HEAD(k); + igraph_int_t nei = HEAD(k); if (DIST(nei) == no_of_nodes) { DIST(nei) = ndist; CURRENT(nei) = FIRST(nei); @@ -489,13 +487,13 @@ static igraph_error_t igraph_i_mf_bfs(igraph_dqueue_int_t *bfsq, igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, igraph_vector_t *flow, igraph_vector_int_t *cut, igraph_vector_int_t *partition, igraph_vector_int_t *partition2, - igraph_integer_t source, igraph_integer_t target, + igraph_int_t source, igraph_int_t target, const igraph_vector_t *capacity, igraph_maxflow_stats_t *stats) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_orig_edges = igraph_ecount(graph); - igraph_integer_t no_of_edges = 2 * no_of_orig_edges; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_orig_edges = igraph_ecount(graph); + const igraph_int_t no_of_edges = 2 * no_of_orig_edges; igraph_vector_t rescap, excess; igraph_vector_int_t from, to, rev, distance; @@ -506,12 +504,12 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, igraph_dqueue_int_t bfsq; - igraph_integer_t i, j, idx; - igraph_integer_t npushsince = 0, nrelabelsince = 0; + igraph_int_t idx; + igraph_int_t npushsince = 0, nrelabelsince = 0; igraph_maxflow_stats_t local_stats; /* used if the user passed a null pointer for stats */ - if (stats == 0) { + if (stats == NULL) { stats = &local_stats; } @@ -595,11 +593,11 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, /* Create the basic data structure */ IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); - IGRAPH_CHECK(igraph_vector_int_rank(&edges, &rank, no_of_nodes)); + IGRAPH_CHECK(igraph_i_vector_int_rank(&edges, &rank, no_of_nodes)); - for (i = 0; i < no_of_edges; i += 2) { - igraph_integer_t pos = VECTOR(rank)[i]; - igraph_integer_t pos2 = VECTOR(rank)[i + 1]; + for (igraph_int_t i = 0; i < no_of_edges; i += 2) { + const igraph_int_t pos = VECTOR(rank)[i]; + const igraph_int_t pos2 = VECTOR(rank)[i + 1]; VECTOR(from)[pos] = VECTOR(edges)[i]; VECTOR(to)[pos] = VECTOR(edges)[i + 1]; VECTOR(from)[pos2] = VECTOR(edges)[i + 1]; @@ -614,13 +612,13 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, think, because of the possible isolate vertices. */ idx = -1; - for (i = 0; i <= VECTOR(from)[0]; i++) { + for (igraph_int_t i = 0; i <= VECTOR(from)[0]; i++) { idx++; VECTOR(first)[idx] = 0; } - for (i = 1; i < no_of_edges; i++) { - igraph_integer_t n = (VECTOR(from)[i] - - VECTOR(from)[ VECTOR(first)[idx] ]); - for (j = 0; j < n; j++) { + for (igraph_int_t i = 1; i < no_of_edges; i++) { + const igraph_int_t n = (VECTOR(from)[i] - + VECTOR(from)[ VECTOR(first)[idx] ]); + for (igraph_int_t j = 0; j < n; j++) { idx++; VECTOR(first)[idx] = i; } } @@ -640,7 +638,7 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, /* And the current pointers, initially the same as the first */ IGRAPH_VECTOR_INT_INIT_FINALLY(¤t, no_of_nodes); - for (i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { VECTOR(current)[i] = VECTOR(first)[i]; } @@ -652,9 +650,9 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, IGRAPH_FINALLY(igraph_dbuckets_destroy, &ibuckets); /* Send as much flow as possible from the source to its neighbors */ - for (i = FIRST(source), j = LAST(source); i < j; i++) { + for (igraph_int_t i = FIRST(source), j = LAST(source); i < j; i++) { if (HEAD(i) != source) { - igraph_real_t delta = RESCAP(i); + const igraph_real_t delta = RESCAP(i); RESCAP(i) = 0; RESCAP(REV(i)) += delta; EXCESS(HEAD(i)) += delta; @@ -665,7 +663,7 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, (stats->nobfs)++; while (!igraph_buckets_empty(&buckets)) { - igraph_integer_t vertex = igraph_buckets_popmax(&buckets); + const igraph_int_t vertex = igraph_buckets_popmax(&buckets); DISCHARGE(vertex); if (npushsince > no_of_nodes / 2 && nrelabelsince > no_of_nodes) { (stats->nobfs)++; @@ -686,7 +684,7 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, backwards. */ igraph_dqueue_int_t Q; igraph_vector_bool_t added; - igraph_integer_t marked = 0; + igraph_int_t marked = 0; IGRAPH_CHECK(igraph_vector_bool_init(&added, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &added); @@ -698,9 +696,9 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, VECTOR(added)[target] = true; marked++; while (!igraph_dqueue_int_empty(&Q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&Q); - for (i = FIRST(actnode), j = LAST(actnode); i < j; i++) { - igraph_integer_t nei = HEAD(i); + const igraph_int_t actnode = igraph_dqueue_int_pop(&Q); + for (igraph_int_t i = FIRST(actnode), j = LAST(actnode); i < j; i++) { + igraph_int_t nei = HEAD(i); if (!VECTOR(added)[nei] && RESCAP(REV(i)) > 0.0) { VECTOR(added)[nei] = true; marked++; @@ -716,9 +714,9 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, if (cut) { igraph_vector_int_clear(cut); - for (i = 0; i < no_of_orig_edges; i++) { - igraph_integer_t f = IGRAPH_FROM(graph, i); - igraph_integer_t t = IGRAPH_TO(graph, i); + for (igraph_int_t i = 0; i < no_of_orig_edges; i++) { + igraph_int_t f = IGRAPH_FROM(graph, i); + igraph_int_t t = IGRAPH_TO(graph, i); if (!VECTOR(added)[f] && VECTOR(added)[t]) { IGRAPH_CHECK(igraph_vector_int_push_back(cut, i)); } @@ -726,9 +724,9 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, } if (partition2) { - igraph_integer_t x = 0; + igraph_int_t x = 0; IGRAPH_CHECK(igraph_vector_int_resize(partition2, marked)); - for (i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(added)[i]) { VECTOR(*partition2)[x++] = i; } @@ -736,10 +734,10 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, } if (partition) { - igraph_integer_t x = 0; + igraph_int_t x = 0; IGRAPH_CHECK(igraph_vector_int_resize(partition, no_of_nodes - marked)); - for (i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (!VECTOR(added)[i]) { VECTOR(*partition)[x++] = i; } @@ -755,7 +753,6 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, from the source */ igraph_dqueue_int_t Q; igraph_vector_int_t added; /* uses more than two values, cannot be bool */ - igraph_integer_t j, k, l; igraph_t flow_graph; igraph_vector_int_t flow_edges; igraph_bool_t dag; @@ -769,12 +766,12 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, IGRAPH_CHECK(igraph_dqueue_int_push(&Q, 0)); VECTOR(added)[source] = 1; while (!igraph_dqueue_int_empty(&Q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&Q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&Q); + const igraph_int_t actnode = igraph_dqueue_int_pop(&Q); + const igraph_int_t actdist = igraph_dqueue_int_pop(&Q); DIST(actnode) = actdist; - for (i = FIRST(actnode), j = LAST(actnode); i < j; i++) { - igraph_integer_t nei = HEAD(i); + for (igraph_int_t i = FIRST(actnode), j = LAST(actnode); i < j; i++) { + const igraph_int_t nei = HEAD(i); if (!VECTOR(added)[nei] && RESCAP(REV(i)) > 0.0) { VECTOR(added)[nei] = 1; IGRAPH_CHECK(igraph_dqueue_int_push(&Q, nei)); @@ -789,7 +786,7 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, /* Reinitialize the buckets */ igraph_buckets_clear(&buckets); - for (i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (EXCESS(i) > 0.0 && i != source && i != target) { igraph_buckets_add(&buckets, DIST(i), i); } @@ -797,13 +794,14 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, /* Now we return the flow to the source */ while (!igraph_buckets_empty(&buckets)) { - igraph_integer_t vertex = igraph_buckets_popmax(&buckets); + const igraph_int_t vertex = igraph_buckets_popmax(&buckets); /* DISCHARGE(vertex) comes here */ do { + igraph_int_t i, j; for (i = CURRENT(vertex), j = LAST(vertex); i < j; i++) { if (RESCAP(i) > 0) { - igraph_integer_t nei = HEAD(i); + igraph_int_t nei = HEAD(i); if (DIST(vertex) == DIST(nei) + 1) { igraph_real_t delta = @@ -830,10 +828,10 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, if (i == j) { /* RELABEL(vertex) comes here */ - igraph_integer_t min; - igraph_integer_t min_edge = 0; + igraph_int_t min; + igraph_int_t min_edge = 0; DIST(vertex) = min = no_of_nodes; - for (k = FIRST(vertex), l = LAST(vertex); k < l; k++) { + for (igraph_int_t k = FIRST(vertex), l = LAST(vertex); k < l; k++) { if (RESCAP(k) > 0) { if (DIST(HEAD(k)) < min) { min = DIST(HEAD(k)); @@ -881,8 +879,8 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, 'stack', but it was visited before. */ IGRAPH_VECTOR_INT_INIT_FINALLY(&flow_edges, 0); - for (i = 0, j = 0; i < no_of_edges; i += 2, j++) { - igraph_integer_t pos = VECTOR(rank)[i]; + for (igraph_int_t i = 0, j = 0; i < no_of_edges; i += 2, j++) { + const igraph_int_t pos = VECTOR(rank)[i]; if ((capacity ? VECTOR(*capacity)[j] : 1.0) > RESCAP(pos)) { IGRAPH_CHECK(igraph_vector_int_push_back(&flow_edges, IGRAPH_FROM(graph, j))); @@ -911,9 +909,9 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, #define MYCAP(i) (VECTOR(mycap)[(i)]) - for (i = 0; i < no_of_edges; i += 2) { - igraph_integer_t pos = VECTOR(rank)[i]; - igraph_integer_t pos2 = VECTOR(rank)[i + 1]; + for (igraph_int_t i = 0; i < no_of_edges; i += 2) { + const igraph_int_t pos = VECTOR(rank)[i]; + const igraph_int_t pos2 = VECTOR(rank)[i + 1]; MYCAP(pos) = (capacity ? VECTOR(*capacity)[i / 2] : 1.0) - RESCAP(pos); MYCAP(pos2) = 0.0; } @@ -928,9 +926,9 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, VECTOR(added)[source] = 1; while (!igraph_vector_int_empty(&stack) && igraph_vector_int_tail(&stack) != target) { - igraph_integer_t actnode = igraph_vector_int_tail(&stack); - igraph_integer_t edge = FIRST(actnode) + CURRENT(actnode); - igraph_integer_t nei; + const igraph_int_t actnode = igraph_vector_int_tail(&stack); + igraph_int_t edge = FIRST(actnode) + CURRENT(actnode); + igraph_int_t nei; while (edge < LAST(actnode) && MYCAP(edge) == 0.0) { edge++; } @@ -948,19 +946,18 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, until we find 'nei' again, determine the flow along the cycle. */ igraph_real_t thisflow = MYCAP(edge); - igraph_integer_t idx; - for (idx = igraph_vector_int_size(&stack) - 2; + for (igraph_int_t idx = igraph_vector_int_size(&stack) - 2; idx >= 0 && VECTOR(stack)[idx + 1] != nei; idx -= 2) { - igraph_integer_t e = VECTOR(stack)[idx]; - igraph_real_t rcap = e >= 0 ? MYCAP(e) : MYCAP(edge); + const igraph_int_t e = VECTOR(stack)[idx]; + const igraph_real_t rcap = e >= 0 ? MYCAP(e) : MYCAP(edge); if (rcap < thisflow) { thisflow = rcap; } } MYCAP(edge) -= thisflow; RESCAP(edge) += thisflow; - for (idx = igraph_vector_int_size(&stack) - 2; + for (igraph_int_t idx = igraph_vector_int_size(&stack) - 2; idx >= 0 && VECTOR(stack)[idx + 1] != nei; idx -= 2) { - igraph_integer_t e = VECTOR(stack)[idx]; + const igraph_int_t e = VECTOR(stack)[idx]; if (e >= 0) { MYCAP(e) -= thisflow; RESCAP(e) += thisflow; @@ -982,17 +979,17 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, /* If non-empty, then it contains a path from source to target in the residual graph. We factor out this path from the flow. */ if (!igraph_vector_int_empty(&stack)) { - igraph_integer_t pl = igraph_vector_int_size(&stack); + const igraph_int_t pl = igraph_vector_int_size(&stack); igraph_real_t thisflow = EXCESS(target); - for (i = 2; i < pl; i += 2) { - igraph_integer_t edge = VECTOR(stack)[i]; - igraph_real_t rcap = MYCAP(edge); + for (igraph_int_t i = 2; i < pl; i += 2) { + const igraph_int_t edge = VECTOR(stack)[i]; + const igraph_real_t rcap = MYCAP(edge); if (rcap < thisflow) { thisflow = rcap; } } - for (i = 2; i < pl; i += 2) { - igraph_integer_t edge = VECTOR(stack)[i]; + for (igraph_int_t i = 2; i < pl; i += 2) { + const igraph_int_t edge = VECTOR(stack)[i]; MYCAP(edge) -= thisflow; } } @@ -1008,8 +1005,8 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, /* ----------------------------------------------------------- */ IGRAPH_CHECK(igraph_vector_resize(flow, no_of_orig_edges)); - for (i = 0, j = 0; i < no_of_edges; i += 2, j++) { - igraph_integer_t pos = VECTOR(rank)[i]; + for (igraph_int_t i = 0, j = 0; i < no_of_edges; i += 2, j++) { + const igraph_int_t pos = VECTOR(rank)[i]; VECTOR(*flow)[j] = (capacity ? VECTOR(*capacity)[j] : 1.0) - RESCAP(pos); } @@ -1089,7 +1086,7 @@ igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, */ igraph_error_t igraph_maxflow_value(const igraph_t *graph, igraph_real_t *value, - igraph_integer_t source, igraph_integer_t target, + igraph_int_t source, igraph_int_t target, const igraph_vector_t *capacity, igraph_maxflow_stats_t *stats) { @@ -1128,14 +1125,14 @@ igraph_error_t igraph_maxflow_value(const igraph_t *graph, igraph_real_t *value, */ igraph_error_t igraph_st_mincut_value(const igraph_t *graph, igraph_real_t *value, - igraph_integer_t source, igraph_integer_t target, + igraph_int_t source, igraph_int_t target, const igraph_vector_t *capacity) { if (source == target) { IGRAPH_ERROR("source and target vertices are the same", IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_maxflow_value(graph, value, source, target, capacity, 0)); + IGRAPH_CHECK(igraph_maxflow_value(graph, value, source, target, capacity, NULL)); return IGRAPH_SUCCESS; } @@ -1179,7 +1176,7 @@ igraph_error_t igraph_st_mincut_value(const igraph_t *graph, igraph_real_t *valu igraph_error_t igraph_st_mincut(const igraph_t *graph, igraph_real_t *value, igraph_vector_int_t *cut, igraph_vector_int_t *partition, igraph_vector_int_t *partition2, - igraph_integer_t source, igraph_integer_t target, + igraph_int_t source, igraph_int_t target, const igraph_vector_t *capacity) { return igraph_maxflow(graph, value, /*flow=*/ NULL, @@ -1202,19 +1199,19 @@ static igraph_error_t igraph_i_mincut_undirected( igraph_vector_int_t *cut, const igraph_vector_t *capacity) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_i_cutheap_t heap; igraph_real_t mincut = IGRAPH_INFINITY; /* infinity */ - igraph_integer_t i; + igraph_int_t i; igraph_adjlist_t adjlist; igraph_inclist_t inclist; igraph_vector_int_t mergehist; igraph_bool_t calc_cut = partition || partition2 || cut; - igraph_integer_t act_step = 0, mincut_step = 0; + igraph_int_t act_step = 0, mincut_step = 0; if (capacity && igraph_vector_size(capacity) != no_of_edges) { IGRAPH_ERROR("Invalid capacity vector size", IGRAPH_EINVAL); @@ -1224,7 +1221,7 @@ static igraph_error_t igraph_i_mincut_undirected( { igraph_vector_int_t memb; igraph_vector_int_t csize; - igraph_integer_t no; + igraph_int_t no; IGRAPH_VECTOR_INT_INIT_FINALLY(&memb, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&csize, 0); IGRAPH_CHECK(igraph_connected_components(graph, &memb, &csize, &no, IGRAPH_WEAK)); @@ -1236,7 +1233,7 @@ static igraph_error_t igraph_i_mincut_undirected( igraph_vector_int_clear(cut); } if (partition) { - igraph_integer_t j = 0; + igraph_int_t j = 0; IGRAPH_CHECK(igraph_vector_int_resize(partition, VECTOR(csize)[0])); for (i = 0; i < no_of_nodes; i++) { @@ -1246,7 +1243,7 @@ static igraph_error_t igraph_i_mincut_undirected( } } if (partition2) { - igraph_integer_t j = 0; + igraph_int_t j = 0; IGRAPH_CHECK(igraph_vector_int_resize(partition2, no_of_nodes - VECTOR(csize)[0])); for (i = 0; i < no_of_nodes; i++) { @@ -1281,9 +1278,9 @@ static igraph_error_t igraph_i_mincut_undirected( while (igraph_i_cutheap_size(&heap) >= 2) { - igraph_integer_t last; + igraph_int_t last; igraph_real_t acut; - igraph_integer_t a, n; + igraph_int_t a, n; igraph_vector_int_t *edges, *edges2; igraph_vector_int_t *neis, *neis2; @@ -1296,8 +1293,8 @@ static igraph_error_t igraph_i_mincut_undirected( neis = igraph_adjlist_get(&adjlist, a); n = igraph_vector_int_size(edges); for (i = 0; i < n; i++) { - igraph_integer_t edge = VECTOR(*edges)[i]; - igraph_integer_t to = VECTOR(*neis)[i]; + igraph_int_t edge = VECTOR(*edges)[i]; + igraph_int_t to = VECTOR(*neis)[i]; igraph_real_t weight = capacity ? VECTOR(*capacity)[edge] : 1.0; igraph_i_cutheap_update(&heap, to, weight); } @@ -1361,8 +1358,8 @@ static igraph_error_t igraph_i_mincut_undirected( neis = igraph_adjlist_get(&adjlist, last); n = igraph_vector_int_size(neis); for (i = 0; i < n; i++) { - igraph_integer_t nei = VECTOR(*neis)[i]; - igraph_integer_t n2, j; + igraph_int_t nei = VECTOR(*neis)[i]; + igraph_int_t n2, j; neis2 = igraph_adjlist_get(&adjlist, nei); n2 = igraph_vector_int_size(neis2); for (j = 0; j < n2; j++) { @@ -1394,21 +1391,19 @@ static igraph_error_t igraph_i_mincut_undirected( IGRAPH_FINALLY_CLEAN(3); if (calc_cut) { - igraph_integer_t bignode = VECTOR(mergehist)[2 * mincut_step + 1]; - igraph_integer_t i, idx; - igraph_integer_t size = 1; - bool *mark; + igraph_int_t bignode = VECTOR(mergehist)[2 * mincut_step + 1]; + igraph_int_t i, idx; + igraph_int_t size = 1; + igraph_bitset_t mark; - mark = IGRAPH_CALLOC(no_of_nodes, bool); - IGRAPH_CHECK_OOM(mark, "Not enough memory for minimum cut."); - IGRAPH_FINALLY(igraph_free, mark); + IGRAPH_BITSET_INIT_FINALLY(&mark, no_of_nodes); /* first count the vertices in the partition */ - mark[bignode] = true; + IGRAPH_BIT_SET(mark, bignode); for (i = mincut_step - 1; i >= 0; i--) { - if ( mark[ VECTOR(mergehist)[2 * i] ] ) { + if ( IGRAPH_BIT_TEST(mark, VECTOR(mergehist)[2 * i]) ) { size++; - mark [ VECTOR(mergehist)[2 * i + 1] ] = true; + IGRAPH_BIT_SET(mark, VECTOR(mergehist)[2 * i + 1]); } } @@ -1418,7 +1413,7 @@ static igraph_error_t igraph_i_mincut_undirected( idx = 0; VECTOR(*partition)[idx++] = bignode; for (i = mincut_step - 1; i >= 0; i--) { - if (mark[ VECTOR(mergehist)[2 * i] ]) { + if (IGRAPH_BIT_TEST(mark, VECTOR(mergehist)[2 * i])) { VECTOR(*partition)[idx++] = VECTOR(mergehist)[2 * i + 1]; } } @@ -1429,7 +1424,7 @@ static igraph_error_t igraph_i_mincut_undirected( IGRAPH_CHECK(igraph_vector_int_resize(partition2, no_of_nodes - size)); idx = 0; for (i = 0; i < no_of_nodes; i++) { - if (!mark[i]) { + if (!IGRAPH_BIT_TEST(mark, i)) { VECTOR(*partition2)[idx++] = i; } } @@ -1440,12 +1435,12 @@ static igraph_error_t igraph_i_mincut_undirected( so we first collect the edges in mergehist, we don't need that anymore. Then we copy it to 'cut'; */ if (cut) { - igraph_integer_t from, to; + igraph_int_t from, to; igraph_vector_int_clear(&mergehist); for (i = 0; i < no_of_edges; i++) { igraph_edge(graph, i, &from, &to); - if ((mark[from] && !mark[to]) || - (mark[to] && !mark[from])) { + if ((IGRAPH_BIT_TEST(mark, from) && !IGRAPH_BIT_TEST(mark, to)) || + (IGRAPH_BIT_TEST(mark, to) && !IGRAPH_BIT_TEST(mark, from))) { IGRAPH_CHECK(igraph_vector_int_push_back(&mergehist, i)); } } @@ -1453,7 +1448,7 @@ static igraph_error_t igraph_i_mincut_undirected( IGRAPH_CHECK(igraph_vector_int_append(cut, &mergehist)); } - IGRAPH_FREE(mark); + igraph_bitset_destroy(&mark); igraph_vector_int_destroy(&mergehist); IGRAPH_FINALLY_CLEAN(2); } @@ -1469,12 +1464,12 @@ static igraph_error_t igraph_i_mincut_directed( igraph_vector_int_t *cut, const igraph_vector_t *capacity) { - igraph_integer_t i; - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i; + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_real_t flow; igraph_real_t minmaxflow = IGRAPH_INFINITY; igraph_vector_int_t mypartition, mypartition2, mycut; - igraph_vector_int_t *ppartition = 0, *ppartition2 = 0, *pcut = 0; + igraph_vector_int_t *ppartition = NULL, *ppartition2 = NULL, *pcut = NULL; igraph_vector_int_t bestpartition, bestpartition2, bestcut; if (partition) { @@ -1696,9 +1691,9 @@ static igraph_error_t igraph_i_mincut_value_undirected( igraph_error_t igraph_mincut_value(const igraph_t *graph, igraph_real_t *res, const igraph_vector_t *capacity) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_real_t minmaxflow, flow; - igraph_integer_t i; + igraph_int_t i; minmaxflow = IGRAPH_INFINITY; @@ -1709,7 +1704,7 @@ igraph_error_t igraph_mincut_value(const igraph_t *graph, igraph_real_t *res, for (i = 1; i < no_of_nodes; i++) { IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, 0, i, - capacity, 0)); + capacity, NULL)); if (flow < minmaxflow) { minmaxflow = flow; if (flow == 0) { @@ -1717,7 +1712,7 @@ igraph_error_t igraph_mincut_value(const igraph_t *graph, igraph_real_t *res, } } IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, i, 0, - capacity, 0)); + capacity, NULL)); if (flow < minmaxflow) { minmaxflow = flow; if (flow == 0) { @@ -1735,15 +1730,15 @@ igraph_error_t igraph_mincut_value(const igraph_t *graph, igraph_real_t *res, static igraph_error_t igraph_i_st_vertex_connectivity_check_errors( const igraph_t *graph, - igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target, + igraph_int_t *res, + igraph_int_t source, + igraph_int_t target, igraph_vconn_nei_t neighbors, igraph_bool_t *done, - igraph_integer_t *no_conn) { + igraph_int_t *no_conn) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t eid; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t eid; igraph_bool_t conn; *done = true; *no_conn = 0; @@ -1793,18 +1788,18 @@ static igraph_error_t igraph_i_st_vertex_connectivity_check_errors( static igraph_error_t igraph_i_st_vertex_connectivity_directed( const igraph_t *graph, - igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target, + igraph_int_t *res, + igraph_int_t source, + igraph_int_t target, igraph_vconn_nei_t neighbors) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges; igraph_real_t real_res; igraph_t newgraph; - igraph_integer_t i, len; + igraph_int_t i, len; igraph_bool_t done; - igraph_integer_t no_conn; + igraph_int_t no_conn; igraph_vector_int_t incs; igraph_vector_t capacity; @@ -1825,12 +1820,12 @@ static igraph_error_t igraph_i_st_vertex_connectivity_directed( /* "Disable" the edges incident on the input half of the source vertex * and the output half of the target vertex */ IGRAPH_VECTOR_INT_INIT_FINALLY(&incs, 0); - IGRAPH_CHECK(igraph_incident(&newgraph, &incs, source + no_of_nodes, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(&newgraph, &incs, source + no_of_nodes, IGRAPH_ALL, IGRAPH_LOOPS)); len = igraph_vector_int_size(&incs); for (i = 0; i < len; i++) { VECTOR(capacity)[VECTOR(incs)[i]] = 0; } - IGRAPH_CHECK(igraph_incident(&newgraph, &incs, target, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(&newgraph, &incs, target, IGRAPH_ALL, IGRAPH_LOOPS)); len = igraph_vector_int_size(&incs); for (i = 0; i < len; i++) { VECTOR(capacity)[VECTOR(incs)[i]] = 0; @@ -1840,8 +1835,8 @@ static igraph_error_t igraph_i_st_vertex_connectivity_directed( /* Do the maximum flow */ IGRAPH_CHECK(igraph_maxflow_value(&newgraph, &real_res, - source, target + no_of_nodes, &capacity, 0)); - *res = (igraph_integer_t) real_res; + source, target + no_of_nodes, &capacity, NULL)); + *res = (igraph_int_t) real_res; *res -= no_conn; @@ -1854,14 +1849,14 @@ static igraph_error_t igraph_i_st_vertex_connectivity_directed( static igraph_error_t igraph_i_st_vertex_connectivity_undirected( const igraph_t *graph, - igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target, + igraph_int_t *res, + igraph_int_t source, + igraph_int_t target, igraph_vconn_nei_t neighbors) { igraph_t newgraph; igraph_bool_t done; - igraph_integer_t no_conn; + igraph_int_t no_conn; IGRAPH_CHECK(igraph_i_st_vertex_connectivity_check_errors(graph, res, source, target, neighbors, &done, &no_conn)); if (done) { @@ -1925,9 +1920,9 @@ static igraph_error_t igraph_i_st_vertex_connectivity_undirected( igraph_error_t igraph_st_vertex_connectivity( const igraph_t *graph, - igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target, + igraph_int_t *res, + igraph_int_t source, + igraph_int_t target, igraph_vconn_nei_t neighbors) { if (igraph_is_directed(graph)) { @@ -1945,17 +1940,17 @@ igraph_error_t igraph_st_vertex_connectivity( static igraph_error_t igraph_i_vertex_connectivity_directed( const igraph_t *graph, - igraph_integer_t *res, + igraph_int_t *res, igraph_bool_t all_edges_are_mutual) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges; - igraph_integer_t i, j, k, len; - igraph_integer_t minconn = no_of_nodes - 1, conn = 0; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges; + igraph_int_t i, j, k, len; + igraph_int_t minconn = no_of_nodes - 1, conn = 0; igraph_t split_graph; igraph_vector_t capacity; igraph_bool_t done; - igraph_integer_t dummy_num_connections; + igraph_int_t dummy_num_connections; igraph_vector_int_t incs; igraph_real_t real_res; @@ -1996,12 +1991,12 @@ static igraph_error_t igraph_i_vertex_connectivity_directed( if (!done) { /* "Disable" the edges incident on the input half of the source vertex * and the output half of the target vertex */ - IGRAPH_CHECK(igraph_incident(&split_graph, &incs, i + no_of_nodes, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(&split_graph, &incs, i + no_of_nodes, IGRAPH_ALL, IGRAPH_LOOPS)); len = igraph_vector_int_size(&incs); for (k = 0; k < len; k++) { VECTOR(capacity)[VECTOR(incs)[k]] = 0; } - IGRAPH_CHECK(igraph_incident(&split_graph, &incs, j, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(&split_graph, &incs, j, IGRAPH_ALL, IGRAPH_LOOPS)); len = igraph_vector_int_size(&incs); for (k = 0; k < len; k++) { VECTOR(capacity)[VECTOR(incs)[k]] = 0; @@ -2009,22 +2004,22 @@ static igraph_error_t igraph_i_vertex_connectivity_directed( /* Do the maximum flow */ IGRAPH_CHECK(igraph_maxflow_value( - &split_graph, &real_res, i, j + no_of_nodes, &capacity, 0 + &split_graph, &real_res, i, j + no_of_nodes, &capacity, NULL )); /* Restore the capacities */ - IGRAPH_CHECK(igraph_incident(&split_graph, &incs, i + no_of_nodes, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(&split_graph, &incs, i + no_of_nodes, IGRAPH_ALL, IGRAPH_LOOPS)); len = igraph_vector_int_size(&incs); for (k = 0; k < len; k++) { VECTOR(capacity)[VECTOR(incs)[k]] = 1; } - IGRAPH_CHECK(igraph_incident(&split_graph, &incs, j, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(&split_graph, &incs, j, IGRAPH_ALL, IGRAPH_LOOPS)); len = igraph_vector_int_size(&incs); for (k = 0; k < len; k++) { VECTOR(capacity)[VECTOR(incs)[k]] = 1; } - conn = (igraph_integer_t) real_res; + conn = (igraph_int_t) real_res; } if (conn < minconn) { @@ -2054,7 +2049,7 @@ static igraph_error_t igraph_i_vertex_connectivity_directed( static igraph_error_t igraph_i_vertex_connectivity_undirected( const igraph_t *graph, - igraph_integer_t *res) { + igraph_int_t *res) { igraph_t newgraph; @@ -2079,7 +2074,7 @@ static igraph_error_t igraph_i_vertex_connectivity_undirected( */ static igraph_error_t igraph_i_connectivity_checks( const igraph_t *graph, - igraph_integer_t *res, + igraph_int_t *res, igraph_bool_t *found) { igraph_bool_t conn; @@ -2160,7 +2155,7 @@ static igraph_error_t igraph_i_connectivity_checks( */ igraph_error_t igraph_vertex_connectivity( - const igraph_t *graph, igraph_integer_t *res, + const igraph_t *graph, igraph_int_t *res, igraph_bool_t checks) { igraph_bool_t ret = false; @@ -2221,9 +2216,9 @@ igraph_error_t igraph_vertex_connectivity( */ igraph_error_t igraph_st_edge_connectivity(const igraph_t *graph, - igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target) { + igraph_int_t *res, + igraph_int_t source, + igraph_int_t target) { igraph_real_t flow; @@ -2231,8 +2226,8 @@ igraph_error_t igraph_st_edge_connectivity(const igraph_t *graph, IGRAPH_ERROR("The source and target vertices must be different.", IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, source, target, 0, 0)); - *res = (igraph_integer_t) flow; + IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, source, target, NULL, NULL)); + *res = (igraph_int_t) flow; return IGRAPH_SUCCESS; } @@ -2272,11 +2267,11 @@ igraph_error_t igraph_st_edge_connectivity(const igraph_t *graph, */ igraph_error_t igraph_edge_connectivity(const igraph_t *graph, - igraph_integer_t *res, + igraph_int_t *res, igraph_bool_t checks) { igraph_bool_t ret = false; - igraph_integer_t number_of_nodes = igraph_vcount(graph); + igraph_int_t number_of_nodes = igraph_vcount(graph); /* igraph_mincut_value returns infinity for the singleton graph, * which cannot be cast to an integer. We catch this case early @@ -2295,7 +2290,7 @@ igraph_error_t igraph_edge_connectivity(const igraph_t *graph, if (!ret) { igraph_real_t real_res; IGRAPH_CHECK(igraph_mincut_value(graph, &real_res, 0)); - *res = (igraph_integer_t)real_res; + *res = (igraph_int_t)real_res; } return IGRAPH_SUCCESS; @@ -2328,9 +2323,9 @@ igraph_error_t igraph_edge_connectivity(const igraph_t *graph, */ igraph_error_t igraph_edge_disjoint_paths(const igraph_t *graph, - igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target) { + igraph_int_t *res, + igraph_int_t source, + igraph_int_t target) { igraph_real_t flow; @@ -2339,9 +2334,9 @@ igraph_error_t igraph_edge_disjoint_paths(const igraph_t *graph, IGRAPH_UNIMPLEMENTED); } - IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, source, target, 0, 0)); + IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, source, target, NULL, NULL)); - *res = (igraph_integer_t) flow; + *res = (igraph_int_t) flow; return IGRAPH_SUCCESS; } @@ -2376,9 +2371,9 @@ igraph_error_t igraph_edge_disjoint_paths(const igraph_t *graph, */ igraph_error_t igraph_vertex_disjoint_paths(const igraph_t *graph, - igraph_integer_t *res, - igraph_integer_t source, - igraph_integer_t target) { + igraph_int_t *res, + igraph_int_t source, + igraph_int_t target) { igraph_vector_int_t eids; @@ -2438,7 +2433,7 @@ igraph_error_t igraph_vertex_disjoint_paths(const igraph_t *graph, */ igraph_error_t igraph_adhesion(const igraph_t *graph, - igraph_integer_t *res, + igraph_int_t *res, igraph_bool_t checks) { return igraph_edge_connectivity(graph, res, checks); } @@ -2472,7 +2467,7 @@ igraph_error_t igraph_adhesion(const igraph_t *graph, */ igraph_error_t igraph_cohesion(const igraph_t *graph, - igraph_integer_t *res, + igraph_int_t *res, igraph_bool_t checks) { IGRAPH_CHECK(igraph_vertex_connectivity(graph, res, checks)); @@ -2526,8 +2521,8 @@ igraph_error_t igraph_gomory_hu_tree(const igraph_t *graph, igraph_vector_t *flows, const igraph_vector_t *capacity) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t source, target, mid, i, n; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t source, target, mid, i, n; igraph_vector_int_t neighbors; igraph_vector_t flow_values; igraph_vector_int_t partition; diff --git a/src/vendor/cigraph/src/flow/flow_conversion.c b/src/vendor/cigraph/src/flow/flow_conversion.c index 01b20a5dddd..1cbebaf495c 100644 --- a/src/vendor/cigraph/src/flow/flow_conversion.c +++ b/src/vendor/cigraph/src/flow/flow_conversion.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -60,9 +59,9 @@ * \param result an uninitialized graph object; the result will be returned here */ igraph_error_t igraph_i_split_vertices(const igraph_t* graph, igraph_t* result) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t i; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t i; igraph_vector_int_t edges; if (!igraph_is_directed(graph)) { @@ -75,7 +74,7 @@ igraph_error_t igraph_i_split_vertices(const igraph_t* graph, igraph_t* result) IGRAPH_CHECK(igraph_vector_int_resize(&edges, 2 * (no_of_edges + no_of_nodes))); for (i = 0; i < 2 * no_of_edges; i += 2) { - igraph_integer_t to = VECTOR(edges)[i + 1]; + igraph_int_t to = VECTOR(edges)[i + 1]; VECTOR(edges)[i + 1] = no_of_nodes + to; } diff --git a/src/vendor/cigraph/src/flow/flow_internal.h b/src/vendor/cigraph/src/flow/flow_internal.h index a269d0090dd..6308baf4f24 100644 --- a/src/vendor/cigraph/src/flow/flow_internal.h +++ b/src/vendor/cigraph/src/flow/flow_internal.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -30,15 +29,15 @@ #include "core/estack.h" #include "core/marked_queue.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_all_st_cuts_pivot( const igraph_t *graph, const igraph_marked_queue_int_t *S, - const igraph_estack_t *T, igraph_integer_t source, igraph_integer_t target, - igraph_integer_t *v, igraph_vector_int_t *Isv, void *arg); + const igraph_estack_t *T, igraph_int_t source, igraph_int_t target, + igraph_int_t *v, igraph_vector_int_t *Isv, void *arg); igraph_error_t igraph_i_split_vertices(const igraph_t* graph, igraph_t* result); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/flow/st-cuts.c b/src/vendor/cigraph/src/flow/st-cuts.c index 6823b0d88e8..6af56657c11 100644 --- a/src/vendor/cigraph/src/flow/st-cuts.c +++ b/src/vendor/cigraph/src/flow/st-cuts.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -27,12 +26,12 @@ #include "igraph_constants.h" #include "igraph_constructors.h" #include "igraph_components.h" +#include "igraph_cycles.h" #include "igraph_error.h" #include "igraph_interface.h" #include "igraph_operators.h" #include "igraph_stack.h" #include "igraph_visitor.h" -#include "igraph_topology.h" #include "core/estack.h" #include "core/marked_queue.h" @@ -43,9 +42,9 @@ typedef igraph_error_t igraph_provan_shier_pivot_t(const igraph_t *graph, const igraph_marked_queue_int_t *S, const igraph_estack_t *T, - igraph_integer_t source, - igraph_integer_t target, - igraph_integer_t *v, + igraph_int_t source, + igraph_int_t target, + igraph_int_t *v, igraph_vector_int_t *Isv, void *arg); @@ -88,15 +87,15 @@ typedef igraph_error_t igraph_provan_shier_pivot_t(const igraph_t *graph, igraph_error_t igraph_even_tarjan_reduction(const igraph_t *graph, igraph_t *graphbar, igraph_vector_t *capacity) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); - igraph_integer_t new_no_of_nodes; - igraph_integer_t new_no_of_edges = no_of_edges * 2; + igraph_int_t new_no_of_nodes; + igraph_int_t new_no_of_edges = no_of_edges * 2; igraph_vector_int_t edges; - igraph_integer_t edgeptr = 0, capptr = 0; - igraph_integer_t i; + igraph_int_t edgeptr = 0, capptr = 0; + igraph_int_t i; IGRAPH_SAFE_MULT(no_of_nodes, 2, &new_no_of_nodes); IGRAPH_SAFE_ADD(new_no_of_edges, no_of_nodes, &new_no_of_edges); @@ -127,8 +126,8 @@ igraph_error_t igraph_even_tarjan_reduction(const igraph_t *graph, igraph_t *gra /* Two news edges for each original edge (from,to) becomes (from'',to'), (to'',from') */ for (i = 0; i < no_of_edges; i++) { - igraph_integer_t from = IGRAPH_FROM(graph, i); - igraph_integer_t to = IGRAPH_TO(graph, i); + igraph_int_t from = IGRAPH_FROM(graph, i); + igraph_int_t to = IGRAPH_TO(graph, i); VECTOR(edges)[edgeptr++] = from + no_of_nodes; VECTOR(edges)[edgeptr++] = to; VECTOR(edges)[edgeptr++] = to + no_of_nodes; @@ -155,10 +154,10 @@ static igraph_error_t igraph_i_residual_graph(const igraph_t *graph, const igraph_vector_t *flow, igraph_vector_int_t *tmp) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t i, no_new_edges = 0; - igraph_integer_t edgeptr = 0, capptr = 0; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t i, no_new_edges = 0; + igraph_int_t edgeptr = 0, capptr = 0; for (i = 0; i < no_of_edges; i++) { if (VECTOR(*flow)[i] < VECTOR(*capacity)[i]) { @@ -174,8 +173,8 @@ static igraph_error_t igraph_i_residual_graph(const igraph_t *graph, for (i = 0; i < no_of_edges; i++) { igraph_real_t c = VECTOR(*capacity)[i] - VECTOR(*flow)[i]; if (c > 0) { - igraph_integer_t from = IGRAPH_FROM(graph, i); - igraph_integer_t to = IGRAPH_TO(graph, i); + igraph_int_t from = IGRAPH_FROM(graph, i); + igraph_int_t to = IGRAPH_TO(graph, i); VECTOR(*tmp)[edgeptr++] = from; VECTOR(*tmp)[edgeptr++] = to; if (residual_capacity) { @@ -197,7 +196,7 @@ igraph_error_t igraph_residual_graph(const igraph_t *graph, const igraph_vector_t *flow) { igraph_vector_int_t tmp; - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); if (igraph_vector_size(capacity) != no_of_edges) { IGRAPH_ERROR("Invalid `capacity' vector size", IGRAPH_EINVAL); @@ -223,10 +222,10 @@ static igraph_error_t igraph_i_reverse_residual_graph(const igraph_t *graph, const igraph_vector_t *flow, igraph_vector_int_t *tmp) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t i, no_new_edges = 0; - igraph_integer_t edgeptr = 0; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t i, no_new_edges = 0; + igraph_int_t edgeptr = 0; for (i = 0; i < no_of_edges; i++) { igraph_real_t cap = capacity ? VECTOR(*capacity)[i] : 1.0; @@ -241,8 +240,8 @@ static igraph_error_t igraph_i_reverse_residual_graph(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_resize(tmp, no_new_edges * 2)); for (i = 0; i < no_of_edges; i++) { - igraph_integer_t from = IGRAPH_FROM(graph, i); - igraph_integer_t to = IGRAPH_TO(graph, i); + igraph_int_t from = IGRAPH_FROM(graph, i); + igraph_int_t to = IGRAPH_TO(graph, i); igraph_real_t cap = capacity ? VECTOR(*capacity)[i] : 1.0; if (VECTOR(*flow)[i] > 0) { VECTOR(*tmp)[edgeptr++] = from; @@ -265,7 +264,7 @@ igraph_error_t igraph_reverse_residual_graph(const igraph_t *graph, igraph_t *residual, const igraph_vector_t *flow) { igraph_vector_int_t tmp; - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); if (capacity && igraph_vector_size(capacity) != no_of_edges) { IGRAPH_ERROR("Invalid `capacity' vector size", IGRAPH_EINVAL); @@ -289,7 +288,7 @@ typedef struct igraph_i_dbucket_t { igraph_vector_int_t next; } igraph_i_dbucket_t; -static igraph_error_t igraph_i_dbucket_init(igraph_i_dbucket_t *buck, igraph_integer_t size) { +static igraph_error_t igraph_i_dbucket_init(igraph_i_dbucket_t *buck, igraph_int_t size) { IGRAPH_VECTOR_INT_INIT_FINALLY(&buck->head, size); IGRAPH_CHECK(igraph_vector_int_init(&buck->next, size)); IGRAPH_FINALLY_CLEAN(1); @@ -301,8 +300,8 @@ static void igraph_i_dbucket_destroy(igraph_i_dbucket_t *buck) { igraph_vector_int_destroy(&buck->next); } -static igraph_error_t igraph_i_dbucket_insert(igraph_i_dbucket_t *buck, igraph_integer_t bid, - igraph_integer_t elem) { +static igraph_error_t igraph_i_dbucket_insert(igraph_i_dbucket_t *buck, igraph_int_t bid, + igraph_int_t elem) { /* Note: we can do this, since elem is not in any buckets */ VECTOR(buck->next)[elem] = VECTOR(buck->head)[bid]; VECTOR(buck->head)[bid] = elem + 1; @@ -310,17 +309,17 @@ static igraph_error_t igraph_i_dbucket_insert(igraph_i_dbucket_t *buck, igraph_i } static igraph_bool_t igraph_i_dbucket_empty(const igraph_i_dbucket_t *buck, - igraph_integer_t bid) { + igraph_int_t bid) { return VECTOR(buck->head)[bid] == 0; } -static igraph_integer_t igraph_i_dbucket_delete(igraph_i_dbucket_t *buck, igraph_integer_t bid) { - igraph_integer_t elem = VECTOR(buck->head)[bid] - 1; +static igraph_int_t igraph_i_dbucket_delete(igraph_i_dbucket_t *buck, igraph_int_t bid) { + igraph_int_t elem = VECTOR(buck->head)[bid] - 1; VECTOR(buck->head)[bid] = VECTOR(buck->next)[elem]; return elem; } -static igraph_error_t igraph_i_dominator_LINK(igraph_integer_t v, igraph_integer_t w, +static igraph_error_t igraph_i_dominator_LINK(igraph_int_t v, igraph_int_t w, igraph_vector_int_t *ancestor) { VECTOR(*ancestor)[w] = v + 1; return IGRAPH_SUCCESS; @@ -328,13 +327,13 @@ static igraph_error_t igraph_i_dominator_LINK(igraph_integer_t v, igraph_integer /* TODO: don't always reallocate path */ -static igraph_error_t igraph_i_dominator_COMPRESS(igraph_integer_t v, +static igraph_error_t igraph_i_dominator_COMPRESS(igraph_int_t v, igraph_vector_int_t *ancestor, igraph_vector_int_t *label, igraph_vector_int_t *semi) { igraph_stack_int_t path; - igraph_integer_t w = v; - igraph_integer_t top, pretop; + igraph_int_t w = v; + igraph_int_t top, pretop; IGRAPH_CHECK(igraph_stack_int_init(&path, 10)); IGRAPH_FINALLY(igraph_stack_int_destroy, &path); @@ -363,7 +362,7 @@ static igraph_error_t igraph_i_dominator_COMPRESS(igraph_integer_t v, return IGRAPH_SUCCESS; } -static igraph_integer_t igraph_i_dominator_EVAL(igraph_integer_t v, +static igraph_int_t igraph_i_dominator_EVAL(igraph_int_t v, igraph_vector_int_t *ancestor, igraph_vector_int_t *label, igraph_vector_int_t *semi) { @@ -433,13 +432,13 @@ static igraph_integer_t igraph_i_dominator_EVAL(igraph_integer_t v, */ igraph_error_t igraph_dominator_tree(const igraph_t *graph, - igraph_integer_t root, + igraph_int_t root, igraph_vector_int_t *dom, igraph_t *domtree, igraph_vector_int_t *leftout, igraph_neimode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_adjlist_t succ, pred; igraph_vector_int_t parent; @@ -453,7 +452,7 @@ igraph_error_t igraph_dominator_tree(const igraph_t *graph, igraph_vector_int_t vdom, *mydom = dom; - igraph_integer_t component_size = 0; + igraph_int_t component_size = 0; if (root < 0 || root >= no_of_nodes) { IGRAPH_ERROR("Invalid root vertex ID for dominator tree.", @@ -499,17 +498,17 @@ igraph_error_t igraph_dominator_tree(const igraph_t *graph, /*dist=*/ NULL, /*in_callback=*/ NULL, /*out_callback=*/ NULL, /*extra=*/ NULL)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(vertex)[i] >= 0) { - igraph_integer_t t = VECTOR(vertex)[i]; + igraph_int_t t = VECTOR(vertex)[i]; VECTOR(semi)[t] = component_size + 1; VECTOR(vertex)[component_size] = t + 1; component_size++; } } if (leftout) { - igraph_integer_t n = no_of_nodes - component_size; - igraph_integer_t p = 0, j; + igraph_int_t n = no_of_nodes - component_size; + igraph_int_t p = 0, j; IGRAPH_CHECK(igraph_vector_int_resize(leftout, n)); for (j = 0; j < no_of_nodes && p < n; j++) { if (VECTOR(parent)[j] < -1) { @@ -520,11 +519,11 @@ igraph_error_t igraph_dominator_tree(const igraph_t *graph, /* We need to go over 'pred' because it should contain only the edges towards the target vertex. */ - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { igraph_vector_int_t *v = igraph_adjlist_get(&pred, i); - igraph_integer_t n = igraph_vector_int_size(v); - for (igraph_integer_t j = 0; j < n; ) { - igraph_integer_t v2 = VECTOR(*v)[j]; + igraph_int_t n = igraph_vector_int_size(v); + for (igraph_int_t j = 0; j < n; ) { + igraph_int_t v2 = VECTOR(*v)[j]; if (VECTOR(parent)[v2] >= -1) { j++; } else { @@ -537,13 +536,13 @@ igraph_error_t igraph_dominator_tree(const igraph_t *graph, /* Now comes the main algorithm, steps 2 & 3 */ - for (igraph_integer_t i = component_size - 1; i > 0; i--) { - igraph_integer_t w = VECTOR(vertex)[i] - 1; + for (igraph_int_t i = component_size - 1; i > 0; i--) { + igraph_int_t w = VECTOR(vertex)[i] - 1; igraph_vector_int_t *predw = igraph_adjlist_get(&pred, w); - igraph_integer_t j, n = igraph_vector_int_size(predw); + igraph_int_t j, n = igraph_vector_int_size(predw); for (j = 0; j < n; j++) { - igraph_integer_t v = VECTOR(*predw)[j]; - igraph_integer_t u = igraph_i_dominator_EVAL(v, &ancestor, &label, &semi); + igraph_int_t v = VECTOR(*predw)[j]; + igraph_int_t u = igraph_i_dominator_EVAL(v, &ancestor, &label, &semi); if (VECTOR(semi)[u] < VECTOR(semi)[w]) { VECTOR(semi)[w] = VECTOR(semi)[u]; } @@ -551,8 +550,8 @@ igraph_error_t igraph_dominator_tree(const igraph_t *graph, igraph_i_dbucket_insert(&bucket, VECTOR(vertex)[ VECTOR(semi)[w] - 1 ] - 1, w); igraph_i_dominator_LINK(VECTOR(parent)[w], w, &ancestor); while (!igraph_i_dbucket_empty(&bucket, VECTOR(parent)[w])) { - igraph_integer_t v = igraph_i_dbucket_delete(&bucket, VECTOR(parent)[w]); - igraph_integer_t u = igraph_i_dominator_EVAL(v, &ancestor, &label, &semi); + igraph_int_t v = igraph_i_dbucket_delete(&bucket, VECTOR(parent)[w]); + igraph_int_t u = igraph_i_dominator_EVAL(v, &ancestor, &label, &semi); VECTOR(*mydom)[v] = VECTOR(semi)[u] < VECTOR(semi)[v] ? u : VECTOR(parent)[w]; } @@ -560,8 +559,8 @@ igraph_error_t igraph_dominator_tree(const igraph_t *graph, /* Finally, step 4 */ - for (igraph_integer_t i = 1; i < component_size; i++) { - igraph_integer_t w = VECTOR(vertex)[i] - 1; + for (igraph_int_t i = 1; i < component_size; i++) { + igraph_int_t w = VECTOR(vertex)[i] - 1; if (VECTOR(*mydom)[w] != VECTOR(vertex)[VECTOR(semi)[w] - 1] - 1) { VECTOR(*mydom)[w] = VECTOR(*mydom)[VECTOR(*mydom)[w]]; } @@ -580,9 +579,9 @@ igraph_error_t igraph_dominator_tree(const igraph_t *graph, if (domtree) { igraph_vector_int_t edges; - igraph_integer_t ptr = 0; + igraph_int_t ptr = 0; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, component_size * 2 - 2); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (i != root && VECTOR(*mydom)[i] >= 0) { if (mode == IGRAPH_OUT) { VECTOR(edges)[ptr++] = VECTOR(*mydom)[i]; @@ -598,9 +597,7 @@ igraph_error_t igraph_dominator_tree(const igraph_t *graph, igraph_vector_int_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); - IGRAPH_I_ATTRIBUTE_DESTROY(domtree); - IGRAPH_I_ATTRIBUTE_COPY(domtree, graph, - /*graph=*/ true, /*vertex=*/ true, /*edge=*/ false); + IGRAPH_CHECK(igraph_i_attribute_copy(domtree, graph, true, true, /*edges=*/ false)); } if (!dom) { @@ -615,14 +612,14 @@ typedef struct igraph_i_all_st_cuts_minimal_dfs_data_t { igraph_stack_int_t *stack; igraph_bitset_t *nomark; const igraph_bitset_t *GammaX; - igraph_integer_t root; + igraph_int_t root; const igraph_vector_int_t *map; } igraph_i_all_st_cuts_minimal_dfs_data_t; static igraph_error_t igraph_i_all_st_cuts_minimal_dfs_incb( const igraph_t *graph, - igraph_integer_t vid, - igraph_integer_t dist, + igraph_int_t vid, + igraph_int_t dist, void *extra) { igraph_i_all_st_cuts_minimal_dfs_data_t *data = extra; @@ -630,13 +627,13 @@ static igraph_error_t igraph_i_all_st_cuts_minimal_dfs_incb( igraph_bitset_t *nomark = data->nomark; const igraph_bitset_t *GammaX = data->GammaX; const igraph_vector_int_t *map = data->map; - igraph_integer_t realvid = VECTOR(*map)[vid]; + igraph_int_t realvid = VECTOR(*map)[vid]; IGRAPH_UNUSED(graph); IGRAPH_UNUSED(dist); if (IGRAPH_BIT_TEST(*GammaX, realvid)) { if (!igraph_stack_int_empty(stack)) { - igraph_integer_t top = igraph_stack_int_top(stack); + igraph_int_t top = igraph_stack_int_top(stack); IGRAPH_BIT_SET(*nomark, top); /* we just found a smaller one */ } IGRAPH_CHECK(igraph_stack_int_push(stack, realvid)); @@ -647,13 +644,13 @@ static igraph_error_t igraph_i_all_st_cuts_minimal_dfs_incb( static igraph_error_t igraph_i_all_st_cuts_minimal_dfs_outcb( const igraph_t *graph, - igraph_integer_t vid, - igraph_integer_t dist, + igraph_int_t vid, + igraph_int_t dist, void *extra) { igraph_i_all_st_cuts_minimal_dfs_data_t *data = extra; igraph_stack_int_t *stack = data->stack; const igraph_vector_int_t *map = data->map; - igraph_integer_t realvid = VECTOR(*map)[vid]; + igraph_int_t realvid = VECTOR(*map)[vid]; IGRAPH_UNUSED(graph); IGRAPH_UNUSED(dist); @@ -667,17 +664,17 @@ static igraph_error_t igraph_i_all_st_cuts_minimal_dfs_outcb( static igraph_error_t igraph_i_all_st_cuts_minimal(const igraph_t *graph, const igraph_t *domtree, - igraph_integer_t root, + igraph_int_t root, const igraph_marked_queue_int_t *X, const igraph_bitset_t *GammaX, const igraph_vector_int_t *invmap, igraph_vector_int_t *minimal) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_stack_int_t stack; igraph_bitset_t nomark; igraph_i_all_st_cuts_minimal_dfs_data_t data; - igraph_integer_t i; + igraph_int_t i; IGRAPH_UNUSED(X); @@ -724,24 +721,24 @@ static igraph_error_t igraph_i_all_st_cuts_minimal(const igraph_t *graph, /* not 'static' because used in igraph_all_st_cuts.c test program */ igraph_error_t igraph_i_all_st_cuts_pivot( const igraph_t *graph, const igraph_marked_queue_int_t *S, - const igraph_estack_t *T, igraph_integer_t source, igraph_integer_t target, - igraph_integer_t *v, igraph_vector_int_t *Isv, void *arg + const igraph_estack_t *T, igraph_int_t source, igraph_int_t target, + igraph_int_t *v, igraph_vector_int_t *Isv, void *arg ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_t Sbar; igraph_vector_int_t Sbar_map, Sbar_invmap; igraph_vector_int_t keep; igraph_t domtree; igraph_vector_int_t leftout; - igraph_integer_t i, nomin, n; - igraph_integer_t root; + igraph_int_t i, nomin, n; + igraph_int_t root; igraph_vector_int_t M; igraph_bitset_t GammaS; igraph_vector_int_t Nuv; igraph_vector_int_t Isv_min; igraph_vector_int_t GammaS_vec; - igraph_integer_t Sbar_size; + igraph_int_t Sbar_size; IGRAPH_UNUSED(arg); @@ -766,7 +763,7 @@ igraph_error_t igraph_i_all_st_cuts_pivot( IGRAPH_FINALLY_CLEAN(1); IGRAPH_FINALLY(igraph_destroy, &Sbar); - root = VECTOR(Sbar_map)[target] - 1; + root = VECTOR(Sbar_map)[target]; /* -------------------------------------------------------------*/ /* Construct the dominator tree of Sbar */ @@ -785,18 +782,19 @@ igraph_error_t igraph_i_all_st_cuts_pivot( /* TODO: use the adjacency list, instead of neighbors() */ IGRAPH_BITSET_INIT_FINALLY(&GammaS, no_of_nodes); if (igraph_marked_queue_int_size(S) == 0) { - IGRAPH_BIT_SET(GammaS, VECTOR(Sbar_map)[source] - 1); + IGRAPH_BIT_SET(GammaS, VECTOR(Sbar_map)[source]); } else { for (i = 0; i < no_of_nodes; i++) { if (igraph_marked_queue_int_iselement(S, i)) { igraph_vector_int_t neis; - igraph_integer_t j; + igraph_int_t j; IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, - IGRAPH_OUT)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, i, IGRAPH_OUT, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); n = igraph_vector_int_size(&neis); for (j = 0; j < n; j++) { - igraph_integer_t nei = VECTOR(neis)[j]; + igraph_int_t nei = VECTOR(neis)[j]; if (!igraph_marked_queue_int_iselement(S, nei)) { IGRAPH_BIT_SET(GammaS, nei); } @@ -840,8 +838,8 @@ igraph_error_t igraph_i_all_st_cuts_pivot( Nu(v) contains all vertices that are dominated by v, for every v, this is a subtree of the dominator tree, rooted at v. The different subtrees are disjoint. */ - igraph_integer_t min = VECTOR(Sbar_map)[ VECTOR(M)[i] ] - 1; - igraph_integer_t nuvsize, isvlen, j; + igraph_int_t min = VECTOR(Sbar_map)[ VECTOR(M)[i] ]; + igraph_int_t nuvsize, isvlen, j; IGRAPH_CHECK(igraph_dfs(&domtree, min, IGRAPH_IN, /*unreachable=*/ false, /*order=*/ &Nuv, /*order_out=*/ NULL, /*parents=*/ NULL, /*dist=*/ NULL, @@ -849,7 +847,7 @@ igraph_error_t igraph_i_all_st_cuts_pivot( /*extra=*/ NULL)); /* Remove the negative values from the end of the vector */ for (nuvsize = 0; nuvsize < Sbar_size; nuvsize++) { - igraph_integer_t t = VECTOR(Nuv)[nuvsize]; + igraph_int_t t = VECTOR(Nuv)[nuvsize]; if (t >= 0) { VECTOR(Nuv)[nuvsize] = VECTOR(Sbar_invmap)[t]; } else { @@ -880,7 +878,7 @@ igraph_error_t igraph_i_all_st_cuts_pivot( such a v is found, compute Isv={x|v[Nu(v) U K]x} and return v and Isv; otherwise return Isv={}. */ for (j = 0; j < isvlen; j++) { - igraph_integer_t u = VECTOR(Isv_min)[j]; + igraph_int_t u = VECTOR(Isv_min)[j]; if (igraph_estack_iselement(T, u) || u == target) { break; } @@ -929,14 +927,14 @@ igraph_error_t igraph_i_all_st_cuts_pivot( static igraph_error_t igraph_i_provan_shier_list_recursive( const igraph_t *graph, igraph_marked_queue_int_t *S, - igraph_estack_t *T, igraph_integer_t source, igraph_integer_t target, + igraph_estack_t *T, igraph_int_t source, igraph_int_t target, igraph_vector_int_list_t *result, igraph_provan_shier_pivot_t *pivot, igraph_vector_int_t *Isv, void *pivot_arg ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t v = 0; - igraph_integer_t i, n; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t v = 0; + igraph_int_t i, n; pivot(graph, S, T, source, target, &v, Isv, pivot_arg); @@ -981,7 +979,7 @@ static igraph_error_t igraph_i_provan_shier_list_recursive( static igraph_error_t igraph_provan_shier_list( const igraph_t *graph, igraph_marked_queue_int_t *S, - igraph_estack_t *T, igraph_integer_t source, igraph_integer_t target, + igraph_estack_t *T, igraph_int_t source, igraph_int_t target, igraph_vector_int_list_t *result, igraph_provan_shier_pivot_t *pivot, void *pivot_arg ) { @@ -1032,8 +1030,8 @@ static igraph_error_t igraph_provan_shier_list( igraph_error_t igraph_all_st_cuts(const igraph_t *graph, igraph_vector_int_list_t *cuts, igraph_vector_int_list_t *partition1s, - igraph_integer_t source, - igraph_integer_t target) { + igraph_int_t source, + igraph_int_t target) { /* S is a special stack, in which elements are pushed in batches. It is then possible to remove the whole batch in one step. @@ -1042,13 +1040,13 @@ igraph_error_t igraph_all_st_cuts(const igraph_t *graph, Every element is included at most once. */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_marked_queue_int_t S; igraph_estack_t T; igraph_vector_int_list_t *mypartition1s = partition1s, vpartition1s; igraph_vector_int_t cut; - igraph_integer_t i, nocuts; + igraph_int_t i, nocuts; if (!igraph_is_directed(graph)) { IGRAPH_ERROR("Listing all s-t cuts only implemented for " @@ -1085,19 +1083,19 @@ igraph_error_t igraph_all_st_cuts(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_list_reserve(cuts, nocuts)); for (i = 0; i < nocuts; i++) { igraph_vector_int_t *part = igraph_vector_int_list_get_ptr(mypartition1s, i); - igraph_integer_t cutsize = 0; - igraph_integer_t j, partlen = igraph_vector_int_size(part); + igraph_int_t cutsize = 0; + igraph_int_t j, partlen = igraph_vector_int_size(part); /* Mark elements */ for (j = 0; j < partlen; j++) { - igraph_integer_t v = VECTOR(*part)[j]; + igraph_int_t v = VECTOR(*part)[j]; VECTOR(inS)[v] = i + 1; } /* Check how many edges */ for (j = 0; j < no_of_edges; j++) { - igraph_integer_t from = IGRAPH_FROM(graph, j); - igraph_integer_t to = IGRAPH_TO(graph, j); - igraph_integer_t pfrom = VECTOR(inS)[from]; - igraph_integer_t pto = VECTOR(inS)[to]; + igraph_int_t from = IGRAPH_FROM(graph, j); + igraph_int_t to = IGRAPH_TO(graph, j); + igraph_int_t pfrom = VECTOR(inS)[from]; + igraph_int_t pto = VECTOR(inS)[to]; if (pfrom == i + 1 && pto != i + 1) { cutsize++; } @@ -1106,10 +1104,10 @@ igraph_error_t igraph_all_st_cuts(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_resize(&cut, cutsize)); cutsize = 0; for (j = 0; j < no_of_edges; j++) { - igraph_integer_t from = IGRAPH_FROM(graph, j); - igraph_integer_t to = IGRAPH_TO(graph, j); - igraph_integer_t pfrom = VECTOR(inS)[from]; - igraph_integer_t pto = VECTOR(inS)[to]; + igraph_int_t from = IGRAPH_FROM(graph, j); + igraph_int_t to = IGRAPH_TO(graph, j); + igraph_int_t pfrom = VECTOR(inS)[from]; + igraph_int_t pto = VECTOR(inS)[to]; if ((pfrom == i + 1 && pto != i + 1)) { VECTOR(cut)[cutsize++] = j; } @@ -1151,8 +1149,8 @@ static igraph_error_t igraph_i_all_st_mincuts_minimal(const igraph_t *residual, const igraph_bitset_t *active, igraph_vector_int_t *minimal) { - igraph_integer_t no_of_nodes = igraph_vcount(residual); - igraph_integer_t i; + igraph_int_t no_of_nodes = igraph_vcount(residual); + igraph_int_t i; igraph_vector_int_t neis; igraph_bitset_t connected_to_minimal; @@ -1170,17 +1168,19 @@ static igraph_error_t igraph_i_all_st_mincuts_minimal(const igraph_t *residual, * active or not. */ for (i = 0; i < no_of_nodes; i++) { - igraph_integer_t j, n; - IGRAPH_CHECK(igraph_neighbors(residual, &neis, i, IGRAPH_IN)); + igraph_int_t j, n; + IGRAPH_CHECK(igraph_neighbors( + residual, &neis, i, IGRAPH_IN, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); n = igraph_vector_int_size(&neis); // Only consider nodes that are not in S. if (!igraph_marked_queue_int_iselement(S, i)) { for (j = 0; j < n; j++) { - igraph_integer_t nei = VECTOR(neis)[j]; + igraph_int_t nei = VECTOR(neis)[j]; /* If connected to node that is connected to node that is minimal, - * this node is also connected to node that is minimal. - */ + * this node is also connected to node that is minimal. + */ if (IGRAPH_BIT_TEST(connected_to_minimal, nei)) { IGRAPH_BIT_SET(connected_to_minimal, i); break; @@ -1188,15 +1188,15 @@ static igraph_error_t igraph_i_all_st_mincuts_minimal(const igraph_t *residual, } /* If this node is not connected to node that is minimal, and this node - * is minimal and active itself, set it as a minimal node. - */ + * is minimal and active itself, set it as a minimal node. + */ if (!IGRAPH_BIT_TEST(connected_to_minimal, i) && IGRAPH_BIT_TEST(*active, i)) { - igraph_vector_int_push_back(minimal, i); + IGRAPH_CHECK(igraph_vector_int_push_back(minimal, i)); /* Also mark this node as connected to minimal, to make sure that - * any descendants will be marked as being connected to a minimal - * node. - */ + * any descendants will be marked as being connected to a minimal + * node. + */ IGRAPH_BIT_SET(connected_to_minimal, i); } } @@ -1216,20 +1216,20 @@ typedef struct igraph_i_all_st_mincuts_data_t { static igraph_error_t igraph_i_all_st_mincuts_pivot(const igraph_t *graph, const igraph_marked_queue_int_t *S, const igraph_estack_t *T, - igraph_integer_t source, - igraph_integer_t target, - igraph_integer_t *v, + igraph_int_t source, + igraph_int_t target, + igraph_int_t *v, igraph_vector_int_t *Isv, void *arg) { igraph_i_all_st_mincuts_data_t *data = arg; const igraph_bitset_t *active = data->active; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t i, j; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i, j; igraph_vector_int_t keep; igraph_vector_int_t M; - igraph_integer_t nomin; + igraph_int_t nomin; IGRAPH_UNUSED(source); IGRAPH_UNUSED(target); @@ -1255,7 +1255,7 @@ static igraph_error_t igraph_i_all_st_mincuts_pivot(const igraph_t *graph, igraph_vector_int_clear(Isv); nomin = igraph_vector_int_size(&M); for (i = 0; i < nomin; i++) { - igraph_integer_t min = VECTOR(M)[i]; + igraph_int_t min = VECTOR(M)[i]; if (min != target) if (!igraph_estack_iselement(T, min)) { break; @@ -1275,7 +1275,7 @@ static igraph_error_t igraph_i_all_st_mincuts_pivot(const igraph_t *graph, /*succ=*/ NULL, /*dist=*/ NULL, /*callback=*/ NULL, /*extra=*/ NULL)); for (j = 0; j < no_of_nodes; j++) { - igraph_integer_t u = VECTOR(Isv_min)[j]; + igraph_int_t u = VECTOR(Isv_min)[j]; if (u < 0) { break; } @@ -1335,23 +1335,23 @@ static igraph_error_t igraph_i_all_st_mincuts_pivot(const igraph_t *graph, igraph_error_t igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value, igraph_vector_int_list_t *cuts, igraph_vector_int_list_t *partition1s, - igraph_integer_t source, - igraph_integer_t target, + igraph_int_t source, + igraph_int_t target, const igraph_vector_t *capacity) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_t flow; igraph_t residual; igraph_vector_int_t NtoL; igraph_vector_int_t cut; - igraph_integer_t newsource, newtarget; + igraph_int_t newsource, newtarget; igraph_marked_queue_int_t S; igraph_estack_t T; igraph_i_all_st_mincuts_data_t pivot_data; igraph_bitset_t VE1bool; - igraph_integer_t i, nocuts; - igraph_integer_t proj_nodes; + igraph_int_t i, nocuts; + igraph_int_t proj_nodes; igraph_vector_int_t revmap_ptr, revmap_next; igraph_vector_int_list_t closedsets; igraph_vector_int_list_t *mypartition1s = partition1s, vpartition1s; @@ -1408,7 +1408,7 @@ igraph_error_t igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value IGRAPH_CHECK(igraph_simplify(&residual, /*remove_multiple=*/ true, /*remove_loops=*/ true, /*edge_comb=*/ NULL)); /* We relabel the residual graph so that it is in topological sort order. */ - igraph_integer_t no_of_nodes_residual = igraph_vcount(&residual); + igraph_int_t no_of_nodes_residual = igraph_vcount(&residual); igraph_vector_int_t order; igraph_t tmpgraph; IGRAPH_VECTOR_INT_INIT_FINALLY(&order, no_of_nodes_residual); @@ -1429,7 +1429,7 @@ igraph_error_t igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value /* Permute vertices and replace residual with tmpgraph that is topologically * sorted. */ - IGRAPH_CHECK(igraph_permute_vertices(&residual, &tmpgraph, &inv_order)); + IGRAPH_CHECK(igraph_permute_vertices(&residual, &tmpgraph, &order)); igraph_destroy(&residual); // We first free memory from original residual graph residual = tmpgraph; // Then we replace it by allocated memory from tmpgraph @@ -1448,10 +1448,10 @@ igraph_error_t igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value IGRAPH_BITSET_INIT_FINALLY(&VE1bool, proj_nodes); for (i = 0; i < no_of_edges; i++) { if (VECTOR(flow)[i] > 0) { - igraph_integer_t from = IGRAPH_FROM(graph, i); - igraph_integer_t to = IGRAPH_TO(graph, i); - igraph_integer_t pfrom = VECTOR(NtoL)[from]; - igraph_integer_t pto = VECTOR(NtoL)[to]; + igraph_int_t from = IGRAPH_FROM(graph, i); + igraph_int_t to = IGRAPH_TO(graph, i); + igraph_int_t pfrom = VECTOR(NtoL)[from]; + igraph_int_t pto = VECTOR(NtoL)[to]; if (!IGRAPH_BIT_TEST(VE1bool, pfrom)) { IGRAPH_BIT_SET(VE1bool, pfrom); } @@ -1490,7 +1490,7 @@ igraph_error_t igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value IGRAPH_VECTOR_INT_INIT_FINALLY(&revmap_ptr, igraph_vcount(&residual)); IGRAPH_VECTOR_INT_INIT_FINALLY(&revmap_next, no_of_nodes); for (i = 0; i < no_of_nodes; i++) { - igraph_integer_t id = VECTOR(NtoL)[i]; + igraph_int_t id = VECTOR(NtoL)[i]; VECTOR(revmap_next)[i] = VECTOR(revmap_ptr)[id]; VECTOR(revmap_ptr)[id] = i + 1; } @@ -1501,12 +1501,12 @@ igraph_error_t igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value IGRAPH_CHECK(igraph_vector_int_list_reserve(mypartition1s, nocuts)); for (i = 0; i < nocuts; i++) { igraph_vector_int_t *supercut = igraph_vector_int_list_get_ptr(&closedsets, i); - igraph_integer_t j, supercutsize = igraph_vector_int_size(supercut); + igraph_int_t j, supercutsize = igraph_vector_int_size(supercut); igraph_vector_int_clear(&cut); for (j = 0; j < supercutsize; j++) { - igraph_integer_t vtx = VECTOR(*supercut)[j]; - igraph_integer_t ovtx = VECTOR(revmap_ptr)[vtx]; + igraph_int_t vtx = VECTOR(*supercut)[j]; + igraph_int_t ovtx = VECTOR(revmap_ptr)[vtx]; while (ovtx != 0) { ovtx--; IGRAPH_CHECK(igraph_vector_int_push_back(&cut, ovtx)); @@ -1533,17 +1533,17 @@ igraph_error_t igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value for (i = 0; i < nocuts; i++) { igraph_vector_int_t *part = igraph_vector_int_list_get_ptr(mypartition1s, i); - igraph_integer_t j, n = igraph_vector_int_size(part); + igraph_int_t j, n = igraph_vector_int_size(part); igraph_vector_int_clear(&cut); for (j = 0; j < n; j++) { - igraph_integer_t vtx = VECTOR(*part)[j]; + igraph_int_t vtx = VECTOR(*part)[j]; VECTOR(memb)[vtx] = i + 1; } for (j = 0; j < no_of_edges; j++) { if (VECTOR(flow)[j] > 0) { - igraph_integer_t from = IGRAPH_FROM(graph, j); - igraph_integer_t to = IGRAPH_TO(graph, j); + igraph_int_t from = IGRAPH_FROM(graph, j); + igraph_int_t to = IGRAPH_TO(graph, j); if (VECTOR(memb)[from] == i + 1 && VECTOR(memb)[to] != i + 1) { IGRAPH_CHECK(igraph_vector_int_push_back(&cut, j)); } diff --git a/src/vendor/cigraph/src/games/barabasi.c b/src/vendor/cigraph/src/games/barabasi.c index 9ef883b2320..49e91292d24 100644 --- a/src/vendor/cigraph/src/games/barabasi.c +++ b/src/vendor/cigraph/src/games/barabasi.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -39,17 +37,17 @@ static igraph_real_t attraction(igraph_real_t degree, igraph_real_t power, igrap return ( power == 0 ? 1.0 : pow(degree, power) ) + A; } -static igraph_error_t igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer_t n, - igraph_integer_t m, +static igraph_error_t igraph_i_barabasi_game_bag(igraph_t *graph, igraph_int_t n, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_bool_t directed, const igraph_t *start_from); static igraph_error_t igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph, - igraph_integer_t n, + igraph_int_t n, igraph_real_t power, - igraph_integer_t m, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t A, @@ -57,30 +55,30 @@ static igraph_error_t igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph, const igraph_t *start_from); static igraph_error_t igraph_i_barabasi_game_psumtree(igraph_t *graph, - igraph_integer_t n, + igraph_int_t n, igraph_real_t power, - igraph_integer_t m, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t A, igraph_bool_t directed, const igraph_t *start_from); -static igraph_error_t igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer_t n, - igraph_integer_t m, +static igraph_error_t igraph_i_barabasi_game_bag(igraph_t *graph, igraph_int_t n, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_bool_t directed, const igraph_t *start_from) { - igraph_integer_t no_of_nodes = n; - igraph_integer_t no_of_neighbors = m; - igraph_integer_t *bag; - igraph_integer_t bagp = 0; + igraph_int_t no_of_nodes = n; + igraph_int_t no_of_neighbors = m; + igraph_int_t *bag; + igraph_int_t bagp = 0; igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t resp; - igraph_integer_t i, j, k; - igraph_integer_t bagsize, start_nodes, start_edges, new_edges, no_of_edges; + igraph_int_t resp; + igraph_int_t i, j, k; + igraph_int_t bagsize, start_nodes, start_edges, new_edges, no_of_edges; if (!directed) { outpref = true; @@ -112,7 +110,7 @@ static igraph_error_t igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges * 2); - bag = IGRAPH_CALLOC(bagsize, igraph_integer_t); + bag = IGRAPH_CALLOC(bagsize, igraph_int_t); if (bag == 0) { IGRAPH_ERROR("barabasi_game failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } @@ -121,14 +119,14 @@ static igraph_error_t igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer /* The first node(s) in the bag */ if (start_from) { igraph_vector_int_t deg; - igraph_integer_t ii, jj, sn = igraph_vcount(start_from); + igraph_int_t ii, jj, sn = igraph_vcount(start_from); igraph_neimode_t mm = outpref ? IGRAPH_ALL : IGRAPH_IN; IGRAPH_VECTOR_INT_INIT_FINALLY(°, sn); IGRAPH_CHECK(igraph_degree(start_from, °, igraph_vss_all(), mm, IGRAPH_LOOPS)); for (ii = 0; ii < sn; ii++) { - igraph_integer_t d = VECTOR(deg)[ii]; + igraph_int_t d = VECTOR(deg)[ii]; for (jj = 0; jj <= d; jj++) { bag[bagp++] = ii; } @@ -146,8 +144,6 @@ static igraph_error_t igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer IGRAPH_CHECK(igraph_vector_int_resize(&edges, no_of_edges * 2)); } - RNG_BEGIN(); - /* and the others */ for (i = (start_from ? start_nodes : 1), k = (start_from ? 0 : 1); @@ -160,7 +156,7 @@ static igraph_error_t igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer no_of_neighbors = VECTOR(*outseq)[k]; } for (j = 0; j < no_of_neighbors; j++) { - igraph_integer_t to = bag[RNG_INTEGER(0, bagp - 1)]; + igraph_int_t to = bag[RNG_INTEGER(0, bagp - 1)]; VECTOR(edges)[resp++] = i; VECTOR(edges)[resp++] = to; } @@ -174,8 +170,6 @@ static igraph_error_t igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer } } - RNG_END(); - IGRAPH_FREE(bag); IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed)); igraph_vector_int_destroy(&edges); @@ -185,23 +179,23 @@ static igraph_error_t igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer } static igraph_error_t igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph, - igraph_integer_t n, + igraph_int_t n, igraph_real_t power, - igraph_integer_t m, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t A, igraph_bool_t directed, const igraph_t *start_from) { - igraph_integer_t no_of_nodes = n; - igraph_integer_t no_of_neighbors = m; + igraph_int_t no_of_nodes = n; + igraph_int_t no_of_neighbors = m; igraph_vector_int_t edges; - igraph_integer_t i, j, k; + igraph_int_t i, j, k; igraph_psumtree_t sumtree; - igraph_integer_t edgeptr = 0; + igraph_int_t edgeptr = 0; igraph_vector_int_t degree; - igraph_integer_t start_nodes, start_edges, new_edges, no_of_edges; + igraph_int_t start_nodes, start_edges, new_edges, no_of_edges; if (!directed) { outpref = true; @@ -233,7 +227,7 @@ static igraph_error_t igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph, /* First node(s): */ if (start_from) { - igraph_integer_t ii, sn = igraph_vcount(start_from); + igraph_int_t ii, sn = igraph_vcount(start_from); igraph_neimode_t mm = outpref ? IGRAPH_ALL : IGRAPH_IN; IGRAPH_CHECK(igraph_degree(start_from, °ree, igraph_vss_all(), mm, IGRAPH_LOOPS)); @@ -253,13 +247,11 @@ static igraph_error_t igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_resize(&edges, no_of_edges * 2)); } - RNG_BEGIN(); - /* And the rest: */ for (i = (start_from ? start_nodes : 1), k = (start_from ? 0 : 1); i < no_of_nodes; i++, k++) { igraph_real_t sum = igraph_psumtree_sum(&sumtree); - igraph_integer_t to; + igraph_int_t to; IGRAPH_ALLOW_INTERRUPTION(); @@ -280,7 +272,7 @@ static igraph_error_t igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph, } /* update probabilities */ for (j = 0; j < no_of_neighbors; j++) { - igraph_integer_t nn = VECTOR(edges)[edgeptr - 2 * j - 1]; + igraph_int_t nn = VECTOR(edges)[edgeptr - 2 * j - 1]; IGRAPH_CHECK(igraph_psumtree_update(&sumtree, nn, attraction(VECTOR(degree)[nn], power, A))); } if (outpref) { @@ -291,8 +283,6 @@ static igraph_error_t igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph, } } - RNG_END(); - igraph_psumtree_destroy(&sumtree); igraph_vector_int_destroy(°ree); IGRAPH_FINALLY_CLEAN(2); @@ -305,23 +295,23 @@ static igraph_error_t igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph, } static igraph_error_t igraph_i_barabasi_game_psumtree(igraph_t *graph, - igraph_integer_t n, + igraph_int_t n, igraph_real_t power, - igraph_integer_t m, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t A, igraph_bool_t directed, const igraph_t *start_from) { - igraph_integer_t no_of_nodes = n; - igraph_integer_t no_of_neighbors = m; + igraph_int_t no_of_nodes = n; + igraph_int_t no_of_neighbors = m; igraph_vector_int_t edges; - igraph_integer_t i, j, k; + igraph_int_t i, j, k; igraph_psumtree_t sumtree; - igraph_integer_t edgeptr = 0; + igraph_int_t edgeptr = 0; igraph_vector_int_t degree; - igraph_integer_t start_nodes, start_edges, new_edges, no_of_edges; + igraph_int_t start_nodes, start_edges, new_edges, no_of_edges; if (!directed) { outpref = true; @@ -352,11 +342,9 @@ static igraph_error_t igraph_i_barabasi_game_psumtree(igraph_t *graph, IGRAPH_FINALLY(igraph_psumtree_destroy, &sumtree); IGRAPH_VECTOR_INT_INIT_FINALLY(°ree, no_of_nodes); - RNG_BEGIN(); - /* First node(s): */ if (start_from) { - igraph_integer_t ii, sn = igraph_vcount(start_from); + igraph_int_t ii, sn = igraph_vcount(start_from); igraph_neimode_t mm = outpref ? IGRAPH_ALL : IGRAPH_IN; IGRAPH_CHECK(igraph_degree(start_from, °ree, igraph_vss_all(), mm, IGRAPH_LOOPS)); @@ -379,7 +367,7 @@ static igraph_error_t igraph_i_barabasi_game_psumtree(igraph_t *graph, for (i = (start_from ? start_nodes : 1), k = (start_from ? 0 : 1); i < no_of_nodes; i++, k++) { igraph_real_t sum; - igraph_integer_t to; + igraph_int_t to; IGRAPH_ALLOW_INTERRUPTION(); @@ -413,7 +401,7 @@ static igraph_error_t igraph_i_barabasi_game_psumtree(igraph_t *graph, } /* update probabilities */ for (j = 0; j < no_of_neighbors; j++) { - igraph_integer_t nn = VECTOR(edges)[edgeptr - 2 * j - 1]; + igraph_int_t nn = VECTOR(edges)[edgeptr - 2 * j - 1]; IGRAPH_CHECK(igraph_psumtree_update(&sumtree, nn, attraction(VECTOR(degree)[nn], power, A))); } } @@ -425,8 +413,6 @@ static igraph_error_t igraph_i_barabasi_game_psumtree(igraph_t *graph, } } - RNG_END(); - igraph_psumtree_destroy(&sumtree); igraph_vector_int_destroy(°ree); IGRAPH_FINALLY_CLEAN(2); @@ -482,7 +468,7 @@ static igraph_error_t igraph_i_barabasi_game_psumtree(igraph_t *graph, * \param m The number of outgoing edges generated for each * vertex. Only used when \p outseq is \c NULL. * \param outseq Gives the (out-)degrees of the vertices. If this is - * constant, this can be a \c NULL pointer or an empty vector. + * constant, this can be a \c NULL pointer. * In this case \p m contains the constant out-degree. * The very first vertex has by definition no outgoing edges, * so the first number in this vector is ignored. @@ -534,9 +520,9 @@ static igraph_error_t igraph_i_barabasi_game_psumtree(igraph_t *graph, * \example examples/simple/igraph_barabasi_game.c * \example examples/simple/igraph_barabasi_game2.c */ -igraph_error_t igraph_barabasi_game(igraph_t *graph, igraph_integer_t n, +igraph_error_t igraph_barabasi_game(igraph_t *graph, igraph_int_t n, igraph_real_t power, - igraph_integer_t m, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t A, @@ -544,13 +530,10 @@ igraph_error_t igraph_barabasi_game(igraph_t *graph, igraph_integer_t n, igraph_barabasi_algorithm_t algo, const igraph_t *start_from) { - igraph_integer_t start_nodes = start_from ? igraph_vcount(start_from) : 0; - igraph_integer_t newn = start_from ? n - start_nodes : n; + igraph_int_t start_nodes = start_from ? igraph_vcount(start_from) : 0; + igraph_int_t newn = start_from ? n - start_nodes : n; - /* Fix obscure parameterizations */ - if (outseq && igraph_vector_int_empty(outseq)) { - outseq = NULL; - } + /* In undirected graphs, always consider the total degree. */ if (!directed) { outpref = true; } @@ -570,7 +553,7 @@ igraph_error_t igraph_barabasi_game(igraph_t *graph, igraph_integer_t n, if (!outseq && m < 0) { IGRAPH_ERROR("Number of edges added per step must not be negative.", IGRAPH_EINVAL); } - if (outseq && igraph_vector_int_min(outseq) < 0) { + if (outseq && newn > 0 && igraph_vector_int_min(outseq) < 0) { IGRAPH_ERROR("Negative out-degree in sequence.", IGRAPH_EINVAL); } if (!outpref && A <= 0) { @@ -683,37 +666,37 @@ static igraph_real_t attraction_aging( * of vertices, |E| the number of edges. */ igraph_error_t igraph_barabasi_aging_game(igraph_t *graph, - igraph_integer_t nodes, - igraph_integer_t m, + igraph_int_t nodes, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t pa_exp, igraph_real_t aging_exp, - igraph_integer_t aging_bins, + igraph_int_t aging_bins, igraph_real_t zero_deg_appeal, igraph_real_t zero_age_appeal, igraph_real_t deg_coef, igraph_real_t age_coef, igraph_bool_t directed) { - igraph_integer_t no_of_nodes = nodes; - igraph_integer_t no_of_neighbors = m; - igraph_integer_t binwidth; - igraph_integer_t no_of_edges; + igraph_int_t no_of_nodes = nodes; + igraph_int_t no_of_neighbors = m; + igraph_int_t binwidth; + igraph_int_t no_of_edges; igraph_vector_int_t edges; - igraph_integer_t i, j, k; + igraph_int_t i, j, k; igraph_psumtree_t sumtree; - igraph_integer_t edgeptr = 0; + igraph_int_t edgeptr = 0; igraph_vector_int_t degree; if (no_of_nodes < 0) { IGRAPH_ERRORF("Number of nodes must not be negative, got %" IGRAPH_PRId ".", IGRAPH_EINVAL, no_of_nodes); } - if (outseq != 0 && igraph_vector_int_size(outseq) != 0 && igraph_vector_int_size(outseq) != no_of_nodes) { + if (outseq && igraph_vector_int_size(outseq) != no_of_nodes) { IGRAPH_ERRORF("The length of the out-degree sequence (%" IGRAPH_PRId ") does not agree with the number of nodes (%" IGRAPH_PRId ").", IGRAPH_EINVAL, igraph_vector_int_size(outseq), no_of_nodes); } - if ( (outseq == 0 || igraph_vector_int_size(outseq) == 0) && m < 0) { + if (!outseq && m < 0) { IGRAPH_ERRORF("The number of edges per time step must not be negative, got %" IGRAPH_PRId ".", IGRAPH_EINVAL, m); @@ -745,13 +728,16 @@ igraph_error_t igraph_barabasi_aging_game(igraph_t *graph, zero_age_appeal); } + /* This effectively also hanbdles an outseq size of 0. + * From here on we assume that outseq has a size of at least 1. */ if (no_of_nodes == 0) { - return igraph_empty(graph, 0, directed); + IGRAPH_CHECK(igraph_empty(graph, 0, directed)); + return IGRAPH_SUCCESS; } binwidth = no_of_nodes / aging_bins + 1; - if (outseq == 0 || igraph_vector_int_size(outseq) == 0) { + if (!outseq) { no_of_neighbors = m; IGRAPH_SAFE_MULT(no_of_nodes - 1, no_of_neighbors, &no_of_edges); } else { @@ -768,8 +754,6 @@ igraph_error_t igraph_barabasi_aging_game(igraph_t *graph, IGRAPH_FINALLY(igraph_psumtree_destroy, &sumtree); IGRAPH_VECTOR_INT_INIT_FINALLY(°ree, no_of_nodes); - RNG_BEGIN(); - /* First node: */ /* Any weight may be used for the first node. In the first step, it will be connected to * with certainty, after which its weight will be set appropriately. */ @@ -778,11 +762,11 @@ igraph_error_t igraph_barabasi_aging_game(igraph_t *graph, /* And the rest: */ for (i = 1; i < no_of_nodes; i++) { igraph_real_t sum; - igraph_integer_t to; + igraph_int_t to; IGRAPH_ALLOW_INTERRUPTION(); - if (outseq != 0 && igraph_vector_int_size(outseq) != 0) { + if (outseq) { no_of_neighbors = VECTOR(*outseq)[i]; } sum = igraph_psumtree_sum(&sumtree); @@ -800,8 +784,8 @@ igraph_error_t igraph_barabasi_aging_game(igraph_t *graph, } /* update probabilities */ for (j = 0; j < no_of_neighbors; j++) { - igraph_integer_t n = VECTOR(edges)[edgeptr - 2 * j - 1]; - igraph_integer_t age = (i - n) / binwidth; + igraph_int_t n = VECTOR(edges)[edgeptr - 2 * j - 1]; + igraph_int_t age = (i - n) / binwidth; IGRAPH_CHECK(igraph_psumtree_update( &sumtree, n, attraction_aging(VECTOR(degree)[n], age+1, @@ -831,9 +815,9 @@ igraph_error_t igraph_barabasi_aging_game(igraph_t *graph, /* aging */ for (k = 1; binwidth * k <= i; k++) { - igraph_integer_t shnode = i - binwidth * k; - igraph_integer_t deg = VECTOR(degree)[shnode]; - igraph_integer_t age = (i - shnode) / binwidth; + igraph_int_t shnode = i - binwidth * k; + igraph_int_t deg = VECTOR(degree)[shnode]; + igraph_int_t age = (i - shnode) / binwidth; /* igraph_real_t old=igraph_psumtree_get(&sumtree, shnode); */ IGRAPH_CHECK(igraph_psumtree_update( &sumtree, shnode, @@ -845,8 +829,6 @@ igraph_error_t igraph_barabasi_aging_game(igraph_t *graph, } } - RNG_END(); - igraph_vector_int_destroy(°ree); igraph_psumtree_destroy(&sumtree); IGRAPH_FINALLY_CLEAN(2); diff --git a/src/vendor/cigraph/src/games/callaway_traits.c b/src/vendor/cigraph/src/games/callaway_traits.c index 8381e4e5544..7b93af44ce7 100644 --- a/src/vendor/cigraph/src/games/callaway_traits.c +++ b/src/vendor/cigraph/src/games/callaway_traits.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -70,13 +68,13 @@ * Time complexity: O(|V|*k*log(|V|)), |V| is the number of vertices, * k is \p edges_per_step. */ -igraph_error_t igraph_callaway_traits_game(igraph_t *graph, igraph_integer_t nodes, - igraph_integer_t types, igraph_integer_t edges_per_step, +igraph_error_t igraph_callaway_traits_game(igraph_t *graph, igraph_int_t nodes, + igraph_int_t types, igraph_int_t edges_per_step, const igraph_vector_t *type_dist, const igraph_matrix_t *pref_matrix, igraph_bool_t directed, igraph_vector_int_t *node_type_vec) { - igraph_integer_t i, j; + igraph_int_t i, j; igraph_vector_int_t edges; igraph_vector_t cumdist; igraph_real_t maxcum; @@ -163,21 +161,19 @@ igraph_error_t igraph_callaway_traits_game(igraph_t *graph, igraph_integer_t nod IGRAPH_VECTOR_INT_INIT_FINALLY(nodetypes, nodes); } - RNG_BEGIN(); - for (i = 0; i < nodes; i++) { igraph_real_t uni = RNG_UNIF(0, maxcum); - igraph_integer_t type; + igraph_int_t type; igraph_vector_binsearch(&cumdist, uni, &type); VECTOR(*nodetypes)[i] = type - 1; } for (i = 1; i < nodes; i++) { for (j = 0; j < edges_per_step; j++) { - igraph_integer_t node1 = RNG_INTEGER(0, i); - igraph_integer_t node2 = RNG_INTEGER(0, i); - igraph_integer_t type1 = VECTOR(*nodetypes)[node1]; - igraph_integer_t type2 = VECTOR(*nodetypes)[node2]; + igraph_int_t node1 = RNG_INTEGER(0, i); + igraph_int_t node2 = RNG_INTEGER(0, i); + igraph_int_t type1 = VECTOR(*nodetypes)[node1]; + igraph_int_t type2 = VECTOR(*nodetypes)[node2]; /* printf("unif: %f, %f, types: %li, %li\n", uni1, uni2, type1, type2); */ if (RNG_UNIF01() < MATRIX(*pref_matrix, type1, type2)) { IGRAPH_CHECK(igraph_vector_int_push_back(&edges, node1)); @@ -186,8 +182,6 @@ igraph_error_t igraph_callaway_traits_game(igraph_t *graph, igraph_integer_t nod } } - RNG_END(); - if (! node_type_vec) { igraph_vector_int_destroy(nodetypes); IGRAPH_FREE(nodetypes); diff --git a/src/vendor/cigraph/src/games/chung_lu.c b/src/vendor/cigraph/src/games/chung_lu.c index b0430774d08..235c7d60c60 100644 --- a/src/vendor/cigraph/src/games/chung_lu.c +++ b/src/vendor/cigraph/src/games/chung_lu.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -196,7 +196,7 @@ igraph_error_t igraph_chung_lu_game(igraph_t *graph, igraph_bool_t loops, igraph_chung_lu_t variant) { - const igraph_integer_t no_of_nodes = igraph_vector_size(out_weights); + const igraph_int_t no_of_nodes = igraph_vector_size(out_weights); const igraph_bool_t directed = in_weights != NULL; igraph_vector_int_t edges, idx; igraph_real_t wsum = igraph_vector_sum(out_weights); @@ -234,13 +234,12 @@ igraph_error_t igraph_chung_lu_game(igraph_t *graph, IGRAPH_CHECK(igraph_vector_sort_ind(in_weights, &idx, IGRAPH_DESCENDING)); - RNG_BEGIN(); - for (igraph_integer_t i=0; i < no_of_nodes; i++) { - igraph_integer_t vi, vj; + for (igraph_int_t i=0; i < no_of_nodes; i++) { + igraph_int_t vi, vj; igraph_real_t wi, wj; igraph_real_t p, q; - igraph_integer_t j = directed ? 0 : i; + igraph_int_t j = directed ? 0 : i; vi = VECTOR(idx)[i]; wi = VECTOR(*out_weights)[vi]; @@ -257,7 +256,7 @@ igraph_error_t igraph_chung_lu_game(igraph_t *graph, /* This formulation not only terminates the loop when necessary, * but also protects against overflow when 'p' is very small * and 'gap' becomes very large, perhaps larger than representable - * in an igraph_integer_t. */ + * in an igraph_int_t. */ if (gap >= no_of_nodes-j) { break; } @@ -309,7 +308,6 @@ igraph_error_t igraph_chung_lu_game(igraph_t *graph, IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 16); } } - RNG_END(); igraph_vector_int_destroy(&idx); IGRAPH_FINALLY_CLEAN(1); diff --git a/src/vendor/cigraph/src/games/citations.c b/src/vendor/cigraph/src/games/citations.c index 729778152f6..9ce6a4143be 100644 --- a/src/vendor/cigraph/src/games/citations.c +++ b/src/vendor/cigraph/src/games/citations.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -32,7 +30,7 @@ #include "math/safe_intop.h" typedef struct { - igraph_integer_t no; + igraph_int_t no; igraph_psumtree_t *sumtrees; } igraph_i_citing_cited_type_game_struct_t; @@ -91,17 +89,17 @@ static void igraph_i_citing_cited_type_game_free ( * |E| is the total number of edges, a is the \p agebins parameter. */ igraph_error_t igraph_lastcit_game(igraph_t *graph, - igraph_integer_t nodes, igraph_integer_t edges_per_node, - igraph_integer_t agebins, + igraph_int_t nodes, igraph_int_t edges_per_node, + igraph_int_t agebins, const igraph_vector_t *preference, igraph_bool_t directed) { - igraph_integer_t no_of_nodes = nodes; + igraph_int_t no_of_nodes = nodes; igraph_psumtree_t sumtree; igraph_vector_int_t edges; - igraph_integer_t *lastcit; - igraph_integer_t *index; - igraph_integer_t binwidth; + igraph_int_t *lastcit; + igraph_int_t *index; + igraph_int_t binwidth; if (agebins != igraph_vector_size(preference) - 1) { IGRAPH_ERRORF("The `preference' vector should be of length `agebins' plus one." @@ -143,11 +141,11 @@ igraph_error_t igraph_lastcit_game(igraph_t *graph, binwidth = no_of_nodes / agebins + 1; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - lastcit = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + lastcit = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(lastcit, "Insufficient memory for lastcit game."); IGRAPH_FINALLY(igraph_free, lastcit); - index = IGRAPH_CALLOC(no_of_nodes + 1, igraph_integer_t); + index = IGRAPH_CALLOC(no_of_nodes + 1, igraph_int_t); IGRAPH_CHECK_OOM(index, "Insufficient memory for lastcit game."); IGRAPH_FINALLY(igraph_free, index); @@ -160,13 +158,11 @@ igraph_error_t igraph_lastcit_game(igraph_t *graph, index[0] = 0; index[1] = 0; - RNG_BEGIN(); - - for (igraph_integer_t i = 1; i < no_of_nodes; i++) { + for (igraph_int_t i = 1; i < no_of_nodes; i++) { /* Add new edges */ - for (igraph_integer_t j = 0; j < edges_per_node; j++) { - igraph_integer_t to; + for (igraph_int_t j = 0; j < edges_per_node; j++) { + igraph_int_t to; const igraph_real_t sum = igraph_psumtree_sum(&sumtree); if (sum == 0) { /* If none of the so-far added nodes have positive weight, @@ -187,11 +183,11 @@ igraph_error_t igraph_lastcit_game(igraph_t *graph, /* Update the preference of some vertices if they got to another bin. We need to know the citations of some older vertices, this is in the index. */ - for (igraph_integer_t k = 1; i - binwidth * k >= 1; k++) { - const igraph_integer_t shnode = i - binwidth * k; - const igraph_integer_t m = index[shnode], n = index[shnode + 1]; - for (igraph_integer_t j = 2 * m; j < 2 * n; j += 2) { - const igraph_integer_t cnode = VECTOR(edges)[j + 1]; + for (igraph_int_t k = 1; i - binwidth * k >= 1; k++) { + const igraph_int_t shnode = i - binwidth * k; + const igraph_int_t m = index[shnode], n = index[shnode + 1]; + for (igraph_int_t j = 2 * m; j < 2 * n; j += 2) { + const igraph_int_t cnode = VECTOR(edges)[j + 1]; if (lastcit[cnode] == shnode + 1) { IGRAPH_CHECK(igraph_psumtree_update(&sumtree, cnode, VECTOR(*preference)[k])); } @@ -200,8 +196,6 @@ igraph_error_t igraph_lastcit_game(igraph_t *graph, } - RNG_END(); - igraph_psumtree_destroy(&sumtree); IGRAPH_FREE(index); IGRAPH_FREE(lastcit); @@ -249,17 +243,17 @@ igraph_error_t igraph_lastcit_game(igraph_t *graph, * vertices and edges, respectively. */ -igraph_error_t igraph_cited_type_game(igraph_t *graph, igraph_integer_t nodes, +igraph_error_t igraph_cited_type_game(igraph_t *graph, igraph_int_t nodes, const igraph_vector_int_t *types, const igraph_vector_t *pref, - igraph_integer_t edges_per_step, + igraph_int_t edges_per_step, igraph_bool_t directed) { igraph_vector_int_t edges; igraph_vector_t cumsum; igraph_real_t sum, nnval; - igraph_integer_t i, j, type; - igraph_integer_t pref_len = igraph_vector_size(pref); + igraph_int_t i, j, type; + igraph_int_t pref_len = igraph_vector_size(pref); if (igraph_vector_int_size(types) != nodes) { IGRAPH_ERRORF("Length of types vector (%" IGRAPH_PRId ") must match number of nodes (%" IGRAPH_PRId ").", @@ -300,11 +294,9 @@ igraph_error_t igraph_cited_type_game(igraph_t *graph, igraph_integer_t nodes, } sum = VECTOR(cumsum)[1] = nnval; - RNG_BEGIN(); - for (i = 1; i < nodes; i++) { for (j = 0; j < edges_per_step; j++) { - igraph_integer_t to; + igraph_int_t to; if (sum > 0) { igraph_vector_binsearch(&cumsum, RNG_UNIF(0, sum), &to); } else { @@ -325,8 +317,6 @@ igraph_error_t igraph_cited_type_game(igraph_t *graph, igraph_integer_t nodes, igraph_vector_push_back(&cumsum, sum); /* reserved */ } - RNG_END(); - igraph_vector_destroy(&cumsum); IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed)); @@ -348,7 +338,7 @@ static void igraph_i_citing_cited_type_game_free(igraph_i_citing_cited_type_game if (!s->sumtrees) { return; } - for (igraph_integer_t i = 0; i < s->no; i++) { + for (igraph_int_t i = 0; i < s->no; i++) { igraph_psumtree_destroy(&s->sumtrees[i]); } IGRAPH_FREE(s->sumtrees); @@ -394,18 +384,18 @@ static void igraph_i_citing_cited_type_game_free(igraph_i_citing_cited_type_game * vertices and edges, respectively. */ -igraph_error_t igraph_citing_cited_type_game(igraph_t *graph, igraph_integer_t nodes, +igraph_error_t igraph_citing_cited_type_game(igraph_t *graph, igraph_int_t nodes, const igraph_vector_int_t *types, const igraph_matrix_t *pref, - igraph_integer_t edges_per_step, + igraph_int_t edges_per_step, igraph_bool_t directed) { igraph_vector_int_t edges; igraph_i_citing_cited_type_game_struct_t str = { 0, NULL }; igraph_psumtree_t *sumtrees; igraph_vector_t sums; - igraph_integer_t no_of_types; - igraph_integer_t i, j, no_of_edges, no_of_edge_endpoints; + igraph_int_t no_of_types; + igraph_int_t i, j, no_of_edges, no_of_edge_endpoints; if (igraph_vector_int_size(types) != nodes) { IGRAPH_ERRORF("Length of types vector (%" IGRAPH_PRId ") not equal to number" @@ -461,7 +451,7 @@ igraph_error_t igraph_citing_cited_type_game(igraph_t *graph, igraph_integer_t n /* First node */ for (i = 0; i < no_of_types; i++) { - igraph_integer_t type = VECTOR(*types)[0]; + igraph_int_t type = VECTOR(*types)[0]; if ( MATRIX(*pref, i, type) < 0) { IGRAPH_ERRORF("Preference matrix contains negative entry: %g.", IGRAPH_EINVAL, MATRIX(*pref, i, type)); } @@ -469,13 +459,11 @@ igraph_error_t igraph_citing_cited_type_game(igraph_t *graph, igraph_integer_t n VECTOR(sums)[i] = MATRIX(*pref, i, type); } - RNG_BEGIN(); - for (i = 1; i < nodes; i++) { - igraph_integer_t type = VECTOR(*types)[i]; + igraph_int_t type = VECTOR(*types)[i]; igraph_real_t sum = VECTOR(sums)[type]; for (j = 0; j < edges_per_step; j++) { - igraph_integer_t to; + igraph_int_t to; if (sum == 0) { /* If none of the so-far added nodes have positive weight, * we choose one uniformly to connect to. */ @@ -497,8 +485,6 @@ igraph_error_t igraph_citing_cited_type_game(igraph_t *graph, igraph_integer_t n } } - RNG_END(); - igraph_i_citing_cited_type_game_free(&str); IGRAPH_FINALLY_CLEAN(1); diff --git a/src/vendor/cigraph/src/games/correlated.c b/src/vendor/cigraph/src/games/correlated.c index 576cffb7c96..5965406e008 100644 --- a/src/vendor/cigraph/src/games/correlated.c +++ b/src/vendor/cigraph/src/games/correlated.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -26,6 +24,7 @@ #include "igraph_conversion.h" #include "igraph_constructors.h" #include "igraph_interface.h" +#include "igraph_isomorphism.h" #include "igraph_qsort.h" #include "igraph_random.h" #include "igraph_structural.h" @@ -44,9 +43,9 @@ /* TODO: Slight speedup may be possible if repeated vertex count queries are avoided. */ static int code_cmp(void *graph, const void *va, const void *vb) { - const igraph_integer_t *a = (const igraph_integer_t *) va; - const igraph_integer_t *b = (const igraph_integer_t *) vb; - const igraph_integer_t no_of_nodes = igraph_vcount((igraph_t *) graph); + const igraph_int_t *a = (const igraph_int_t *) va; + const igraph_int_t *b = (const igraph_int_t *) vb; + const igraph_int_t no_of_nodes = igraph_vcount((igraph_t *) graph); const igraph_bool_t directed = igraph_is_directed((igraph_t *) graph); const igraph_real_t codea = CODE(a[0], a[1]); const igraph_real_t codeb = CODE(b[0], b[1]); @@ -61,7 +60,7 @@ static int code_cmp(void *graph, const void *va, const void *vb) { /* Sort an edge vector by edge codes. */ static void sort_edges(igraph_vector_int_t *edges, const igraph_t *graph) { - igraph_qsort_r(VECTOR(*edges), igraph_vector_int_size(edges) / 2, 2*sizeof(igraph_integer_t), (void *) graph, code_cmp); + igraph_qsort_r(VECTOR(*edges), igraph_vector_int_size(edges) / 2, 2*sizeof(igraph_int_t), (void *) graph, code_cmp); } /** @@ -71,41 +70,43 @@ static void sort_edges(igraph_vector_int_t *edges, const igraph_t *graph) { * Sample a new graph by perturbing the adjacency matrix of a * given simple graph and shuffling its vertices. * - * \param old_graph The original graph, it must be simple. - * \param new_graph The new graph will be stored here. + * \param new_graph The new graph to initialize based on an existing graph. + * \param old_graph The original graph, which must be a simple graph. * \param corr A value in the unit interval [0,1], the target Pearson * correlation between the adjacency matrices of the original and the * generated graph (the adjacency matrix being used as a vector). * \param p The probability of an edge between two vertices. It must in the * open (0,1) interval. Typically, the density of \p old_graph. * \param permutation A permutation to apply to the vertices of the - * generated graph. It can also be a null pointer, in which case - * the vertices will not be permuted. + * generated graph. The i-th element of the vector specifies the index + * of the vertex in the \em original graph that will become vertex i in the + * new graph. It can also be a null pointer, in which case the vertices + * will not be permuted. * \return Error code * * \sa \ref igraph_correlated_pair_game() for generating a pair * of correlated random graphs in one go. */ -igraph_error_t igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_graph, +igraph_error_t igraph_correlated_game(igraph_t *new_graph, const igraph_t *old_graph, igraph_real_t corr, igraph_real_t p, const igraph_vector_int_t *permutation) { - igraph_integer_t no_of_nodes = igraph_vcount(old_graph); - igraph_integer_t no_of_edges = igraph_ecount(old_graph); - igraph_bool_t directed = igraph_is_directed(old_graph); - igraph_real_t no_of_all = directed ? ((igraph_real_t) no_of_nodes) * (no_of_nodes - 1) : + const igraph_int_t no_of_nodes = igraph_vcount(old_graph); + const igraph_int_t no_of_edges = igraph_ecount(old_graph); + const igraph_bool_t directed = igraph_is_directed(old_graph); + const igraph_real_t no_of_all = directed ? ((igraph_real_t) no_of_nodes) * (no_of_nodes - 1) : ((igraph_real_t) no_of_nodes) * (no_of_nodes - 1) / 2; - igraph_real_t no_of_missing = no_of_all - no_of_edges; - igraph_real_t q = p + corr * (1 - p); - igraph_real_t p_del = 1 - q; - igraph_real_t p_add = ((1 - q) * (p / (1 - p))); + const igraph_real_t no_of_missing = no_of_all - no_of_edges; + const igraph_real_t q = p + corr * (1 - p); + const igraph_real_t p_del = 1 - q; + const igraph_real_t p_add = ((1 - q) * (p / (1 - p))); igraph_vector_t add, delete; igraph_vector_int_t edges, newedges; + igraph_vector_int_t inverted_permutation; igraph_real_t last; - igraph_integer_t p_e = 0, p_a = 0, p_d = 0; - igraph_integer_t no_add, no_del; + igraph_int_t p_e = 0, p_a = 0, p_d = 0; + igraph_int_t no_add, no_del; igraph_real_t next_e, next_a, next_d; - igraph_integer_t i, newec; igraph_bool_t simple; if (corr < 0 || corr > 1) { @@ -122,7 +123,7 @@ igraph_error_t igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_g IGRAPH_EINVAL); } } - IGRAPH_CHECK(igraph_is_simple(old_graph, &simple)); + IGRAPH_CHECK(igraph_is_simple(old_graph, &simple, IGRAPH_DIRECTED)); if (! simple) { IGRAPH_ERROR("The original graph must be simple for correlated Erdos-Renyi game.", IGRAPH_EINVAL); @@ -131,18 +132,26 @@ igraph_error_t igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_g /* Special cases */ if (corr == 0) { - return igraph_erdos_renyi_game_gnp(new_graph, no_of_nodes, p, directed, IGRAPH_NO_LOOPS); + return igraph_erdos_renyi_game_gnp(new_graph, no_of_nodes, p, directed, IGRAPH_SIMPLE_SW, IGRAPH_EDGE_UNLABELED); } if (corr == 1) { /* We don't copy, because we don't need the attributes.... */ IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges * 2); - IGRAPH_CHECK(igraph_get_edgelist(old_graph, &edges, /* bycol= */ 0)); + IGRAPH_CHECK(igraph_get_edgelist(old_graph, &edges, /* bycol= */ false)); if (permutation) { - newec = igraph_vector_int_size(&edges); - for (i = 0; i < newec; i++) { - igraph_integer_t tmp = VECTOR(edges)[i]; - VECTOR(edges)[i] = VECTOR(*permutation)[tmp]; + const igraph_int_t newec = igraph_vector_int_size(&edges); + + IGRAPH_VECTOR_INT_INIT_FINALLY(&inverted_permutation, no_of_nodes); + /* Also checks that 'permutation' is valid: */ + IGRAPH_CHECK(igraph_invert_permutation(permutation, &inverted_permutation)); + + for (igraph_int_t i = 0; i < newec; i++) { + igraph_int_t tmp = VECTOR(edges)[i]; + VECTOR(edges)[i] = VECTOR(inverted_permutation)[tmp]; } + + igraph_vector_int_destroy(&inverted_permutation); + IGRAPH_FINALLY_CLEAN(1); } IGRAPH_CHECK(igraph_create(new_graph, &edges, no_of_nodes, directed)); igraph_vector_int_destroy(&edges); @@ -162,8 +171,6 @@ igraph_error_t igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_g */ sort_edges(&edges, old_graph); - RNG_BEGIN(); - if (p_del > 0) { last = RNG_GEOM(p_del); while (last < no_of_edges) { @@ -184,8 +191,6 @@ igraph_error_t igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_g } no_add = igraph_vector_size(&add); - RNG_END(); - /* Now we are merging the original edges, the edges that are removed, and the new edges. We have the following pointers: - p_a: the next edge to add @@ -199,10 +204,10 @@ igraph_error_t igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_g /* First we (re)code the edges to delete */ - for (i = 0; i < no_del; i++) { - igraph_integer_t td = VECTOR(delete)[i]; - igraph_integer_t from = VECTOR(edges)[2 * td]; - igraph_integer_t to = VECTOR(edges)[2 * td + 1]; + for (igraph_int_t i = 0; i < no_del; i++) { + igraph_int_t td = VECTOR(delete)[i]; + igraph_int_t from = VECTOR(edges)[2 * td]; + igraph_int_t to = VECTOR(edges)[2 * td + 1]; VECTOR(delete)[i] = CODE(from, to); } @@ -241,16 +246,16 @@ igraph_error_t igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_g } else { /* add an edge */ - igraph_integer_t to, from; + igraph_int_t to, from; IGRAPH_ASSERT(isfinite(next_a)); if (directed) { - to = floor(next_a / no_of_nodes); + to = trunc(next_a / no_of_nodes); from = next_a - ((igraph_real_t)to) * no_of_nodes; if (from == to) { to = no_of_nodes - 1; } } else { - to = floor((sqrt(8 * next_a + 1) + 1) / 2); + to = trunc((sqrt(8 * next_a + 1) + 1) / 2); from = next_a - (((igraph_real_t)to) * (to - 1)) / 2; } IGRAPH_CHECK(igraph_vector_int_push_back(&newedges, from)); @@ -266,11 +271,19 @@ igraph_error_t igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_g IGRAPH_FINALLY_CLEAN(3); if (permutation) { - newec = igraph_vector_int_size(&newedges); - for (i = 0; i < newec; i++) { - igraph_integer_t tmp = VECTOR(newedges)[i]; - VECTOR(newedges)[i] = VECTOR(*permutation)[tmp]; + igraph_int_t newec = igraph_vector_int_size(&newedges); + + IGRAPH_VECTOR_INT_INIT_FINALLY(&inverted_permutation, no_of_nodes); + /* Also checks that 'permutation' is valid: */ + IGRAPH_CHECK(igraph_invert_permutation(permutation, &inverted_permutation)); + + for (igraph_int_t i = 0; i < newec; i++) { + igraph_int_t tmp = VECTOR(newedges)[i]; + VECTOR(newedges)[i] = VECTOR(inverted_permutation)[tmp]; } + + igraph_vector_int_destroy(&inverted_permutation); + IGRAPH_FINALLY_CLEAN(1); } IGRAPH_CHECK(igraph_create(new_graph, &newedges, no_of_nodes, directed)); @@ -305,19 +318,21 @@ igraph_error_t igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_g * vertices, it must in the open (0,1) interval. * \param directed Whether to generate directed graphs. * \param permutation A permutation to apply to the vertices of the - * second graph. It can also be a null pointer, in which case - * the vertices will not be permuted. + * generated graph. The i-th element of the vector specifies the index + * of the vertex in the \em first graph that will become vertex i in the + * second graph. It can also be a null pointer, in which case the vertices + * will not be permuted. * \return Error code * * \sa \ref igraph_correlated_game() for generating a correlated pair * to a given graph. */ igraph_error_t igraph_correlated_pair_game(igraph_t *graph1, igraph_t *graph2, - igraph_integer_t n, igraph_real_t corr, igraph_real_t p, + igraph_int_t n, igraph_real_t corr, igraph_real_t p, igraph_bool_t directed, const igraph_vector_int_t *permutation) { - IGRAPH_CHECK(igraph_erdos_renyi_game_gnp(graph1, n, p, directed, IGRAPH_NO_LOOPS)); - IGRAPH_CHECK(igraph_correlated_game(graph1, graph2, corr, p, permutation)); + IGRAPH_CHECK(igraph_erdos_renyi_game_gnp(graph1, n, p, directed, IGRAPH_SIMPLE_SW, IGRAPH_EDGE_UNLABELED)); + IGRAPH_CHECK(igraph_correlated_game(graph2, graph1, corr, p, permutation)); return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/games/degree_sequence.c b/src/vendor/cigraph/src/games/degree_sequence.c index 37679de4964..5addbff2222 100644 --- a/src/vendor/cigraph/src/games/degree_sequence.c +++ b/src/vendor/cigraph/src/games/degree_sequence.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2003-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -39,12 +39,12 @@ static igraph_error_t configuration( const igraph_vector_int_t *out_seq, const igraph_vector_int_t *in_seq) { - const igraph_bool_t directed = (in_seq != NULL && igraph_vector_int_size(in_seq) != 0); - igraph_integer_t outsum = 0, insum = 0; + const igraph_bool_t directed = (in_seq != NULL); + igraph_int_t outsum = 0, insum = 0; igraph_bool_t graphical; - igraph_integer_t no_of_nodes, no_of_edges; - igraph_integer_t *bag1, *bag2; - igraph_integer_t bagp1 = 0, bagp2 = 0; + igraph_int_t no_of_nodes, no_of_edges; + igraph_int_t *bag1, *bag2; + igraph_int_t bagp1 = 0, bagp2 = 0; igraph_vector_int_t edges; IGRAPH_CHECK(igraph_is_graphical(out_seq, in_seq, IGRAPH_LOOPS_SW | IGRAPH_MULTI_SW, &graphical)); @@ -61,21 +61,21 @@ static igraph_error_t configuration( no_of_nodes = igraph_vector_int_size(out_seq); no_of_edges = directed ? outsum : outsum / 2; - bag1 = IGRAPH_CALLOC(outsum, igraph_integer_t); + bag1 = IGRAPH_CALLOC(outsum, igraph_int_t); IGRAPH_CHECK_OOM(bag1, "Insufficient memory for sampling from configuration model."); IGRAPH_FINALLY(igraph_free, bag1); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - for (igraph_integer_t j = 0; j < VECTOR(*out_seq)[i]; j++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t j = 0; j < VECTOR(*out_seq)[i]; j++) { bag1[bagp1++] = i; } } if (directed) { - bag2 = IGRAPH_CALLOC(insum, igraph_integer_t); + bag2 = IGRAPH_CALLOC(insum, igraph_int_t); IGRAPH_CHECK_OOM(bag2, "Insufficient memory for sampling from configuration model."); IGRAPH_FINALLY(igraph_free, bag2); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - for (igraph_integer_t j = 0; j < VECTOR(*in_seq)[i]; j++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t j = 0; j < VECTOR(*in_seq)[i]; j++) { bag2[bagp2++] = i; } } @@ -84,12 +84,10 @@ static igraph_error_t configuration( IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges * 2)); - RNG_BEGIN(); - if (directed) { - for (igraph_integer_t i = 0; i < no_of_edges; i++) { - igraph_integer_t from = RNG_INTEGER(0, bagp1 - 1); - igraph_integer_t to = RNG_INTEGER(0, bagp2 - 1); + for (igraph_int_t i = 0; i < no_of_edges; i++) { + igraph_int_t from = RNG_INTEGER(0, bagp1 - 1); + igraph_int_t to = RNG_INTEGER(0, bagp2 - 1); igraph_vector_int_push_back(&edges, bag1[from]); /* safe, already reserved */ igraph_vector_int_push_back(&edges, bag2[to]); /* ditto */ bag1[from] = bag1[bagp1 - 1]; @@ -97,9 +95,9 @@ static igraph_error_t configuration( bagp1--; bagp2--; } } else { - for (igraph_integer_t i = 0; i < no_of_edges; i++) { - igraph_integer_t from = RNG_INTEGER(0, bagp1 - 1); - igraph_integer_t to; + for (igraph_int_t i = 0; i < no_of_edges; i++) { + igraph_int_t from = RNG_INTEGER(0, bagp1 - 1); + igraph_int_t to; igraph_vector_int_push_back(&edges, bag1[from]); /* safe, already reserved */ bag1[from] = bag1[bagp1 - 1]; bagp1--; @@ -110,8 +108,6 @@ static igraph_error_t configuration( } } - RNG_END(); - IGRAPH_FREE(bag1); IGRAPH_FINALLY_CLEAN(1); if (directed) { @@ -136,9 +132,9 @@ static igraph_error_t fast_heur_undirected( igraph_set_t incomplete_vertices; igraph_adjlist_t al; igraph_bool_t finished, failed; - igraph_integer_t from, to, dummy; - igraph_integer_t i, j, k; - igraph_integer_t no_of_nodes, outsum = 0; + igraph_int_t from, to, dummy; + igraph_int_t i, j, k; + igraph_int_t no_of_nodes, outsum = 0; igraph_bool_t graphical; int iter = 0; @@ -160,9 +156,6 @@ static igraph_error_t fast_heur_undirected( IGRAPH_CHECK(igraph_set_init(&incomplete_vertices, 0)); IGRAPH_FINALLY(igraph_set_destroy, &incomplete_vertices); - /* Start the RNG */ - RNG_BEGIN(); - /* Outer loop; this will try to construct a graph several times from scratch * until it finally succeeds. */ finished = false; @@ -184,7 +177,7 @@ static igraph_error_t fast_heur_undirected( igraph_vector_int_clear(&stubs); for (i = 0; i < no_of_nodes; i++) { for (j = 0; j < VECTOR(residual_degrees)[i]; j++) { - igraph_vector_int_push_back(&stubs, i); + igraph_vector_int_push_back(&stubs, i); /* reserved */ } } @@ -248,9 +241,6 @@ static igraph_error_t fast_heur_undirected( } } - /* Finish the RNG */ - RNG_END(); - /* Clean up */ igraph_set_destroy(&incomplete_vertices); igraph_vector_int_destroy(&residual_degrees); @@ -282,9 +272,9 @@ static igraph_error_t fast_heur_directed( igraph_vector_int_t *neis; igraph_vector_int_t residual_in_degrees, residual_out_degrees; igraph_set_t incomplete_in_vertices, incomplete_out_vertices; - igraph_integer_t from, to; - igraph_integer_t i, j, k; - igraph_integer_t no_of_nodes, outsum; + igraph_int_t from, to; + igraph_int_t i, j, k; + igraph_int_t no_of_nodes, outsum; int iter = 0; IGRAPH_CHECK(igraph_is_graphical(out_seq, in_seq, IGRAPH_SIMPLE_SW, °_seq_ok)); @@ -310,9 +300,6 @@ static igraph_error_t fast_heur_directed( IGRAPH_CHECK(igraph_set_init(&incomplete_in_vertices, 0)); IGRAPH_FINALLY(igraph_set_destroy, &incomplete_in_vertices); - /* Start the RNG */ - RNG_BEGIN(); - /* Outer loop; this will try to construct a graph several times from scratch * until it finally succeeds. */ finished = false; @@ -336,10 +323,10 @@ static igraph_error_t fast_heur_directed( igraph_vector_int_clear(&in_stubs); for (i = 0; i < no_of_nodes; i++) { for (j = 0; j < VECTOR(residual_out_degrees)[i]; j++) { - igraph_vector_int_push_back(&out_stubs, i); + igraph_vector_int_push_back(&out_stubs, i); /* reserved */ } for (j = 0; j < VECTOR(residual_in_degrees)[i]; j++) { - igraph_vector_int_push_back(&in_stubs, i); + igraph_vector_int_push_back(&in_stubs, i); /* reserved */ } } @@ -395,9 +382,6 @@ static igraph_error_t fast_heur_directed( } } - /* Finish the RNG */ - RNG_END(); - /* Clean up */ igraph_set_destroy(&incomplete_in_vertices); igraph_set_destroy(&incomplete_out_vertices); @@ -420,7 +404,7 @@ static igraph_error_t fast_heur_directed( /* swap two elements of a vector_int */ #define SWAP_INT_ELEM(vec, i, j) \ { \ - igraph_integer_t temp; \ + igraph_int_t temp; \ temp = VECTOR(vec)[i]; \ VECTOR(vec)[i] = VECTOR(vec)[j]; \ VECTOR(vec)[j] = temp; \ @@ -430,9 +414,9 @@ static igraph_error_t fast_heur_directed( static igraph_error_t configuration_simple_undirected_set( const igraph_vector_int_t *degseq, igraph_vector_int_t *stubs, - igraph_integer_t vcount, igraph_integer_t stub_count) { + igraph_int_t vcount, igraph_int_t stub_count) { - const igraph_integer_t ecount = stub_count / 2; + const igraph_int_t ecount = stub_count / 2; igraph_vector_ptr_t adjlist; int iter = 0; @@ -440,7 +424,7 @@ static igraph_error_t configuration_simple_undirected_set( IGRAPH_CHECK(igraph_vector_ptr_init(&adjlist, vcount)); IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&adjlist, igraph_set_destroy); IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &adjlist); - for (igraph_integer_t i = 0; i < vcount; ++i) { + for (igraph_int_t i = 0; i < vcount; ++i) { igraph_set_t *set = IGRAPH_CALLOC(1, igraph_set_t); IGRAPH_CHECK_OOM(set, "Insufficient memory for configuration model (simple graphs)."); IGRAPH_CHECK(igraph_set_init(set, 0)); @@ -448,14 +432,12 @@ static igraph_error_t configuration_simple_undirected_set( IGRAPH_CHECK(igraph_set_reserve(set, VECTOR(*degseq)[i])); } - RNG_BEGIN(); - for (;;) { igraph_bool_t success = true; /* Shuffle stubs vector with Fisher-Yates and check for self-loops and multi-edges as we go. */ - for (igraph_integer_t i = 0; i < ecount; ++i) { - igraph_integer_t k, from, to; + for (igraph_int_t i = 0; i < ecount; ++i) { + igraph_int_t k, from, to; k = RNG_INTEGER(2*i, stub_count-1); SWAP_INT_ELEM(*stubs, 2*i, k); @@ -488,15 +470,13 @@ static igraph_error_t configuration_simple_undirected_set( } /* Clear adjacency list. */ - for (igraph_integer_t j = 0; j < vcount; ++j) { + for (igraph_int_t j = 0; j < vcount; ++j) { igraph_set_clear((igraph_set_t *) VECTOR(adjlist)[j]); } IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 8); } - RNG_END(); - igraph_vector_ptr_destroy_all(&adjlist); IGRAPH_FINALLY_CLEAN(1); @@ -506,26 +486,24 @@ static igraph_error_t configuration_simple_undirected_set( /* Uses a bitset to check for multi-edges. Efficient for smaller graphs. */ static igraph_error_t configuration_simple_undirected_bitset( igraph_vector_int_t *stubs, - igraph_integer_t vcount, igraph_integer_t stub_count) { + igraph_int_t vcount, igraph_int_t stub_count) { - const igraph_integer_t ecount = stub_count / 2; + const igraph_int_t ecount = stub_count / 2; igraph_bitset_list_t adjlist; int iter = 0; /* Build an adjacency list in terms of bitsets; used to check for multi-edges. */ IGRAPH_BITSET_LIST_INIT_FINALLY(&adjlist, vcount); - for (igraph_integer_t i = 0; i < vcount; ++i) { + for (igraph_int_t i = 0; i < vcount; ++i) { IGRAPH_CHECK(igraph_bitset_resize(igraph_bitset_list_get_ptr(&adjlist, i), vcount)); } - RNG_BEGIN(); - for (;;) { igraph_bool_t success = true; /* Shuffle stubs vector with Fisher-Yates and check for self-loops and multi-edges as we go. */ - for (igraph_integer_t i = 0; i < ecount; ++i) { - igraph_integer_t k, from, to; + for (igraph_int_t i = 0; i < ecount; ++i) { + igraph_int_t k, from, to; k = RNG_INTEGER(2*i, stub_count-1); SWAP_INT_ELEM(*stubs, 2*i, k); @@ -558,15 +536,13 @@ static igraph_error_t configuration_simple_undirected_bitset( } /* Clear adjacency list. */ - for (igraph_integer_t j = 0; j < vcount; ++j) { + for (igraph_int_t j = 0; j < vcount; ++j) { igraph_bitset_null(igraph_bitset_list_get_ptr(&adjlist, j)); } IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 8); } - RNG_END(); - igraph_bitset_list_destroy(&adjlist); IGRAPH_FINALLY_CLEAN(1); @@ -579,7 +555,7 @@ static igraph_error_t configuration_simple_undirected( igraph_vector_int_t stubs; igraph_bool_t graphical; - igraph_integer_t vcount, stub_count; + igraph_int_t vcount, stub_count; IGRAPH_CHECK(igraph_is_graphical(degseq, NULL, IGRAPH_SIMPLE_SW, &graphical)); if (!graphical) { @@ -593,10 +569,10 @@ static igraph_error_t configuration_simple_undirected( /* Fill stubs vector. */ { - igraph_integer_t k = 0; - for (igraph_integer_t i = 0; i < vcount; ++i) { - igraph_integer_t deg = VECTOR(*degseq)[i]; - for (igraph_integer_t j = 0; j < deg; ++j) { + igraph_int_t k = 0; + for (igraph_int_t i = 0; i < vcount; ++i) { + igraph_int_t deg = VECTOR(*degseq)[i]; + for (igraph_int_t j = 0; j < deg; ++j) { VECTOR(stubs)[k++] = i; } } @@ -627,7 +603,7 @@ static igraph_error_t configuration_simple_directed( igraph_vector_int_t edges; igraph_vector_int_t vertex_done; igraph_bool_t graphical; - igraph_integer_t vcount, ecount; + igraph_int_t vcount, ecount; int iter = 0; IGRAPH_CHECK(igraph_is_graphical(out_deg, in_deg, IGRAPH_SIMPLE_SW, &graphical)); @@ -653,33 +629,31 @@ static igraph_error_t configuration_simple_directed( /* Fill in- and out-stubs vectors. */ { - igraph_integer_t k = 0, l = 0; - for (igraph_integer_t i = 0; i < vcount; ++i) { - igraph_integer_t dout, din; + igraph_int_t k = 0, l = 0; + for (igraph_int_t i = 0; i < vcount; ++i) { + igraph_int_t dout, din; dout = VECTOR(*out_deg)[i]; - for (igraph_integer_t j = 0; j < dout; ++j) { + for (igraph_int_t j = 0; j < dout; ++j) { VECTOR(out_stubs)[k++] = i; } din = VECTOR(*in_deg)[i]; - for (igraph_integer_t j = 0; j < din; ++j) { + for (igraph_int_t j = 0; j < din; ++j) { VECTOR(in_stubs)[l++] = i; } } } - igraph_integer_t vertex_done_mark = 1; - - RNG_BEGIN(); + igraph_int_t vertex_done_mark = 1; for (;;) { igraph_bool_t success = true; - igraph_integer_t previous_to = -1; + igraph_int_t previous_to = -1; /* Shuffle out-stubs vector with Fisher-Yates and check for self-loops and multi-edges as we go. */ - for (igraph_integer_t i = 0; i < ecount; ++i) { - igraph_integer_t k, from, to; + for (igraph_int_t i = 0; i < ecount; ++i) { + igraph_int_t k, from, to; k = RNG_INTEGER(i, ecount-1); SWAP_INT_ELEM(out_stubs, i, k); @@ -715,9 +689,7 @@ static igraph_error_t configuration_simple_directed( IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 8); } - RNG_END(); - - for (igraph_integer_t i=0; i < ecount; i++) { + for (igraph_int_t i=0; i < ecount; i++) { VECTOR(edges)[2*i] = VECTOR(out_stubs)[i]; VECTOR(edges)[2*i+1] = VECTOR(in_stubs)[i]; } @@ -744,7 +716,7 @@ igraph_error_t edge_switching( IGRAPH_CHECK(igraph_realize_degree_sequence(graph, out_seq, in_seq, IGRAPH_SIMPLE_SW, IGRAPH_REALIZE_DEGSEQ_INDEX)); IGRAPH_FINALLY(igraph_destroy, graph); - IGRAPH_CHECK(igraph_rewire(graph, 10 * igraph_ecount(graph), IGRAPH_REWIRING_SIMPLE)); + IGRAPH_CHECK(igraph_rewire(graph, 10 * igraph_ecount(graph), IGRAPH_SIMPLE_SW, NULL)); IGRAPH_FINALLY_CLEAN(1); return IGRAPH_SUCCESS; } @@ -778,13 +750,10 @@ igraph_error_t edge_switching( * https://doi.org/10.1088/2632-072x/abced5. * * \param graph Pointer to an uninitialized graph object. - * \param out_deg The degree sequence for an undirected graph (if - * \p in_seq is \c NULL or of length zero), or the out-degree - * sequence of a directed graph (if \p in_deq is not - * of length zero). - * \param in_deg It is either a zero-length vector or - * \c NULL (if an undirected - * graph is generated), or the in-degree sequence. + * \param out_degrees A vector of integers specifying the degree sequence for + * undirected graphs or the out-degree sequence for directed graphs. + * \param in_degrees A vector of integers specifying the in-degree sequence for + * directed graphs. For undirected graphs, it must be \c NULL. * \param method The method to generate the graph. Possible values: * \clist * \cli IGRAPH_DEGSEQ_CONFIGURATION @@ -861,37 +830,33 @@ igraph_error_t edge_switching( igraph_error_t igraph_degree_sequence_game( igraph_t *graph, - const igraph_vector_int_t *out_deg, - const igraph_vector_int_t *in_deg, + const igraph_vector_int_t *out_degrees, + const igraph_vector_int_t *in_degrees, igraph_degseq_t method) { - if (in_deg && igraph_vector_int_empty(in_deg) && !igraph_vector_int_empty(out_deg)) { - in_deg = NULL; - } - switch (method) { case IGRAPH_DEGSEQ_CONFIGURATION: - return configuration(graph, out_deg, in_deg); + return configuration(graph, out_degrees, in_degrees); case IGRAPH_DEGSEQ_VL: - return igraph_i_degree_sequence_game_vl(graph, out_deg, in_deg); + return igraph_i_degree_sequence_game_vl(graph, out_degrees, in_degrees); case IGRAPH_DEGSEQ_FAST_HEUR_SIMPLE: - if (! in_deg) { - return fast_heur_undirected(graph, out_deg); + if (! in_degrees) { + return fast_heur_undirected(graph, out_degrees); } else { - return fast_heur_directed(graph, out_deg, in_deg); + return fast_heur_directed(graph, out_degrees, in_degrees); } case IGRAPH_DEGSEQ_CONFIGURATION_SIMPLE: - if (! in_deg) { - return configuration_simple_undirected(graph, out_deg); + if (! in_degrees) { + return configuration_simple_undirected(graph, out_degrees); } else { - return configuration_simple_directed(graph, out_deg, in_deg); + return configuration_simple_directed(graph, out_degrees, in_degrees); } case IGRAPH_DEGSEQ_EDGE_SWITCHING_SIMPLE: - return edge_switching(graph, out_deg, in_deg); + return edge_switching(graph, out_degrees, in_degrees); default: IGRAPH_ERROR("Invalid degree sequence game method.", IGRAPH_EINVAL); diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/degree_sequence_vl.h b/src/vendor/cigraph/src/games/degree_sequence_vl/degree_sequence_vl.h index be905308b3e..9daa8f70a99 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/degree_sequence_vl.h +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/degree_sequence_vl.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -23,12 +23,12 @@ #include "igraph_datatype.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS igraph_error_t igraph_i_degree_sequence_game_vl(igraph_t *graph, const igraph_vector_int_t *out_seq, const igraph_vector_int_t *in_seq); -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_GAMES_DEGREE_SEQUENCE_VL_H */ diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_definitions.h b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_definitions.h index c96e24b35bc..faf551ca64c 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_definitions.h +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_definitions.h @@ -82,8 +82,8 @@ double my_random01(); // (0,1] //Edge type typedef struct { - igraph_integer_t from; - igraph_integer_t to; + igraph_int_t from; + igraph_int_t to; } edge; // Tag Int @@ -105,15 +105,15 @@ inline double logp(double x) { //Fast search or replace -inline igraph_integer_t* fast_rpl(igraph_integer_t *m, igraph_integer_t a, igraph_integer_t b) { +inline igraph_int_t* fast_rpl(igraph_int_t *m, igraph_int_t a, igraph_int_t b) { while (*m != a) { m++; } *m = b; return m; } -inline igraph_integer_t* fast_search(igraph_integer_t *m, igraph_integer_t size, igraph_integer_t a) { - igraph_integer_t *p = m + size; +inline igraph_int_t* fast_search(igraph_int_t *m, igraph_int_t size, igraph_int_t a) { + igraph_int_t *p = m + size; while (m != p--) { if (*p == a) { return p; diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_degree_sequence.cpp b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_degree_sequence.cpp index 2db0a080abd..347083dca1e 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_degree_sequence.cpp +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_degree_sequence.cpp @@ -33,11 +33,11 @@ using namespace std; namespace gengraph { -// shuffle an igraph_integer_t[] randomly -void random_permute(igraph_integer_t *a, igraph_integer_t n); +// shuffle an igraph_int_t[] randomly +void random_permute(igraph_int_t *a, igraph_int_t n); // sort an array of positive integers in time & place O(n + max) -void cumul_sort(igraph_integer_t *q, igraph_integer_t n); +void cumul_sort(igraph_int_t *q, igraph_int_t n); degree_sequence::~degree_sequence() { @@ -46,13 +46,13 @@ degree_sequence::~degree_sequence() { void degree_sequence::compute_total() { total = 0; - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { total += deg[i]; } } degree_sequence:: -degree_sequence(igraph_integer_t n0, igraph_integer_t *degs) { +degree_sequence(igraph_int_t n0, igraph_int_t *degs) { deg = degs; n = n0; compute_total(); @@ -71,11 +71,11 @@ degree_sequence(const igraph_vector_int_t *out_seq) { bool degree_sequence::havelhakimi() { - igraph_integer_t i; - igraph_integer_t dm = dmax() + 1; + igraph_int_t i; + igraph_int_t dm = dmax() + 1; // Sort vertices using basket-sort, in descending degrees - igraph_integer_t *nb = new igraph_integer_t[dm]; - igraph_integer_t *sorted = new igraph_integer_t[n]; + igraph_int_t *nb = new igraph_int_t[dm]; + igraph_int_t *sorted = new igraph_int_t[n]; // init basket for (i = 0; i < dm; i++) { nb[i] = 0; @@ -85,9 +85,9 @@ bool degree_sequence::havelhakimi() { nb[deg[i]]++; } // cumul - igraph_integer_t c = 0; + igraph_int_t c = 0; for (i = dm - 1; i >= 0; i--) { - igraph_integer_t t = nb[i]; + igraph_int_t t = nb[i]; nb[i] = c; c += t; } @@ -97,8 +97,8 @@ bool degree_sequence::havelhakimi() { } // Binding process starts - igraph_integer_t first = 0; // vertex with biggest residual degree - igraph_integer_t d = dm - 1; // maximum residual degree available + igraph_int_t first = 0; // vertex with biggest residual degree + igraph_int_t d = dm - 1; // maximum residual degree available for (c = total / 2; c > 0; ) { // We design by 'v' the vertex of highest degree (indexed by first) @@ -107,14 +107,14 @@ bool degree_sequence::havelhakimi() { d--; } // store it in dv - igraph_integer_t dv = d; + igraph_int_t dv = d; // bind it ! c -= dv; - igraph_integer_t dc = d; // residual degree of vertices we bind to - igraph_integer_t fc = ++first; // position of the first vertex with degree dc + igraph_int_t dc = d; // residual degree of vertices we bind to + igraph_int_t fc = ++first; // position of the first vertex with degree dc while (dv > 0 && dc > 0) { - igraph_integer_t lc = nb[dc]; + igraph_int_t lc = nb[dc]; if (lc != fc) { while (dv > 0 && lc > fc) { // binds v with sorted[--lc] diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_degree_sequence.h b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_degree_sequence.h index ef286bf0f8a..3d9eb5c92c7 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_degree_sequence.h +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_degree_sequence.h @@ -29,37 +29,37 @@ namespace gengraph { class degree_sequence { private: - igraph_integer_t n; - igraph_integer_t *deg; - igraph_integer_t total; + igraph_int_t n; + igraph_int_t *deg; + igraph_int_t total; public : // #vertices - inline igraph_integer_t size() { + inline igraph_int_t size() { return n; }; - inline igraph_integer_t sum() { + inline igraph_int_t sum() { return total; }; - inline igraph_integer_t operator[](igraph_integer_t i) { + inline igraph_int_t operator[](igraph_int_t i) { return deg[i]; }; - inline igraph_integer_t *seq() { + inline igraph_int_t *seq() { return deg; }; - inline void assign(igraph_integer_t n0, igraph_integer_t* d0) { + inline void assign(igraph_int_t n0, igraph_int_t* d0) { n = n0; deg = d0; }; - inline igraph_integer_t dmax() { - igraph_integer_t dm = deg[0]; - for (igraph_integer_t i = 1; i < n; i++) if (deg[i] > dm) { + inline igraph_int_t dmax() { + igraph_int_t dm = deg[0]; + for (igraph_int_t i = 1; i < n; i++) if (deg[i] > dm) { dm = deg[i]; } return dm; } - degree_sequence(igraph_integer_t n, igraph_integer_t *degs); + degree_sequence(igraph_int_t n, igraph_int_t *degs); // igraph constructor degree_sequence(const igraph_vector_int_t *out_seq); diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_hash.cpp b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_hash.cpp index 586d944fc4c..9d534fafbd2 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_hash.cpp +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_hash.cpp @@ -38,8 +38,8 @@ namespace gengraph { //_________________________________________________________________________ void graph_molloy_hash::compute_neigh() { - igraph_integer_t *p = links; - for (igraph_integer_t i = 0; i < n; i++) { + igraph_int_t *p = links; + for (igraph_int_t i = 0; i < n; i++) { neigh[i] = p; p += HASH_SIZE(deg[i]); } @@ -48,14 +48,14 @@ void graph_molloy_hash::compute_neigh() { //_________________________________________________________________________ void graph_molloy_hash::compute_size() { size = 0; - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { size += HASH_SIZE(deg[i]); } } //_________________________________________________________________________ void graph_molloy_hash::init() { - for (igraph_integer_t i = 0; i < size; i++) { + for (igraph_int_t i = 0; i < size; i++) { links[i] = HASH_NONE; } } @@ -66,29 +66,29 @@ graph_molloy_hash::graph_molloy_hash(degree_sequence °s) { } //_________________________________________________________________________ -igraph_integer_t graph_molloy_hash::alloc(degree_sequence °s) { +igraph_int_t graph_molloy_hash::alloc(degree_sequence °s) { n = degs.size(); a = degs.sum(); assert(a % 2 == 0); deg = degs.seq(); compute_size(); - deg = new igraph_integer_t[n + size]; + deg = new igraph_int_t[n + size]; if (deg == NULL) { return 0; } - igraph_integer_t i; + igraph_int_t i; for (i = 0; i < n; i++) { deg[i] = degs[i]; } links = deg + n; init(); - neigh = new igraph_integer_t*[n]; + neigh = new igraph_int_t*[n]; if (neigh == NULL) { return 0; } compute_neigh(); - return sizeof(igraph_integer_t *)*n + sizeof(igraph_integer_t) * (n + size); + return sizeof(igraph_int_t *)*n + sizeof(igraph_int_t) * (n + size); } //_________________________________________________________________________ @@ -104,7 +104,7 @@ graph_molloy_hash::~graph_molloy_hash() { } //_________________________________________________________________________ -graph_molloy_hash::graph_molloy_hash(igraph_integer_t *svg) { +graph_molloy_hash::graph_molloy_hash(igraph_int_t *svg) { // Read n n = *(svg++); // Read a @@ -119,15 +119,15 @@ graph_molloy_hash::graph_molloy_hash(igraph_integer_t *svg) { } //_________________________________________________________________________ -igraph_integer_t *graph_molloy_hash::hard_copy() { - igraph_integer_t *hc = new igraph_integer_t[2 + n + a / 2]; // to store n,a,deg[] and links[] +igraph_int_t *graph_molloy_hash::hard_copy() { + igraph_int_t *hc = new igraph_int_t[2 + n + a / 2]; // to store n,a,deg[] and links[] hc[0] = n; hc[1] = a; - memcpy(hc + 2, deg, sizeof(igraph_integer_t)*n); - igraph_integer_t *p = hc + 2 + n; - igraph_integer_t *l = links; - for (igraph_integer_t i = 0; i < n; i++) for (igraph_integer_t j = HASH_SIZE(deg[i]); j--; l++) { - igraph_integer_t d; + memcpy(hc + 2, deg, sizeof(igraph_int_t)*n); + igraph_int_t *p = hc + 2 + n; + igraph_int_t *l = links; + for (igraph_int_t i = 0; i < n; i++) for (igraph_int_t j = HASH_SIZE(deg[i]); j--; l++) { + igraph_int_t d; if ((d = *l) != HASH_NONE && d >= i) { *(p++) = d; } @@ -139,20 +139,20 @@ igraph_integer_t *graph_molloy_hash::hard_copy() { //_________________________________________________________________________ bool graph_molloy_hash::is_connected() { bool *visited = new bool[n]; - igraph_integer_t *buff = new igraph_integer_t[n]; - igraph_integer_t comp_size = depth_search(visited, buff); + igraph_int_t *buff = new igraph_int_t[n]; + igraph_int_t comp_size = depth_search(visited, buff); delete[] visited; delete[] buff; return (comp_size == n); } //_________________________________________________________________________ -igraph_integer_t* graph_molloy_hash::backup() { - igraph_integer_t *b = new igraph_integer_t[a / 2]; - igraph_integer_t *c = b; - igraph_integer_t *p = links; - for (igraph_integer_t i = 0; i < n; i++) - for (igraph_integer_t d = HASH_SIZE(deg[i]); d--; p++) if (*p != HASH_NONE && *p > i) { +igraph_int_t* graph_molloy_hash::backup() { + igraph_int_t *b = new igraph_int_t[a / 2]; + igraph_int_t *c = b; + igraph_int_t *p = links; + for (igraph_int_t i = 0; i < n; i++) + for (igraph_int_t d = HASH_SIZE(deg[i]); d--; p++) if (*p != HASH_NONE && *p > i) { *(c++) = *p; } assert(c == b + (a / 2)); @@ -160,11 +160,11 @@ igraph_integer_t* graph_molloy_hash::backup() { } //_________________________________________________________________________ -void graph_molloy_hash::restore(igraph_integer_t* b) { +void graph_molloy_hash::restore(igraph_int_t* b) { init(); - igraph_integer_t i; - igraph_integer_t *dd = new igraph_integer_t[n]; - memcpy(dd, deg, sizeof(igraph_integer_t)*n); + igraph_int_t i; + igraph_int_t *dd = new igraph_int_t[n]; + memcpy(dd, deg, sizeof(igraph_int_t)*n); for (i = 0; i < n; i++) { deg[i] = 0; } @@ -178,7 +178,7 @@ void graph_molloy_hash::restore(igraph_integer_t* b) { } //_________________________________________________________________________ -bool graph_molloy_hash::isolated(igraph_integer_t v, igraph_integer_t K, igraph_integer_t *Kbuff, bool *visited) { +bool graph_molloy_hash::isolated(igraph_int_t v, igraph_int_t K, igraph_int_t *Kbuff, bool *visited) { if (K < 2) { return false; } @@ -187,18 +187,18 @@ bool graph_molloy_hash::isolated(igraph_integer_t v, igraph_integer_t K, igraph_ return false; } #endif //OPT_ISOLATED - igraph_integer_t *seen = Kbuff; - igraph_integer_t *known = Kbuff; - igraph_integer_t *max = Kbuff + K; + igraph_int_t *seen = Kbuff; + igraph_int_t *known = Kbuff; + igraph_int_t *max = Kbuff + K; *(known++) = v; visited[v] = true; bool is_isolated = true; while (known != seen) { v = *(seen++); - igraph_integer_t *ww = neigh[v]; - igraph_integer_t w; - for (igraph_integer_t d = HASH_SIZE(deg[v]); d--; ww++) if ((w = *ww) != HASH_NONE && !visited[w]) { + igraph_int_t *ww = neigh[v]; + igraph_int_t w; + for (igraph_int_t d = HASH_SIZE(deg[v]); d--; ww++) if ((w = *ww) != HASH_NONE && !visited[w]) { #ifdef OPT_ISOLATED if (K <= deg[w] + 1 || known == max) { #else //OPT_ISOLATED @@ -220,19 +220,19 @@ bool graph_molloy_hash::isolated(igraph_integer_t v, igraph_integer_t K, igraph_ } //_________________________________________________________________________ -int graph_molloy_hash::random_edge_swap(igraph_integer_t K, igraph_integer_t *Kbuff, bool *visited) { +int graph_molloy_hash::random_edge_swap(igraph_int_t K, igraph_int_t *Kbuff, bool *visited) { // Pick two random vertices a and c - igraph_integer_t f1 = pick_random_vertex(); - igraph_integer_t f2 = pick_random_vertex(); + igraph_int_t f1 = pick_random_vertex(); + igraph_int_t f2 = pick_random_vertex(); // Check that f1 != f2 if (f1 == f2) { return 0; } // Get two random edges (f1,*f1t1) and (f2,*f2t2) - igraph_integer_t *f1t1 = random_neighbour(f1); - igraph_integer_t t1 = *f1t1; - igraph_integer_t *f2t2 = random_neighbour(f2); - igraph_integer_t t2 = *f2t2; + igraph_int_t *f1t1 = random_neighbour(f1); + igraph_int_t t1 = *f1t1; + igraph_int_t *f2t2 = random_neighbour(f2); + igraph_int_t t2 = *f2t2; // Check simplicity if (t1 == t2 || f1 == t2 || f2 == t1) { return 0; @@ -241,10 +241,10 @@ int graph_molloy_hash::random_edge_swap(igraph_integer_t K, igraph_integer_t *Kb return 0; } // Swap - igraph_integer_t *f1t2 = H_rpl(neigh[f1], deg[f1], f1t1, t2); - igraph_integer_t *f2t1 = H_rpl(neigh[f2], deg[f2], f2t2, t1); - igraph_integer_t *t1f2 = H_rpl(neigh[t1], deg[t1], f1, f2); - igraph_integer_t *t2f1 = H_rpl(neigh[t2], deg[t2], f2, f1); + igraph_int_t *f1t2 = H_rpl(neigh[f1], deg[f1], f1t1, t2); + igraph_int_t *f2t1 = H_rpl(neigh[f2], deg[f2], f2t2, t1); + igraph_int_t *t1f2 = H_rpl(neigh[t1], deg[t1], f1, f2); + igraph_int_t *t2f1 = H_rpl(neigh[t2], deg[t2], f2, f1); // isolation test if (K <= 2) { return 1; @@ -261,13 +261,13 @@ int graph_molloy_hash::random_edge_swap(igraph_integer_t K, igraph_integer_t *Kb } //_________________________________________________________________________ -igraph_integer_t graph_molloy_hash::shuffle(igraph_integer_t times, - igraph_integer_t maxtimes, int type) { +igraph_int_t graph_molloy_hash::shuffle(igraph_int_t times, + igraph_int_t maxtimes, int type) { igraph_progress("Shuffle", 0, 0); // assert(verify()); // counters - igraph_integer_t nb_swaps = 0; - igraph_integer_t all_swaps = 0; + igraph_int_t nb_swaps = 0; + igraph_int_t all_swaps = 0; unsigned long cost = 0; // window double T = double(((a < times) ? a : times) / 10); @@ -279,14 +279,14 @@ igraph_integer_t graph_molloy_hash::shuffle(igraph_integer_t times, } // isolation test parameter, and buffers double K = 2.4; - igraph_integer_t *Kbuff = new igraph_integer_t[int(K) + 1]; + igraph_int_t *Kbuff = new igraph_int_t[int(K) + 1]; bool *visited = new bool[n]; - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { visited[i] = false; } // Used for monitoring , active only if VERBOSE() - igraph_integer_t failures = 0; - igraph_integer_t successes = 0; + igraph_int_t failures = 0; + igraph_int_t successes = 0; double avg_K = 0; double avg_T = 0; unsigned long next = times; @@ -295,14 +295,14 @@ igraph_integer_t graph_molloy_hash::shuffle(igraph_integer_t times, // Shuffle: while #edge swap attempts validated by connectivity < times ... while (times > nb_swaps && maxtimes > all_swaps) { // Backup graph - igraph_integer_t *save = backup(); + igraph_int_t *save = backup(); // Prepare counters, K, T - igraph_integer_t swaps = 0; - igraph_integer_t K_int = 0; + igraph_int_t swaps = 0; + igraph_int_t K_int = 0; if (type == FINAL_HEURISTICS || type == BRUTE_FORCE_HEURISTICS) { - K_int = igraph_integer_t(K); + K_int = igraph_int_t(K); } - igraph_integer_t T_int = (igraph_integer_t)(floor(T)); + igraph_int_t T_int = (igraph_int_t)(floor(T)); if (T_int < 1) { T_int = 1; } @@ -312,7 +312,7 @@ igraph_integer_t graph_molloy_hash::shuffle(igraph_integer_t times, cost += K_int + T_int; } // Perform T edge swap attempts - for (igraph_integer_t i = T_int; i > 0; i--) { + for (igraph_int_t i = T_int; i > 0; i--) { // try one swap swaps += random_edge_swap(K_int, Kbuff, visited); all_swaps++; @@ -377,7 +377,7 @@ igraph_integer_t graph_molloy_hash::shuffle(igraph_integer_t times, } else { K *= 1.35; delete[] Kbuff; - Kbuff = new igraph_integer_t[igraph_integer_t(K) + 1]; + Kbuff = new igraph_int_t[igraph_int_t(K) + 1]; } break; case OPTIMAL_HEURISTICS: @@ -386,7 +386,7 @@ igraph_integer_t graph_molloy_hash::shuffle(igraph_integer_t times, } break; case BRUTE_FORCE_HEURISTICS: - K *= 2; delete[] Kbuff; Kbuff = new igraph_integer_t[igraph_integer_t(K) + 1]; + K *= 2; delete[] Kbuff; Kbuff = new igraph_int_t[igraph_int_t(K) + 1]; break; default: throw std::invalid_argument("Error in graph_molloy_hash::shuffle(): Unknown heuristics type."); @@ -407,7 +407,7 @@ igraph_integer_t graph_molloy_hash::shuffle(igraph_integer_t times, /* void graph_molloy_hash::print(FILE *f) { - igraph_integer_t i, j; + igraph_int_t i, j; for (i = 0; i < n; i++) { fprintf(f, "%" IGRAPH_PRId, i); for (j = 0; j < HASH_SIZE(deg[i]); j++) if (neigh[i][j] != HASH_NONE) { @@ -419,8 +419,8 @@ void graph_molloy_hash::print(FILE *f) { */ igraph_error_t graph_molloy_hash::print(igraph_t *graph) { - igraph_integer_t i, j; - igraph_integer_t ptr = 0; + igraph_int_t i, j; + igraph_int_t ptr = 0; igraph_vector_int_t edges; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, a); // every edge is counted twice.... @@ -444,18 +444,18 @@ igraph_error_t graph_molloy_hash::print(igraph_t *graph) { } //_________________________________________________________________________ -bool graph_molloy_hash::try_shuffle(igraph_integer_t T, igraph_integer_t K, igraph_integer_t *backup_graph) { +bool graph_molloy_hash::try_shuffle(igraph_int_t T, igraph_int_t K, igraph_int_t *backup_graph) { // init all - igraph_integer_t *Kbuff = NULL; + igraph_int_t *Kbuff = NULL; bool *visited = NULL; if (K > 2) { - Kbuff = new igraph_integer_t[K]; + Kbuff = new igraph_int_t[K]; visited = new bool[n]; - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { visited[i] = false; } } - igraph_integer_t *back = backup_graph; + igraph_int_t *back = backup_graph; if (back == NULL) { back = backup(); } @@ -506,7 +506,7 @@ bool bernoulli_param_is_lower(int success, int trials, double param) { //_________________________________________________________________________ #define _MIN_SUCCESS_FOR_BERNOULLI_TRUST 100 -double graph_molloy_hash::average_cost(igraph_integer_t T, igraph_integer_t *backup, double min_cost) { +double graph_molloy_hash::average_cost(igraph_int_t T, igraph_int_t *backup, double min_cost) { if (T < 1) { return 1e+99; } @@ -527,11 +527,11 @@ double graph_molloy_hash::average_cost(igraph_integer_t T, igraph_integer_t *bac } //_________________________________________________________________________ -igraph_integer_t graph_molloy_hash::optimal_window() { - igraph_integer_t Tmax; - igraph_integer_t optimal_T = 1; +igraph_int_t graph_molloy_hash::optimal_window() { + igraph_int_t Tmax; + igraph_int_t optimal_T = 1; double min_cost = 1e+99; - igraph_integer_t *back = backup(); + igraph_int_t *back = backup(); // on cherche une borne sup pour Tmax int been_greater = 0; for (Tmax = 1; Tmax <= 5 * a ; Tmax *= 2) { @@ -551,8 +551,8 @@ igraph_integer_t graph_molloy_hash::optimal_window() { double span = 2.0; int try_again = 4; while (span > 1.05 && optimal_T <= 5 * a) { - igraph_integer_t T_low = igraph_integer_t(double(optimal_T) / span); - igraph_integer_t T_high = igraph_integer_t(double(optimal_T) * span); + igraph_int_t T_low = igraph_int_t(double(optimal_T) / span); + igraph_int_t T_high = igraph_int_t(double(optimal_T) * span); double c_low = average_cost(T_low, back, min_cost); double c_high = average_cost(T_high, back, min_cost); if (c_low < min_cost && c_high < min_cost) { @@ -594,21 +594,21 @@ double graph_molloy_hash::eval_K(int quality) { } //_________________________________________________________________________ -double graph_molloy_hash::effective_K(igraph_integer_t K, int quality) { +double graph_molloy_hash::effective_K(igraph_int_t K, int quality) { if (K < 3) { return 0.0; } long sum_K = 0; - igraph_integer_t *Kbuff = new igraph_integer_t[K]; + igraph_int_t *Kbuff = new igraph_int_t[K]; bool *visited = new bool[n]; - igraph_integer_t i; + igraph_int_t i; for (i = 0; i < n; i++) { visited[i] = false; } for (i = 0; i < quality; i++) { // assert(verify()); - igraph_integer_t f1, f2, t1, t2; - igraph_integer_t *f1t1, *f2t2; + igraph_int_t f1, f2, t1, t2; + igraph_int_t *f1t1, *f2t2; do { // Pick two random vertices do { @@ -639,14 +639,14 @@ double graph_molloy_hash::effective_K(igraph_integer_t K, int quality) { } //_________________________________________________________________________ -igraph_integer_t graph_molloy_hash::effective_isolated(igraph_integer_t v, igraph_integer_t K, igraph_integer_t *Kbuff, bool *visited) { - igraph_integer_t i; +igraph_int_t graph_molloy_hash::effective_isolated(igraph_int_t v, igraph_int_t K, igraph_int_t *Kbuff, bool *visited) { + igraph_int_t i; for (i = 0; i < K; i++) { Kbuff[i] = -1; } - igraph_integer_t count = 0; - igraph_integer_t left = K; - igraph_integer_t *KB = Kbuff; + igraph_int_t count = 0; + igraph_int_t left = K; + igraph_int_t *KB = Kbuff; //yapido = (my_random()%1000 == 0); depth_isolated(v, count, left, K, KB, visited); while (KB-- != Kbuff) { @@ -657,7 +657,7 @@ igraph_integer_t graph_molloy_hash::effective_isolated(igraph_integer_t v, igrap } //_________________________________________________________________________ -void graph_molloy_hash::depth_isolated(igraph_integer_t v, igraph_integer_t &calls, igraph_integer_t &left_to_explore, igraph_integer_t dmax, igraph_integer_t * &Kbuff, bool *visited) { +void graph_molloy_hash::depth_isolated(igraph_int_t v, igraph_int_t &calls, igraph_int_t &left_to_explore, igraph_int_t dmax, igraph_int_t * &Kbuff, bool *visited) { if (left_to_explore == 0) { return; } @@ -674,16 +674,16 @@ void graph_molloy_hash::depth_isolated(igraph_integer_t v, igraph_integer_t &cal // print(); // fflush(stdout); calls++; - igraph_integer_t *copy = NULL; - igraph_integer_t *w = neigh[v]; + igraph_int_t *copy = NULL; + igraph_int_t *w = neigh[v]; if (IS_HASH(deg[v])) { - copy = new igraph_integer_t[deg[v]]; + copy = new igraph_int_t[deg[v]]; H_copy(copy, w, deg[v]); w = copy; } qsort(deg, w, deg[v]); w += deg[v]; - for (igraph_integer_t i = deg[v]; i--; ) { + for (igraph_int_t i = deg[v]; i--; ) { if (visited[*--w]) { calls++; } else { @@ -699,19 +699,19 @@ void graph_molloy_hash::depth_isolated(igraph_integer_t v, igraph_integer_t &cal } //_________________________________________________________________________ -igraph_integer_t graph_molloy_hash::depth_search(bool *visited, igraph_integer_t *buff, igraph_integer_t v0) { - for (igraph_integer_t i = 0; i < n; i++) { +igraph_int_t graph_molloy_hash::depth_search(bool *visited, igraph_int_t *buff, igraph_int_t v0) { + for (igraph_int_t i = 0; i < n; i++) { visited[i] = false; } - igraph_integer_t *to_visit = buff; - igraph_integer_t nb_visited = 1; + igraph_int_t *to_visit = buff; + igraph_int_t nb_visited = 1; visited[v0] = true; *(to_visit++) = v0; while (to_visit != buff && nb_visited < n) { - igraph_integer_t v = *(--to_visit); - igraph_integer_t *ww = neigh[v]; - igraph_integer_t w; - for (igraph_integer_t k = HASH_SIZE(deg[v]); k--; ww++) { + igraph_int_t v = *(--to_visit); + igraph_int_t *ww = neigh[v]; + igraph_int_t w; + for (igraph_int_t k = HASH_SIZE(deg[v]); k--; ww++) { if (HASH_NONE != (w = *ww) && !visited[w]) { visited[w] = true; nb_visited++; diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_hash.h b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_hash.h index 086bcd9e082..ae19f71f711 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_hash.h +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_hash.h @@ -47,27 +47,27 @@ class graph_molloy_hash { private: // Number of vertices - igraph_integer_t n; + igraph_int_t n; //Number of arcs ( = #edges * 2 ) - igraph_integer_t a; + igraph_int_t a; //Total size of links[] - igraph_integer_t size; + igraph_int_t size; // The degree sequence of the graph - igraph_integer_t *deg; + igraph_int_t *deg; // The array containing all links - igraph_integer_t *links; + igraph_int_t *links; // The array containing pointers to adjacency list of every vertices - igraph_integer_t **neigh; + igraph_int_t **neigh; // Counts total size void compute_size(); // Build neigh with deg and links void compute_neigh(); // Allocate memory according to degree_sequence (for constructor use only!!) - igraph_integer_t alloc(degree_sequence &); + igraph_int_t alloc(degree_sequence &); // Add edge (u,v). Return FALSE if vertex a is already full. // WARNING : only to be used by havelhakimi(), restore() or constructors - inline bool add_edge(igraph_integer_t u, igraph_integer_t v, igraph_integer_t *realdeg) { - igraph_integer_t deg_u = realdeg[u]; + inline bool add_edge(igraph_int_t u, igraph_int_t v, igraph_int_t *realdeg) { + igraph_int_t deg_u = realdeg[u]; if (deg_u == deg[u]) { return false; } @@ -75,7 +75,7 @@ class graph_molloy_hash { assert(fast_search(neigh[u], (u == n - 1 ? links + size : neigh[u + 1]) - neigh[u], v) == NULL); assert(fast_search(neigh[v], (v == n - 1 ? links + size : neigh[v + 1]) - neigh[v], u) == NULL); assert(deg[u] < deg_u); - igraph_integer_t deg_v = realdeg[v]; + igraph_int_t deg_v = realdeg[v]; if (IS_HASH(deg_u)) { *H_add(neigh[u], HASH_EXPAND(deg_u), v) = v; } else { @@ -94,39 +94,39 @@ class graph_molloy_hash { return true; } // Swap edges - inline void swap_edges(igraph_integer_t from1, igraph_integer_t to1, igraph_integer_t from2, igraph_integer_t to2) { + inline void swap_edges(igraph_int_t from1, igraph_int_t to1, igraph_int_t from2, igraph_int_t to2) { H_rpl(neigh[from1], deg[from1], to1, to2); H_rpl(neigh[from2], deg[from2], to2, to1); H_rpl(neigh[to1], deg[to1], from1, from2); H_rpl(neigh[to2], deg[to2], from2, from1); } - // Backup graph [sizeof(igraph_integer_t) bytes per edge] - igraph_integer_t* backup(); + // Backup graph [sizeof(igraph_int_t) bytes per edge] + igraph_int_t* backup(); // Test if vertex is in an isolated component of size dmax. - void depth_isolated(igraph_integer_t v, igraph_integer_t &calls, igraph_integer_t &left_to_explore, igraph_integer_t dmax, igraph_integer_t * &Kbuff, bool *visited); + void depth_isolated(igraph_int_t v, igraph_int_t &calls, igraph_int_t &left_to_explore, igraph_int_t dmax, igraph_int_t * &Kbuff, bool *visited); public: //degree of v - inline igraph_integer_t degree(igraph_integer_t v) { + inline igraph_int_t degree(igraph_int_t v) { return deg[v]; }; // For debug purposes : verify validity of the graph (symetry, simplicity) @@ -136,19 +136,19 @@ class graph_molloy_hash { // Allocate memory for the graph. Create deg and links. No edge is created. graph_molloy_hash(degree_sequence &); // Create graph from hard copy - graph_molloy_hash(igraph_integer_t *); + graph_molloy_hash(igraph_int_t *); // Create hard copy of graph - igraph_integer_t *hard_copy(); + igraph_int_t *hard_copy(); // Restore from backup - void restore(igraph_integer_t* back); + void restore(igraph_int_t* back); //Clear hash tables void init(); // nb arcs - inline igraph_integer_t nbarcs() { + inline igraph_int_t nbarcs() { return a; }; // nb vertices - inline igraph_integer_t nbvertices() { + inline igraph_int_t nbvertices() { return n; }; // print graph in SUCC_LIST mode, in stdout @@ -157,7 +157,7 @@ class graph_molloy_hash { // Test if graph is connected bool is_connected(); // is edge ? - inline bool is_edge(igraph_integer_t u, igraph_integer_t v) { + inline bool is_edge(igraph_int_t u, igraph_int_t v) { assert(H_is(neigh[u], deg[u], v) == (fast_search(neigh[u], HASH_SIZE(deg[u]), v) != NULL)); assert(H_is(neigh[v], deg[v], u) == (fast_search(neigh[v], HASH_SIZE(deg[v]), u) != NULL)); assert(H_is(neigh[u], deg[u], v) == H_is(neigh[v], deg[v], u)); @@ -168,19 +168,19 @@ class graph_molloy_hash { } } // Random edge swap ATTEMPT. Return 1 if attempt was a succes, 0 otherwise - int random_edge_swap(igraph_integer_t K = 0, igraph_integer_t *Kbuff = NULL, bool *visited = NULL); + int random_edge_swap(igraph_int_t K = 0, igraph_int_t *Kbuff = NULL, bool *visited = NULL); // Connected Shuffle - igraph_integer_t shuffle(igraph_integer_t, igraph_integer_t, int type); + igraph_int_t shuffle(igraph_int_t, igraph_int_t, int type); // Optimal window for the gkantsidis heuristics - igraph_integer_t optimal_window(); + igraph_int_t optimal_window(); // Average unitary cost per post-validated edge swap, for some window - double average_cost(igraph_integer_t T, igraph_integer_t *back, double min_cost); + double average_cost(igraph_int_t T, igraph_int_t *back, double min_cost); // Get caracteristic K double eval_K(int quality = 100); // Get effective K - double effective_K(igraph_integer_t K, int quality = 10000); + double effective_K(igraph_int_t K, int quality = 10000); // Try to shuffle T times. Return true if at the end, the graph was still connected. - bool try_shuffle(igraph_integer_t T, igraph_integer_t K, igraph_integer_t *back = NULL); + bool try_shuffle(igraph_int_t T, igraph_int_t K, igraph_int_t *back = NULL); }; } // namespace gengraph diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_optimized.cpp b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_optimized.cpp index dc45a2aba4c..f5049ce99c7 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_optimized.cpp +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_optimized.cpp @@ -37,17 +37,17 @@ using namespace std; namespace gengraph { -igraph_integer_t graph_molloy_opt::max_degree() { - igraph_integer_t m = 0; - for (igraph_integer_t k = 0; k < n; k++) if (deg[k] > m) { +igraph_int_t graph_molloy_opt::max_degree() { + igraph_int_t m = 0; + for (igraph_int_t k = 0; k < n; k++) if (deg[k] > m) { m = deg[k]; } return m; } void graph_molloy_opt::compute_neigh() { - igraph_integer_t *p = links; - for (igraph_integer_t i = 0; i < n; i++) { + igraph_int_t *p = links; + for (igraph_int_t i = 0; i < n; i++) { neigh[i] = p; p += deg[i]; } @@ -57,12 +57,12 @@ void graph_molloy_opt::alloc(degree_sequence °s) { n = degs.size(); a = degs.sum(); assert(a % 2 == 0); - deg = new igraph_integer_t[n + a]; - for (igraph_integer_t i = 0; i < n; i++) { + deg = new igraph_int_t[n + a]; + for (igraph_int_t i = 0; i < n; i++) { deg[i] = degs[i]; } links = deg + n; - neigh = new igraph_integer_t*[n]; + neigh = new igraph_int_t*[n]; compute_neigh(); } @@ -119,7 +119,7 @@ graph_molloy_opt::graph_molloy_opt(degree_sequence °s) { // if(VERBOSE()) fprintf(stderr,"done\n"); // } -graph_molloy_opt::graph_molloy_opt(igraph_integer_t *svg) { +graph_molloy_opt::graph_molloy_opt(igraph_int_t *svg) { // Read n n = *(svg++); // Read a @@ -148,14 +148,14 @@ graph_molloy_opt::~graph_molloy_opt() { detach(); } -igraph_integer_t* graph_molloy_opt::backup(igraph_integer_t *b) { +igraph_int_t* graph_molloy_opt::backup(igraph_int_t *b) { if (b == NULL) { - b = new igraph_integer_t[a / 2]; + b = new igraph_int_t[a / 2]; } - igraph_integer_t *c = b; - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t *p = neigh[i]; - for (igraph_integer_t d = deg[i]; d--; p++) { + igraph_int_t *c = b; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t *p = neigh[i]; + for (igraph_int_t d = deg[i]; d--; p++) { assert(*p != i); if (*p >= i) { *(c++) = *p; @@ -166,15 +166,15 @@ igraph_integer_t* graph_molloy_opt::backup(igraph_integer_t *b) { return b; } -igraph_integer_t *graph_molloy_opt::hard_copy() { - igraph_integer_t *hc = new igraph_integer_t[2 + n + a / 2]; // to store n,a,deg[] and links[] +igraph_int_t *graph_molloy_opt::hard_copy() { + igraph_int_t *hc = new igraph_int_t[2 + n + a / 2]; // to store n,a,deg[] and links[] hc[0] = n; hc[1] = a; - memcpy(hc + 2, deg, sizeof(igraph_integer_t)*n); - igraph_integer_t *c = hc + 2 + n; - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t *p = neigh[i]; - for (igraph_integer_t d = deg[i]; d--; p++) { + memcpy(hc + 2, deg, sizeof(igraph_int_t)*n); + igraph_int_t *c = hc + 2 + n; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t *p = neigh[i]; + for (igraph_int_t d = deg[i]; d--; p++) { assert(*p != i); if (*p >= i) { *(c++) = *p; @@ -185,15 +185,15 @@ igraph_integer_t *graph_molloy_opt::hard_copy() { return hc; } -void graph_molloy_opt::restore(igraph_integer_t* b) { - igraph_integer_t i; +void graph_molloy_opt::restore(igraph_int_t* b) { + igraph_int_t i; for (i = 0; i < n; i++) { deg[i] = 0; } - igraph_integer_t *p = links; + igraph_int_t *p = links; for (i = 0; i < n - 1; i++) { p += deg[i]; - deg[i] = igraph_integer_t(neigh[i + 1] - neigh[i]); + deg[i] = igraph_int_t(neigh[i + 1] - neigh[i]); assert((neigh[i] + deg[i]) == neigh[i + 1]); while (p != neigh[i + 1]) { // b points to the current 'j' @@ -203,95 +203,95 @@ void graph_molloy_opt::restore(igraph_integer_t* b) { } } -igraph_integer_t* graph_molloy_opt::backup_degs(igraph_integer_t *b) { +igraph_int_t* graph_molloy_opt::backup_degs(igraph_int_t *b) { if (b == NULL) { - b = new igraph_integer_t[n]; + b = new igraph_int_t[n]; } - memcpy(b, deg, sizeof(igraph_integer_t)*n); + memcpy(b, deg, sizeof(igraph_int_t)*n); return b; } -void graph_molloy_opt::restore_degs_only(igraph_integer_t *b) { - memcpy(deg, b, sizeof(igraph_integer_t)*n); +void graph_molloy_opt::restore_degs_only(igraph_int_t *b) { + memcpy(deg, b, sizeof(igraph_int_t)*n); refresh_nbarcs(); } -void graph_molloy_opt::restore_degs_and_neigh(igraph_integer_t *b) { +void graph_molloy_opt::restore_degs_and_neigh(igraph_int_t *b) { restore_degs_only(b); compute_neigh(); } -void graph_molloy_opt::restore_degs(igraph_integer_t last_degree) { +void graph_molloy_opt::restore_degs(igraph_int_t last_degree) { a = last_degree; deg[n - 1] = last_degree; - for (igraph_integer_t i = n - 2; i >= 0; i--) { - a += (deg[i] = igraph_integer_t(neigh[i + 1] - neigh[i])); + for (igraph_int_t i = n - 2; i >= 0; i--) { + a += (deg[i] = igraph_int_t(neigh[i + 1] - neigh[i])); } refresh_nbarcs(); } void graph_molloy_opt::clean() { - igraph_integer_t *b = hard_copy(); + igraph_int_t *b = hard_copy(); replace(b); delete[] b; } -void graph_molloy_opt::replace(igraph_integer_t *_hardcopy) { +void graph_molloy_opt::replace(igraph_int_t *_hardcopy) { delete[] deg; n = *(_hardcopy++); a = *(_hardcopy++); - deg = new igraph_integer_t[a + n]; - memcpy(deg, _hardcopy, sizeof(igraph_integer_t)*n); + deg = new igraph_int_t[a + n]; + memcpy(deg, _hardcopy, sizeof(igraph_int_t)*n); links = deg + n; compute_neigh(); restore(_hardcopy + n); } -igraph_integer_t* graph_molloy_opt::components(igraph_integer_t *comp) { - igraph_integer_t i; +igraph_int_t* graph_molloy_opt::components(igraph_int_t *comp) { + igraph_int_t i; // breadth-first search buffer - igraph_integer_t *buff = new igraph_integer_t[n]; + igraph_int_t *buff = new igraph_int_t[n]; // comp[i] will contain the index of the component that contains vertex i if (comp == NULL) { - comp = new igraph_integer_t[n]; + comp = new igraph_int_t[n]; } - memset(comp, 0, sizeof(igraph_integer_t)*n); + memset(comp, 0, sizeof(igraph_int_t)*n); // current component index - igraph_integer_t curr_comp = 0; + igraph_int_t curr_comp = 0; // loop over all non-visited vertices... - for (igraph_integer_t v0 = 0; v0 < n; v0++) if (comp[v0] == 0) { + for (igraph_int_t v0 = 0; v0 < n; v0++) if (comp[v0] == 0) { curr_comp++; // initiate breadth-first search - igraph_integer_t *to_visit = buff; - igraph_integer_t *visited = buff; + igraph_int_t *to_visit = buff; + igraph_int_t *visited = buff; *(to_visit++) = v0; comp[v0] = curr_comp; // breadth-first search while (visited != to_visit) { - igraph_integer_t v = *(visited++); - igraph_integer_t d = deg[v]; - for (igraph_integer_t *w = neigh[v]; d--; w++) if (comp[*w] == 0) { + igraph_int_t v = *(visited++); + igraph_int_t d = deg[v]; + for (igraph_int_t *w = neigh[v]; d--; w++) if (comp[*w] == 0) { comp[*w] = curr_comp; *(to_visit++) = *w; } } } // compute component sizes and store them in buff[] - igraph_integer_t nb_comp = 0; - memset(buff, 0, sizeof(igraph_integer_t)*n); + igraph_int_t nb_comp = 0; + memset(buff, 0, sizeof(igraph_int_t)*n); for (i = 0; i < n; i++) if (buff[comp[i] - 1]++ == 0 && comp[i] > nb_comp) { nb_comp = comp[i]; } // box-sort sizes - igraph_integer_t offset = 0; - igraph_integer_t *box = pre_boxsort(buff, nb_comp, offset); + igraph_int_t offset = 0; + igraph_int_t *box = pre_boxsort(buff, nb_comp, offset); for (i = nb_comp - 1; i >= 0; i--) { buff[i] = --box[buff[i] - offset]; } delete[] box; // reassign component indexes - for (igraph_integer_t *c = comp + n; comp != c--; *c = buff[*c - 1]) { } + for (igraph_int_t *c = comp + n; comp != c--; *c = buff[*c - 1]) { } // clean.. at last! delete[] buff; return comp; @@ -299,11 +299,11 @@ igraph_integer_t* graph_molloy_opt::components(igraph_integer_t *comp) { bool graph_molloy_opt::havelhakimi() { - igraph_integer_t i; - igraph_integer_t dmax = max_degree() + 1; + igraph_int_t i; + igraph_int_t dmax = max_degree() + 1; // Sort vertices using basket-sort, in descending degrees - igraph_integer_t *nb = new igraph_integer_t[dmax]; - igraph_integer_t *sorted = new igraph_integer_t[n]; + igraph_int_t *nb = new igraph_int_t[dmax]; + igraph_int_t *sorted = new igraph_int_t[n]; // init basket for (i = 0; i < dmax; i++) { nb[i] = 0; @@ -313,7 +313,7 @@ bool graph_molloy_opt::havelhakimi() { nb[deg[i]]++; } // cumul - igraph_integer_t c = 0; + igraph_int_t c = 0; for (i = dmax - 1; i >= 0; i--) { c += nb[i]; nb[i] = -nb[i] + c; @@ -324,30 +324,30 @@ bool graph_molloy_opt::havelhakimi() { } // Binding process starts - igraph_integer_t first = 0; // vertex with biggest residual degree - igraph_integer_t d = dmax - 1; // maximum residual degree available + igraph_int_t first = 0; // vertex with biggest residual degree + igraph_int_t d = dmax - 1; // maximum residual degree available for (c = a / 2; c > 0; ) { // pick a vertex. we could pick any, but here we pick the one with biggest degree - igraph_integer_t v = sorted[first]; + igraph_int_t v = sorted[first]; // look for current degree of v while (nb[d] <= first) { d--; } // store it in dv - igraph_integer_t dv = d; + igraph_int_t dv = d; // bind it ! c -= dv; - igraph_integer_t dc = d; // residual degree of vertices we bind to - igraph_integer_t fc = ++first; // position of the first vertex with degree dc + igraph_int_t dc = d; // residual degree of vertices we bind to + igraph_int_t fc = ++first; // position of the first vertex with degree dc while (dv > 0 && dc > 0) { - igraph_integer_t lc = nb[dc]; + igraph_int_t lc = nb[dc]; if (lc != fc) { while (dv > 0 && lc > fc) { // binds v with sorted[--lc] dv--; - igraph_integer_t w = sorted[--lc]; + igraph_int_t w = sorted[--lc]; *(neigh[v]++) = w; *(neigh[w]++) = v; } @@ -381,16 +381,16 @@ bool graph_molloy_opt::havelhakimi() { bool graph_molloy_opt::is_connected() { bool *visited = new bool[n]; - for (igraph_integer_t i = n; i > 0; visited[--i] = false) { } - igraph_integer_t *to_visit = new igraph_integer_t[n]; - igraph_integer_t *stop = to_visit; - igraph_integer_t left = n - 1; + for (igraph_int_t i = n; i > 0; visited[--i] = false) { } + igraph_int_t *to_visit = new igraph_int_t[n]; + igraph_int_t *stop = to_visit; + igraph_int_t left = n - 1; *(to_visit++) = 0; visited[0] = true; while (left > 0 && to_visit != stop) { - igraph_integer_t v = *(--to_visit); - igraph_integer_t *w = neigh[v]; - for (igraph_integer_t k = deg[v]; k--; w++) { + igraph_int_t v = *(--to_visit); + igraph_int_t *w = neigh[v]; + for (igraph_int_t k = deg[v]; k--; w++) { if (!visited[*w]) { visited[*w] = true; left--; @@ -411,13 +411,13 @@ bool graph_molloy_opt::make_connected() { // fprintf(stderr,"\ngraph::make_connected() failed : #edges < #vertices-1\n"); return false; } - igraph_integer_t i; + igraph_int_t i; // Data struct for the visit : // - buff[] contains vertices to visit // - dist[V] is V's distance modulo 4 to the root of its comp, or -1 if it hasn't been visited yet #define MC_BUFF_SIZE (n+2) - igraph_integer_t *buff = new igraph_integer_t[MC_BUFF_SIZE]; + igraph_int_t *buff = new igraph_int_t[MC_BUFF_SIZE]; unsigned char * dist = new unsigned char[n]; #define NOT_VISITED 255 #define FORBIDDEN 254 @@ -426,17 +426,17 @@ bool graph_molloy_opt::make_connected() { // Data struct to store components : either surplus trees or surplus edges are stored at buff[]'s end // - A Tree is coded by one of its vertices // - An edge (a,b) is coded by the TWO ints a and b - igraph_integer_t *ffub = buff + MC_BUFF_SIZE; + igraph_int_t *ffub = buff + MC_BUFF_SIZE; edge *edges = (edge *) ffub; - igraph_integer_t *trees = ffub; - igraph_integer_t *min_ffub = buff + 1 + (MC_BUFF_SIZE % 2 ? 0 : 1); + igraph_int_t *trees = ffub; + igraph_int_t *min_ffub = buff + 1 + (MC_BUFF_SIZE % 2 ? 0 : 1); // There will be only one "fatty" component, and trees. edge fatty_edge = { -1, -1 }; bool enough_edges = false; // start main loop - for (igraph_integer_t v0 = 0; v0 < n; v0++) if (dist[v0] == NOT_VISITED) { + for (igraph_int_t v0 = 0; v0 < n; v0++) if (dist[v0] == NOT_VISITED) { // is v0 an isolated vertex? if (deg[v0] == 0) { delete[] dist; @@ -445,20 +445,20 @@ bool graph_molloy_opt::make_connected() { return false; } dist[v0] = 0; // root - igraph_integer_t *to_visit = buff; - igraph_integer_t *current = buff; + igraph_int_t *to_visit = buff; + igraph_int_t *current = buff; *(to_visit++) = v0; // explore component connected to v0 bool is_a_tree = true; while (current != to_visit) { - igraph_integer_t v = *(current++); + igraph_int_t v = *(current++); unsigned char current_dist = dist[v]; unsigned char next_dist = (current_dist + 1) & 0x03; //unsigned char prev_dist = (current_dist-1) & 0x03; - igraph_integer_t* ww = neigh[v]; - igraph_integer_t w; - for (igraph_integer_t k = deg[v]; k--; ww++) { + igraph_int_t* ww = neigh[v]; + igraph_int_t w; + for (igraph_int_t k = deg[v]; k--; ww++) { if (dist[w = *ww] == NOT_VISITED) { // we didn't visit *w yet dist[w] = next_dist; @@ -539,7 +539,7 @@ bool graph_molloy_opt::make_connected() { return (trees == ffub || ((trees + 1) == ffub && fatty_edge.from < 0)); } -bool graph_molloy_opt::swap_edges_simple(igraph_integer_t from1, igraph_integer_t to1, igraph_integer_t from2, igraph_integer_t to2) { +bool graph_molloy_opt::swap_edges_simple(igraph_int_t from1, igraph_int_t to1, igraph_int_t from2, igraph_int_t to2) { if (from1 == to1 || from1 == from2 || from1 == to2 || to1 == from2 || to1 == to2 || from2 == to2) { return false; } @@ -551,7 +551,7 @@ bool graph_molloy_opt::swap_edges_simple(igraph_integer_t from1, igraph_integer_ } void graph_molloy_opt::print(FILE *f, bool NOZERO) { - igraph_integer_t i, j; + igraph_int_t i, j; for (i = 0; i < n; i++) { if (!NOZERO || deg[i] > 0) { fprintf(f, "%" IGRAPH_PRId, i); @@ -563,14 +563,14 @@ void graph_molloy_opt::print(FILE *f, bool NOZERO) { } } -igraph_integer_t graph_molloy_opt::effective_isolated(igraph_integer_t v, igraph_integer_t K, igraph_integer_t *Kbuff, bool *visited) { - igraph_integer_t i; +igraph_int_t graph_molloy_opt::effective_isolated(igraph_int_t v, igraph_int_t K, igraph_int_t *Kbuff, bool *visited) { + igraph_int_t i; for (i = 0; i < K; i++) { Kbuff[i] = -1; } - igraph_integer_t count = 0; - igraph_integer_t left = K; - igraph_integer_t *KB = Kbuff; + igraph_int_t count = 0; + igraph_int_t left = K; + igraph_int_t *KB = Kbuff; //yapido = (my_random()%1000 == 0); depth_isolated(v, count, left, K, KB, visited); while (KB-- != Kbuff) { @@ -580,7 +580,7 @@ igraph_integer_t graph_molloy_opt::effective_isolated(igraph_integer_t v, igraph return count; } -void graph_molloy_opt::depth_isolated(igraph_integer_t v, igraph_integer_t &calls, igraph_integer_t &left_to_explore, igraph_integer_t dmax, igraph_integer_t * &Kbuff, bool *visited) { +void graph_molloy_opt::depth_isolated(igraph_int_t v, igraph_int_t &calls, igraph_int_t &left_to_explore, igraph_int_t dmax, igraph_int_t * &Kbuff, bool *visited) { if (left_to_explore == 0) { return; } @@ -595,10 +595,10 @@ void graph_molloy_opt::depth_isolated(igraph_integer_t v, igraph_integer_t &call *(Kbuff++) = v; visited[v] = true; calls++; - igraph_integer_t *w = neigh[v]; + igraph_int_t *w = neigh[v]; qsort(deg, w, deg[v]); w += deg[v]; - for (igraph_integer_t i = deg[v]; i--; ) { + for (igraph_int_t i = deg[v]; i--; ) { if (visited[*--w]) { calls++; } else { @@ -610,19 +610,19 @@ void graph_molloy_opt::depth_isolated(igraph_integer_t v, igraph_integer_t &call } } -igraph_integer_t graph_molloy_opt::depth_search(bool *visited, igraph_integer_t *buff, igraph_integer_t v0) { - for (igraph_integer_t i = 0; i < n; i++) { +igraph_int_t graph_molloy_opt::depth_search(bool *visited, igraph_int_t *buff, igraph_int_t v0) { + for (igraph_int_t i = 0; i < n; i++) { visited[i] = false; } - igraph_integer_t *to_visit = buff; - igraph_integer_t nb_visited = 1; + igraph_int_t *to_visit = buff; + igraph_int_t nb_visited = 1; visited[v0] = true; *(to_visit++) = v0; while (to_visit != buff && nb_visited < n) { - igraph_integer_t v = *(--to_visit); - igraph_integer_t *ww = neigh[v]; - igraph_integer_t w; - for (igraph_integer_t k = deg[v]; k--; ww++) if (!visited[w = *ww]) { + igraph_int_t v = *(--to_visit); + igraph_int_t *ww = neigh[v]; + igraph_int_t w; + for (igraph_int_t k = deg[v]; k--; ww++) if (!visited[w = *ww]) { visited[w] = true; nb_visited++; *(to_visit++) = w; @@ -631,23 +631,23 @@ igraph_integer_t graph_molloy_opt::depth_search(bool *visited, igraph_integer_t return nb_visited; } -igraph_integer_t graph_molloy_opt::width_search(unsigned char *dist, igraph_integer_t *buff, igraph_integer_t v0, igraph_integer_t toclear) { - if (toclear >= 0) for (igraph_integer_t i = 0; i < toclear; i++) { +igraph_int_t graph_molloy_opt::width_search(unsigned char *dist, igraph_int_t *buff, igraph_int_t v0, igraph_int_t toclear) { + if (toclear >= 0) for (igraph_int_t i = 0; i < toclear; i++) { dist[buff[i]] = 0; - } else for (igraph_integer_t i = 0; i < n; i++) { + } else for (igraph_int_t i = 0; i < n; i++) { dist[i] = 0; } - igraph_integer_t *to_visit = buff; - igraph_integer_t *to_add = buff; - igraph_integer_t nb_visited = 1; + igraph_int_t *to_visit = buff; + igraph_int_t *to_add = buff; + igraph_int_t nb_visited = 1; dist[v0] = 1; *(to_add++) = v0; while (to_visit != to_add && nb_visited < n) { - igraph_integer_t v = *(to_visit++); - igraph_integer_t *ww = neigh[v]; - igraph_integer_t w; + igraph_int_t v = *(to_visit++); + igraph_int_t *ww = neigh[v]; + igraph_int_t w; unsigned char d = next_dist(dist[v]); - for (igraph_integer_t k = deg[v]; k--; ww++) if (dist[w = *ww] == 0) { + for (igraph_int_t k = deg[v]; k--; ww++) if (dist[w = *ww] == 0) { dist[w] = d; nb_visited++; *(to_add++) = w; @@ -657,25 +657,25 @@ igraph_integer_t graph_molloy_opt::width_search(unsigned char *dist, igraph_inte } // dist[] MUST be full of zeros !!!! -igraph_integer_t graph_molloy_opt::breadth_path_search(igraph_integer_t src, igraph_integer_t *buff, double *paths, unsigned char *dist) { +igraph_int_t graph_molloy_opt::breadth_path_search(igraph_int_t src, igraph_int_t *buff, double *paths, unsigned char *dist) { unsigned char last_dist = 0; unsigned char curr_dist = 1; - igraph_integer_t *to_visit = buff; - igraph_integer_t *visited = buff; + igraph_int_t *to_visit = buff; + igraph_int_t *visited = buff; *(to_visit++) = src; paths[src] = 1.0; dist[src] = curr_dist; - igraph_integer_t nb_visited = 1; + igraph_int_t nb_visited = 1; while (visited != to_visit) { - igraph_integer_t v = *(visited++); + igraph_int_t v = *(visited++); if (last_dist == (curr_dist = dist[v])) { break; } unsigned char nd = next_dist(curr_dist); - igraph_integer_t *ww = neigh[v]; + igraph_int_t *ww = neigh[v]; double p = paths[v]; - for (igraph_integer_t k = deg[v]; k--;) { - igraph_integer_t w = *(ww++); + for (igraph_int_t k = deg[v]; k--;) { + igraph_int_t w = *(ww++); unsigned char d = dist[w]; if (d == 0) { // not visited yet ! @@ -697,8 +697,8 @@ igraph_integer_t graph_molloy_opt::breadth_path_search(igraph_integer_t src, igr return nb_visited; } -igraph_integer_t *graph_molloy_opt::vertices_real(igraph_integer_t &nb_v) { - igraph_integer_t *yo; +igraph_int_t *graph_molloy_opt::vertices_real(igraph_int_t &nb_v) { + igraph_int_t *yo; if (nb_v < 0) { nb_v = 0; for (yo = deg; yo != deg + n; ) if (*(yo++) > 0) { @@ -709,9 +709,9 @@ igraph_integer_t *graph_molloy_opt::vertices_real(igraph_integer_t &nb_v) { IGRAPH_WARNING("graph is empty"); return NULL; } - igraph_integer_t *buff = new igraph_integer_t[nb_v]; + igraph_int_t *buff = new igraph_int_t[nb_v]; yo = buff; - for (igraph_integer_t i = 0; i < n; i++) if (deg[i] > 0) { + for (igraph_int_t i = 0; i < n; i++) if (deg[i] > 0) { *(yo++) = i; } if (yo != buff + nb_v) { @@ -723,7 +723,7 @@ igraph_integer_t *graph_molloy_opt::vertices_real(igraph_integer_t &nb_v) { } } -bool graph_molloy_opt::isolated(igraph_integer_t v, igraph_integer_t K, igraph_integer_t *Kbuff, bool *visited) { +bool graph_molloy_opt::isolated(igraph_int_t v, igraph_int_t K, igraph_int_t *Kbuff, bool *visited) { if (K < 2) { return false; } @@ -732,17 +732,17 @@ bool graph_molloy_opt::isolated(igraph_integer_t v, igraph_integer_t K, igraph_i return false; } #endif //OPT_ISOLATED - igraph_integer_t *seen = Kbuff; - igraph_integer_t *known = Kbuff; - igraph_integer_t *max = Kbuff + (K - 1); + igraph_int_t *seen = Kbuff; + igraph_int_t *known = Kbuff; + igraph_int_t *max = Kbuff + (K - 1); *(known++) = v; visited[v] = true; bool is_isolated = true; while (known != seen) { v = *(seen++); - igraph_integer_t *w = neigh[v]; - for (igraph_integer_t d = deg[v]; d--; w++) if (!visited[*w]) { + igraph_int_t *w = neigh[v]; + for (igraph_int_t d = deg[v]; d--; w++) if (!visited[*w]) { #ifdef OPT_ISOLATED if (K <= deg[*w] + 1 || known == max) { #else //OPT_ISOLATED @@ -776,7 +776,7 @@ void graph_molloy_opt::sort() { bool graph_molloy_opt::verify(int mode) { IGRAPH_UNUSED(mode); #ifndef NDEBUG - igraph_integer_t i, j, k; + igraph_int_t i, j, k; assert(neigh[0] == links); // verify edges count if ((mode & VERIFY_NOARCS) == 0) { @@ -800,8 +800,8 @@ bool graph_molloy_opt::verify(int mode) { // assert(neigh[i][j]!=neigh[i][k]); // verify symmetry for (i = 0; i < n; i++) for (j = 0; j < deg[i]; j++) { - igraph_integer_t v = neigh[i][j]; - igraph_integer_t nb = 0; + igraph_int_t v = neigh[i][j]; + igraph_int_t nb = 0; for (k = 0; k < deg[v]; k++) if (neigh[v][k] == i) { nb++; } diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_optimized.h b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_optimized.h index 657273c6033..b662bd7966e 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_optimized.h +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_graph_molloy_optimized.h @@ -37,28 +37,28 @@ class graph_molloy_opt { // Random generator KW_RNG::RNG rng; // Number of vertices - igraph_integer_t n; + igraph_int_t n; //Number of arcs ( = #edges * 2 ) - igraph_integer_t a; + igraph_int_t a; // The degree sequence of the graph - igraph_integer_t *deg; + igraph_int_t *deg; // The array containing all links - igraph_integer_t *links; + igraph_int_t *links; // The array containing pointers to adjacency list of every vertices - igraph_integer_t **neigh; + igraph_int_t **neigh; // Allocate memory according to degree_sequence (for constructor use only!!) void alloc(degree_sequence &); // Compute #edges inline void refresh_nbarcs() { a = 0; - for (igraph_integer_t* d = deg + n; d != deg; ) { + for (igraph_int_t* d = deg + n; d != deg; ) { a += *(--d); } } // Build neigh with deg and links void compute_neigh(); // Swap edges. The swap MUST be valid !!! - inline void swap_edges(igraph_integer_t from1, igraph_integer_t to1, igraph_integer_t from2, igraph_integer_t to2) { + inline void swap_edges(igraph_int_t from1, igraph_int_t to1, igraph_int_t from2, igraph_int_t to2) { fast_rpl(neigh[from1], to1, to2); fast_rpl(neigh[from2], to2, to1); fast_rpl(neigh[to1], from1, from2); @@ -66,46 +66,46 @@ class graph_molloy_opt { } // Swap edges only if they are simple. return false if unsuccessful. - bool swap_edges_simple(igraph_integer_t, igraph_integer_t, igraph_integer_t, igraph_integer_t); + bool swap_edges_simple(igraph_int_t, igraph_int_t, igraph_int_t, igraph_int_t); // Test if vertex is in an isolated component of size dmax. - void depth_isolated(igraph_integer_t v, igraph_integer_t &calls, igraph_integer_t &left_to_explore, igraph_integer_t dmax, igraph_integer_t * &Kbuff, bool *visited); + void depth_isolated(igraph_int_t v, igraph_int_t &calls, igraph_int_t &left_to_explore, igraph_int_t dmax, igraph_int_t * &Kbuff, bool *visited); // breadth-first search. Store the distance (modulo 3) in dist[]. Returns eplorated component size. - igraph_integer_t width_search(unsigned char *dist, igraph_integer_t *buff, igraph_integer_t v0 = 0, igraph_integer_t toclear = -1); + igraph_int_t width_search(unsigned char *dist, igraph_int_t *buff, igraph_int_t v0 = 0, igraph_int_t toclear = -1); // depth-first search. - igraph_integer_t depth_search(bool *visited, igraph_integer_t *buff, igraph_integer_t v0 = 0); + igraph_int_t depth_search(bool *visited, igraph_int_t *buff, igraph_int_t v0 = 0); // breadth-first search that count the number of shortest paths going from src to each vertex - igraph_integer_t breadth_path_search(igraph_integer_t src, igraph_integer_t *buff, double *paths, unsigned char *dist); + igraph_int_t breadth_path_search(igraph_int_t src, igraph_int_t *buff, double *paths, unsigned char *dist); // Return component indexes where vertices belong to, starting from 0, // sorted by size (biggest component has index 0) - igraph_integer_t *components(igraph_integer_t *comp = NULL); + igraph_int_t *components(igraph_int_t *comp = NULL); public: // neigh[] - inline igraph_integer_t** neighbors() { + inline igraph_int_t** neighbors() { return neigh; }; // deg[] - inline igraph_integer_t* degrees() { + inline igraph_int_t* degrees() { return deg; }; //adjacency list of v - inline igraph_integer_t* operator[](const igraph_integer_t v) { + inline igraph_int_t* operator[](const igraph_int_t v) { return neigh[v]; }; //degree of v - inline igraph_integer_t degree(const igraph_integer_t v) { + inline igraph_int_t degree(const igraph_int_t v) { return deg[v]; }; // Detach deg[] and neigh[] @@ -117,27 +117,27 @@ class graph_molloy_opt { // Allocate memory for the graph. Create deg and links. No edge is created. graph_molloy_opt(degree_sequence &); // Create graph from hard copy - graph_molloy_opt(igraph_integer_t *); + graph_molloy_opt(igraph_int_t *); // Create hard copy of graph - igraph_integer_t *hard_copy(); + igraph_int_t *hard_copy(); // Remove unused edges, updates neigh[], recreate links[] void clean(); // nb arcs - inline igraph_integer_t nbarcs() { + inline igraph_int_t nbarcs() { return a; }; // last degree - inline igraph_integer_t last_degree() { + inline igraph_int_t last_degree() { return deg[n - 1]; }; // nb vertices - inline igraph_integer_t nbvertices() { + inline igraph_int_t nbvertices() { return n; }; // nb vertices having degree > 0 - inline igraph_integer_t nbvertices_real() { - igraph_integer_t s = 0; - for (igraph_integer_t *d = deg + n; d-- != deg; ) { + inline igraph_int_t nbvertices_real() { + igraph_int_t s = 0; + for (igraph_int_t *d = deg + n; d-- != deg; ) { if (*d) { s++; } @@ -145,7 +145,7 @@ class graph_molloy_opt { return s; }; // return list of vertices with degree > 0. Compute #vertices, if not given. - igraph_integer_t *vertices_real(igraph_integer_t &nb_v); + igraph_int_t *vertices_real(igraph_int_t &nb_v); // print graph in SUCC_LIST mode, in stdout void print(FILE *f = stdout, bool NOZERO = true); // Bind the graph avoiding multiple edges or self-edges (return false if fail) @@ -155,29 +155,29 @@ class graph_molloy_opt { // Test if graph is connected bool is_connected(); // Maximum degree - igraph_integer_t max_degree(); + igraph_int_t max_degree(); // is edge ? - inline bool is_edge(const igraph_integer_t u, const igraph_integer_t v) { + inline bool is_edge(const igraph_int_t u, const igraph_int_t v) { if (deg[v] < deg[u]) { return (fast_search(neigh[v], deg[v], u) != NULL); } else { return (fast_search(neigh[u], deg[u], v) != NULL); } } - // Backup graph [sizeof(igraph_integer_t) bytes per edge] - igraph_integer_t* backup(igraph_integer_t *here = NULL); + // Backup graph [sizeof(igraph_int_t) bytes per edge] + igraph_int_t* backup(igraph_int_t *here = NULL); // Restore from backup. Assume that degrees haven't changed - void restore(igraph_integer_t* back); + void restore(igraph_int_t* back); // Resplace with hard backup. - void replace(igraph_integer_t* _hardbackup); + void replace(igraph_int_t* _hardbackup); // Backup degs of graph - igraph_integer_t* backup_degs(igraph_integer_t *here = NULL); + igraph_int_t* backup_degs(igraph_int_t *here = NULL); // Restore degs from neigh[]. Need last degree, though - void restore_degs(igraph_integer_t last_degree); + void restore_degs(igraph_int_t last_degree); // Restore degs[] from backup. Assume that links[] has only been permuted - void restore_degs_only(igraph_integer_t* backup_degs); + void restore_degs_only(igraph_int_t* backup_degs); // Restore degs[] and neigh[]. Assume that links[] has only been permuted - void restore_degs_and_neigh(igraph_integer_t* backup_degs); + void restore_degs_and_neigh(igraph_int_t* backup_degs); // sort adjacency lists void sort(); // count cycles passing through vertex v diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_hash.h b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_hash.h index 9689c0a79b0..40601b86f88 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_hash.h +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_hash.h @@ -85,7 +85,7 @@ namespace gengraph { #define HASH_NONE (-1) #ifdef HASH_SIZE_IS_POWER2 -inline igraph_integer_t HASH_EXPAND(igraph_integer_t x) { +inline igraph_int_t HASH_EXPAND(igraph_int_t x) { /* Returns pow(2, floor(log2(x)) + 2) if x > 0, 1 otherwise. Works up to * x == 2^64, starts to break down afterwards */ _HASH_EXP_CALL(); @@ -109,19 +109,19 @@ inline igraph_integer_t HASH_EXPAND(igraph_integer_t x) { #define HASH_REKEY(k,size) ((k)==0 ? (size)-1 : (k)-1) #else //MACRO_RATHER_THAN_INLINE #ifndef HASH_SIZE_IS_POWER2 -inline igraph_integer_t HASH_KEY(igraph_integer_t x, igraph_integer_t size) { +inline igraph_int_t HASH_KEY(igraph_int_t x, igraph_int_t size) { assert(x >= 0); return x % size; }; -inline igraph_integer_t HASH_EXPAND(igraph_integer_t x) { +inline igraph_int_t HASH_EXPAND(igraph_int_t x) { _HASH_EXP_CALL(); return x + (x >> 1); }; -inline int HASH_UNEXPAND(igraph_integer_t x) { +inline int HASH_UNEXPAND(igraph_int_t x) { return ((x << 1) + 1) / 3; }; #endif //HASH_SIZE_IS_POWER2 -inline int HASH_REKEY(igraph_integer_t k, igraph_integer_t s) { +inline int HASH_REKEY(igraph_int_t k, igraph_int_t s) { assert(k >= 0); if (k == 0) { return s - 1; @@ -129,7 +129,7 @@ inline int HASH_REKEY(igraph_integer_t k, igraph_integer_t s) { return k - 1; } }; -inline int HASH_SIZE(igraph_integer_t x) { +inline int HASH_SIZE(igraph_int_t x) { if (IS_HASH(x)) { return HASH_EXPAND(x); } else { @@ -138,7 +138,7 @@ inline int HASH_SIZE(igraph_integer_t x) { }; #endif //MACRO_RATHER_THAN_INLINE -inline igraph_integer_t HASH_PAIR_KEY(igraph_integer_t x, igraph_integer_t y, igraph_integer_t size) { +inline igraph_int_t HASH_PAIR_KEY(igraph_int_t x, igraph_int_t y, igraph_int_t size) { return HASH_KEY(x * 1434879443 + y, size); } @@ -148,8 +148,8 @@ inline igraph_integer_t HASH_PAIR_KEY(igraph_integer_t x, igraph_integer_t y, ig //_________________________________________________________________________ // copy hash table into raw vector -inline void H_copy(igraph_integer_t *mem, igraph_integer_t *h, igraph_integer_t size) { - for (igraph_integer_t i = HASH_EXPAND(size); i--; h++) { +inline void H_copy(igraph_int_t *mem, igraph_int_t *h, igraph_int_t size) { + for (igraph_int_t i = HASH_EXPAND(size); i--; h++) { if (*h != HASH_NONE) { *(mem++) = *h; } @@ -157,10 +157,10 @@ inline void H_copy(igraph_integer_t *mem, igraph_integer_t *h, igraph_integer_t } // Look for the place to add an element. Return NULL if element is already here. -inline igraph_integer_t* H_add(igraph_integer_t* h, igraph_integer_t size, igraph_integer_t a) { +inline igraph_int_t* H_add(igraph_int_t* h, igraph_int_t size, igraph_int_t a) { _HASH_ADD_CALL(); _HASH_ADD_ITER(); - igraph_integer_t k = HASH_KEY(a, size); + igraph_int_t k = HASH_KEY(a, size); if (h[k] == HASH_NONE) { return h + k; } @@ -175,8 +175,8 @@ inline igraph_integer_t* H_add(igraph_integer_t* h, igraph_integer_t size, igrap } // would element be well placed in newk ? -inline bool H_better(igraph_integer_t a, igraph_integer_t size, igraph_integer_t currentk, igraph_integer_t newk) { - igraph_integer_t k = HASH_KEY(a, size); +inline bool H_better(igraph_int_t a, igraph_int_t size, igraph_int_t currentk, igraph_int_t newk) { + igraph_int_t k = HASH_KEY(a, size); if (newk < currentk) { return (k < currentk && k >= newk); } else { @@ -185,13 +185,13 @@ inline bool H_better(igraph_integer_t a, igraph_integer_t size, igraph_integer_t } // removes h[k] -inline void H_rm(igraph_integer_t* h, igraph_integer_t size, igraph_integer_t k) { +inline void H_rm(igraph_int_t* h, igraph_int_t size, igraph_int_t k) { _HASH_RM_CALL(); - igraph_integer_t lasthole = k; + igraph_int_t lasthole = k; do { _HASH_RM_ITER(); k = HASH_REKEY(k, size); - igraph_integer_t next = h[k]; + igraph_int_t next = h[k]; if (next == HASH_NONE) { break; } @@ -204,11 +204,11 @@ inline void H_rm(igraph_integer_t* h, igraph_integer_t size, igraph_integer_t k) } //put a -inline igraph_integer_t* H_put(igraph_integer_t* h, igraph_integer_t size, igraph_integer_t a) { +inline igraph_int_t* H_put(igraph_int_t* h, igraph_int_t size, igraph_int_t a) { assert(H_add(h, size, a) != NULL); _HASH_PUT_CALL(); _HASH_PUT_ITER(); - igraph_integer_t k = HASH_KEY(a, size); + igraph_int_t k = HASH_KEY(a, size); while (h[k] != HASH_NONE) { k = HASH_REKEY(k, size); _HASH_PUT_ITER(); @@ -219,11 +219,11 @@ inline igraph_integer_t* H_put(igraph_integer_t* h, igraph_integer_t size, igrap } // find A -inline igraph_integer_t H_find(igraph_integer_t *h, igraph_integer_t size, igraph_integer_t a) { +inline igraph_int_t H_find(igraph_int_t *h, igraph_int_t size, igraph_int_t a) { assert(H_add(h, size, a) == NULL); _HASH_FIND_CALL(); _HASH_FIND_ITER(); - igraph_integer_t k = HASH_KEY(a, size); + igraph_int_t k = HASH_KEY(a, size); while (h[k] != a) { k = HASH_REKEY(k, size); _HASH_FIND_ITER(); @@ -232,10 +232,10 @@ inline igraph_integer_t H_find(igraph_integer_t *h, igraph_integer_t size, igrap } // Look for the place to add an element. Return NULL if element is already here. -inline bool H_pair_insert(igraph_integer_t* h, igraph_integer_t size, igraph_integer_t a, igraph_integer_t b) { +inline bool H_pair_insert(igraph_int_t* h, igraph_int_t size, igraph_int_t a, igraph_int_t b) { _HASH_ADD_CALL(); _HASH_ADD_ITER(); - igraph_integer_t k = HASH_PAIR_KEY(a, b, size); + igraph_int_t k = HASH_PAIR_KEY(a, b, size); if (h[2 * k] == HASH_NONE) { h[2 * k] = a; h[2 * k + 1] = b; @@ -260,7 +260,7 @@ inline bool H_pair_insert(igraph_integer_t* h, igraph_integer_t size, igraph_int //_________________________________________________________________________ // Look for an element -inline bool H_is(igraph_integer_t *mem, igraph_integer_t size, igraph_integer_t elem) { +inline bool H_is(igraph_int_t *mem, igraph_int_t size, igraph_int_t elem) { if (IS_HASH(size)) { return (H_add(mem, HASH_EXPAND(size), elem) == NULL); } else { @@ -269,13 +269,13 @@ inline bool H_is(igraph_integer_t *mem, igraph_integer_t size, igraph_integer_t } //pick random location (containing an element) -inline igraph_integer_t* H_random(igraph_integer_t* mem, igraph_integer_t size) { +inline igraph_int_t* H_random(igraph_int_t* mem, igraph_int_t size) { if (!IS_HASH(size)) { return mem + (my_random() % size); } _HASH_RAND_CALL(); size = HASH_EXPAND(size); - igraph_integer_t* yo; + igraph_int_t* yo; do { yo = mem + HASH_KEY(my_random(), size); _HASH_RAND_ITER(); @@ -284,7 +284,7 @@ inline igraph_integer_t* H_random(igraph_integer_t* mem, igraph_integer_t size) } // replace *k by b -inline igraph_integer_t* H_rpl(igraph_integer_t *mem, igraph_integer_t size, igraph_integer_t* k, igraph_integer_t b) { +inline igraph_int_t* H_rpl(igraph_int_t *mem, igraph_int_t size, igraph_int_t* k, igraph_int_t b) { assert(!H_is(mem, size, b)); if (!IS_HASH(size)) { *k = b; @@ -298,7 +298,7 @@ inline igraph_integer_t* H_rpl(igraph_integer_t *mem, igraph_integer_t size, igr } // replace a by b -inline igraph_integer_t* H_rpl(igraph_integer_t *mem, igraph_integer_t size, igraph_integer_t a, igraph_integer_t b) { +inline igraph_int_t* H_rpl(igraph_int_t *mem, igraph_int_t size, igraph_int_t a, igraph_int_t b) { assert(H_is(mem, size, a)); assert(!H_is(mem, size, b)); if (!IS_HASH(size)) { diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_mr-connected.cpp b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_mr-connected.cpp index 0e512751c26..9dd5e2b1077 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_mr-connected.cpp +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_mr-connected.cpp @@ -151,8 +151,6 @@ igraph_error_t igraph_i_degree_sequence_game_vl(igraph_t *graph, IGRAPH_EINVAL); } - RNG_BEGIN(); - degree_sequence *dd = new degree_sequence(out_seq); graph_molloy_opt *g = new graph_molloy_opt(*dd); @@ -160,18 +158,16 @@ igraph_error_t igraph_i_degree_sequence_game_vl(igraph_t *graph, if (!g->havelhakimi()) { delete g; - RNG_END(); IGRAPH_FATAL("g->havelhakimi() failed; please report as a bug."); } if (!g->make_connected()) { delete g; - RNG_END(); IGRAPH_ERROR("Cannot make a connected graph from the given degree sequence.", IGRAPH_EINVAL); } - igraph_integer_t *hc = g->hard_copy(); + igraph_int_t *hc = g->hard_copy(); delete g; graph_molloy_hash *gh = new graph_molloy_hash(hc); delete [] hc; @@ -180,8 +176,6 @@ igraph_error_t igraph_i_degree_sequence_game_vl(igraph_t *graph, IGRAPH_CHECK(gh->print(graph)); delete gh; - - RNG_END(); ); return IGRAPH_SUCCESS; diff --git a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_qsort.h b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_qsort.h index 85df8bc4464..383bb6388aa 100644 --- a/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_qsort.h +++ b/src/vendor/cigraph/src/games/degree_sequence_vl/gengraph_qsort.h @@ -30,8 +30,8 @@ namespace gengraph { //___________________________________________________________________________ // check if every element is zero -inline bool check_zero(igraph_integer_t *mem, igraph_integer_t n) { - for (igraph_integer_t *v = mem + n; v != mem; ) { +inline bool check_zero(igraph_int_t *mem, igraph_int_t n) { + for (igraph_int_t *v = mem + n; v != mem; ) { if (*(--v) != 0) { return false; } @@ -42,7 +42,7 @@ inline bool check_zero(igraph_integer_t *mem, igraph_integer_t n) { //___________________________________________________________________________ // Sort simple integer arrays in ASCENDING order //___________________________________________________________________________ -inline igraph_integer_t med3(igraph_integer_t a, igraph_integer_t b, igraph_integer_t c) { +inline igraph_int_t med3(igraph_int_t a, igraph_int_t b, igraph_int_t c) { if (a < b) { if (c < b) { return (a < c) ? c : a; @@ -58,13 +58,13 @@ inline igraph_integer_t med3(igraph_integer_t a, igraph_integer_t b, igraph_inte } } -inline void isort(igraph_integer_t *v, igraph_integer_t t) { +inline void isort(igraph_int_t *v, igraph_int_t t) { if (t < 2) { return; } - for (igraph_integer_t i = 1; i < t; i++) { - igraph_integer_t *w = v + i; - igraph_integer_t tmp = *w; + for (igraph_int_t i = 1; i < t; i++) { + igraph_int_t *w = v + i; + igraph_int_t tmp = *w; while (w != v && *(w - 1) > tmp) { *w = *(w - 1); w--; @@ -73,9 +73,9 @@ inline void isort(igraph_integer_t *v, igraph_integer_t t) { } } -inline igraph_integer_t partitionne(igraph_integer_t *v, igraph_integer_t t, igraph_integer_t p) { - igraph_integer_t i = 0; - igraph_integer_t j = t - 1; +inline igraph_int_t partitionne(igraph_int_t *v, igraph_int_t t, igraph_int_t p) { + igraph_int_t i = 0; + igraph_int_t j = t - 1; while (i < j) { while (i <= j && v[i] < p) { i++; @@ -84,7 +84,7 @@ inline igraph_integer_t partitionne(igraph_integer_t *v, igraph_integer_t t, igr j--; } if (i < j) { - igraph_integer_t tmp = v[i]; + igraph_int_t tmp = v[i]; v[i++] = v[j]; v[j--] = tmp; } @@ -96,22 +96,22 @@ inline igraph_integer_t partitionne(igraph_integer_t *v, igraph_integer_t t, igr return i; } -inline void qsort(igraph_integer_t *v, igraph_integer_t t) { +inline void qsort(igraph_int_t *v, igraph_int_t t) { if (t < 15) { isort(v, t); } else { - igraph_integer_t x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2])); + igraph_int_t x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2])); qsort(v, x); qsort(v + x, t - x); } } -inline igraph_integer_t qsort_median(igraph_integer_t *v, igraph_integer_t t, igraph_integer_t pos) { +inline igraph_int_t qsort_median(igraph_int_t *v, igraph_int_t t, igraph_int_t pos) { if (t < 10) { isort(v, t); return v[pos]; } - igraph_integer_t x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2])); + igraph_int_t x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2])); if (pos < x) { return qsort_median(v, x, pos); } else { @@ -119,7 +119,7 @@ inline igraph_integer_t qsort_median(igraph_integer_t *v, igraph_integer_t t, ig } } -inline igraph_integer_t qsort_median(igraph_integer_t *v, igraph_integer_t t) { +inline igraph_int_t qsort_median(igraph_int_t *v, igraph_int_t t) { return qsort_median(v, t, t / 2); } @@ -142,11 +142,11 @@ inline double med3(double a, double b, double c) { } } -inline void isort(double *v, igraph_integer_t t) { +inline void isort(double *v, igraph_int_t t) { if (t < 2) { return; } - for (igraph_integer_t i = 1; i < t; i++) { + for (igraph_int_t i = 1; i < t; i++) { double *w = v + i; double tmp = *w; while (w != v && *(w - 1) > tmp) { @@ -157,9 +157,9 @@ inline void isort(double *v, igraph_integer_t t) { } } -inline igraph_integer_t partitionne(double *v, igraph_integer_t t, double p) { - igraph_integer_t i = 0; - igraph_integer_t j = t - 1; +inline igraph_int_t partitionne(double *v, igraph_int_t t, double p) { + igraph_int_t i = 0; + igraph_int_t j = t - 1; while (i < j) { while (i <= j && v[i] < p) { i++; @@ -180,22 +180,22 @@ inline igraph_integer_t partitionne(double *v, igraph_integer_t t, double p) { return i; } -inline void qsort(double *v, igraph_integer_t t) { +inline void qsort(double *v, igraph_int_t t) { if (t < 15) { isort(v, t); } else { - igraph_integer_t x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2])); + igraph_int_t x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2])); qsort(v, x); qsort(v + x, t - x); } } -inline double qsort_median(double *v, igraph_integer_t t, igraph_integer_t pos) { +inline double qsort_median(double *v, igraph_int_t t, igraph_int_t pos) { if (t < 10) { isort(v, t); return v[pos]; } - igraph_integer_t x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2])); + igraph_int_t x = partitionne(v, t, med3(v[t >> 1], v[(t >> 2) + 2], v[t - (t >> 1) - 2])); if (pos < x) { return qsort_median(v, x, pos); } else { @@ -203,20 +203,20 @@ inline double qsort_median(double *v, igraph_integer_t t, igraph_integer_t pos) } } -inline double qsort_median(double *v, igraph_integer_t t) { +inline double qsort_median(double *v, igraph_int_t t) { return qsort_median(v, t, t / 2); } //___________________________________________________________________________ // Sort integer arrays according to value stored in mem[], in ASCENDING order -inline void isort(igraph_integer_t *mem, igraph_integer_t *v, igraph_integer_t t) { +inline void isort(igraph_int_t *mem, igraph_int_t *v, igraph_int_t t) { if (t < 2) { return; } - for (igraph_integer_t i = 1; i < t; i++) { - igraph_integer_t vtmp = v[i]; - igraph_integer_t tmp = mem[vtmp]; - igraph_integer_t j; + for (igraph_int_t i = 1; i < t; i++) { + igraph_int_t vtmp = v[i]; + igraph_int_t tmp = mem[vtmp]; + igraph_int_t j; for (j = i; j > 0 && tmp < mem[v[j - 1]]; j--) { v[j] = v[j - 1]; } @@ -224,13 +224,13 @@ inline void isort(igraph_integer_t *mem, igraph_integer_t *v, igraph_integer_t t } } -inline void qsort(igraph_integer_t *mem, igraph_integer_t *v, igraph_integer_t t) { +inline void qsort(igraph_int_t *mem, igraph_int_t *v, igraph_int_t t) { if (t < 15) { isort(mem, v, t); } else { - igraph_integer_t p = med3(mem[v[t >> 1]], mem[v[(t >> 2) + 3]], mem[v[t - (t >> 1) - 3]]); - igraph_integer_t i = 0; - igraph_integer_t j = t - 1; + igraph_int_t p = med3(mem[v[t >> 1]], mem[v[(t >> 2) + 3]], mem[v[t - (t >> 1) - 3]]); + igraph_int_t i = 0; + igraph_int_t j = t - 1; while (i < j) { while (i <= j && mem[v[i]] < p) { i++; @@ -239,7 +239,7 @@ inline void qsort(igraph_integer_t *mem, igraph_integer_t *v, igraph_integer_t t j--; } if (i < j) { - igraph_integer_t tmp = v[i]; + igraph_int_t tmp = v[i]; v[i++] = v[j]; v[j--] = tmp; } @@ -254,13 +254,13 @@ inline void qsort(igraph_integer_t *mem, igraph_integer_t *v, igraph_integer_t t } //Box-Sort 1..n according to value stored in mem[], in DESCENDING order. -inline igraph_integer_t *pre_boxsort(igraph_integer_t *mem, igraph_integer_t n, igraph_integer_t &offset) { - igraph_integer_t *yo; +inline igraph_int_t *pre_boxsort(igraph_int_t *mem, igraph_int_t n, igraph_int_t &offset) { + igraph_int_t *yo; // maximum and minimum - igraph_integer_t mx = mem[0]; - igraph_integer_t mn = mem[0]; + igraph_int_t mx = mem[0]; + igraph_int_t mn = mem[0]; for (yo = mem + n - 1; yo != mem; yo--) { - igraph_integer_t x = *yo; + igraph_int_t x = *yo; if (x > mx) { mx = x; } @@ -269,12 +269,12 @@ inline igraph_integer_t *pre_boxsort(igraph_integer_t *mem, igraph_integer_t n, } } // box - igraph_integer_t c = mx - mn + 1; - igraph_integer_t *box = new igraph_integer_t[c]; + igraph_int_t c = mx - mn + 1; + igraph_int_t *box = new igraph_int_t[c]; for (yo = box + c; yo != box; * (--yo) = 0) { } for (yo = mem + n; yo != mem; box[*(--yo) - mn]++) { } // cumul sum - igraph_integer_t sum = 0; + igraph_int_t sum = 0; for (yo = box + c; yo != box; ) { sum += *(--yo); *yo = sum; @@ -283,16 +283,16 @@ inline igraph_integer_t *pre_boxsort(igraph_integer_t *mem, igraph_integer_t n, return box; } -inline igraph_integer_t *boxsort(igraph_integer_t *mem, igraph_integer_t n, igraph_integer_t *buff = NULL) { - igraph_integer_t i; +inline igraph_int_t *boxsort(igraph_int_t *mem, igraph_int_t n, igraph_int_t *buff = NULL) { + igraph_int_t i; if (n <= 0) { return buff; } - igraph_integer_t offset = 0; - igraph_integer_t *box = pre_boxsort(mem, n, offset); + igraph_int_t offset = 0; + igraph_int_t *box = pre_boxsort(mem, n, offset); // sort if (buff == NULL) { - buff = new igraph_integer_t[n]; + buff = new igraph_int_t[n]; } for (i = 0; i < n; i++) { buff[--box[mem[i] - offset]] = i; diff --git a/src/vendor/cigraph/src/games/dotproduct.c b/src/vendor/cigraph/src/games/dotproduct.c index e372af0e5b7..9281d3f07e7 100644 --- a/src/vendor/cigraph/src/games/dotproduct.c +++ b/src/vendor/cigraph/src/games/dotproduct.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2014 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -52,35 +51,32 @@ * Time complexity: O(n*n*m), where n is the number of vertices, * and m is the length of the latent vectors. * - * \sa \ref igraph_sample_dirichlet(), \ref - * igraph_sample_sphere_volume(), \ref igraph_sample_sphere_surface() + * \sa \ref igraph_rng_sample_dirichlet(), \ref + * igraph_rng_sample_sphere_volume(), \ref igraph_rng_sample_sphere_surface() * for functions to generate the latent vectors. */ igraph_error_t igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *vecs, igraph_bool_t directed) { - igraph_integer_t nrow = igraph_matrix_nrow(vecs); - igraph_integer_t ncol = igraph_matrix_ncol(vecs); - igraph_integer_t i, j; + igraph_int_t nrow = igraph_matrix_nrow(vecs); + igraph_int_t ncol = igraph_matrix_ncol(vecs); + igraph_int_t i, j; igraph_vector_int_t edges; igraph_bool_t warned_neg = false, warned_big = false; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - RNG_BEGIN(); - for (i = 0; i < ncol; i++) { - igraph_integer_t from = directed ? 0 : i + 1; - igraph_vector_t v1; - igraph_vector_view(&v1, &MATRIX(*vecs, 0, i), nrow); + igraph_int_t from = directed ? 0 : i + 1; + const igraph_vector_t v1 = igraph_vector_view(&MATRIX(*vecs, 0, i), nrow); for (j = from; j < ncol; j++) { igraph_real_t prob; - igraph_vector_t v2; + const igraph_vector_t v2 = igraph_vector_view(&MATRIX(*vecs, 0, j), nrow); + if (i == j) { continue; } - igraph_vector_view(&v2, &MATRIX(*vecs, 0, j), nrow); IGRAPH_CHECK(igraph_blas_ddot(&v1, &v2, &prob)); if (prob < 0 && ! warned_neg) { warned_neg = true; @@ -97,8 +93,6 @@ igraph_error_t igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *v } } - RNG_END(); - IGRAPH_CHECK(igraph_create(graph, &edges, ncol, directed)); igraph_vector_int_destroy(&edges); @@ -106,185 +100,3 @@ igraph_error_t igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *v return IGRAPH_SUCCESS; } - -/** - * \function igraph_sample_sphere_surface - * \brief Sample points uniformly from the surface of a sphere. - * - * The center of the sphere is at the origin. - * - * \param dim The dimension of the random vectors. - * \param n The number of vectors to sample. - * \param radius Radius of the sphere, it must be positive. - * \param positive Whether to restrict sampling to the positive - * orthant. - * \param res Pointer to an initialized matrix, the result is - * stored here, each column will be a sampled vector. The matrix is - * resized, as needed. - * \return Error code. - * - * Time complexity: O(n*dim*g), where g is the time complexity of - * generating a standard normal random number. - * - * \sa \ref igraph_sample_sphere_volume(), \ref - * igraph_sample_dirichlet() for other similar samplers. - */ - -igraph_error_t igraph_sample_sphere_surface(igraph_integer_t dim, igraph_integer_t n, - igraph_real_t radius, - igraph_bool_t positive, - igraph_matrix_t *res) { - igraph_integer_t i, j; - - if (dim < 2) { - IGRAPH_ERROR("Sphere must be at least two dimensional to sample from " - "surface.", IGRAPH_EINVAL); - } - if (n < 0) { - IGRAPH_ERROR("Number of samples must be non-negative.", IGRAPH_EINVAL); - } - if (radius <= 0) { - IGRAPH_ERROR("Sphere radius must be positive.", IGRAPH_EINVAL); - } - - IGRAPH_CHECK(igraph_matrix_resize(res, dim, n)); - - RNG_BEGIN(); - - for (i = 0; i < n; i++) { - igraph_real_t *col = &MATRIX(*res, 0, i); - igraph_real_t sum = 0.0; - for (j = 0; j < dim; j++) { - col[j] = RNG_NORMAL(0, 1); - sum += col[j] * col[j]; - } - sum = sqrt(sum); - for (j = 0; j < dim; j++) { - col[j] = radius * col[j] / sum; - } - if (positive) { - for (j = 0; j < dim; j++) { - col[j] = fabs(col[j]); - } - } - } - - RNG_END(); - - return IGRAPH_SUCCESS; -} - -/** - * \function igraph_sample_sphere_volume - * \brief Sample points uniformly from the volume of a sphere. - * - * The center of the sphere is at the origin. - * - * \param dim The dimension of the random vectors. - * \param n The number of vectors to sample. - * \param radius Radius of the sphere, it must be positive. - * \param positive Whether to restrict sampling to the positive - * orthant. - * \param res Pointer to an initialized matrix, the result is - * stored here, each column will be a sampled vector. The matrix is - * resized, as needed. - * \return Error code. - * - * Time complexity: O(n*dim*g), where g is the time complexity of - * generating a standard normal random number. - * - * \sa \ref igraph_sample_sphere_surface(), \ref - * igraph_sample_dirichlet() for other similar samplers. - */ - - -igraph_error_t igraph_sample_sphere_volume(igraph_integer_t dim, igraph_integer_t n, - igraph_real_t radius, - igraph_bool_t positive, - igraph_matrix_t *res) { - - igraph_integer_t i, j; - - /* Arguments are checked by the following call */ - - IGRAPH_CHECK(igraph_sample_sphere_surface(dim, n, radius, positive, res)); - - RNG_BEGIN(); - - for (i = 0; i < n; i++) { - igraph_real_t *col = &MATRIX(*res, 0, i); - igraph_real_t U = pow(RNG_UNIF01(), 1.0 / dim); - for (j = 0; j < dim; j++) { - col[j] *= U; - } - } - - RNG_END(); - - return IGRAPH_SUCCESS; -} - -/** - * \function igraph_sample_dirichlet - * \brief Sample points from a Dirichlet distribution. - * - * \param n The number of vectors to sample. - * \param alpha The parameters of the Dirichlet distribution. They - * must be positive. The length of this vector gives the dimension - * of the generated samples. - * \param res Pointer to an initialized matrix, the result is stored - * here, one sample in each column. It will be resized, as needed. - * \return Error code. - * - * Time complexity: O(n * dim * g), where dim is the dimension of the - * sample vectors, set by the length of alpha, and g is the time - * complexity of sampling from a Gamma distribution. - * - * \sa \ref igraph_sample_sphere_surface() and - * \ref igraph_sample_sphere_volume() for other methods to sample - * latent vectors. - */ - -igraph_error_t igraph_sample_dirichlet(igraph_integer_t n, const igraph_vector_t *alpha, - igraph_matrix_t *res) { - - igraph_integer_t len = igraph_vector_size(alpha); - igraph_integer_t i, j; - igraph_real_t sum, num; - igraph_rng_t* rng = igraph_rng_default(); - - if (n < 0) { - IGRAPH_ERRORF("Number of samples should be non-negative, got %" IGRAPH_PRId ".", - IGRAPH_EINVAL, n); - } - - if (len < 2) { - IGRAPH_ERRORF("Dirichlet parameter vector too short, must " - "have at least two entries, got %" IGRAPH_PRId - ".", IGRAPH_EINVAL, len); - } - - if (igraph_vector_min(alpha) <= 0) { - IGRAPH_ERRORF("Dirichlet concentration parameters must be positive, got %g.", - IGRAPH_EINVAL, igraph_vector_min(alpha)); - } - - IGRAPH_CHECK(igraph_matrix_resize(res, len, n)); - - RNG_BEGIN(); - - for (i = 0; i < n; i++) { - for (j = 0, sum = 0.0; j < len; j++) { - num = igraph_rng_get_gamma(rng, VECTOR(*alpha)[j], 1.0); - sum += num; - MATRIX(*res, j, i) = num; - } - for (j = 0; j < len; j++) { - MATRIX(*res, j, i) /= sum; - } - } - - RNG_END(); - - return IGRAPH_SUCCESS; -} diff --git a/src/vendor/cigraph/src/games/erdos_renyi.c b/src/vendor/cigraph/src/games/erdos_renyi.c index 8ee699b40c0..7d08e40c639 100644 --- a/src/vendor/cigraph/src/games/erdos_renyi.c +++ b/src/vendor/cigraph/src/games/erdos_renyi.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -28,27 +26,533 @@ #include "igraph_random.h" #include "core/interruption.h" +#include "internal/utils.h" #include "math/safe_intop.h" +#include "misc/graphicality.h" #include "random/random_internal.h" /** - * \section about_games + * \section about_erdos_renyi * - * Games are random graph generators, i.e. they generate a different - * graph every time they are called. igraph includes many such generators. - * Some implement stochastic graph construction processes inspired by real-world - * mechanics, such as preferential attachment, while others are designed to - * produce graphs with certain used properties (e.g. fixed number of edges, - * fixed degrees, etc.) + * + * There are two classic random graph models referred to as the Erdős-Rényi + * random graph, or sometimes simply \em the random graph. Both fix the vertex + * count n, but while the G(n,m) model prescribes precisely m edges, the G(n,p) + * model connects all vertex pairs independently with probability p. While + * these models look superficially different, when n is large they behave in + * a similar manner. G(n,m) graphs have a density of exactly + * p = m / m_max, while G(n,p) graphs have m = p m_max + * edges on \em average, where \c m_max is the number of vertex pairs. Indeed, + * these two models turns out to be two sides of the same coin: both can be + * understood as maximum entropy models with a constraint on the number of + * edges. The G(n,m) is obtained from a sharp constraint, while G(n,p) from + * an average constraint (soft constraint). + * + * + * + * The maximum entropy framework allows for rigorous generalizations of these + * models to various scenarios, of which igraph supports many, such as models + * defined over directed graphs, bipartite graphs, multigraphs, or even over + * edge-labelled graphs. Constraining edge counts between various subsets of + * vertices yields further families of related models, such as + * \ref igraph_sbm_game() (given connection probabilities between categories) + * or \ref igraph_degree_sequence_game() (given incident edge counts, i.e. + * degrees, for each vertex). + * */ -/* This implementation is used only with very large vertex counts, above + +static igraph_error_t iea_game( + igraph_t *graph, + igraph_int_t n, igraph_int_t m, + igraph_bool_t directed, igraph_bool_t loops) { + + igraph_vector_int_t edges; + int iter = 0; + + IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); + IGRAPH_CHECK(igraph_vector_int_reserve(&edges, m * 2)); + + for (igraph_int_t i = 0; i < m; i++) { + igraph_int_t from, to; + from = RNG_INTEGER(0, n - 1); + if (loops) { + to = RNG_INTEGER(0, n - 1); + } else { + to = RNG_INTEGER(0, n - 2); + if (from == to) { + to = n - 1; + } + } + igraph_vector_int_push_back(&edges, from); /* reserved */ + igraph_vector_int_push_back(&edges, to); /* reserved */ + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); + } + + IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); + igraph_vector_int_destroy(&edges); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} + +/* Uniform sampling of multigraphs from G(n,m) */ +static igraph_error_t gnm_multi( + igraph_t *graph, + igraph_int_t n, igraph_int_t m, + igraph_bool_t directed, igraph_bool_t loops) { + + /* Conceptually, uniform multigraph sampling works as follows: + * + * - Consider a list containing all vertex pairs. Use unordered pairs for + * undirected graphs, ordered pairs for directed ones, and include + * self-pairs if desired. + * - Pick a list element uniformly at random with replacement and append + * it to the list. Add the corresponding edge to the graph. + * - Continue picking elements form the list uniformly at random and + * appending the pick to the list until we have sampled the desired + * number of edges. + * + * Let's illustrate how this is implemented on the directed case with loops + * allowed. Each element of the n*n adjacency matrix corresponds to an + * ordered vertex pair. Uniformly sampling a matrix element is possible + * by generating two random matrix indices. As an analog of appending to the + * list of pairs, we extend the matrix with additional rows. The last row + * will generally be incomplete, so we use rejection sampling to avoid + * exceeding its length. + * + * In the undirected case, we still sample _ordered_ vertex pairs for + * simplicity. To account for the resulting duplication, we append the + * sampled pair _twice_. In the undirected case with loops, we must also + * duplicate the matrix diagonal. + */ + + igraph_vector_int_t edges; + igraph_int_t nrow, ncol; + igraph_int_t last; /* column index of last element in last row */ + int iter = 0; + + /* Constraining n and m by IGRAPH_VCOUNT_MAX and IGRAPH_ECOUNT_MAX, + * as done in the caller, is sufficient to prevent overflow, + * except for the one special case below: + */ + + if (!directed && !loops && + n == IGRAPH_VCOUNT_MAX && m == IGRAPH_ECOUNT_MAX) { + IGRAPH_ERROR("Too many edges or vertices for G(n,m) multigraph.", IGRAPH_EINVAL); + } + + IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 2*m); + + if (directed && loops) { + nrow = ncol = n; + last = ncol-1; + for (igraph_int_t i=0; i < m; i++) { + while (true) { + igraph_int_t r = RNG_INTEGER(0, nrow-1); + igraph_int_t c = RNG_INTEGER(0, ncol-1); + + if (r >= n) { + igraph_int_t j = (r - n) * ncol + c; + if (IGRAPH_UNLIKELY(j >= i)) continue; /* rejection sampling */ + VECTOR(edges)[2*i] = VECTOR(edges)[2*j]; + VECTOR(edges)[2*i+1] = VECTOR(edges)[2*j+1]; + } else { + VECTOR(edges)[2*i] = r; + VECTOR(edges)[2*i+1] = c; + } + + last += 1; + if (last >= ncol) { + last -= ncol; + nrow++; + } + + break; + } + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); + } + } else if (directed && !loops) { + nrow = n; + ncol = n-1; + last = ncol-1; + for (igraph_int_t i=0; i < m; i++) { + while (true) { + igraph_int_t r = RNG_INTEGER(0, nrow-1); + igraph_int_t c = RNG_INTEGER(0, ncol-1); + + if (r >= n) { + igraph_int_t j = (r - n) * ncol + c; + if (IGRAPH_UNLIKELY(j >= i)) continue; /* rejection sampling */ + VECTOR(edges)[2*i] = VECTOR(edges)[2*j]; + VECTOR(edges)[2*i+1] = VECTOR(edges)[2*j+1]; + } else { + + /* Eliminate self-loops. */ + if (c == r) { + c = n-1; + } + + VECTOR(edges)[2*i] = r; + VECTOR(edges)[2*i+1] = c; + } + + last += 1; + if (last >= ncol) { + last -= ncol; + nrow++; + } + + break; + } + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); + } + } else if (!directed && loops) { + nrow = n; + ncol = n+1; + last = ncol-1; + for (igraph_int_t i=0; i < m; i++) { + while (true) { + igraph_int_t r = RNG_INTEGER(0, nrow-1); + igraph_int_t c = RNG_INTEGER(0, ncol-1); + + if (r >= n) { + igraph_int_t j = (r - n) * ncol + c; + if (IGRAPH_UNLIKELY(j >= 2*i)) continue; /* rejection sampling */ + VECTOR(edges)[2*i] = VECTOR(edges)[2*(j/2)]; + VECTOR(edges)[2*i+1] = VECTOR(edges)[2*(j/2)+1]; + } else { + + /* Two chances to sample from matrix diagonal, + * when c == r and when c == n. */ + if (c == n) { + c = r; + } + + VECTOR(edges)[2*i] = r; + VECTOR(edges)[2*i+1] = c; + } + + last += 2; + while (last >= ncol) { + last -= ncol; + nrow++; + } + + break; + } + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); + } + } else /* !directed && !loops */ { + nrow = n; + ncol = n-1; + last = ncol-1; + for (igraph_int_t i=0; i < m; i++) { + while (true) { + igraph_int_t r = RNG_INTEGER(0, nrow-1); + igraph_int_t c = RNG_INTEGER(0, ncol-1); + + if (r >= n) { + igraph_int_t j = (r - n) * ncol + c; + if (IGRAPH_UNLIKELY(j >= 2*i)) continue; /* rejection sampling */ + VECTOR(edges)[2*i] = VECTOR(edges)[2*(j/2)]; + VECTOR(edges)[2*i+1] = VECTOR(edges)[2*(j/2)+1]; + } else { + + /* Eliminate self-loops. */ + if (c == r) { + c = n-1; + } + + VECTOR(edges)[2*i] = r; + VECTOR(edges)[2*i+1] = c; + } + + last += 2; + while (last >= ncol) { + last -= ncol; + nrow++; + } + + break; + } + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); + } + } + + IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); + + igraph_vector_int_destroy(&edges); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} + +/* Uniform sampling of simple graphs (with loops) from G(n,m) */ +static igraph_error_t gnm_simple( + igraph_t *graph, + igraph_int_t n, igraph_int_t m, + igraph_bool_t directed, igraph_bool_t loops, + igraph_bool_t edge_labeled) { + + /* This function uses doubles in its `s` vector, and for `maxedges` and `last`. + * This is because on a system with 32-bit ints, maxedges will be larger than + * IGRAPH_INTEGER_MAX and this will cause overflows when calculating `from` and `to` + * for tests on large graphs. This is also why we need a 'real' version of random_sample. + */ + igraph_real_t n_real = (igraph_real_t) n; /* for divisions below */ + igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; + igraph_vector_t s = IGRAPH_VECTOR_NULL; + int iter = 0; + + + igraph_real_t maxedges = n; + if (directed && loops) { + maxedges *= n; + } else if (directed && !loops) { + maxedges *= (n - 1); + } else if (!directed && loops) { + maxedges *= (n + 1) / 2.0; + } else { + maxedges *= (n - 1) / 2.0; + } + + if (m > maxedges) { + IGRAPH_ERROR( + "Too many edges requested compared to the number of vertices for G(n,m) model.", + IGRAPH_EINVAL); + } + + if (maxedges == m && ! edge_labeled) { + /* TODO: Cannot use igraph_full() when edge_labeled as we must shuffle edges. */ + IGRAPH_CHECK(igraph_full(graph, n, directed, loops)); + } else { + igraph_int_t slen; + + IGRAPH_VECTOR_INIT_FINALLY(&s, 0); + IGRAPH_CHECK(igraph_i_random_sample_real(&s, 0, maxedges - 1, m)); + + IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); + IGRAPH_CHECK(igraph_vector_int_reserve(&edges, igraph_vector_size(&s) * 2)); + + slen = igraph_vector_size(&s); + if (directed && loops) { + for (igraph_int_t i = 0; i < slen; i++) { + igraph_int_t to = trunc(VECTOR(s)[i] / n_real); + igraph_int_t from = VECTOR(s)[i] - to * n_real; + igraph_vector_int_push_back(&edges, from); + igraph_vector_int_push_back(&edges, to); + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); + } + } else if (directed && !loops) { + for (igraph_int_t i = 0; i < slen; i++) { + igraph_int_t from = trunc(VECTOR(s)[i] / (n_real - 1)); + igraph_int_t to = VECTOR(s)[i] - from * (n_real - 1); + if (from == to) { + to = n - 1; + } + igraph_vector_int_push_back(&edges, from); + igraph_vector_int_push_back(&edges, to); + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); + } + } else if (!directed && loops) { + for (igraph_int_t i = 0; i < slen; i++) { + igraph_int_t to = trunc((sqrt(8 * VECTOR(s)[i] + 1) - 1) / 2); + igraph_int_t from = VECTOR(s)[i] - (((igraph_real_t)to) * (to + 1)) / 2; + igraph_vector_int_push_back(&edges, from); + igraph_vector_int_push_back(&edges, to); + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); + } + } else { /* !directed && !loops */ + for (igraph_int_t i = 0; i < slen; i++) { + igraph_int_t to = trunc((sqrt(8 * VECTOR(s)[i] + 1) + 1) / 2); + igraph_int_t from = VECTOR(s)[i] - (((igraph_real_t)to) * (to - 1)) / 2; + igraph_vector_int_push_back(&edges, from); + igraph_vector_int_push_back(&edges, to); + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); + } + } + + igraph_vector_destroy(&s); + IGRAPH_FINALLY_CLEAN(1); + + if (edge_labeled) { + IGRAPH_CHECK(igraph_i_vector_int_shuffle_pairs(&edges)); + } + + IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); + + igraph_vector_int_destroy(&edges); + IGRAPH_FINALLY_CLEAN(1); + } + + return IGRAPH_SUCCESS; +} + +/** + * \ingroup generators + * \function igraph_erdos_renyi_game_gnm + * \brief Generates a random (Erdős-Rényi) graph with a fixed number of edges. + * + * In the G(n, m) Erdős-Rényi model, a graph with \p n vertices + * and \p m edges is generated uniformly at random. + * + * \param graph Pointer to an uninitialized graph object. + * \param n The number of vertices in the graph. + * \param m The number of edges in the graph. + * \param directed Whether to generate a directed graph. + * \param allowed_edge_types Controls whether multi-edges and self-loops + * are generated. See \ref igraph_edge_type_sw_t. + * \param edge_labeled If true, the sampling is done uniformly from the set + * of ordered edge lists. See \ref igraph_iea_game() for more information. + * Set this to \c false to select the classic Erdős-Rényi model. + * The constants \c IGRAPH_EDGE_UNLABELED and \c IGRAPH_EDGE_LABELED + * may be used instead of \c false and \c true for better readability. + * \return Error code: + * \c IGRAPH_EINVAL: invalid \p n or \p m parameter. + * \c IGRAPH_ENOMEM: there is not enough memory for the operation. + * + * Time complexity: O(|V|+|E|), the + * number of vertices plus the number of edges in the graph. + * + * \sa \ref igraph_erdos_renyi_game_gnp() to sample from the related + * G(n, p) model, which constrains the \em expected edge count; + * \ref igraph_iea_game() to generate multigraph by assigning edges to vertex + * pairs uniformly and independently; + * \ref igraph_degree_sequence_game() to constrain the degree sequence; + * \ref igraph_bipartite_game_gnm() for the bipartite version of this model; + * \ref igraph_barabasi_game() and \ref igraph_growing_random_game() for other + * commonly used random graph models. + * + * \example examples/simple/igraph_erdos_renyi_game_gnm.c + */ +igraph_error_t igraph_erdos_renyi_game_gnm( + igraph_t *graph, + igraph_int_t n, igraph_int_t m, + igraph_bool_t directed, + igraph_edge_type_sw_t allowed_edge_types, + igraph_bool_t edge_labeled) { + + igraph_bool_t loops, multiple; + + /* The multigraph implementation relies on the below checks to avoid overflow. */ + if (n < 0 || n > IGRAPH_VCOUNT_MAX) { + IGRAPH_ERROR("Invalid number of vertices for G(n,m) model.", IGRAPH_EINVAL); + } + if (m < 0 || m > IGRAPH_ECOUNT_MAX) { + IGRAPH_ERROR("Invalid number of edges for G(n,m) model.", IGRAPH_EINVAL); + } + + IGRAPH_CHECK(igraph_i_edge_type_to_loops_multiple(allowed_edge_types, &loops, &multiple)); + + /* Special cases of "too many edges" that also apply to multigraphs: + * - The null graph cannot have edges. + * - The singleton graph cannot have edges unless loops are allowed. + */ + if (m > 0 && ((n == 0) || (!loops && n == 1))) { + IGRAPH_ERROR( + "Too many edges requested compared to the number of vertices for G(n,m) model.", + IGRAPH_EINVAL); + } + + if (m == 0) { + return igraph_empty(graph, n, directed); + } + + if (edge_labeled) { + if (multiple) { + return iea_game(graph, n, m, directed, loops); + } else { + return gnm_simple(graph, n, m, directed, loops, /*edge_labeled=*/ true); + } + } else { + if (multiple) { + return gnm_multi(graph, n, m, directed, loops); + } else { + return gnm_simple(graph, n, m, directed, loops, /*edge_labeled=*/ false); + } + } +} + + +/** + * \ingroup generators + * \function igraph_iea_game + * \brief Generates a random multigraph through independent edge assignment. + * + * \experimental + * + * This model generates random multigraphs on \p n vertices with \p m edges + * through independent edge assignment (IEA). Each of the \p m edges is assigned + * uniformly at random to an \em ordered vertex pair, independently of each + * other. + * + * + * This model does not sample multigraphs uniformly. Undirected graphs are + * generated with probability proportional to + * + * + * (prod_(i<j) A_ij ! prod_i A_ii !!)^(-1), + * + * + * where \c A denotes the adjacency matrix and !! denotes + * the double factorial. Here \c A is assumed to have twice the number of + * self-loops on its diagonal. The corresponding expression for directed + * graphs is + * + * + * (prod_(i,j) A_ij !)^(-1). + * + * + * Thus the probability of all simple graphs (which only have 0s and 1s in + * the adjacency matrix) is the same, while that of non-simple ones depends + * on their edge and self-loop multiplicities. + * + * + * An alternative way to think of this model is that it performs uniform + * sampling of \em edge-labeled graphs, i.e. graphs in which not only vertices, + * but also edges carry unique identities and are distinguishable. + * + * \param graph Pointer to an uninitialized graph object. + * \param n The number of vertices in the graph. + * \param m The number of edges in the graph. + * \param directed Whether to generate a directed graph. + * \param loops Whether to generate self-loops. + * \return Error code: + * \c IGRAPH_EINVAL: invalid \p n or \p m parameter. + * \c IGRAPH_ENOMEM: there is not enough + * memory for the operation. + * + * Time complexity: O(|V|+|E|), the + * number of vertices plus the number of edges in the graph. + * + * \sa \ref igraph_erdos_renyi_game_gnm() to uniformly sample graphs with + * a given number of vertices and edges. + */ +igraph_error_t igraph_iea_game( + igraph_t *graph, + igraph_int_t n, igraph_int_t m, + igraph_bool_t directed, igraph_bool_t loops) { + + igraph_edge_type_sw_t allowed_edge_types = IGRAPH_MULTI_SW; + if (loops) { + allowed_edge_types |= IGRAPH_LOOPS_SW; + } + return igraph_erdos_renyi_game_gnm(graph, n, m, directed, allowed_edge_types, true); +} + +/* This G(n,p) implementation is used only with very large vertex counts, above * sqrt(MAX_EXACT_REAL) ~ 100 million, when the default implementation would * fail due to overflow. While this version avoids overflow and uses less memory, - * it is also slower than the default implementation. */ + * it is also slower than the default implementation. + * + * This function expects that when multiple=true, the p parameter has already + * been transformed by p = p / (1 + p). This is currently done by the caller. + */ static igraph_error_t gnp_large( - igraph_t *graph, igraph_integer_t n, igraph_real_t p, - igraph_bool_t directed, igraph_bool_t loops, igraph_integer_t ecount_estimate + igraph_t *graph, igraph_int_t n, igraph_real_t p, + igraph_bool_t directed, igraph_bool_t loops, igraph_bool_t multiple, + igraph_int_t ecount_estimate ) { igraph_vector_int_t edges; @@ -66,9 +570,8 @@ static igraph_error_t gnp_large( IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, 2*ecount_estimate)); - RNG_BEGIN(); - for (igraph_integer_t i=0; i < n; i++) { - igraph_integer_t j = directed ? 0 : i; + for (igraph_int_t i=0; i < n; i++) { + igraph_int_t j = directed ? 0 : i; while (true) { igraph_real_t gap = RNG_GEOM(p); @@ -76,7 +579,7 @@ static igraph_error_t gnp_large( /* This formulation not only terminates the loop when necessary, * but also protects against overflow when 'p' is very small * and 'gap' becomes very large, perhaps larger than representable - * in an igraph_integer_t. */ + * in an igraph_int_t. */ if (gap >= n - j) { break; } @@ -88,12 +591,11 @@ static igraph_error_t gnp_large( IGRAPH_CHECK(igraph_vector_int_push_back(&edges, j)); } - j++; + j += ! multiple; /* 1 for simple graph, 0 for multigraph */ IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); } } - RNG_END(); IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); igraph_vector_int_destroy(&edges); @@ -102,6 +604,37 @@ static igraph_error_t gnp_large( return IGRAPH_SUCCESS; } +static igraph_error_t gnp_edge_labeled( + igraph_t *graph, + igraph_int_t n, igraph_real_t p, + igraph_bool_t directed, + igraph_bool_t loops, igraph_bool_t multiple) { + + if (multiple) { + igraph_real_t maxedges = n; + + if (directed && loops) { + maxedges *= n; + } else if (directed && !loops) { + maxedges *= (n - 1); + } else if (!directed && loops) { + maxedges *= (n + 1) / 2.0; + } else { + maxedges *= (n - 1) / 2.0; + } + + igraph_real_t m; + do { + m = RNG_GEOM( 1.0 / (1.0 + maxedges * p) ); + } while (m > (igraph_real_t) IGRAPH_INTEGER_MAX); + + return iea_game(graph, n, m, directed, loops); + } else { + IGRAPH_ERROR("The edge-labeled G(n,p) model is not yet implemented for graphs without multi-edges.", + IGRAPH_UNIMPLEMENTED); + } +} + /** * \ingroup generators * \function igraph_erdos_renyi_game_gnp @@ -111,22 +644,58 @@ static igraph_error_t gnp_large( * or Bernoulli random graph, a graph with \p n vertices is generated such that * every possible edge is included in the graph independently with probability * \p p. This is equivalent to a maximum entropy random graph model model with - * a constraint on the \em expected edge count. Setting p = 1/2 - * generates all graphs on \p n vertices with the same probability. + * a constraint on the \em expected edge count. The maximum entropy view allows + * for extending the model to multigraphs, as discussed by Park and Newman (2004), + * section III.D. In this case, \p p is interpreted as the expected number of + * edges between any vertex pair. + * + * + * Setting p = 1/2 and multiple = false generates all + * graphs without multi-edges on \p n vertices with the same probability. * * - * The expected mean degree of the graph is approximately p n; - * set p = k/n when a mean degree of approximately \c k is - * desired. More precisely, the expected mean degree is p(n-1) - * in (undirected or directed) graphs without self-loops, + * For both simple and multigraphs, the expected mean degree of the graph is + * approximately p n; set p = k/n when a mean degree + * of approximately \c k is desired. More precisely, the expected mean degree is + * p(n-1) in (undirected or directed) graphs without self-loops, * p(n+1) in undirected graphs with self-loops, and * p n in directed graphs with self-loops. * + * + * When generating multigraphs, the distribution of the edge multiplicities is + * geometric, i.e. the probability of finding \c m edges between two vertices + * is q (1-q)^m, where q = 1 / (1+p). + * + * + * This function uses the sequential geometric sampling technique described in + * Batagelj and Brandes (2005), with a modification to handle multigraphs. + * + * + * References: + * + * + * J. Park and M. E. J. Newman: "Statistical Mechanics of Networks". + * Phys. Rev. E 70, 066117 (2004). + * https://doi.org/10.1103/PhysRevE.70.066117 + * + * + * V. Batagelj and U. Brandes: "Efficient Generation of Large Random Networks". + * Phys. Rev. E 71, 036113 (2005). + * https://doi.org/10.1103/PhysRevE.71.036113 + * * \param graph Pointer to an uninitialized graph object. * \param n The number of vertices in the graph. - * \param p The probability of the existence of an edge in the graph. + * \param p The expected number of edges between any vertex pair. + * When multi-edges are disallowed, this is equivalent to the probability + * of having a connection between any two vertices. * \param directed Whether to generate a directed graph. - * \param loops Whether to generate self-loops. + * \param allowed_edge_types Controls whether multi-edges and self-loops + * are generated. See \ref igraph_edge_type_sw_t. + * \param edge_labeled If true, the model is defined over the set of ordered + * edge lists, i.e. over the set of edge-labeled graphs. Set it to + * \c false to select the classic Erdős-Rényi model. + * The constants \c IGRAPH_EDGE_UNLABELED and \c IGRAPH_EDGE_LABELED + * may be used instead of \c false and \c true for better readability. * \return Error code: * \c IGRAPH_EINVAL: invalid \p n or \p p parameter. * \c IGRAPH_ENOMEM: there is not enough memory for the operation. @@ -144,34 +713,58 @@ static igraph_error_t gnp_large( * \example examples/simple/igraph_erdos_renyi_game_gnp.c */ igraph_error_t igraph_erdos_renyi_game_gnp( - igraph_t *graph, igraph_integer_t n, igraph_real_t p, - igraph_bool_t directed, igraph_bool_t loops -) { + igraph_t *graph, + igraph_int_t n, igraph_real_t p, + igraph_bool_t directed, + igraph_edge_type_sw_t allowed_edge_types, + igraph_bool_t edge_labeled) { + /* This function uses doubles in its `s` vector, and for `maxedges` and `last`. * This is because on a system with 32-bit ints, maxedges will be larger than * IGRAPH_INTEGER_MAX and this will cause overflows when calculating `from` and `to` * for tests on large graphs. */ - igraph_integer_t no_of_nodes = n; + igraph_int_t no_of_nodes = n; igraph_real_t no_of_nodes_real = (igraph_real_t) no_of_nodes; /* for divisions below */ igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; igraph_vector_t s = IGRAPH_VECTOR_NULL; + igraph_bool_t loops, multiple; int iter = 0; if (n < 0) { - IGRAPH_ERROR("Invalid number of vertices.", IGRAPH_EINVAL); + IGRAPH_ERROR("Invalid number of vertices for G(n,p) model.", IGRAPH_EINVAL); } - if (p < 0.0 || p > 1.0) { - IGRAPH_ERROR("Invalid probability given.", IGRAPH_EINVAL); + + IGRAPH_CHECK(igraph_i_edge_type_to_loops_multiple(allowed_edge_types, &loops, &multiple)); + + if (multiple) { + if (p < 0.0) { + IGRAPH_ERROR("Invalid expected edge multiplicity given for G(n,p) multigraph model.", IGRAPH_EINVAL); + } + } else { + if (p < 0.0 || p > 1.0) { + IGRAPH_ERROR("Invalid probability given for G(n,p) model.", IGRAPH_EINVAL); + } + } + + if (edge_labeled) { + return gnp_edge_labeled(graph, n, p, directed, loops, multiple); + } + + if (multiple) { + /* Convert the expected edge count to the appropriate probability parameter + * of the geometric distribution when sampling lengths of runs of 0s in the + * adjacency matrix. */ + p = p / (1 + p); } if (p == 0.0 || no_of_nodes == 0) { IGRAPH_CHECK(igraph_empty(graph, n, directed)); - } else if (p == 1.0) { + } else if (! multiple && p == 1.0) { IGRAPH_CHECK(igraph_full(graph, n, directed, loops)); } else { igraph_real_t maxedges = n, last; - igraph_integer_t ecount_estimate, ecount; + igraph_int_t ecount_estimate, ecount; if (directed && loops) { maxedges *= n; @@ -187,24 +780,20 @@ igraph_error_t igraph_erdos_renyi_game_gnp( if (maxedges > IGRAPH_MAX_EXACT_REAL) { /* Use a slightly slower, but overflow-free implementation. */ - return gnp_large(graph, n, p, directed, loops, ecount_estimate); + return gnp_large(graph, n, p, directed, loops, multiple, ecount_estimate); } IGRAPH_VECTOR_INIT_FINALLY(&s, 0); IGRAPH_CHECK(igraph_vector_reserve(&s, ecount_estimate)); - RNG_BEGIN(); - last = RNG_GEOM(p); while (last < maxedges) { IGRAPH_CHECK(igraph_vector_push_back(&s, last)); last += RNG_GEOM(p); - last += 1; + last += ! multiple; /* 1 for simple graph, 0 for multigraph */ IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); } - RNG_END(); - ecount = igraph_vector_size(&s); if (ecount > IGRAPH_ECOUNT_MAX) { IGRAPH_ERROR("Overflow in number of edges.", IGRAPH_EOVERFLOW); @@ -215,17 +804,17 @@ igraph_error_t igraph_erdos_renyi_game_gnp( iter = 0; if (directed && loops) { - for (igraph_integer_t i = 0; i < ecount; i++) { - igraph_integer_t to = floor(VECTOR(s)[i] / no_of_nodes_real); - igraph_integer_t from = VECTOR(s)[i] - to * no_of_nodes_real; + for (igraph_int_t i = 0; i < ecount; i++) { + igraph_int_t to = trunc(VECTOR(s)[i] / no_of_nodes_real); + igraph_int_t from = VECTOR(s)[i] - to * no_of_nodes_real; igraph_vector_int_push_back(&edges, from); igraph_vector_int_push_back(&edges, to); IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); } } else if (directed && !loops) { - for (igraph_integer_t i = 0; i < ecount; i++) { - igraph_integer_t to = floor(VECTOR(s)[i] / no_of_nodes_real); - igraph_integer_t from = VECTOR(s)[i] - to * no_of_nodes_real; + for (igraph_int_t i = 0; i < ecount; i++) { + igraph_int_t to = trunc(VECTOR(s)[i] / no_of_nodes_real); + igraph_int_t from = VECTOR(s)[i] - to * no_of_nodes_real; if (from == to) { to = no_of_nodes - 1; } @@ -234,17 +823,17 @@ igraph_error_t igraph_erdos_renyi_game_gnp( IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); } } else if (!directed && loops) { - for (igraph_integer_t i = 0; i < ecount; i++) { - igraph_integer_t to = floor((sqrt(8 * VECTOR(s)[i] + 1) - 1) / 2); - igraph_integer_t from = VECTOR(s)[i] - (((igraph_real_t)to) * (to + 1)) / 2; + for (igraph_int_t i = 0; i < ecount; i++) { + igraph_int_t to = trunc((sqrt(8 * VECTOR(s)[i] + 1) - 1) / 2); + igraph_int_t from = VECTOR(s)[i] - (((igraph_real_t)to) * (to + 1)) / 2; igraph_vector_int_push_back(&edges, from); igraph_vector_int_push_back(&edges, to); IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); } } else { /* !directed && !loops */ - for (igraph_integer_t i = 0; i < ecount; i++) { - igraph_integer_t to = floor((sqrt(8 * VECTOR(s)[i] + 1) + 1) / 2); - igraph_integer_t from = VECTOR(s)[i] - (((igraph_real_t)to) * (to - 1)) / 2; + for (igraph_int_t i = 0; i < ecount; i++) { + igraph_int_t to = trunc((sqrt(8 * VECTOR(s)[i] + 1) + 1) / 2); + igraph_int_t from = VECTOR(s)[i] - (((igraph_real_t)to) * (to - 1)) / 2; igraph_vector_int_push_back(&edges, from); igraph_vector_int_push_back(&edges, to); IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); @@ -260,192 +849,3 @@ igraph_error_t igraph_erdos_renyi_game_gnp( return IGRAPH_SUCCESS; } - -/** - * \ingroup generators - * \function igraph_erdos_renyi_game_gnm - * \brief Generates a random (Erdős-Rényi) graph with a fixed number of edges. - * - * In the G(n, m) Erdős-Rényi model, a graph with \p n vertices - * and \p m edges is generated uniformly at random. - * - * \param graph Pointer to an uninitialized graph object. - * \param n The number of vertices in the graph. - * \param m The number of edges in the graph. - * \param directed Whether to generate a directed graph. - * \param loops Whether to generate self-loops. - * \return Error code: - * \c IGRAPH_EINVAL: invalid \p n or \p m parameter. - * \c IGRAPH_ENOMEM: there is not enough memory for the operation. - * - * Time complexity: O(|V|+|E|), the - * number of vertices plus the number of edges in the graph. - * - * \sa \ref igraph_erdos_renyi_game_gnp() to sample from the related - * G(n, p) model, which constrains the \em expected edge count; - * \ref igraph_degree_sequence_game() to constrain the degree sequence; - * \ref igraph_bipartite_game_gnm() for the bipartite version of this model; - * \ref igraph_barabasi_game() and \ref igraph_growing_random_game() for other - * commonly used random graph models. - * - * \example examples/simple/igraph_erdos_renyi_game_gnm.c - */ -igraph_error_t igraph_erdos_renyi_game_gnm( - igraph_t *graph, igraph_integer_t n, igraph_integer_t m, - igraph_bool_t directed, igraph_bool_t loops -) { - - /* This function uses doubles in its `s` vector, and for `maxedges` and `last`. - * This is because on a system with 32-bit ints, maxedges will be larger than - * IGRAPH_INTEGER_MAX and this will cause overflows when calculating `from` and `to` - * for tests on large graphs. This is also why we need a 'real' version of random_sample. - */ - igraph_integer_t no_of_nodes = n; - igraph_integer_t no_of_edges = m; - igraph_real_t no_of_nodes_real = (igraph_real_t) no_of_nodes; /* for divisions below */ - igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_vector_t s = IGRAPH_VECTOR_NULL; - int iter = 0; - - if (n < 0) { - IGRAPH_ERROR("Invalid number of vertices.", IGRAPH_EINVAL); - } - if (m < 0 || m > IGRAPH_ECOUNT_MAX) { - IGRAPH_ERROR("Invalid number of edges.", IGRAPH_EINVAL); - } - - if (m == 0.0 || no_of_nodes == 0) { - IGRAPH_CHECK(igraph_empty(graph, n, directed)); - } else { - - igraph_integer_t i; - igraph_real_t maxedges = n; - if (directed && loops) { - maxedges *= n; - } else if (directed && !loops) { - maxedges *= (n - 1); - } else if (!directed && loops) { - maxedges *= (n + 1) / 2.0; - } else { - maxedges *= (n - 1) / 2.0; - } - - if (no_of_edges > maxedges) { - IGRAPH_ERROR("Too many edges requested compared to the number of vertices.", IGRAPH_EINVAL); - } - - if (maxedges == no_of_edges) { - IGRAPH_CHECK(igraph_full(graph, n, directed, loops)); - } else { - - igraph_integer_t slen; - - IGRAPH_VECTOR_INIT_FINALLY(&s, 0); - IGRAPH_CHECK(igraph_random_sample_real(&s, 0, maxedges - 1, no_of_edges)); - - IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - IGRAPH_CHECK(igraph_vector_int_reserve(&edges, igraph_vector_size(&s) * 2)); - - slen = igraph_vector_size(&s); - if (directed && loops) { - for (i = 0; i < slen; i++) { - igraph_integer_t to = floor(VECTOR(s)[i] / no_of_nodes_real); - igraph_integer_t from = VECTOR(s)[i] - to * no_of_nodes_real; - igraph_vector_int_push_back(&edges, from); - igraph_vector_int_push_back(&edges, to); - IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); - } - } else if (directed && !loops) { - for (i = 0; i < slen; i++) { - igraph_integer_t from = floor(VECTOR(s)[i] / (no_of_nodes_real - 1)); - igraph_integer_t to = VECTOR(s)[i] - from * (no_of_nodes_real - 1); - if (from == to) { - to = no_of_nodes - 1; - } - igraph_vector_int_push_back(&edges, from); - igraph_vector_int_push_back(&edges, to); - IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); - } - } else if (!directed && loops) { - for (i = 0; i < slen; i++) { - igraph_integer_t to = floor((sqrt(8 * VECTOR(s)[i] + 1) - 1) / 2); - igraph_integer_t from = VECTOR(s)[i] - (((igraph_real_t)to) * (to + 1)) / 2; - igraph_vector_int_push_back(&edges, from); - igraph_vector_int_push_back(&edges, to); - IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); - } - } else { /* !directed && !loops */ - for (i = 0; i < slen; i++) { - igraph_integer_t to = floor((sqrt(8 * VECTOR(s)[i] + 1) + 1) / 2); - igraph_integer_t from = VECTOR(s)[i] - (((igraph_real_t)to) * (to - 1)) / 2; - igraph_vector_int_push_back(&edges, from); - igraph_vector_int_push_back(&edges, to); - IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); - } - } - - igraph_vector_destroy(&s); - IGRAPH_FINALLY_CLEAN(1); - IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); - igraph_vector_int_destroy(&edges); - IGRAPH_FINALLY_CLEAN(1); - } - } - - return IGRAPH_SUCCESS; -} - -/** - * \ingroup generators - * \function igraph_erdos_renyi_game - * \brief Generates a random (Erdős-Rényi) graph. - * - * This function is deprecated; use \ref igraph_erdos_renyi_game_gnm() or - * \ref igraph_erdos_renyi_game_gnp() instead. - * - * \param graph Pointer to an uninitialized graph object. - * \param type The type of the random graph, possible values: - * \clist - * \cli IGRAPH_ERDOS_RENYI_GNM - * G(n,m) graph, - * m edges are - * selected uniformly randomly in a graph with - * n vertices. - * \cli IGRAPH_ERDOS_RENYI_GNP - * G(n,p) graph, - * every possible edge is included in the graph with - * probability p. - * \endclist - * \param n The number of vertices in the graph. - * \param p_or_m This is the p parameter for - * G(n,p) graphs and the - * m - * parameter for G(n,m) graphs. - * \param directed Whether to generate a directed graph. - * \param loops Whether to generate loops (self) edges. - * \return Error code: - * \c IGRAPH_EINVAL: invalid - * \p type, \p n, - * \p p or \p m - * parameter. - * \c IGRAPH_ENOMEM: there is not enough - * memory for the operation. - * - * Time complexity: O(|V|+|E|), the - * number of vertices plus the number of edges in the graph. - * - * \sa \ref igraph_barabasi_game(), \ref igraph_growing_random_game(), - * \ref igraph_erdos_renyi_game_gnm(), \ref igraph_erdos_renyi_game_gnp() - */ -igraph_error_t igraph_erdos_renyi_game(igraph_t *graph, igraph_erdos_renyi_t type, - igraph_integer_t n, igraph_real_t p_or_m, - igraph_bool_t directed, igraph_bool_t loops) { - - if (type == IGRAPH_ERDOS_RENYI_GNP) { - return igraph_erdos_renyi_game_gnp(graph, n, p_or_m, directed, loops); - } else if (type == IGRAPH_ERDOS_RENYI_GNM) { - return igraph_erdos_renyi_game_gnm(graph, n, (igraph_integer_t) p_or_m, directed, loops); - } else { - IGRAPH_ERROR("Invalid type", IGRAPH_EINVAL); - } -} diff --git a/src/vendor/cigraph/src/games/establishment.c b/src/vendor/cigraph/src/games/establishment.c index 9df705606c9..5bbf08ea753 100644 --- a/src/vendor/cigraph/src/games/establishment.c +++ b/src/vendor/cigraph/src/games/establishment.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -56,13 +54,13 @@ * Time complexity: O(|V|*k*log(|V|)), |V| is the number of vertices * and k is the \p k parameter. */ -igraph_error_t igraph_establishment_game(igraph_t *graph, igraph_integer_t nodes, - igraph_integer_t types, igraph_integer_t k, +igraph_error_t igraph_establishment_game(igraph_t *graph, igraph_int_t nodes, + igraph_int_t types, igraph_int_t k, const igraph_vector_t *type_dist, const igraph_matrix_t *pref_matrix, igraph_bool_t directed, igraph_vector_int_t *node_type_vec) { - igraph_integer_t i, j; + igraph_int_t i, j; igraph_vector_int_t edges; igraph_vector_t cumdist; igraph_vector_int_t potneis; @@ -147,20 +145,18 @@ igraph_error_t igraph_establishment_game(igraph_t *graph, igraph_integer_t nodes IGRAPH_VECTOR_INT_INIT_FINALLY(nodetypes, nodes); } - RNG_BEGIN(); - for (i = 0; i < nodes; i++) { igraph_real_t uni = RNG_UNIF(0, maxcum); - igraph_integer_t type; + igraph_int_t type; igraph_vector_binsearch(&cumdist, uni, &type); VECTOR(*nodetypes)[i] = type - 1; } for (i = k; i < nodes; i++) { - igraph_integer_t type1 = VECTOR(*nodetypes)[i]; + igraph_int_t type1 = VECTOR(*nodetypes)[i]; igraph_random_sample(&potneis, 0, i - 1, k); for (j = 0; j < k; j++) { - igraph_integer_t type2 = VECTOR(*nodetypes)[VECTOR(potneis)[j]]; + igraph_int_t type2 = VECTOR(*nodetypes)[VECTOR(potneis)[j]]; if (RNG_UNIF01() < MATRIX(*pref_matrix, type1, type2)) { IGRAPH_CHECK(igraph_vector_int_push_back(&edges, i)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, VECTOR(potneis)[j])); @@ -168,8 +164,6 @@ igraph_error_t igraph_establishment_game(igraph_t *graph, igraph_integer_t nodes } } - RNG_END(); - if (! node_type_vec) { igraph_vector_int_destroy(nodetypes); IGRAPH_FREE(nodetypes); diff --git a/src/vendor/cigraph/src/games/forestfire.c b/src/vendor/cigraph/src/games/forestfire.c index 417320c0a66..9d85e94d3d4 100644 --- a/src/vendor/cigraph/src/games/forestfire.c +++ b/src/vendor/cigraph/src/games/forestfire.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -35,12 +34,12 @@ typedef struct igraph_i_forest_fire_data_t { igraph_vector_int_t *inneis; igraph_vector_int_t *outneis; - igraph_integer_t no_of_nodes; + igraph_int_t no_of_nodes; } igraph_i_forest_fire_data_t; static void igraph_i_forest_fire_free(igraph_i_forest_fire_data_t *data) { - for (igraph_integer_t i = 0; i < data->no_of_nodes; i++) { + for (igraph_int_t i = 0; i < data->no_of_nodes; i++) { igraph_vector_int_destroy(data->inneis + i); igraph_vector_int_destroy(data->outneis + i); } @@ -104,17 +103,17 @@ static void igraph_i_forest_fire_free(igraph_i_forest_fire_data_t *data) { * Time complexity: TODO. */ -igraph_error_t igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes, +igraph_error_t igraph_forest_fire_game(igraph_t *graph, igraph_int_t nodes, igraph_real_t fw_prob, igraph_real_t bw_factor, - igraph_integer_t pambs, igraph_bool_t directed) { + igraph_int_t pambs, igraph_bool_t directed) { igraph_vector_int_t visited; - igraph_integer_t no_of_nodes = nodes, actnode, i; + igraph_int_t no_of_nodes = nodes, actnode, i; igraph_vector_int_t edges; igraph_vector_int_t *inneis, *outneis; igraph_i_forest_fire_data_t data; igraph_dqueue_int_t neiq; - igraph_integer_t ambs = pambs; + igraph_int_t ambs = pambs; igraph_real_t param_geom_out = 1 - fw_prob; igraph_real_t param_geom_in = 1 - fw_prob * bw_factor; @@ -159,8 +158,6 @@ igraph_error_t igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes, IGRAPH_FINALLY(igraph_vector_int_destroy, &visited); IGRAPH_DQUEUE_INT_INIT_FINALLY(&neiq, 10); - RNG_BEGIN(); - #define ADD_EDGE_TO(nei) \ if (VECTOR(visited)[(nei)] != actnode+1) { \ VECTOR(visited)[(nei)] = actnode+1; \ @@ -184,29 +181,29 @@ igraph_error_t igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes, /* Choose ambassador(s) */ for (i = 0; i < ambs; i++) { - igraph_integer_t a = RNG_INTEGER(0, actnode - 1); + igraph_int_t a = RNG_INTEGER(0, actnode - 1); ADD_EDGE_TO(a); } while (!igraph_dqueue_int_empty(&neiq)) { - igraph_integer_t actamb = igraph_dqueue_int_pop(&neiq); + igraph_int_t actamb = igraph_dqueue_int_pop(&neiq); igraph_vector_int_t *outv = outneis + actamb; igraph_vector_int_t *inv = inneis + actamb; - igraph_integer_t no_in = igraph_vector_int_size(inv); - igraph_integer_t no_out = igraph_vector_int_size(outv); - igraph_integer_t neis_out = RNG_GEOM(param_geom_out); - igraph_integer_t neis_in = RNG_GEOM(param_geom_in); + igraph_int_t no_in = igraph_vector_int_size(inv); + igraph_int_t no_out = igraph_vector_int_size(outv); + igraph_int_t neis_out = RNG_GEOM(param_geom_out); + igraph_int_t neis_in = RNG_GEOM(param_geom_in); /* outgoing neighbors */ if (neis_out >= no_out) { for (i = 0; i < no_out; i++) { - igraph_integer_t nei = VECTOR(*outv)[i]; + igraph_int_t nei = VECTOR(*outv)[i]; ADD_EDGE_TO(nei); } } else { - igraph_integer_t oleft = no_out; + igraph_int_t oleft = no_out; for (i = 0; i < neis_out && oleft > 0; ) { - igraph_integer_t which = RNG_INTEGER(0, oleft - 1); - igraph_integer_t nei = VECTOR(*outv)[which]; + igraph_int_t which = RNG_INTEGER(0, oleft - 1); + igraph_int_t nei = VECTOR(*outv)[which]; VECTOR(*outv)[which] = VECTOR(*outv)[oleft - 1]; VECTOR(*outv)[oleft - 1] = nei; if (VECTOR(visited)[nei] != actnode + 1) { @@ -219,14 +216,14 @@ igraph_error_t igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes, /* incoming neighbors */ if (neis_in >= no_in) { for (i = 0; i < no_in; i++) { - igraph_integer_t nei = VECTOR(*inv)[i]; + igraph_int_t nei = VECTOR(*inv)[i]; ADD_EDGE_TO(nei); } } else { - igraph_integer_t ileft = no_in; + igraph_int_t ileft = no_in; for (i = 0; i < neis_in && ileft > 0; ) { - igraph_integer_t which = RNG_INTEGER(0, ileft - 1); - igraph_integer_t nei = VECTOR(*inv)[which]; + igraph_int_t which = RNG_INTEGER(0, ileft - 1); + igraph_int_t nei = VECTOR(*inv)[which]; VECTOR(*inv)[which] = VECTOR(*inv)[ileft - 1]; VECTOR(*inv)[ileft - 1] = nei; if (VECTOR(visited)[nei] != actnode + 1) { @@ -243,8 +240,6 @@ igraph_error_t igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes, #undef ADD_EDGE_TO - RNG_END(); - IGRAPH_PROGRESS("Forest fire: ", 100.0, NULL); igraph_dqueue_int_destroy(&neiq); diff --git a/src/vendor/cigraph/src/games/grg.c b/src/vendor/cigraph/src/games/grg.c index 008bf247134..246c9f735c5 100644 --- a/src/vendor/cigraph/src/games/grg.c +++ b/src/vendor/cigraph/src/games/grg.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -55,11 +53,11 @@ * * \example examples/simple/igraph_grg_game.c */ -igraph_error_t igraph_grg_game(igraph_t *graph, igraph_integer_t nodes, +igraph_error_t igraph_grg_game(igraph_t *graph, igraph_int_t nodes, igraph_real_t radius, igraph_bool_t torus, igraph_vector_t *x, igraph_vector_t *y) { - igraph_integer_t i; + igraph_int_t i; igraph_vector_t myx, myy, *xx = &myx, *yy = &myy; igraph_vector_int_t edges; igraph_real_t r2; @@ -91,22 +89,18 @@ igraph_error_t igraph_grg_game(igraph_t *graph, igraph_integer_t nodes, IGRAPH_VECTOR_INIT_FINALLY(yy, nodes); } - RNG_BEGIN(); - for (i = 0; i < nodes; i++) { VECTOR(*xx)[i] = RNG_UNIF01(); VECTOR(*yy)[i] = RNG_UNIF01(); } - RNG_END(); - igraph_vector_sort(xx); if (!torus) { for (i = 0; i < nodes; i++) { igraph_real_t xx1 = VECTOR(*xx)[i]; igraph_real_t yy1 = VECTOR(*yy)[i]; - igraph_integer_t j = i + 1; + igraph_int_t j = i + 1; igraph_real_t dx, dy; IGRAPH_ALLOW_INTERRUPTION(); @@ -125,7 +119,7 @@ igraph_error_t igraph_grg_game(igraph_t *graph, igraph_integer_t nodes, for (i = 0; i < nodes; i++) { igraph_real_t xx1 = VECTOR(*xx)[i]; igraph_real_t yy1 = VECTOR(*yy)[i]; - igraph_integer_t j = i + 1; + igraph_int_t j = i + 1; igraph_real_t dx, dy; IGRAPH_ALLOW_INTERRUPTION(); diff --git a/src/vendor/cigraph/src/games/growing_random.c b/src/vendor/cigraph/src/games/growing_random.c index 79e5231f3f1..98954faa74d 100644 --- a/src/vendor/cigraph/src/games/growing_random.c +++ b/src/vendor/cigraph/src/games/growing_random.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -54,16 +52,16 @@ * Time complexity: O(|V|+|E|), the * number of vertices plus the number of edges. */ -igraph_error_t igraph_growing_random_game(igraph_t *graph, igraph_integer_t n, - igraph_integer_t m, igraph_bool_t directed, +igraph_error_t igraph_growing_random_game(igraph_t *graph, igraph_int_t n, + igraph_int_t m, igraph_bool_t directed, igraph_bool_t citation) { - igraph_integer_t no_of_nodes = n; - igraph_integer_t no_of_neighbors = m; - igraph_integer_t no_of_edges; + igraph_int_t no_of_nodes = n; + igraph_int_t no_of_neighbors = m; + igraph_int_t no_of_edges; igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t resp = 0; + igraph_int_t resp = 0; if (n < 0) { IGRAPH_ERROR("Invalid number of vertices.", IGRAPH_EINVAL); @@ -84,25 +82,21 @@ igraph_error_t igraph_growing_random_game(igraph_t *graph, igraph_integer_t n, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges * 2); - RNG_BEGIN(); - - for (igraph_integer_t i = 1; i < no_of_nodes; i++) { - for (igraph_integer_t j = 0; j < no_of_neighbors; j++) { + for (igraph_int_t i = 1; i < no_of_nodes; i++) { + for (igraph_int_t j = 0; j < no_of_neighbors; j++) { if (citation) { - igraph_integer_t to = RNG_INTEGER(0, i - 1); + igraph_int_t to = RNG_INTEGER(0, i - 1); VECTOR(edges)[resp++] = i; VECTOR(edges)[resp++] = to; } else { - igraph_integer_t from = RNG_INTEGER(0, i); - igraph_integer_t to = RNG_INTEGER(1, i); + igraph_int_t from = RNG_INTEGER(0, i); + igraph_int_t to = RNG_INTEGER(1, i); VECTOR(edges)[resp++] = from; VECTOR(edges)[resp++] = to; } } } - RNG_END(); - IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); igraph_vector_int_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); diff --git a/src/vendor/cigraph/src/games/islands.c b/src/vendor/cigraph/src/games/islands.c index edececa2be1..181a436d328 100644 --- a/src/vendor/cigraph/src/games/islands.c +++ b/src/vendor/cigraph/src/games/islands.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -57,21 +55,21 @@ */ igraph_error_t igraph_simple_interconnected_islands_game( igraph_t *graph, - igraph_integer_t islands_n, - igraph_integer_t islands_size, + igraph_int_t islands_n, + igraph_int_t islands_size, igraph_real_t islands_pin, - igraph_integer_t n_inter) { + igraph_int_t n_inter) { igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; igraph_vector_t s = IGRAPH_VECTOR_NULL; - igraph_integer_t number_of_nodes; + igraph_int_t number_of_nodes; igraph_real_t max_possible_edges_per_island; igraph_real_t avg_edges_per_island; - igraph_integer_t number_of_inter_island_edges; - igraph_integer_t start_index_of_island, start_index_of_other_island; - igraph_integer_t i, j, is, from, to; + igraph_int_t number_of_inter_island_edges; + igraph_int_t start_index_of_island, start_index_of_other_island; + igraph_int_t i, j, is, from, to; igraph_real_t last; - igraph_integer_t island_ecount; + igraph_int_t island_ecount; igraph_real_t nr_edges_reserved; if (islands_n < 0) { @@ -114,8 +112,6 @@ igraph_error_t igraph_simple_interconnected_islands_game( IGRAPH_VECTOR_INIT_FINALLY(&s, 0); IGRAPH_CHECK(igraph_vector_reserve(&s, 1.1 * avg_edges_per_island)); - RNG_BEGIN(); - /* first create all the islands */ for (is = 0; is < islands_n; is++) { /* for each island */ /* index for start and end of nodes in this island, both inclusive */ @@ -145,7 +141,7 @@ igraph_error_t igraph_simple_interconnected_islands_game( island_ecount = islands_size * islands_size; number_of_inter_island_edges = n_inter; for (i = is + 1; i < islands_n; i++) { /* for each other island (not the previous ones) */ - IGRAPH_CHECK(igraph_random_sample_real(&s, 0, island_ecount - 1, n_inter)); + IGRAPH_CHECK(igraph_i_random_sample_real(&s, 0, island_ecount - 1, n_inter)); start_index_of_other_island = i * islands_size; for (j = 0; j < n_inter; j++) { /* for each link between islands */ @@ -163,8 +159,6 @@ igraph_error_t igraph_simple_interconnected_islands_game( igraph_vector_destroy(&s); IGRAPH_FINALLY_CLEAN(1); - RNG_END(); - /* actually fill the graph object */ IGRAPH_CHECK(igraph_create(graph, &edges, number_of_nodes, 0)); diff --git a/src/vendor/cigraph/src/games/k_regular.c b/src/vendor/cigraph/src/games/k_regular.c index 0cebc213ad2..0eab6e487a9 100644 --- a/src/vendor/cigraph/src/games/k_regular.c +++ b/src/vendor/cigraph/src/games/k_regular.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -57,7 +55,7 @@ * Time complexity: O(|V|+|E|) if \c multiple is true, otherwise not known. */ igraph_error_t igraph_k_regular_game(igraph_t *graph, - igraph_integer_t no_of_nodes, igraph_integer_t k, + igraph_int_t no_of_nodes, igraph_int_t k, igraph_bool_t directed, igraph_bool_t multiple) { igraph_vector_int_t degseq; igraph_degseq_t mode = multiple ? IGRAPH_DEGSEQ_CONFIGURATION : IGRAPH_DEGSEQ_FAST_HEUR_SIMPLE; diff --git a/src/vendor/cigraph/src/games/preference.c b/src/vendor/cigraph/src/games/preference.c index 4ef26d6ac85..e7b98e8d71e 100644 --- a/src/vendor/cigraph/src/games/preference.c +++ b/src/vendor/cigraph/src/games/preference.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -82,8 +80,8 @@ * \ref igraph_establishment_game(), \ref igraph_callaway_traits_game() */ -igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, - igraph_integer_t types, +igraph_error_t igraph_preference_game(igraph_t *graph, igraph_int_t nodes, + igraph_int_t types, const igraph_vector_t *type_dist, igraph_bool_t fixed_sizes, const igraph_matrix_t *pref_matrix, @@ -91,7 +89,7 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, igraph_bool_t directed, igraph_bool_t loops) { - igraph_integer_t i, j, no_reserved_edges; + igraph_int_t i, j, no_reserved_edges; igraph_vector_int_t edges; igraph_vector_t s; igraph_vector_int_t* nodetypes; @@ -161,8 +159,6 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(&vids_by_type, types); - RNG_BEGIN(); - if (!fixed_sizes) { igraph_vector_t cumdist; @@ -181,7 +177,7 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, maxcum = igraph_vector_tail(&cumdist); for (i = 0; i < nodes; i++) { - igraph_integer_t type1; + igraph_int_t type1; igraph_real_t uni1 = RNG_UNIF(0, maxcum); igraph_vector_binsearch(&cumdist, uni1, &type1); VECTOR(*nodetypes)[i] = type1 - 1; @@ -194,10 +190,10 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, IGRAPH_FINALLY_CLEAN(1); } else { - igraph_integer_t an = 0; + igraph_int_t an = 0; if (type_dist) { for (i = 0; i < types; i++) { - igraph_integer_t no = VECTOR(*type_dist)[i]; + igraph_int_t no = VECTOR(*type_dist)[i]; igraph_vector_int_t *v = igraph_vector_int_list_get_ptr(&vids_by_type, i); for (j = 0; j < no && an < nodes; j++) { VECTOR(*nodetypes)[an] = i; @@ -206,8 +202,8 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, } } } else { - igraph_integer_t size_of_one_group = nodes / types; - igraph_integer_t num_groups_with_one_extra_node = nodes - size_of_one_group * types; + igraph_int_t size_of_one_group = nodes / types; + igraph_int_t num_groups_with_one_extra_node = nodes - size_of_one_group * types; for (i = 0; i < types; i++) { igraph_vector_int_t *v = igraph_vector_int_list_get_ptr(&vids_by_type, i); for (j = 0; j < size_of_one_group; j++) { @@ -230,10 +226,10 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, for (i = 0; i < types; i++) { for (j = 0; j < types; j++) { /* Generating the random subgraph between vertices of type i and j */ - igraph_integer_t k, l, l_x2; + igraph_int_t k, l, l_x2; igraph_real_t p, last; igraph_vector_int_t *v1, *v2; - igraph_integer_t v1_size, v2_size; + igraph_int_t v1_size, v2_size; IGRAPH_ALLOW_INTERRUPTION(); @@ -284,8 +280,8 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, if (i != j) { /* Generating the subgraph between vertices of type i and j */ for (k = 0; k < l; k++) { - igraph_integer_t to = floor(VECTOR(s)[k] / v1_size); - igraph_integer_t from = (VECTOR(s)[k] - ((igraph_real_t)to) * v1_size); + igraph_int_t to = floor(VECTOR(s)[k] / v1_size); + igraph_int_t from = (VECTOR(s)[k] - ((igraph_real_t)to) * v1_size); igraph_vector_int_push_back(&edges, VECTOR(*v1)[from]); igraph_vector_int_push_back(&edges, VECTOR(*v2)[to]); } @@ -293,15 +289,15 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, /* Generating the subgraph among vertices of type i */ if (directed && loops) { for (k = 0; k < l; k++) { - igraph_integer_t to = floor(VECTOR(s)[k] / v1_size); - igraph_integer_t from = (VECTOR(s)[k] - ((igraph_real_t)to) * v1_size); + igraph_int_t to = floor(VECTOR(s)[k] / v1_size); + igraph_int_t from = (VECTOR(s)[k] - ((igraph_real_t)to) * v1_size); igraph_vector_int_push_back(&edges, VECTOR(*v1)[from]); igraph_vector_int_push_back(&edges, VECTOR(*v1)[to]); } } else if (directed && !loops) { for (k = 0; k < l; k++) { - igraph_integer_t to = floor(VECTOR(s)[k] / v1_size); - igraph_integer_t from = (VECTOR(s)[k] - ((igraph_real_t)to) * v1_size); + igraph_int_t to = floor(VECTOR(s)[k] / v1_size); + igraph_int_t from = (VECTOR(s)[k] - ((igraph_real_t)to) * v1_size); if (from == to) { to = v1_size - 1; } @@ -310,15 +306,15 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, } } else if (!directed && loops) { for (k = 0; k < l; k++) { - igraph_integer_t to = floor((sqrt(8 * VECTOR(s)[k] + 1) - 1) / 2); - igraph_integer_t from = (VECTOR(s)[k] - (((igraph_real_t)to) * (to + 1)) / 2); + igraph_int_t to = floor((sqrt(8 * VECTOR(s)[k] + 1) - 1) / 2); + igraph_int_t from = (VECTOR(s)[k] - (((igraph_real_t)to) * (to + 1)) / 2); igraph_vector_int_push_back(&edges, VECTOR(*v1)[from]); igraph_vector_int_push_back(&edges, VECTOR(*v1)[to]); } } else { for (k = 0; k < l; k++) { - igraph_integer_t to = floor((sqrt(8 * VECTOR(s)[k] + 1) + 1) / 2); - igraph_integer_t from = (VECTOR(s)[k] - (((igraph_real_t)to) * (to - 1)) / 2); + igraph_int_t to = floor((sqrt(8 * VECTOR(s)[k] + 1) + 1) / 2); + igraph_int_t from = (VECTOR(s)[k] - (((igraph_real_t)to) * (to - 1)) / 2); igraph_vector_int_push_back(&edges, VECTOR(*v1)[from]); igraph_vector_int_push_back(&edges, VECTOR(*v1)[to]); } @@ -327,8 +323,6 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, } } - RNG_END(); - igraph_vector_destroy(&s); igraph_vector_int_list_destroy(&vids_by_type); IGRAPH_FINALLY_CLEAN(2); @@ -384,16 +378,16 @@ igraph_error_t igraph_preference_game(igraph_t *graph, igraph_integer_t nodes, * \sa \ref igraph_preference_game() */ -igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_integer_t nodes, - igraph_integer_t no_out_types, - igraph_integer_t no_in_types, +igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_int_t nodes, + igraph_int_t no_out_types, + igraph_int_t no_in_types, const igraph_matrix_t *type_dist_matrix, const igraph_matrix_t *pref_matrix, igraph_vector_int_t *node_type_out_vec, igraph_vector_int_t *node_type_in_vec, igraph_bool_t loops) { - igraph_integer_t i, j, k, no_reserved_edges; + igraph_int_t i, j, k, no_reserved_edges; igraph_vector_int_t edges; igraph_vector_t s; igraph_vector_t cumdist; @@ -490,10 +484,8 @@ igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_integer } maxcum = igraph_vector_tail(&cumdist); - RNG_BEGIN(); - for (i = 0; i < nodes; i++) { - igraph_integer_t in_type, out_type; + igraph_int_t in_type, out_type; igraph_real_t uni1 = RNG_UNIF(0, maxcum); igraph_vector_binsearch(&cumdist, uni1, &in_type); out_type = (in_type - 1) % no_out_types; @@ -516,11 +508,11 @@ igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_integer IGRAPH_VECTOR_INT_INIT_FINALLY(&intersect, 0); for (i = 0; i < no_out_types; i++) { for (j = 0; j < no_in_types; j++) { - igraph_integer_t kk, l, l_x2; - igraph_integer_t c = 0; + igraph_int_t kk, l, l_x2; + igraph_int_t c = 0; igraph_real_t p, last; igraph_vector_int_t *v1, *v2; - igraph_integer_t v1_size, v2_size; + igraph_int_t v1_size, v2_size; IGRAPH_ALLOW_INTERRUPTION(); @@ -562,8 +554,8 @@ igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_integer if (!loops && c > 0) { for (kk = 0; kk < l; kk++) { - igraph_integer_t to = floor(VECTOR(s)[kk] / v1_size); - igraph_integer_t from = (VECTOR(s)[kk] - ((igraph_real_t) to) * v1_size); + igraph_int_t to = floor(VECTOR(s)[kk] / v1_size); + igraph_int_t from = (VECTOR(s)[kk] - ((igraph_real_t) to) * v1_size); if (VECTOR(*v1)[from] == VECTOR(*v2)[to]) { /* remap loop edges */ to = v2_size - 1; @@ -584,8 +576,8 @@ igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_integer } } else { for (kk = 0; kk < l; kk++) { - igraph_integer_t to = floor(VECTOR(s)[kk] / v1_size); - igraph_integer_t from = (VECTOR(s)[kk] - ((igraph_real_t)to) * v1_size); + igraph_int_t to = floor(VECTOR(s)[kk] / v1_size); + igraph_int_t from = (VECTOR(s)[kk] - ((igraph_real_t)to) * v1_size); igraph_vector_int_push_back(&edges, VECTOR(*v1)[from]); igraph_vector_int_push_back(&edges, VECTOR(*v2)[to]); } @@ -593,8 +585,6 @@ igraph_error_t igraph_asymmetric_preference_game(igraph_t *graph, igraph_integer } } - RNG_END(); - igraph_vector_destroy(&s); igraph_vector_int_destroy(&intersect); igraph_vector_int_list_destroy(&vids_by_intype); diff --git a/src/vendor/cigraph/src/games/recent_degree.c b/src/vendor/cigraph/src/games/recent_degree.c index 63d9fbb93ad..9461fda9067 100644 --- a/src/vendor/cigraph/src/games/recent_degree.c +++ b/src/vendor/cigraph/src/games/recent_degree.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -63,34 +61,33 @@ * vertices, |E| is the number of edges in the graph. * */ -igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_integer_t nodes, +igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_int_t nodes, igraph_real_t power, - igraph_integer_t time_window, - igraph_integer_t m, + igraph_int_t time_window, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t zero_appeal, igraph_bool_t directed) { - igraph_integer_t no_of_nodes = nodes; - igraph_integer_t no_of_neighbors = 0; - igraph_integer_t no_of_edges; + igraph_int_t no_of_nodes = nodes; + igraph_int_t no_of_neighbors = 0; + igraph_int_t no_of_edges; igraph_vector_int_t edges; - igraph_integer_t i, j; + igraph_int_t i, j; igraph_psumtree_t sumtree; - igraph_integer_t edgeptr = 0; + igraph_int_t edgeptr = 0; igraph_vector_t degree; igraph_dqueue_int_t history; - igraph_bool_t have_outseq = outseq && igraph_vector_int_size(outseq) > 0; if (no_of_nodes < 0) { IGRAPH_ERRORF("Number of vertices cannot be negative, got %" IGRAPH_PRId ".", IGRAPH_EINVAL, no_of_nodes); } - if (have_outseq && igraph_vector_int_size(outseq) != no_of_nodes) { + if (outseq && igraph_vector_int_size(outseq) != no_of_nodes) { IGRAPH_ERRORF("Out-degree sequence is specified, but its length (%" IGRAPH_PRId ") does not equal the number of nodes (%" IGRAPH_PRId ").", IGRAPH_EINVAL, igraph_vector_int_size(outseq), no_of_nodes); } - if (!have_outseq && m < 0) { + if (!outseq && m < 0) { IGRAPH_ERRORF("Number of edges per step cannot be negative, got %" IGRAPH_PRId ".", IGRAPH_EINVAL, m); } @@ -101,12 +98,14 @@ igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_integer_t nodes IGRAPH_ERRORF("The zero appeal cannot be negative, got %g.", IGRAPH_EINVAL, zero_appeal); } + /* This effectively also hanbdles an outseq size of 0. + * From here on we assume that outseq has a size of at least 1. */ if (no_of_nodes == 0) { IGRAPH_CHECK(igraph_empty(graph, 0, directed)); return IGRAPH_SUCCESS; } - if (!have_outseq) { + if (!outseq) { no_of_neighbors = m; IGRAPH_SAFE_MULT(no_of_nodes - 1, no_of_neighbors, &no_of_edges); } else { @@ -126,8 +125,6 @@ igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_integer_t nodes 1.5 * time_window * no_of_edges / no_of_nodes + 10)); IGRAPH_FINALLY(igraph_dqueue_int_destroy, &history); - RNG_BEGIN(); - /* first node */ IGRAPH_CHECK(igraph_psumtree_update(&sumtree, 0, zero_appeal)); IGRAPH_CHECK(igraph_dqueue_int_push(&history, -1)); @@ -135,8 +132,8 @@ igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_integer_t nodes /* and the rest */ for (i = 1; i < no_of_nodes; i++) { igraph_real_t sum; - igraph_integer_t to; - if (have_outseq) { + igraph_int_t to; + if (outseq) { no_of_neighbors = VECTOR(*outseq)[i]; } @@ -165,7 +162,7 @@ igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_integer_t nodes /* update probabilities */ for (j = 0; j < no_of_neighbors; j++) { - igraph_integer_t nn = VECTOR(edges)[edgeptr - 2 * j - 1]; + igraph_int_t nn = VECTOR(edges)[edgeptr - 2 * j - 1]; IGRAPH_CHECK(igraph_psumtree_update(&sumtree, nn, pow(VECTOR(degree)[nn], power) + zero_appeal)); } if (outpref) { @@ -176,8 +173,6 @@ igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_integer_t nodes } } - RNG_END(); - igraph_dqueue_int_destroy(&history); igraph_psumtree_destroy(&sumtree); igraph_vector_destroy(°ree); @@ -231,37 +226,36 @@ igraph_error_t igraph_recent_degree_game(igraph_t *graph, igraph_integer_t nodes * of vertices, |E| the number of edges. */ igraph_error_t igraph_recent_degree_aging_game(igraph_t *graph, - igraph_integer_t nodes, - igraph_integer_t m, + igraph_int_t nodes, + igraph_int_t m, const igraph_vector_int_t *outseq, igraph_bool_t outpref, igraph_real_t pa_exp, igraph_real_t aging_exp, - igraph_integer_t aging_bins, - igraph_integer_t time_window, + igraph_int_t aging_bins, + igraph_int_t time_window, igraph_real_t zero_appeal, igraph_bool_t directed) { - igraph_integer_t no_of_nodes = nodes; - igraph_integer_t no_of_neighbors; - igraph_integer_t binwidth; - igraph_integer_t no_of_edges; + igraph_int_t no_of_nodes = nodes; + igraph_int_t no_of_neighbors; + igraph_int_t binwidth; + igraph_int_t no_of_edges; igraph_vector_int_t edges; - igraph_integer_t i, j, k; + igraph_int_t i, j, k; igraph_psumtree_t sumtree; - igraph_integer_t edgeptr = 0; + igraph_int_t edgeptr = 0; igraph_vector_t degree; igraph_dqueue_int_t history; - igraph_bool_t have_outseq = outseq && igraph_vector_int_size(outseq) > 0; if (no_of_nodes < 0) { IGRAPH_ERRORF("Number of nodes should not be negative, got %" IGRAPH_PRId ".", IGRAPH_EINVAL, no_of_nodes); } - if (have_outseq && igraph_vector_int_size(outseq) != no_of_nodes) { + if (outseq && igraph_vector_int_size(outseq) != no_of_nodes) { IGRAPH_ERRORF("Out-degree sequence is specified, but its length (%" IGRAPH_PRId ") does not equal the number of nodes (%" IGRAPH_PRId ").", IGRAPH_EINVAL, igraph_vector_int_size(outseq), no_of_nodes); } - if (!have_outseq && m < 0) { + if (!outseq && m < 0) { IGRAPH_ERRORF("Numer of edges per step cannot be negative, got %" IGRAPH_PRId ".", IGRAPH_EINVAL, m); } if (aging_bins <= 0) { @@ -274,12 +268,14 @@ igraph_error_t igraph_recent_degree_aging_game(igraph_t *graph, IGRAPH_ERRORF("The zero appeal cannot be negative, got %g.", IGRAPH_EINVAL, zero_appeal); } + /* This effectively also hanbdles an outseq size of 0. + * From here on we assume that outseq has a size of at least 1. */ if (no_of_nodes == 0) { IGRAPH_CHECK(igraph_empty(graph, 0, directed)); return IGRAPH_SUCCESS; } - if (!have_outseq) { + if (!outseq) { no_of_neighbors = m; IGRAPH_SAFE_MULT(no_of_nodes - 1, no_of_neighbors, &no_of_edges); } else { @@ -301,8 +297,6 @@ igraph_error_t igraph_recent_degree_aging_game(igraph_t *graph, 1.5 * time_window * no_of_edges / no_of_nodes + 10)); IGRAPH_FINALLY(igraph_dqueue_int_destroy, &history); - RNG_BEGIN(); - /* first node */ IGRAPH_CHECK(igraph_psumtree_update(&sumtree, 0, zero_appeal)); IGRAPH_CHECK(igraph_dqueue_int_push(&history, -1)); @@ -310,15 +304,15 @@ igraph_error_t igraph_recent_degree_aging_game(igraph_t *graph, /* and the rest */ for (i = 1; i < no_of_nodes; i++) { igraph_real_t sum; - igraph_integer_t to; + igraph_int_t to; - if (have_outseq) { + if (outseq) { no_of_neighbors = VECTOR(*outseq)[i]; } if (i >= time_window) { while ((j = igraph_dqueue_int_pop(&history)) != -1) { - igraph_integer_t age = (i - j) / binwidth; + igraph_int_t age = (i - j) / binwidth; VECTOR(degree)[j] -= 1; IGRAPH_CHECK(igraph_psumtree_update( &sumtree, j, @@ -345,8 +339,8 @@ igraph_error_t igraph_recent_degree_aging_game(igraph_t *graph, /* update probabilities */ for (j = 0; j < no_of_neighbors; j++) { - igraph_integer_t n = VECTOR(edges)[edgeptr - 2 * j - 1]; - igraph_integer_t age = (i - n) / binwidth; + igraph_int_t n = VECTOR(edges)[edgeptr - 2 * j - 1]; + igraph_int_t age = (i - n) / binwidth; IGRAPH_CHECK(igraph_psumtree_update( &sumtree, n, (pow(VECTOR(degree)[n], pa_exp) + zero_appeal) * pow(age + 1, aging_exp) @@ -364,9 +358,9 @@ igraph_error_t igraph_recent_degree_aging_game(igraph_t *graph, /* aging */ for (k = 1; binwidth * k <= i; k++) { - igraph_integer_t shnode = i - binwidth * k; - igraph_integer_t deg = VECTOR(degree)[shnode]; - igraph_integer_t age = (i - shnode) / binwidth; + igraph_int_t shnode = i - binwidth * k; + igraph_int_t deg = VECTOR(degree)[shnode]; + igraph_int_t age = (i - shnode) / binwidth; IGRAPH_CHECK(igraph_psumtree_update( &sumtree, shnode, (pow(deg, pa_exp) + zero_appeal) * pow(age + 2, aging_exp) @@ -374,8 +368,6 @@ igraph_error_t igraph_recent_degree_aging_game(igraph_t *graph, } } - RNG_END(); - igraph_dqueue_int_destroy(&history); igraph_vector_destroy(°ree); igraph_psumtree_destroy(&sumtree); diff --git a/src/vendor/cigraph/src/games/sbm.c b/src/vendor/cigraph/src/games/sbm.c index 12cf6639536..db8b1dd6416 100644 --- a/src/vendor/cigraph/src/games/sbm.c +++ b/src/vendor/cigraph/src/games/sbm.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2003-2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -25,6 +25,7 @@ #include "core/interruption.h" #include "math/safe_intop.h" +#include "misc/graphicality.h" #include /* for DBL_EPSILON */ #include /* for sqrt and floor */ @@ -33,67 +34,88 @@ * \function igraph_sbm_game * \brief Sample from a stochastic block model. * - * This function samples graphs from a stochastic block - * model by (doing the equivalent of) Bernoulli - * trials for each potential edge with the probabilities - * given by the Bernoulli rate matrix, \p pref_matrix. - * See Faust, K., & Wasserman, S. (1992a). Blockmodels: - * Interpretation and evaluation. Social Networks, 14, 5-–61. + * This function samples graphs from a stochastic block model, a generalization + * of the G(n,p) model where the connection probability p (or expected number + * of edges for multigraphs) is specified separately between and within a given + * group of vertices. * * * The order of the vertex IDs in the generated graph corresponds to * the \p block_sizes argument. * + * + * Reference: + * + * + * Faust, K., & Wasserman, S. (1992a). + * Blockmodels: Interpretation and evaluation. + * Social Networks, 14, 5-–61. + * https://doi.org/10.1016/0378-8733(92)90013-W + * * \param graph The output graph. This should be a pointer to an * uninitialized graph. - * \param n Number of vertices. - * \param pref_matrix The matrix giving the Bernoulli rates. - * This is a KxK matrix, where K is the number of groups. + * \param pref_matrix The matrix giving the connection probabilities + * (or expected edge multiplicities for multigraphs) between groups. + * This is a k-by-k matrix, where k is the number of groups. * The probability of creating an edge between vertices from * groups i and j is given by element (i,j). * \param block_sizes An integer vector giving the number of * vertices in each group. * \param directed Boolean, whether to create a directed graph. If - * this argument is false, then \p pref_matrix must be symmetric. - * \param loops Boolean, whether to create self-loops. + * this argument is \c false, then \p pref_matrix must be symmetric. + * \param allowed_edge_types Controls whether multi-edges and self-loops + * are generated. See \ref igraph_edge_type_sw_t. * \return Error code. * - * Time complexity: O(|V|+|E|+K^2), where |V| is the number of - * vertices, |E| is the number of edges, and K is the number of + * Time complexity: O(|V|+|E|+k^2), where |V| is the number of + * vertices, |E| is the number of edges, and k is the number of * groups. * * \sa \ref igraph_erdos_renyi_game_gnp() for a simple Bernoulli graph. * */ -igraph_error_t igraph_sbm_game(igraph_t *graph, igraph_integer_t n, - const igraph_matrix_t *pref_matrix, - const igraph_vector_int_t *block_sizes, - igraph_bool_t directed, igraph_bool_t loops) { +igraph_error_t igraph_sbm_game( + igraph_t *graph, + const igraph_matrix_t *pref_matrix, + const igraph_vector_int_t *block_sizes, + igraph_bool_t directed, + igraph_edge_type_sw_t allowed_edge_types) { -#define IGRAPH_CHECK_MAXEDGES() \ +#define CHECK_MAXEDGES() \ do {if (maxedges > IGRAPH_MAX_EXACT_REAL) { \ IGRAPH_ERROR("Too many vertices, overflow in maximum number of edges.", IGRAPH_EOVERFLOW); \ }} while (0) - igraph_integer_t no_blocks = igraph_matrix_nrow(pref_matrix); - igraph_integer_t from, to, fromoff = 0; + const igraph_int_t n = igraph_vector_int_sum(block_sizes); + const igraph_int_t no_blocks = igraph_matrix_nrow(pref_matrix); + igraph_int_t from, to, fromoff = 0; igraph_real_t minp, maxp; igraph_vector_int_t edges; + igraph_bool_t loops, multiple; + + IGRAPH_CHECK(igraph_i_edge_type_to_loops_multiple(allowed_edge_types, &loops, &multiple)); /* ------------------------------------------------------------ */ /* Check arguments */ /* ------------------------------------------------------------ */ if (igraph_matrix_ncol(pref_matrix) != no_blocks) { - IGRAPH_ERROR("Preference matrix is not square.", - IGRAPH_NONSQUARE); + IGRAPH_ERROR("Preference matrix is not square.", IGRAPH_EINVAL); } if (no_blocks > 0) { igraph_matrix_minmax(pref_matrix, &minp, &maxp); - if (minp < 0 || maxp > 1) { - IGRAPH_ERROR("Connection probabilities must be in [0,1].", IGRAPH_EINVAL); + if (multiple) { + if (minp < 0.0) { + IGRAPH_ERRORF("Expected edge multiplicities must not be negative " + "for SBM multigraph model, got %g.", + IGRAPH_EINVAL, minp); + } + } else { + if (minp < 0 || maxp > 1) { + IGRAPH_ERROR("Connection probabilities must be in [0,1] for SBM model.", IGRAPH_EINVAL); + } } } @@ -115,24 +137,12 @@ igraph_error_t igraph_sbm_game(igraph_t *graph, igraph_integer_t n, } } - if (igraph_vector_int_sum(block_sizes) != n) { - IGRAPH_ERRORF("Sum of the block sizes (%" IGRAPH_PRId ") must equal the number of vertices (%" IGRAPH_PRId ").", - IGRAPH_EINVAL, igraph_vector_int_sum(block_sizes), n); - } - - /* Since the sum of the block sizes should equal the number of vertices, - * and the block sizes are non-negative, the number of vertices is - * guaranteed to be non-negative. This shouldn't be checked separately. - */ - IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - RNG_BEGIN(); - for (from = 0; from < no_blocks; from++) { - igraph_integer_t fromsize = VECTOR(*block_sizes)[from]; - igraph_integer_t start = directed ? 0 : from; - igraph_integer_t i, tooff = 0; + igraph_int_t fromsize = VECTOR(*block_sizes)[from]; + igraph_int_t start = directed ? 0 : from; + igraph_int_t i, tooff = 0; IGRAPH_ALLOW_INTERRUPTION(); @@ -140,37 +150,42 @@ igraph_error_t igraph_sbm_game(igraph_t *graph, igraph_integer_t n, tooff += VECTOR(*block_sizes)[i]; } for (to = start; to < no_blocks; to++) { - igraph_integer_t tosize = VECTOR(*block_sizes)[to]; + igraph_int_t tosize = VECTOR(*block_sizes)[to]; + igraph_real_t prob = MATRIX(*pref_matrix, from, to); + if (multiple) { + prob = prob / (1 + prob); + } + igraph_real_t maxedges; - igraph_real_t last = RNG_GEOM(prob); /* RNG_GEOM may return NaN so igraph_integer_t is not suitable */ - igraph_integer_t vfrom, vto; + igraph_real_t last = RNG_GEOM(prob); /* RNG_GEOM may return NaN so igraph_int_t is not suitable */ + igraph_int_t vfrom, vto; if (directed && loops) { maxedges = ((igraph_real_t) fromsize) * tosize; - IGRAPH_CHECK_MAXEDGES(); + CHECK_MAXEDGES(); while (last < maxedges) { vto = floor(last / fromsize); vfrom = last - ((igraph_real_t) vto) * fromsize; igraph_vector_int_push_back(&edges, fromoff + vfrom); igraph_vector_int_push_back(&edges, tooff + vto); last += RNG_GEOM(prob); - last += 1; + last += ! multiple; /* 1 for simple graph, 0 for multigraph */; } } else if (directed && !loops && from != to) { maxedges = ((igraph_real_t) fromsize) * tosize; - IGRAPH_CHECK_MAXEDGES(); + CHECK_MAXEDGES(); while (last < maxedges) { vto = floor(last / fromsize); vfrom = last - ((igraph_real_t) vto) * fromsize; igraph_vector_int_push_back(&edges, fromoff + vfrom); igraph_vector_int_push_back(&edges, tooff + vto); last += RNG_GEOM(prob); - last += 1; + last += ! multiple; /* 1 for simple graph, 0 for multigraph */; } } else if (directed && !loops && from == to) { maxedges = ((igraph_real_t) fromsize) * (fromsize - 1.0); - IGRAPH_CHECK_MAXEDGES(); + CHECK_MAXEDGES(); while (last < maxedges) { vto = floor(last / fromsize); vfrom = last - ((igraph_real_t) vto) * fromsize; @@ -180,51 +195,51 @@ igraph_error_t igraph_sbm_game(igraph_t *graph, igraph_integer_t n, igraph_vector_int_push_back(&edges, fromoff + vfrom); igraph_vector_int_push_back(&edges, tooff + vto); last += RNG_GEOM(prob); - last += 1; + last += ! multiple; /* 1 for simple graph, 0 for multigraph */; } } else if (!directed && loops && from != to) { maxedges = ((igraph_real_t) fromsize) * tosize; - IGRAPH_CHECK_MAXEDGES(); + CHECK_MAXEDGES(); while (last < maxedges) { vto = floor(last / fromsize); vfrom = last - ((igraph_real_t) vto) * fromsize; igraph_vector_int_push_back(&edges, fromoff + vfrom); igraph_vector_int_push_back(&edges, tooff + vto); last += RNG_GEOM(prob); - last += 1; + last += ! multiple; /* 1 for simple graph, 0 for multigraph */; } } else if (!directed && loops && from == to) { maxedges = ((igraph_real_t) fromsize) * (fromsize + 1.0) / 2.0; - IGRAPH_CHECK_MAXEDGES(); + CHECK_MAXEDGES(); while (last < maxedges) { vto = floor((sqrt(8 * last + 1) - 1) / 2); vfrom = last - (((igraph_real_t) vto) * (vto + 1.0)) / 2.0; igraph_vector_int_push_back(&edges, fromoff + vfrom); igraph_vector_int_push_back(&edges, tooff + vto); last += RNG_GEOM(prob); - last += 1; + last += ! multiple; /* 1 for simple graph, 0 for multigraph */; } } else if (!directed && !loops && from != to) { maxedges = ((igraph_real_t) fromsize) * tosize; - IGRAPH_CHECK_MAXEDGES(); + CHECK_MAXEDGES(); while (last < maxedges) { vto = floor(last / fromsize); vfrom = last - ((igraph_real_t) vto) * fromsize; igraph_vector_int_push_back(&edges, fromoff + vfrom); igraph_vector_int_push_back(&edges, tooff + vto); last += RNG_GEOM(prob); - last += 1; + last += ! multiple; /* 1 for simple graph, 0 for multigraph */; } } else { /*!directed && !loops && from==to */ maxedges = ((igraph_real_t) fromsize) * (fromsize - 1.0) / 2.0; - IGRAPH_CHECK_MAXEDGES(); + CHECK_MAXEDGES(); while (last < maxedges) { vto = floor((sqrt(8 * last + 1) + 1) / 2); vfrom = last - (((igraph_real_t) vto) * (vto - 1.0)) / 2.0; igraph_vector_int_push_back(&edges, fromoff + vfrom); igraph_vector_int_push_back(&edges, tooff + vto); last += RNG_GEOM(prob); - last += 1; + last += ! multiple; /* 1 for simple graph, 0 for multigraph */; } } @@ -233,15 +248,13 @@ igraph_error_t igraph_sbm_game(igraph_t *graph, igraph_integer_t n, fromoff += fromsize; } - RNG_END(); - IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); igraph_vector_int_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); return IGRAPH_SUCCESS; -#undef IGRAPH_CHECK_MAXEDGES +#undef CHECK_MAXEDGES } /** @@ -268,20 +281,20 @@ igraph_error_t igraph_sbm_game(igraph_t *graph, igraph_integer_t n, * \ref igraph_hsbm_list_game() for a more general version. */ -igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, - igraph_integer_t m, const igraph_vector_t *rho, +igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_int_t n, + igraph_int_t m, const igraph_vector_t *rho, const igraph_matrix_t *C, igraph_real_t p) { -#define IGRAPH_CHECK_MAXEDGES() \ +#define CHECK_MAXEDGES() \ do {if (maxedges > IGRAPH_MAX_EXACT_REAL) { \ IGRAPH_ERROR("Too many vertices, overflow in maximum number of edges.", IGRAPH_EOVERFLOW); \ }} while (0) - igraph_integer_t b, i, k = igraph_vector_size(rho); + igraph_int_t b, i, k = igraph_vector_size(rho); igraph_vector_t csizes; igraph_real_t sq_dbl_epsilon = sqrt(DBL_EPSILON); - igraph_integer_t no_blocks = n / m; + igraph_int_t no_blocks = n / m; igraph_vector_int_t edges; - igraph_integer_t offset = 0; + igraph_int_t offset = 0; if (n < 1) { IGRAPH_ERROR("`n' must be positive for HSBM", IGRAPH_EINVAL); @@ -326,30 +339,28 @@ igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - RNG_BEGIN(); - /* Block models first */ for (b = 0; b < no_blocks; b++) { - igraph_integer_t from, to, fromoff = 0; + igraph_int_t from, to, fromoff = 0; for (from = 0; from < k; from++) { - igraph_integer_t fromsize = VECTOR(csizes)[from]; - igraph_integer_t i, tooff = 0; + igraph_int_t fromsize = VECTOR(csizes)[from]; + igraph_int_t i, tooff = 0; for (i = 0; i < from; i++) { tooff += VECTOR(csizes)[i]; } for (to = from; to < k; to++) { - igraph_integer_t tosize = VECTOR(csizes)[to]; + igraph_int_t tosize = VECTOR(csizes)[to]; igraph_real_t prob = MATRIX(*C, from, to); igraph_real_t maxedges; - igraph_real_t last = RNG_GEOM(prob); /* RNG_GEOM may return NaN so igraph_integer_t is not suitable */ + igraph_real_t last = RNG_GEOM(prob); /* RNG_GEOM may return NaN so igraph_int_t is not suitable */ if (from != to) { maxedges = ((igraph_real_t) fromsize) * tosize; - IGRAPH_CHECK_MAXEDGES(); + CHECK_MAXEDGES(); while (last < maxedges) { - igraph_integer_t vto = floor(last / fromsize); - igraph_integer_t vfrom = last - ((igraph_real_t) vto) * fromsize; + igraph_int_t vto = floor(last / fromsize); + igraph_int_t vfrom = last - ((igraph_real_t) vto) * fromsize; IGRAPH_CHECK(igraph_vector_int_push_back(&edges, offset + fromoff + vfrom)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, offset + tooff + vto)); last += RNG_GEOM(prob); @@ -357,10 +368,10 @@ igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, } } else { /* from==to */ maxedges = ((igraph_real_t) fromsize) * (fromsize - 1.0) / 2.0; - IGRAPH_CHECK_MAXEDGES(); + CHECK_MAXEDGES(); while (last < maxedges) { - igraph_integer_t vto = floor((sqrt(8 * last + 1) + 1) / 2); - igraph_integer_t vfrom = last - (((igraph_real_t) vto) * (vto - 1.0)) / 2.0; + igraph_int_t vto = floor((sqrt(8 * last + 1) + 1) / 2); + igraph_int_t vfrom = last - (((igraph_real_t) vto) * (vto - 1.0)) / 2.0; IGRAPH_CHECK(igraph_vector_int_push_back(&edges, offset + fromoff + vfrom)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, offset + tooff + vto)); last += RNG_GEOM(prob); @@ -379,11 +390,11 @@ igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, /* And now the rest, if not a special case */ if (p == 1) { - igraph_integer_t fromoff = 0, tooff = m; + igraph_int_t fromoff = 0, tooff = m; for (b = 0; b < no_blocks; b++) { - igraph_integer_t fromsize = m; - igraph_integer_t tosize = n - tooff; - igraph_integer_t from, to; + igraph_int_t fromsize = m; + igraph_int_t tosize = n - tooff; + igraph_int_t from, to; for (from = 0; from < fromsize; from++) { for (to = 0; to < tosize; to++) { IGRAPH_CHECK(igraph_vector_int_push_back(&edges, fromoff + from)); @@ -394,16 +405,16 @@ igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, tooff += m; } } else if (p > 0) { - igraph_integer_t fromoff = 0, tooff = m; + igraph_int_t fromoff = 0, tooff = m; for (b = 0; b < no_blocks; b++) { - igraph_integer_t fromsize = m; - igraph_integer_t tosize = n - tooff; + igraph_int_t fromsize = m; + igraph_int_t tosize = n - tooff; igraph_real_t maxedges = ((igraph_real_t) fromsize) * tosize; - IGRAPH_CHECK_MAXEDGES(); - igraph_real_t last = RNG_GEOM(p); /* RNG_GEOM may return NaN so igraph_integer_t is not suitable */ + CHECK_MAXEDGES(); + igraph_real_t last = RNG_GEOM(p); /* RNG_GEOM may return NaN so igraph_int_t is not suitable */ while (last < maxedges) { - igraph_integer_t vto = floor(last / fromsize); - igraph_integer_t vfrom = last - ((igraph_real_t) vto) * fromsize; + igraph_int_t vto = floor(last / fromsize); + igraph_int_t vfrom = last - ((igraph_real_t) vto) * fromsize; IGRAPH_CHECK(igraph_vector_int_push_back(&edges, fromoff + vfrom)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, tooff + vto)); last += RNG_GEOM(p); @@ -415,8 +426,6 @@ igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, } } - RNG_END(); - IGRAPH_CHECK(igraph_create(graph, &edges, n, /*directed=*/ 0)); igraph_vector_int_destroy(&edges); @@ -424,7 +433,7 @@ igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, IGRAPH_FINALLY_CLEAN(2); return IGRAPH_SUCCESS; -#undef IGRAPH_CHECK_MAXEDGES +#undef CHECK_MAXEDGES } /** @@ -450,17 +459,17 @@ igraph_error_t igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, * \ref igraph_hsbm_game() for a simpler general version. */ -igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n, +igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_int_t n, const igraph_vector_int_t *mlist, const igraph_vector_list_t *rholist, const igraph_matrix_list_t *Clist, igraph_real_t p) { - igraph_integer_t i, no_blocks = igraph_vector_list_size(rholist); + igraph_int_t i, no_blocks = igraph_vector_list_size(rholist); igraph_real_t sq_dbl_epsilon = sqrt(DBL_EPSILON); igraph_vector_int_t edges; igraph_vector_t csizes; - igraph_integer_t b, offset = 0; + igraph_int_t b, offset = 0; if (n < 1) { IGRAPH_ERROR("`n' must be positive for HSBM.", IGRAPH_EINVAL); @@ -509,7 +518,7 @@ igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n, for (i = 0; i < no_blocks; i++) { const igraph_vector_t *rho = igraph_vector_list_get_ptr(rholist, i); const igraph_matrix_t *C = igraph_matrix_list_get_ptr(Clist, i); - igraph_integer_t k = igraph_vector_size(rho); + igraph_int_t k = igraph_vector_size(rho); if (igraph_matrix_nrow(C) != k || igraph_matrix_ncol(C) != k) { IGRAPH_ERROR("All Bernoulli rate matrix dimensions must match `rho' " "dimensions in HSBM.", @@ -520,7 +529,7 @@ igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n, for (i = 0; i < no_blocks; i++) { const igraph_vector_t *rho = igraph_vector_list_get_ptr(rholist, i); igraph_real_t m = VECTOR(*mlist)[i]; - igraph_integer_t j, k = igraph_vector_size(rho); + igraph_int_t j, k = igraph_vector_size(rho); for (j = 0; j < k; j++) { igraph_real_t s = VECTOR(*rho)[j] * m; if (fabs(round(s) - s) > sq_dbl_epsilon) { @@ -532,16 +541,14 @@ igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n, IGRAPH_VECTOR_INIT_FINALLY(&csizes, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - RNG_BEGIN(); - /* Block models first */ for (b = 0; b < no_blocks; b++) { - igraph_integer_t from, to, fromoff = 0; + igraph_int_t from, to, fromoff = 0; const igraph_vector_t *rho = igraph_vector_list_get_ptr(rholist, b); const igraph_matrix_t *C = igraph_matrix_list_get_ptr(Clist, b); - igraph_integer_t m = VECTOR(*mlist)[b]; - igraph_integer_t k = igraph_vector_size(rho); + igraph_int_t m = VECTOR(*mlist)[b]; + igraph_int_t k = igraph_vector_size(rho); IGRAPH_CHECK(igraph_vector_resize(&csizes, k)); for (i = 0; i < k; i++) { @@ -549,21 +556,21 @@ igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n, } for (from = 0; from < k; from++) { - igraph_integer_t fromsize = VECTOR(csizes)[from]; - igraph_integer_t i, tooff = 0; + igraph_int_t fromsize = VECTOR(csizes)[from]; + igraph_int_t i, tooff = 0; for (i = 0; i < from; i++) { tooff += VECTOR(csizes)[i]; } for (to = from; to < k; to++) { - igraph_integer_t tosize = VECTOR(csizes)[to]; + igraph_int_t tosize = VECTOR(csizes)[to]; igraph_real_t prob = MATRIX(*C, from, to); igraph_real_t maxedges; - igraph_real_t last = RNG_GEOM(prob); /* RNG_GEOM may return NaN so igraph_integer_t is not suitable */ + igraph_real_t last = RNG_GEOM(prob); /* RNG_GEOM may return NaN so igraph_int_t is not suitable */ if (from != to) { maxedges = ((igraph_real_t) fromsize) * tosize; while (last < maxedges) { - igraph_integer_t vto = floor(last / fromsize); - igraph_integer_t vfrom = last - ((igraph_real_t) vto) * fromsize; + igraph_int_t vto = floor(last / fromsize); + igraph_int_t vfrom = last - ((igraph_real_t) vto) * fromsize; IGRAPH_CHECK(igraph_vector_int_push_back(&edges, offset + fromoff + vfrom)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, offset + tooff + vto)); last += RNG_GEOM(prob); @@ -572,8 +579,8 @@ igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n, } else { /* from==to */ maxedges = ((igraph_real_t) fromsize) * (fromsize - 1.0) / 2.0; while (last < maxedges) { - igraph_integer_t vto = floor((sqrt(8 * last + 1) + 1) / 2); - igraph_integer_t vfrom = last - (((igraph_real_t) vto) * (vto - 1.0)) / 2.0; + igraph_int_t vto = floor((sqrt(8 * last + 1) + 1) / 2); + igraph_int_t vfrom = last - (((igraph_real_t) vto) * (vto - 1.0)) / 2.0; IGRAPH_CHECK(igraph_vector_int_push_back(&edges, offset + fromoff + vfrom)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, offset + tooff + vto)); last += RNG_GEOM(prob); @@ -592,11 +599,11 @@ igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n, /* And now the rest, if not a special case */ if (p == 1) { - igraph_integer_t fromoff = 0, tooff = VECTOR(*mlist)[0]; + igraph_int_t fromoff = 0, tooff = VECTOR(*mlist)[0]; for (b = 0; b < no_blocks; b++) { - igraph_integer_t fromsize = VECTOR(*mlist)[b]; - igraph_integer_t tosize = n - tooff; - igraph_integer_t from, to; + igraph_int_t fromsize = VECTOR(*mlist)[b]; + igraph_int_t tosize = n - tooff; + igraph_int_t from, to; for (from = 0; from < fromsize; from++) { for (to = 0; to < tosize; to++) { IGRAPH_CHECK(igraph_vector_int_push_back(&edges, fromoff + from)); @@ -609,15 +616,15 @@ igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n, } } } else if (p > 0) { - igraph_integer_t fromoff = 0, tooff = VECTOR(*mlist)[0]; + igraph_int_t fromoff = 0, tooff = VECTOR(*mlist)[0]; for (b = 0; b < no_blocks; b++) { - igraph_integer_t fromsize = VECTOR(*mlist)[b]; - igraph_integer_t tosize = n - tooff; + igraph_int_t fromsize = VECTOR(*mlist)[b]; + igraph_int_t tosize = n - tooff; igraph_real_t maxedges = ((igraph_real_t) fromsize) * tosize; - igraph_real_t last = RNG_GEOM(p); /* RNG_GEOM may return NaN so igraph_integer_t is not suitable */ + igraph_real_t last = RNG_GEOM(p); /* RNG_GEOM may return NaN so igraph_int_t is not suitable */ while (last < maxedges) { - igraph_integer_t vto = floor(last / fromsize); - igraph_integer_t vfrom = last - ((igraph_real_t) vto) * fromsize; + igraph_int_t vto = floor(last / fromsize); + igraph_int_t vfrom = last - ((igraph_real_t) vto) * fromsize; IGRAPH_CHECK(igraph_vector_int_push_back(&edges, fromoff + vfrom)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, tooff + vto)); last += RNG_GEOM(p); @@ -631,8 +638,6 @@ igraph_error_t igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n, } } - RNG_END(); - IGRAPH_CHECK(igraph_create(graph, &edges, n, /*directed=*/ 0)); igraph_vector_int_destroy(&edges); diff --git a/src/vendor/cigraph/src/games/static_fitness.c b/src/vendor/cigraph/src/games/static_fitness.c index bc03c38a9b2..19177f3d135 100644 --- a/src/vendor/cigraph/src/games/static_fitness.c +++ b/src/vendor/cigraph/src/games/static_fitness.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -32,6 +30,7 @@ #include "core/interruption.h" #include "core/math.h" /* M_SQRT2 */ +#include "misc/graphicality.h" /** * \ingroup generators @@ -95,8 +94,8 @@ * \param fitness_in If \c NULL, the generated graph will be undirected. * If not \c NULL, this argument specifies the in-fitness * of each vertex. - * \param loops Whether to allow loop edges in the generated graph. - * \param multiple Whether to allow multiple edges in the generated graph. + * \param allowed_edge_types Controls whether multi-edges and self-loops + * are allowed in the generated graph. See \ref igraph_edge_type_sw_t. * * \return Error code: * \c IGRAPH_EINVAL: invalid parameter @@ -108,11 +107,11 @@ * * Time complexity: O(|V| + |E| log |E|). */ -igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_of_edges, +igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_int_t no_of_edges, const igraph_vector_t *fitness_out, const igraph_vector_t *fitness_in, - igraph_bool_t loops, igraph_bool_t multiple) { + igraph_edge_type_sw_t allowed_edge_types) { - const igraph_integer_t no_of_nodes = igraph_vector_size(fitness_out); + const igraph_int_t no_of_nodes = igraph_vector_size(fitness_out); const igraph_bool_t directed = (fitness_in != NULL); igraph_vector_int_t edges; igraph_vector_t cum_fitness_in, cum_fitness_out; @@ -120,9 +119,12 @@ igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_o igraph_real_t x, max_in, max_out; igraph_real_t max_no_of_edges; igraph_real_t num_steps; - igraph_integer_t from, to, pos; + igraph_int_t from, to, pos; + igraph_bool_t loops, multiple; int iter = 0; + IGRAPH_CHECK(igraph_i_edge_type_to_loops_multiple(allowed_edge_types, &loops, &multiple)); + IGRAPH_ASSERT(fitness_out != NULL); if (no_of_edges < 0) { @@ -148,11 +150,11 @@ igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_o /* Avoid getting into an infinite loop when too many edges are requested. */ { - igraph_integer_t nodes; + igraph_int_t nodes; if (directed) { - igraph_integer_t outnodes, innodes; + igraph_int_t outnodes, innodes; outnodes = innodes = nodes = 0; - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(*fitness_out)[i] != 0) { outnodes++; } @@ -166,7 +168,7 @@ igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_o max_no_of_edges = ((igraph_real_t) outnodes) * innodes - (loops ? 0 : nodes); } else { nodes = 0; - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(*fitness_out)[i] != 0) { nodes++; } @@ -202,7 +204,6 @@ igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_o p_cum_fitness_in = &cum_fitness_out; } - RNG_BEGIN(); num_steps = no_of_edges; if (multiple) { /* Generating when multiple edges are allowed */ @@ -227,8 +228,8 @@ igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_o continue; } - igraph_vector_int_push_back(&edges, from); - igraph_vector_int_push_back(&edges, to); + igraph_vector_int_push_back(&edges, from); /* reserved */ + igraph_vector_int_push_back(&edges, to); /* reserved */ no_of_edges--; } @@ -292,7 +293,6 @@ igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_o igraph_adjlist_destroy(&al); IGRAPH_FINALLY_CLEAN(1); } - RNG_END(); IGRAPH_PROGRESS("Static fitness game", 100.0, NULL); @@ -372,8 +372,8 @@ igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_o * the exponent of the in-degree distribution. If * non-negative but less than 2, an error will be * generated. - * \param loops Whether to allow loop edges in the generated graph. - * \param multiple Whether to allow multiple edges in the generated graph. + * \param allowed_edge_types Controls whether multi-edges and self-loops + * are allowed in the generated graph. See \ref igraph_edge_type_sw_t. * \param finite_size_correction Whether to use the proposed finite size * correction of Cho et al. * @@ -385,9 +385,9 @@ igraph_error_t igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_o * Time complexity: O(|V| + |E| log |E|). */ igraph_error_t igraph_static_power_law_game(igraph_t *graph, - igraph_integer_t no_of_nodes, igraph_integer_t no_of_edges, + igraph_int_t no_of_nodes, igraph_int_t no_of_edges, igraph_real_t exponent_out, igraph_real_t exponent_in, - igraph_bool_t loops, igraph_bool_t multiple, + igraph_edge_type_sw_t allowed_edge_types, igraph_bool_t finite_size_correction) { igraph_vector_t fitness_out, fitness_in; @@ -418,7 +418,7 @@ igraph_error_t igraph_static_power_law_game(igraph_t *graph, if (j < no_of_nodes) { j = no_of_nodes; } - for (igraph_integer_t i = 0; i < no_of_nodes; i++, j--) { + for (igraph_int_t i = 0; i < no_of_nodes; i++, j--) { VECTOR(fitness_out)[i] = pow(j, alpha_out); } @@ -442,19 +442,19 @@ igraph_error_t igraph_static_power_law_game(igraph_t *graph, if (j < no_of_nodes) { j = no_of_nodes; } - for (igraph_integer_t i = 0; i < no_of_nodes; i++, j--) { + for (igraph_int_t i = 0; i < no_of_nodes; i++, j--) { VECTOR(fitness_in)[i] = pow(j, alpha_in); } - IGRAPH_CHECK(igraph_vector_shuffle(&fitness_in)); + igraph_vector_shuffle(&fitness_in); IGRAPH_CHECK(igraph_static_fitness_game(graph, no_of_edges, - &fitness_out, &fitness_in, loops, multiple)); + &fitness_out, &fitness_in, allowed_edge_types)); igraph_vector_destroy(&fitness_in); IGRAPH_FINALLY_CLEAN(1); } else { IGRAPH_CHECK(igraph_static_fitness_game(graph, no_of_edges, - &fitness_out, NULL, loops, multiple)); + &fitness_out, NULL, allowed_edge_types)); } igraph_vector_destroy(&fitness_out); diff --git a/src/vendor/cigraph/src/games/tree.c b/src/vendor/cigraph/src/games/tree.c index 52b1b94144d..73fc097f2c3 100644 --- a/src/vendor/cigraph/src/games/tree.c +++ b/src/vendor/cigraph/src/games/tree.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -36,7 +34,7 @@ * them to trees. */ -static igraph_error_t igraph_i_tree_game_prufer(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed) { +static igraph_error_t igraph_i_tree_game_prufer(igraph_t *graph, igraph_int_t n, igraph_bool_t directed) { igraph_vector_int_t prufer; if (directed) { @@ -45,11 +43,9 @@ static igraph_error_t igraph_i_tree_game_prufer(igraph_t *graph, igraph_integer_ IGRAPH_VECTOR_INT_INIT_FINALLY(&prufer, n - 2); - RNG_BEGIN(); - for (igraph_integer_t i = 0; i < n - 2; ++i) { + for (igraph_int_t i = 0; i < n - 2; ++i) { VECTOR(prufer)[i] = RNG_INTEGER(0, n - 1); } - RNG_END(); IGRAPH_CHECK(igraph_from_prufer(graph, &prufer)); @@ -67,18 +63,18 @@ static igraph_error_t igraph_i_tree_game_prufer(igraph_t *graph, igraph_integer_ /* swap two elements of a vector_int */ #define SWAP_INT_ELEM(vec, i, j) \ { \ - igraph_integer_t temp; \ + igraph_int_t temp; \ temp = VECTOR(vec)[i]; \ VECTOR(vec)[i] = VECTOR(vec)[j]; \ VECTOR(vec)[j] = temp; \ } -static igraph_error_t igraph_i_tree_game_loop_erased_random_walk(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed) { +static igraph_error_t igraph_i_tree_game_loop_erased_random_walk(igraph_t *graph, igraph_int_t n, igraph_bool_t directed) { igraph_vector_int_t edges; igraph_vector_int_t vertices; igraph_bitset_t visited; - igraph_integer_t i, j; - igraph_integer_t no_edges; + igraph_int_t i, j; + igraph_int_t no_edges; IGRAPH_SAFE_MULT(n - 1, 2, &no_edges); @@ -91,8 +87,6 @@ static igraph_error_t igraph_i_tree_game_loop_erased_random_walk(igraph_t *graph IGRAPH_CHECK(igraph_vector_int_init_range(&vertices, 0, n)); IGRAPH_FINALLY(igraph_vector_int_destroy, &vertices); - RNG_BEGIN(); - /* A simple implementation could be as below. This is for illustration only. * The actually implemented algorithm avoids unnecessary walking on the already visited * portion of the vertex set. @@ -121,7 +115,7 @@ static igraph_error_t igraph_i_tree_game_loop_erased_random_walk(igraph_t *graph IGRAPH_BIT_SET(visited, i); SWAP_INT_ELEM(vertices, 0, i); - for (igraph_integer_t k = 1; k < n; ++k) { + for (igraph_int_t k = 1; k < n; ++k) { j = RNG_INTEGER(0, n - 1); if (IGRAPH_BIT_TEST(visited, VECTOR(vertices)[j])) { i = VECTOR(vertices)[j]; @@ -134,8 +128,6 @@ static igraph_error_t igraph_i_tree_game_loop_erased_random_walk(igraph_t *graph VECTOR(edges)[2 * k - 1] = i; } - RNG_END(); - IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); igraph_vector_int_destroy(&vertices); @@ -181,7 +173,7 @@ static igraph_error_t igraph_i_tree_game_loop_erased_random_walk(igraph_t *graph * */ -igraph_error_t igraph_tree_game(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, igraph_random_tree_t method) { +igraph_error_t igraph_tree_game(igraph_t *graph, igraph_int_t n, igraph_bool_t directed, igraph_random_tree_t method) { if (n < 2) { IGRAPH_CHECK(igraph_empty(graph, n, directed)); return IGRAPH_SUCCESS; diff --git a/src/vendor/cigraph/src/games/watts_strogatz.c b/src/vendor/cigraph/src/games/watts_strogatz.c index d7aa1c5aeff..24eb208e9eb 100644 --- a/src/vendor/cigraph/src/games/watts_strogatz.c +++ b/src/vendor/cigraph/src/games/watts_strogatz.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -62,8 +60,8 @@ * the same as the \p order argument of \ref igraph_connect_neighborhood(). * \param p The rewiring probability. A real number between zero and * one (inclusive). - * \param loops Whether to generate loop edges. - * \param multiple Whether to allow multiple edges in the generated graph. + * \param allowed_edge_types Controls whether multi-edges and self-loops + * are allowed in the generated graph. See \ref igraph_edge_type_sw_t. * \return Error code. * * \sa \ref igraph_square_lattice(), \ref igraph_connect_neighborhood() and @@ -74,10 +72,11 @@ * vertices and edges, d is the average degree, o is the \p nei * argument. */ -igraph_error_t igraph_watts_strogatz_game(igraph_t *graph, igraph_integer_t dim, - igraph_integer_t size, igraph_integer_t nei, - igraph_real_t p, igraph_bool_t loops, - igraph_bool_t multiple) { +igraph_error_t igraph_watts_strogatz_game( + igraph_t *graph, igraph_int_t dim, + igraph_int_t size, igraph_int_t nei, + igraph_real_t p, + igraph_edge_type_sw_t allowed_edge_types) { igraph_vector_int_t dimvector; igraph_vector_bool_t periodic; @@ -112,7 +111,7 @@ igraph_error_t igraph_watts_strogatz_game(igraph_t *graph, igraph_integer_t dim, /* Rewire the edges then */ - IGRAPH_CHECK(igraph_rewire_edges(graph, p, loops, multiple)); + IGRAPH_CHECK(igraph_rewire_edges(graph, p, allowed_edge_types)); IGRAPH_FINALLY_CLEAN(1); return IGRAPH_SUCCESS; diff --git a/src/vendor/cigraph/src/graph/adjlist.c b/src/vendor/cigraph/src/graph/adjlist.c index 15706dcc991..5bf58943e2c 100644 --- a/src/vendor/cigraph/src/graph/adjlist.c +++ b/src/vendor/cigraph/src/graph/adjlist.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -51,19 +50,11 @@ * there is no loop or multiple edge, only that the function hasn't found one. */ static igraph_error_t igraph_i_simplify_sorted_int_adjacency_vector_in_place( - igraph_vector_int_t *v, igraph_integer_t index, igraph_neimode_t mode, - igraph_loops_t loops, igraph_multiple_t multiple, igraph_bool_t *has_loops, + igraph_vector_int_t *v, igraph_int_t index, igraph_neimode_t mode, + igraph_loops_t loops, igraph_bool_t multiple, igraph_bool_t *has_loops, igraph_bool_t *has_multiple ); -/** - * Helper function that removes loops from an incidence vector (either both - * occurrences or only one of them). - */ -static igraph_error_t igraph_i_remove_loops_from_incidence_vector_in_place( - igraph_vector_int_t *v, const igraph_t *graph, igraph_loops_t loops -); - /** * \section about_adjlists * @@ -118,7 +109,13 @@ static igraph_error_t igraph_i_remove_loops_from_incidence_vector_in_place( * * * This function returns each neighbor list in sorted order, just - * like \ref igraph_neighbors(). + * like \ref igraph_neighbors(). However, adjacency lists \em "in general" + * are not guaranteed to be sorted, and we reserve the right to change the + * ordering of vertices in the result in the future without considering this + * a breaking change. If you need to ensure that the adjacency lists are + * sorted, you can use \ref igraph_adjlist_sort() to sort all the adjacency + * lists, or call \ref igraph_vector_int_sort() on the individual adjacency + * vectors after the initialization. * * * As of igraph 0.10, there is a small performance cost to setting \p loops @@ -155,9 +152,10 @@ static igraph_error_t igraph_i_remove_loops_from_incidence_vector_in_place( igraph_error_t igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al, igraph_neimode_t mode, igraph_loops_t loops, - igraph_multiple_t multiple) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_bool_t multiple) { + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t degrees; + int iter = 0; if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) { IGRAPH_ERROR("Cannot create adjacency list view.", IGRAPH_EINVMODE); @@ -169,7 +167,7 @@ igraph_error_t igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al, IGRAPH_VECTOR_INT_INIT_FINALLY(°rees, no_of_nodes); /* igraph_degree() is fast when loops=true */ - IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), mode, /* loops= */ true)); + IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), mode, IGRAPH_LOOPS)); al->length = no_of_nodes; al->adjs = IGRAPH_CALLOC(al->length, igraph_vector_int_t); @@ -194,11 +192,18 @@ igraph_error_t igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al, igraph_bool_t has_loops = false; igraph_bool_t has_multiple = false; - for (igraph_integer_t i = 0; i < al->length; i++) { - IGRAPH_ALLOW_INTERRUPTION(); + + /* In theory, we could just run igraph_neighbors() in a loop with 'loops' + * and 'multiple' set exactly how the caller wants it. However, we take the + * opportunity to also _cache_ whether the graph has multiple or loop edges + * if we are looping over all vertices anyway, and that requires us to query + * the neighbors in full */ + + for (igraph_int_t i = 0; i < al->length; i++) { + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1000); IGRAPH_CHECK(igraph_vector_int_init(&al->adjs[i], VECTOR(degrees)[i])); - IGRAPH_CHECK(igraph_neighbors(graph, &al->adjs[i], i, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, &al->adjs[i], i, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); /* Attention: This function will only set values for has_loops and has_multiple * if it finds loops/multi-edges. Otherwise they are left at their original value. */ @@ -245,16 +250,16 @@ igraph_error_t igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al, * \param no_of_nodes The number of vertices * \return Error code. * - * Time complexity: O(|V|), linear in the number of vertices. + * Time complexity: O(n), linear in the number of vertices. */ -igraph_error_t igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_integer_t no_of_nodes) { +igraph_error_t igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_int_t no_of_nodes) { al->length = no_of_nodes; al->adjs = IGRAPH_CALLOC(al->length, igraph_vector_int_t); IGRAPH_CHECK_OOM(al->adjs, "Insufficient memory for creating adjlist."); IGRAPH_FINALLY(igraph_adjlist_destroy, al); - for (igraph_integer_t i = 0; i < al->length; i++) { + for (igraph_int_t i = 0; i < al->length; i++) { IGRAPH_CHECK(igraph_vector_int_init(&al->adjs[i], 0)); } @@ -282,7 +287,13 @@ igraph_error_t igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_integer_t * or both (\c IGRAPH_ALL) types of neighbors (in the * complementer graph) to include in the adjacency list. It is * ignored for undirected networks. - * \param loops Whether to consider loop edges. + * \param loops Specifies how to treat loop edges. \c IGRAPH_NO_LOOPS will not + * include loops edges in the returned adjacency list. \c IGRAPH_LOOPS_ONCE + * will include vertex \p i in the adjacency list of vetex \p i \em once if + * the original graph did not have a loop edge incident on vertex \p i, + * while \c IGRAPH_LOOPS_TWICE will include vertex \p i \em twice \em if + * \p mode is set to \c IGRAPH_ALL (otherwise it is treated the same way as + * \c IGRAPH_LOOPS_ONCE ). * \return Error code. * * \sa \ref igraph_adjlist_init(), \ref igraph_complementer() @@ -292,10 +303,11 @@ igraph_error_t igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_integer_t igraph_error_t igraph_adjlist_init_complementer(const igraph_t *graph, igraph_adjlist_t *al, igraph_neimode_t mode, - igraph_bool_t loops) { + igraph_loops_t loops) { igraph_bitset_t seen; igraph_vector_int_t neis; + int iter = 0; if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) { IGRAPH_ERROR("Invalid neighbor mode specified for complementer adjlist view.", IGRAPH_EINVMODE); @@ -305,6 +317,10 @@ igraph_error_t igraph_adjlist_init_complementer(const igraph_t *graph, mode = IGRAPH_ALL; } + if (loops == IGRAPH_LOOPS_TWICE && mode != IGRAPH_ALL) { + loops = IGRAPH_LOOPS_ONCE; + } + al->length = igraph_vcount(graph); al->adjs = IGRAPH_CALLOC(al->length, igraph_vector_int_t); IGRAPH_CHECK_OOM(al->adjs, "Insufficient memory for creating complementer adjlist view."); @@ -313,37 +329,50 @@ igraph_error_t igraph_adjlist_init_complementer(const igraph_t *graph, IGRAPH_BITSET_INIT_FINALLY(&seen, al->length); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); - for (igraph_integer_t i = 0; i < al->length; i++) { + for (igraph_int_t i = 0; i < al->length; i++) { /* For each vertex, we mark neighbors within the 'seen' bitset. * Then we iterate over 'seen' and record non-marked vertices in * the adjacency list. */ - IGRAPH_ALLOW_INTERRUPTION(); + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1000); /* Reset neighbor counter and 'seen' vector. */ igraph_bitset_null(&seen); - igraph_integer_t n = al->length; + igraph_int_t n = al->length; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, mode, loops, IGRAPH_NO_MULTIPLE)); - if (!loops) { + if (loops == IGRAPH_NO_LOOPS) { + /* If we want no loops, we pretend that we have always seen one */ IGRAPH_BIT_SET(seen, i); n--; } - igraph_integer_t neis_size = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < neis_size; j++) { + igraph_int_t neis_size = igraph_vector_int_size(&neis); + for (igraph_int_t j = 0; j < neis_size; j++) { if (! IGRAPH_BIT_TEST(seen, VECTOR(neis)[j]) ) { n--; IGRAPH_BIT_SET(seen, VECTOR(neis)[j]); } } + if (loops == IGRAPH_LOOPS_TWICE) { + /* If we want loops twice and the bit corresponding to the loop + * edge is _not_ set, we need one extra slot in the allocated + * vector */ + if (!IGRAPH_BIT_TEST(seen, i)) { + n++; + } + } + /* Produce "non-neighbor" list in sorted order. */ IGRAPH_CHECK(igraph_vector_int_init(&al->adjs[i], n)); - for (igraph_integer_t j = 0, k = 0; k < n; j++) { + for (igraph_int_t j = 0, k = 0; k < n; j++) { if (!IGRAPH_BIT_TEST(seen, j)) { VECTOR(al->adjs[i])[k++] = j; + if (loops == IGRAPH_LOOPS_TWICE && i == j) { + VECTOR(al->adjs[i])[k++] = j; + } } } } @@ -386,8 +415,8 @@ igraph_error_t igraph_adjlist_init_complementer(const igraph_t *graph, igraph_error_t igraph_adjlist_init_from_inclist( const igraph_t *graph, igraph_adjlist_t *al, const igraph_inclist_t *il) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t i, j, num_neis; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i, j, num_neis; igraph_vector_int_t *neis; igraph_vector_int_t *incs; @@ -424,11 +453,10 @@ igraph_error_t igraph_adjlist_init_from_inclist( * Free all memory allocated for an adjacency list. * \param al The adjacency list to destroy. * - * Time complexity: depends on memory management. + * Time complexity: O(n), where n is the size of the adjacency list. */ void igraph_adjlist_destroy(igraph_adjlist_t *al) { - igraph_integer_t i; - for (i = 0; i < al->length; i++) { + for (igraph_int_t i = 0; i < al->length; i++) { /* This works if some igraph_vector_int_t's contain NULL, because igraph_vector_int_destroy can handle this. */ igraph_vector_int_destroy(&al->adjs[i]); @@ -438,15 +466,17 @@ void igraph_adjlist_destroy(igraph_adjlist_t *al) { /** * \function igraph_adjlist_clear - * Removes all edges from an adjacency list. + * \brief Removes all edges from an adjacency list. + * + * The size of the adjacency list stays unchanged, but all adjacent + * vertices will be removed. * * \param al The adjacency list. - * Time complexity: depends on memory management, typically O(n), where n is - * the total number of elements in the adjacency list. + * + * Time complexity: O(n), where n is the size of the adjacency list. */ void igraph_adjlist_clear(igraph_adjlist_t *al) { - igraph_integer_t i; - for (i = 0; i < al->length; i++) { + for (igraph_int_t i = 0; i < al->length; i++) { igraph_vector_int_clear(&al->adjs[i]); } } @@ -460,7 +490,7 @@ void igraph_adjlist_clear(igraph_adjlist_t *al) { * * Time complexity: O(1). */ -igraph_integer_t igraph_adjlist_size(const igraph_adjlist_t *al) { +igraph_int_t igraph_adjlist_size(const igraph_adjlist_t *al) { return al->length; } @@ -476,11 +506,11 @@ igraph_integer_t igraph_adjlist_size(const igraph_adjlist_t *al) { * * \param al The adjacency list. * - * Time complexity: O(n log n), n is the total number of elements in - * the adjacency list. + * Time complexity: O(m log m), m is the total number of neighbors stored + * in the adjacency list. */ void igraph_adjlist_sort(igraph_adjlist_t *al) { - igraph_integer_t i; + igraph_int_t i; for (i = 0; i < al->length; i++) { igraph_vector_int_sort(&al->adjs[i]); } @@ -503,17 +533,17 @@ void igraph_adjlist_sort(igraph_adjlist_t *al) { * vertices. */ igraph_error_t igraph_adjlist_simplify(igraph_adjlist_t *al) { - igraph_integer_t i; - igraph_integer_t n = al->length; + igraph_int_t i; + igraph_int_t n = al->length; igraph_vector_int_t mark; IGRAPH_VECTOR_INT_INIT_FINALLY(&mark, n); for (i = 0; i < n; i++) { igraph_vector_int_t *v = &al->adjs[i]; - igraph_integer_t j, l = igraph_vector_int_size(v); + igraph_int_t j, l = igraph_vector_int_size(v); VECTOR(mark)[i] = i + 1; for (j = 0; j < l; /* nothing */) { - igraph_integer_t e = VECTOR(*v)[j]; + igraph_int_t e = VECTOR(*v)[j]; if (VECTOR(mark)[e] != i + 1) { VECTOR(mark)[e] = i + 1; j++; @@ -532,8 +562,8 @@ igraph_error_t igraph_adjlist_simplify(igraph_adjlist_t *al) { #ifndef USING_R igraph_error_t igraph_adjlist_print(const igraph_adjlist_t *al) { - igraph_integer_t i; - igraph_integer_t n = al->length; + igraph_int_t i; + igraph_int_t n = al->length; for (i = 0; i < n; i++) { igraph_vector_int_t *v = &al->adjs[i]; igraph_vector_int_print(v); @@ -543,8 +573,8 @@ igraph_error_t igraph_adjlist_print(const igraph_adjlist_t *al) { #endif igraph_error_t igraph_adjlist_fprint(const igraph_adjlist_t *al, FILE *outfile) { - igraph_integer_t i; - igraph_integer_t n = al->length; + igraph_int_t i; + igraph_int_t n = al->length; for (i = 0; i < n; i++) { igraph_vector_int_t *v = &al->adjs[i]; igraph_vector_int_fprint(v, outfile); @@ -554,7 +584,7 @@ igraph_error_t igraph_adjlist_fprint(const igraph_adjlist_t *al, FILE *outfile) #define ADJLIST_CANON_EDGE(from, to, directed) \ do { \ - igraph_integer_t temp; \ + igraph_int_t temp; \ if ((!directed) && from < to) { \ temp = to; \ to = from; \ @@ -575,7 +605,7 @@ igraph_error_t igraph_adjlist_fprint(const igraph_adjlist_t *al, FILE *outfile) igraph_bool_t igraph_adjlist_has_edge( igraph_adjlist_t* al, - igraph_integer_t from, igraph_integer_t to, + igraph_int_t from, igraph_int_t to, igraph_bool_t directed) { const igraph_vector_int_t *fromvec; @@ -586,13 +616,13 @@ igraph_bool_t igraph_adjlist_has_edge( igraph_error_t igraph_adjlist_replace_edge( igraph_adjlist_t* al, - igraph_integer_t from, igraph_integer_t oldto, igraph_integer_t newto, + igraph_int_t from, igraph_int_t oldto, igraph_int_t newto, igraph_bool_t directed) { igraph_vector_int_t *oldfromvec, *newfromvec; igraph_bool_t found_old, found_new; - igraph_integer_t oldpos, newpos; - igraph_integer_t oldfrom = from, newfrom = from; + igraph_int_t oldpos, newpos; + igraph_int_t oldfrom = from, newfrom = from; ADJLIST_CANON_EDGE(oldfrom, oldto, directed); ADJLIST_CANON_EDGE(newfrom, newto, directed); @@ -630,80 +660,10 @@ igraph_error_t igraph_adjlist_replace_edge( } -static igraph_error_t igraph_i_remove_loops_from_incidence_vector_in_place( - igraph_vector_int_t *v, const igraph_t *graph, igraph_loops_t loops -) { - igraph_integer_t i, length, eid, write_ptr; - igraph_vector_int_t *seen_loops = 0; - - /* In this function we make use of the fact that we are dealing with - * _incidence_ lists, and the only way for an edge ID to appear twice - * within an incidence list is if the edge is a loop edge; otherwise each - * element will be unique. - * - * Note that incidence vectors are not sorted by edge ID, so we need to - * look up the edges in the graph to decide whether they are loops or not. - * - * Also, it may be tempting to introduce a boolean in case of IGRAPH_LOOPS_ONCE, - * and flip it every time we see a loop to get rid of half of the occurrences, - * but the problem is that even if the same loop edge ID appears twice in - * the input list, they are not guaranteed to be next to each other; it - * may be the case that there are multiple loop edges, each edge appears - * twice, and we want to keep exactly one of them for each ID. That's why - * we have a "seen_loops" vector. - */ - - if (loops == IGRAPH_LOOPS_TWICE) { - /* Loop edges appear twice by default, nothing to do. */ - return IGRAPH_SUCCESS; - } - - length = igraph_vector_int_size(v); - if (length == 0) { - return IGRAPH_SUCCESS; - } - - if (loops == IGRAPH_LOOPS_ONCE) { - /* We need a helper vector */ - seen_loops = IGRAPH_CALLOC(1, igraph_vector_int_t); - IGRAPH_FINALLY(igraph_free, seen_loops); - IGRAPH_CHECK(igraph_vector_int_init(seen_loops, 0)); - IGRAPH_FINALLY(igraph_vector_int_destroy, seen_loops); - } else if (loops != IGRAPH_NO_LOOPS) { - IGRAPH_ERROR("Invalid value for 'loops' argument", IGRAPH_EINVAL); - } - - for (i = 0, write_ptr = 0; i < length; i++) { - eid = VECTOR(*v)[i]; - if (IGRAPH_FROM(graph, eid) == IGRAPH_TO(graph, eid)) { - /* Loop edge */ - if (seen_loops && !igraph_vector_int_contains(seen_loops, eid)) { - VECTOR(*v)[write_ptr++] = eid; - IGRAPH_CHECK(igraph_vector_int_push_back(seen_loops, eid)); - } - } else { - /* Not a loop edge */ - VECTOR(*v)[write_ptr++] = eid; - } - } - - /* Always succeeds since we never grow the vector */ - igraph_vector_int_resize(v, write_ptr); - - /* Destroy the helper vector */ - if (seen_loops) { - igraph_vector_int_destroy(seen_loops); - IGRAPH_FREE(seen_loops); - IGRAPH_FINALLY_CLEAN(2); - } - - return IGRAPH_SUCCESS; -} - #ifndef USING_R igraph_error_t igraph_inclist_print(const igraph_inclist_t *al) { - igraph_integer_t i; - igraph_integer_t n = al->length; + igraph_int_t i; + igraph_int_t n = al->length; for (i = 0; i < n; i++) { igraph_vector_int_t *v = &al->incs[i]; igraph_vector_int_print(v); @@ -713,8 +673,8 @@ igraph_error_t igraph_inclist_print(const igraph_inclist_t *al) { #endif igraph_error_t igraph_inclist_fprint(const igraph_inclist_t *al, FILE *outfile) { - igraph_integer_t i; - igraph_integer_t n = al->length; + igraph_int_t i; + igraph_int_t n = al->length; for (i = 0; i < n; i++) { igraph_vector_int_t *v = &al->incs[i]; igraph_vector_int_fprint(v, outfile); @@ -767,8 +727,9 @@ igraph_error_t igraph_inclist_init(const igraph_t *graph, igraph_inclist_t *il, igraph_neimode_t mode, igraph_loops_t loops) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t degrees; + int iter = 0; if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) { IGRAPH_ERROR("Cannot create incidence list view.", IGRAPH_EINVMODE); @@ -780,7 +741,7 @@ igraph_error_t igraph_inclist_init(const igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(°rees, no_of_nodes); /* igraph_degrees() is fast when loops=true */ - IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), mode, /* loops= */ 1)); + IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), mode, IGRAPH_LOOPS)); il->length = no_of_nodes; il->incs = IGRAPH_CALLOC(il->length, igraph_vector_int_t); @@ -789,17 +750,11 @@ igraph_error_t igraph_inclist_init(const igraph_t *graph, } IGRAPH_FINALLY(igraph_inclist_destroy, il); - for (igraph_integer_t i = 0; i < il->length; i++) { - IGRAPH_ALLOW_INTERRUPTION(); + for (igraph_int_t i = 0; i < il->length; i++) { + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1000); IGRAPH_CHECK(igraph_vector_int_init(&il->incs[i], VECTOR(degrees)[i])); - IGRAPH_CHECK(igraph_incident(graph, &il->incs[i], i, mode)); - - if (loops != IGRAPH_LOOPS_TWICE) { - IGRAPH_CHECK( - igraph_i_remove_loops_from_incidence_vector_in_place(&il->incs[i], graph, loops) - ); - } + IGRAPH_CHECK(igraph_incident(graph, &il->incs[i], i, mode, loops)); } igraph_vector_int_destroy(°rees); @@ -820,11 +775,11 @@ igraph_error_t igraph_inclist_init(const igraph_t *graph, * \param n The number of vertices in the incidence list. * \return Error code. * - * Time complexity: O(|V|), linear in the number of vertices. + * Time complexity: O(n), linear in the number of vertices. */ -igraph_error_t igraph_inclist_init_empty(igraph_inclist_t *il, igraph_integer_t n) { - igraph_integer_t i; +igraph_error_t igraph_inclist_init_empty(igraph_inclist_t *il, igraph_int_t n) { + igraph_int_t i; il->length = n; il->incs = IGRAPH_CALLOC(il->length, igraph_vector_int_t); @@ -847,12 +802,11 @@ igraph_error_t igraph_inclist_init_empty(igraph_inclist_t *il, igraph_integer_t * * \param il The incidence list to destroy. * - * Time complexity: depends on memory management. + * Time complexity: O(n), where n is the size of the incidence list. */ void igraph_inclist_destroy(igraph_inclist_t *il) { - igraph_integer_t i; - for (i = 0; i < il->length; i++) { + for (igraph_int_t i = 0; i < il->length; i++) { /* This works if some igraph_vector_int_t's contain NULL, because igraph_vector_int_destroy can handle this. */ igraph_vector_int_destroy(&il->incs[i]); @@ -864,13 +818,15 @@ void igraph_inclist_destroy(igraph_inclist_t *il) { * \function igraph_inclist_clear * \brief Removes all edges from an incidence list. * + * The size of the incidence list stays unchanged, but all incident edges + * will be removed. + * * \param il The incidence list. * - * Time complexity: depends on memory management, typically O(n), where n is - * the total number of elements in the incidence list. + * Time complexity: O(n), where n is the size of the incidence list. */ void igraph_inclist_clear(igraph_inclist_t *il) { - igraph_integer_t i; + igraph_int_t i; for (i = 0; i < il->length; i++) { igraph_vector_int_clear(&il->incs[i]); } @@ -885,14 +841,14 @@ void igraph_inclist_clear(igraph_inclist_t *il) { * * Time complexity: O(1). */ -igraph_integer_t igraph_inclist_size(const igraph_inclist_t *il) { +igraph_int_t igraph_inclist_size(const igraph_inclist_t *il) { return il->length; } /* See the prototype above for a description of this function. */ static igraph_error_t igraph_i_simplify_sorted_int_adjacency_vector_in_place( - igraph_vector_int_t *v, igraph_integer_t index, igraph_neimode_t mode, - igraph_loops_t loops, igraph_multiple_t multiple, igraph_bool_t *has_loops, + igraph_vector_int_t *v, igraph_int_t index, igraph_neimode_t mode, + igraph_loops_t loops, igraph_bool_t multiple, igraph_bool_t *has_loops, igraph_bool_t *has_multiple ) { @@ -903,8 +859,8 @@ static igraph_error_t igraph_i_simplify_sorted_int_adjacency_vector_in_place( if (has_multiple == NULL) { has_multiple = &dummy2; } - igraph_integer_t i, p = 0; - igraph_integer_t n = igraph_vector_int_size(v); + igraph_int_t i, p = 0; + igraph_int_t n = igraph_vector_int_size(v); if ( multiple == IGRAPH_MULTIPLE && @@ -1091,7 +1047,7 @@ igraph_error_t igraph_lazy_adjlist_init(const igraph_t *graph, igraph_lazy_adjlist_t *al, igraph_neimode_t mode, igraph_loops_t loops, - igraph_multiple_t multiple) { + igraph_bool_t multiple) { if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) { IGRAPH_ERROR("Cannot create lazy adjacency list view.", IGRAPH_EINVMODE); } @@ -1152,7 +1108,7 @@ void igraph_lazy_adjlist_destroy(igraph_lazy_adjlist_t *al) { * the total number of elements in the adjacency list. */ void igraph_lazy_adjlist_clear(igraph_lazy_adjlist_t *al) { - igraph_integer_t i, n = al->length; + igraph_int_t i, n = al->length; for (i = 0; i < n; i++) { if (al->adjs[i] != 0) { igraph_vector_int_destroy(al->adjs[i]); @@ -1170,11 +1126,11 @@ void igraph_lazy_adjlist_clear(igraph_lazy_adjlist_t *al) { * * Time complexity: O(1). */ -igraph_integer_t igraph_lazy_adjlist_size(const igraph_lazy_adjlist_t *al) { +igraph_int_t igraph_lazy_adjlist_size(const igraph_lazy_adjlist_t *al) { return al->length; } -igraph_vector_int_t *igraph_i_lazy_adjlist_get_real(igraph_lazy_adjlist_t *al, igraph_integer_t no) { +igraph_vector_int_t *igraph_i_lazy_adjlist_get_real(igraph_lazy_adjlist_t *al, igraph_int_t no) { igraph_error_t ret; if (al->adjs[no] == NULL) { @@ -1189,17 +1145,7 @@ igraph_vector_int_t *igraph_i_lazy_adjlist_get_real(igraph_lazy_adjlist_t *al, i return NULL; } - ret = igraph_neighbors(al->graph, al->adjs[no], no, al->mode); - if (ret != IGRAPH_SUCCESS) { - igraph_vector_int_destroy(al->adjs[no]); - IGRAPH_FREE(al->adjs[no]); - return NULL; - } - - ret = igraph_i_simplify_sorted_int_adjacency_vector_in_place( - al->adjs[no], no, al->mode, al->loops, al->multiple, NULL, - NULL - ); + ret = igraph_neighbors(al->graph, al->adjs[no], no, al->mode, al->loops, al->multiple); if (ret != IGRAPH_SUCCESS) { igraph_vector_int_destroy(al->adjs[no]); IGRAPH_FREE(al->adjs[no]); @@ -1303,7 +1249,7 @@ void igraph_lazy_inclist_destroy(igraph_lazy_inclist_t *il) { * the total number of elements in the incidence list. */ void igraph_lazy_inclist_clear(igraph_lazy_inclist_t *il) { - igraph_integer_t i, n = il->length; + igraph_int_t i, n = il->length; for (i = 0; i < n; i++) { if (il->incs[i] != 0) { igraph_vector_int_destroy(il->incs[i]); @@ -1321,11 +1267,11 @@ void igraph_lazy_inclist_clear(igraph_lazy_inclist_t *il) { * * Time complexity: O(1). */ -igraph_integer_t igraph_lazy_inclist_size(const igraph_lazy_inclist_t *il) { +igraph_int_t igraph_lazy_inclist_size(const igraph_lazy_inclist_t *il) { return il->length; } -igraph_vector_int_t *igraph_i_lazy_inclist_get_real(igraph_lazy_inclist_t *il, igraph_integer_t no) { +igraph_vector_int_t *igraph_i_lazy_inclist_get_real(igraph_lazy_inclist_t *il, igraph_int_t no) { igraph_error_t ret; if (il->incs[no] == NULL) { @@ -1340,21 +1286,12 @@ igraph_vector_int_t *igraph_i_lazy_inclist_get_real(igraph_lazy_inclist_t *il, i return NULL; } - ret = igraph_incident(il->graph, il->incs[no], no, il->mode); + ret = igraph_incident(il->graph, il->incs[no], no, il->mode, il->loops); if (ret != IGRAPH_SUCCESS) { igraph_vector_int_destroy(il->incs[no]); IGRAPH_FREE(il->incs[no]); return NULL; } - - if (il->loops != IGRAPH_LOOPS_TWICE) { - ret = igraph_i_remove_loops_from_incidence_vector_in_place(il->incs[no], il->graph, il->loops); - if (ret != IGRAPH_SUCCESS) { - igraph_vector_int_destroy(il->incs[no]); - IGRAPH_FREE(il->incs[no]); - return NULL; - } - } } return il->incs[no]; diff --git a/src/vendor/cigraph/src/graph/attributes.c b/src/vendor/cigraph/src/graph/attributes.c index 731d628d9d3..fd827f67bbd 100644 --- a/src/vendor/cigraph/src/graph/attributes.c +++ b/src/vendor/cigraph/src/graph/attributes.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -30,21 +29,603 @@ #include #include +/** + * \section about_attributes + * + * Attributes are numbers, boolean values or strings associated with + * the vertices or edges of a graph, or with the graph itself. E.g. you may + * label vertices with symbolic names or attach numeric weights to the edges + * of a graph. In addition to these three basic types, a custom object + * type is supported as well. + * + * igraph attributes are designed to be flexible and extensible. + * In igraph attributes are implemented via an interface abstraction: + * any type implementing the functions in the interface can be used + * for storing vertex, edge and graph attributes. This means that + * different attribute implementations can be used together with + * igraph. This is reasonable: if igraph is used from Python attributes can be + * of any Python type, from R all R types are allowed. There is also an + * experimental attribute implementation to be used when programming + * in C, but by default it is currently turned off. + * + * First we briefly look over how attribute handlers can be + * implemented. This is not something a user does every day. It is + * rather typically the job of the high level interface writers. (But + * it is possible to write an interface without implementing + * attributes.) Then we show the experimental C attribute handler. + */ + +/** + * \section about_attribute_table + * It is possible to attach an attribute handling + * interface to \a igraph. This is simply a table of functions, of + * type \ref igraph_attribute_table_t. These functions are invoked to + * notify the attribute handling code about the structural changes in + * a graph. See the documentation of this type for details. + * + * By default there is no attribute interface attached to \a igraph. + * To attach one, call \ref igraph_set_attribute_table with your new + * table. This is normally done on program startup, and is kept untouched + * for the program's lifetime. It must be done before any graph object + * is created, as graphs created with a given attribute handler + * cannot be manipulated while a different attribute handler is + * active. + */ + +/** + * \section about_attribute_record + * + * Functions in the attribute handler interface may refer to + * \em "attribute records" or \em "attribute record lists". An attribute record + * is simply a triplet consisting of an attribute name, an attribute type and + * a vector containing the values of the attribute. Attribute record lists are + * typed containers that contain a sequence of attribute records. Attribute + * record lists own the attribute records that they contain, and similarly, + * attribute records own the vectors contained in them. Destroying an attribute + * record destroys the vector of values inside it, and destroying an attribute + * record list destroys all attribute records in the list. + */ + +/** + * \section about_attribute_combination + * + * Several graph operations may collapse multiple vertices or edges into + * a single one. Attribute combination lists are used to indicate to the attribute + * handler how to combine the attributes of the original vertices or edges and + * how to derive the final attribute value that is to be assigned to the collapsed + * vertex or edge. For example, \ref igraph_simplify() removes loops and combines + * multiple edges into a single one; in case of a graph with an edge attribute + * named \c weight the attribute combination list can tell the attribute handler + * whether the weight of a collapsed edge should be the sum, the mean or some other + * function of the weights of the original edges that were collapsed into one. + * + * One attribute combination list may contain several attribute combination + * records, one for each vertex or edge attribute that is to be handled during the + * operation. + */ + +static void igraph_i_attribute_record_set_type( + igraph_attribute_record_t *attr, igraph_attribute_type_t type, void *ptr +); +static void igraph_i_attribute_record_destroy_values(igraph_attribute_record_t *attr); + +/** + * \function igraph_attribute_record_init + * \brief Initializes an attribute record with a given name and type. + * + * \param attr the attribute record to initialize + * \param name name of the attribute + * \param type type of the attribute + * \return Error code: + * \c IGRAPH_ENOMEM if there is not enough memory. + * + * Time complexity: O(1). + */ +igraph_error_t igraph_attribute_record_init( + igraph_attribute_record_t *attr, const char* name, igraph_attribute_type_t type +) { + attr->name = NULL; + attr->type = IGRAPH_ATTRIBUTE_UNSPECIFIED; + attr->value.as_raw = NULL; + attr->default_value.string = NULL; + + IGRAPH_CHECK(igraph_attribute_record_set_name(attr, name)); + IGRAPH_CHECK(igraph_attribute_record_set_type(attr, type)); + + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_attribute_record_init_copy + * \brief Initializes an attribute record by copying another record. + * + * + * Copies made by this function are deep copies: a full copy of the value + * vector contained in the record is placed in the new record so they become + * independent of each other. + * + * \param to the attribute record to initialize + * \param from the attribute record to copy data from + * \return Error code: + * \c IGRAPH_ENOMEM if there is not enough memory. + * + * Time complexity: operating system dependent, usually O(n), where n is the + * size of the value vector in the attribute record. + */ +igraph_error_t igraph_attribute_record_init_copy( + igraph_attribute_record_t *to, const igraph_attribute_record_t *from +) { + IGRAPH_CHECK(igraph_attribute_record_init(to, from->name, from->type)); + + switch (from->type) { + case IGRAPH_ATTRIBUTE_NUMERIC: + IGRAPH_CHECK(igraph_vector_update(to->value.as_vector, from->value.as_vector)); + break; + + case IGRAPH_ATTRIBUTE_STRING: + IGRAPH_CHECK(igraph_strvector_update(to->value.as_strvector, from->value.as_strvector)); + break; + + case IGRAPH_ATTRIBUTE_BOOLEAN: + IGRAPH_CHECK(igraph_vector_bool_update(to->value.as_vector_bool, from->value.as_vector_bool)); + break; + + case IGRAPH_ATTRIBUTE_UNSPECIFIED: + break; + + default: + break; + } + + return IGRAPH_SUCCESS; +} + +static void igraph_i_attribute_record_destroy_values(igraph_attribute_record_t *attr) { + IGRAPH_ASSERT(attr != NULL); + + if (attr->value.as_raw) { + switch (attr->type) { + case IGRAPH_ATTRIBUTE_NUMERIC: + igraph_vector_destroy(attr->value.as_vector); + break; + + case IGRAPH_ATTRIBUTE_STRING: + igraph_strvector_destroy(attr->value.as_strvector); + break; + + case IGRAPH_ATTRIBUTE_BOOLEAN: + igraph_vector_bool_destroy(attr->value.as_vector_bool); + break; + + default: + break; + } + + igraph_free(attr->value.as_raw); + attr->value.as_raw = NULL; + } + + switch (attr->type) { + case IGRAPH_ATTRIBUTE_NUMERIC: + attr->default_value.numeric = 0; + break; + + case IGRAPH_ATTRIBUTE_STRING: + if (attr->default_value.string) { + igraph_free(attr->default_value.string); + attr->default_value.string = NULL; + } + break; + + case IGRAPH_ATTRIBUTE_BOOLEAN: + attr->default_value.boolean = 0; + break; + + default: + break; + } + + attr->type = IGRAPH_ATTRIBUTE_UNSPECIFIED; +} + +/** + * \function igraph_attribute_record_destroy + * \brief Destroys an attribute record. + * + * \param attr the previously initialized attribute record to destroy. + * + * Time complexity: operating system dependent. + */ +void igraph_attribute_record_destroy(igraph_attribute_record_t *attr) { + igraph_i_attribute_record_destroy_values(attr); + + if (attr->name) { + igraph_free(attr->name); + attr->name = NULL; + } +} + +/** + * \function igraph_attribute_record_check_type + * \brief Checks whether the type of the attribute record is equal to an expected type. + * + * \param attr the attribute record to test + * \param type the expected type of the attribute record + * \return Error code: + * \c IGRAPH_EINVAL if the type of the attribute record is not equal to + * the expected type + * + * Time complexity: O(1). + */ +igraph_error_t igraph_attribute_record_check_type( + const igraph_attribute_record_t *attr, igraph_attribute_type_t type +) { + if (type != attr->type) { + switch (type) { + case IGRAPH_ATTRIBUTE_STRING: + IGRAPH_ERROR("String attribute expected.", IGRAPH_EINVAL); + break; + case IGRAPH_ATTRIBUTE_NUMERIC: + IGRAPH_ERROR("Numeric attribute expected.", IGRAPH_EINVAL); + break; + case IGRAPH_ATTRIBUTE_BOOLEAN: + IGRAPH_ERROR("Boolean attribute expected.", IGRAPH_EINVAL); + break; + case IGRAPH_ATTRIBUTE_OBJECT: + IGRAPH_ERROR("Object attribute expected.", IGRAPH_EINVAL); + break; + default: + IGRAPH_ERROR("Attribute with unknown type expected.", IGRAPH_EINVAL); + break; + } + } + + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_attribute_record_size + * \brief Returns the size of the value vector in an attribute record. + * + * \param attr the attribute record to query + * \return the number of elements in the value vector of the attribute record + */ +igraph_int_t igraph_attribute_record_size(const igraph_attribute_record_t *attr) { + IGRAPH_ASSERT(attr != NULL); + + switch (attr->type) { + case IGRAPH_ATTRIBUTE_NUMERIC: + return igraph_vector_size(attr->value.as_vector); + + case IGRAPH_ATTRIBUTE_STRING: + return igraph_strvector_size(attr->value.as_strvector); + + case IGRAPH_ATTRIBUTE_BOOLEAN: + return igraph_vector_bool_size(attr->value.as_vector_bool); + + case IGRAPH_ATTRIBUTE_UNSPECIFIED: + return 0; + + default: + IGRAPH_ERRORF("Unsupported attribute type: %d", IGRAPH_EINVAL, (int) attr->type); + } +} + +/** + * \function igraph_attribute_record_resize + * \brief Resizes the value vector in an attribute record. + * + * When the value vector is shorter than the desired length, it + * will be expanded with \c IGRAPH_NAN for numeric vectors, \c false for Boolean + * vectors and empty strings for string vectors. + * + * \param attr the attribute record to update + * \param new_size the new size of the value vector + * \return Error code: + * \c IGRAPH_ENOMEM if there is not enough memory. + * \c IGRAPH_EINVAL if the type of the attribute record is not specified yet. + */ +igraph_error_t igraph_attribute_record_resize( + igraph_attribute_record_t *attr, igraph_int_t new_size +) { + igraph_int_t i; + igraph_vector_t *vec; + igraph_vector_bool_t *log; + igraph_strvector_t *str; + + IGRAPH_ASSERT(attr != NULL); + + switch (attr->type) { + + case IGRAPH_ATTRIBUTE_NUMERIC: + vec = attr->value.as_vector; + i = igraph_vector_size(vec); + IGRAPH_CHECK(igraph_vector_resize(vec, new_size)); + while (i < new_size) { + VECTOR(*vec)[i++] = attr->default_value.numeric; + } + break; + + case IGRAPH_ATTRIBUTE_BOOLEAN: + log = attr->value.as_vector_bool; + i = igraph_vector_bool_size(log); + IGRAPH_CHECK(igraph_vector_bool_resize(log, new_size)); + while (i < new_size) { + VECTOR(*log)[i++] = attr->default_value.boolean; + } + break; + + case IGRAPH_ATTRIBUTE_STRING: + str = attr->value.as_strvector; + if (attr->default_value.string == 0 || (*attr->default_value.string == 0)) { + IGRAPH_CHECK(igraph_strvector_resize(str, new_size)); + } else { + i = igraph_strvector_size(str); + IGRAPH_CHECK(igraph_strvector_resize(str, new_size)); + while (i < new_size) { + IGRAPH_CHECK(igraph_strvector_set(str, i++, attr->default_value.string)); + } + } + break; + + case IGRAPH_ATTRIBUTE_UNSPECIFIED: + IGRAPH_ERROR("Attribute record has no type yet.", IGRAPH_EINVAL); + break; + + default: + IGRAPH_ERRORF("Unsupported attribute type: %d", IGRAPH_EINVAL, (int) attr->type); + } + + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_attribute_record_set_default_numeric + * \brief Sets the default value of the attribute to the given number. + * + * + * This function must be called for numeric attribute records only. When not + * specified, the default value of numeric attributes is NaN. + * + * \param attr the attribute record to update + * \param value the new default value + * \return Error code: + * \c IGRAPH_EINVAL if the attribute record has a non-numeric type + */ +igraph_error_t igraph_attribute_record_set_default_numeric( + igraph_attribute_record_t *attr, igraph_real_t value +) { + if (attr->type != IGRAPH_ATTRIBUTE_NUMERIC) { + return IGRAPH_EINVAL; + } + + attr->default_value.numeric = value; + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_attribute_record_set_default_boolean + * \brief Sets the default value of the attribute to the given logical value. + * + * + * This function must be called for Boolean attribute records only. When not + * specified, the default value of Boolean attributes is \c false. + * + * \param attr the attribute record to update + * \param value the new default value + * \return Error code: + * \c IGRAPH_EINVAL if the attribute record is not of Boolean type + */ +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_set_default_boolean( + igraph_attribute_record_t *attr, igraph_bool_t value +) { + if (attr->type != IGRAPH_ATTRIBUTE_BOOLEAN) { + return IGRAPH_EINVAL; + } + + attr->default_value.boolean = value; + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_attribute_record_set_default_string + * \brief Sets the default value of the attribute to the given string. + * + * + * This function must be called for string attribute records only. When not + * specified, the default value of string attributes is an empty string. + * + * \param attr the attribute record to update + * \param value the new default value. \c NULL means an empty string. + * + * \return Error code: + * \c IGRAPH_ENOMEM if there is not enough memory + * \c IGRAPH_EINVAL if the attribute record is not of string type + */ +IGRAPH_EXPORT igraph_error_t igraph_attribute_record_set_default_string( + igraph_attribute_record_t *attr, const char* value +) { + char* copy; + + if (attr->type != IGRAPH_ATTRIBUTE_STRING) { + return IGRAPH_EINVAL; + } + + if (value && (*value != 0)) { + copy = strdup(value); + IGRAPH_CHECK_OOM(copy, "Insufficient memory to duplicate default value."); + } else { + copy = NULL; + } + + if (attr->default_value.string) { + igraph_free(attr->default_value.string); + } + attr->default_value.string = copy; + + return IGRAPH_SUCCESS; +} + + +/** + * \function igraph_attribute_record_set_name + * \brief Sets the attribute name in an attribute record. + * + * \param attr the attribute record to update + * \param name the new name + * \return Error code: + * \c IGRAPH_ENOMEM if there is not enough memory. + */ +igraph_error_t igraph_attribute_record_set_name( + igraph_attribute_record_t *attr, const char* name +) { + char* new_name; + + IGRAPH_ASSERT(attr != NULL); + + if (name != NULL) { + new_name = strdup(name); + IGRAPH_CHECK_OOM(new_name, "Insufficient memory for allocating attribute name."); + } else { + new_name = NULL; + } + + if (attr->name) { + igraph_free(attr->name); + } + + attr->name = new_name; + + return IGRAPH_SUCCESS; +} + +static void igraph_i_attribute_record_set_type( + igraph_attribute_record_t *attr, igraph_attribute_type_t type, void *ptr +) { + bool type_changed = attr->type != type; + + if (type_changed || attr->value.as_raw != ptr) { + igraph_i_attribute_record_destroy_values(attr); + attr->type = type; + attr->value.as_raw = ptr; + } + + if (type_changed && type == IGRAPH_ATTRIBUTE_NUMERIC) { + IGRAPH_ASSERT( + igraph_attribute_record_set_default_numeric(attr, IGRAPH_NAN) == IGRAPH_SUCCESS + ); + } +} + +/** + * \function igraph_attribute_record_set_type + * \brief Sets the type of an attribute record. + * + * + * When the new type being set is different from the old type, any values already + * stored in the attribute record will be destroyed and a new, empty attribute + * value vector will be allocated. When the new type is the same as the old + * type, this function is a no-op. + * + * \param attr the attribute record to update + * \param type the new type + * \return Error code: + * \c IGRAPH_ENOMEM if there is not enough memory. + */ +igraph_error_t igraph_attribute_record_set_type( + igraph_attribute_record_t *attr, igraph_attribute_type_t type +) { + void* ptr; + + IGRAPH_ASSERT(attr != NULL); + + if (attr->type != type) { + switch (type) { + case IGRAPH_ATTRIBUTE_NUMERIC: { + igraph_vector_t* vec = IGRAPH_CALLOC(1, igraph_vector_t); + IGRAPH_CHECK_OOM(vec, "Insufficient memory for attribute record."); + IGRAPH_FINALLY(igraph_free, vec); + IGRAPH_VECTOR_INIT_FINALLY(vec, 0); + ptr = vec; + } + break; + + case IGRAPH_ATTRIBUTE_STRING: { + igraph_strvector_t* strvec = IGRAPH_CALLOC(1, igraph_strvector_t); + IGRAPH_CHECK_OOM(strvec, "Insufficient memory for attribute record."); + IGRAPH_FINALLY(igraph_free, strvec); + IGRAPH_CHECK(igraph_strvector_init(strvec, 0)); + IGRAPH_FINALLY(igraph_strvector_destroy, strvec); + ptr = strvec; + } + break; + + case IGRAPH_ATTRIBUTE_BOOLEAN: { + igraph_vector_bool_t* boolvec = IGRAPH_CALLOC(1, igraph_vector_bool_t); + IGRAPH_CHECK_OOM(boolvec, "Insufficient memory for attribute record."); + IGRAPH_FINALLY(igraph_free, boolvec); + IGRAPH_VECTOR_BOOL_INIT_FINALLY(boolvec, 0); + ptr = boolvec; + } + break; + + default: + IGRAPH_ERRORF("Unsupported attribute type: %d", IGRAPH_EINVAL, (int) type); + } + + igraph_i_attribute_record_set_type(attr, type, ptr); + IGRAPH_FINALLY_CLEAN(2); + } + + return IGRAPH_SUCCESS; +} + +#define ATTRIBUTE_RECORD_LIST +#define BASE_ATTRIBUTE_RECORD +#define CUSTOM_INIT_DESTROY +#include "igraph_pmt.h" +#include "../core/typed_list.pmt" +#include "igraph_pmt_off.h" +#undef CUSTOM_INIT_DESTROY +#undef BASE_ATTRIBUTE_RECORD +#undef ATTRIBUTE_RECORD_LIST + +static igraph_error_t igraph_i_attribute_record_list_init_item( + const igraph_attribute_record_list_t* list, igraph_attribute_record_t* item +) { + IGRAPH_UNUSED(list); + return igraph_attribute_record_init(item, NULL, IGRAPH_ATTRIBUTE_UNSPECIFIED); +} + +static igraph_error_t igraph_i_attribute_record_list_copy_item( + igraph_attribute_record_t* dest, const igraph_attribute_record_t* source +) { + return igraph_attribute_record_init_copy(dest, source); +} + +static void igraph_i_attribute_record_list_destroy_item(igraph_attribute_record_t* item) { + igraph_attribute_record_destroy(item); +} + /* Should you ever want to have a thread-local attribute handler table, prepend * IGRAPH_THREAD_LOCAL to the following declaration and #include "config.h". */ igraph_attribute_table_t *igraph_i_attribute_table = NULL; -igraph_error_t igraph_i_attribute_init(igraph_t *graph, void *attr) { +igraph_error_t igraph_i_attribute_init( + igraph_t *graph, const igraph_attribute_record_list_t *attr +) { graph->attr = NULL; if (igraph_i_attribute_table) { - return igraph_i_attribute_table->init(graph, attr); - } else { - return IGRAPH_SUCCESS; + IGRAPH_CHECK(igraph_i_attribute_table->init(graph, attr)); + if (graph->attr == NULL) { + IGRAPH_ERROR("Attribute handler did not initialize attr pointer", IGRAPH_FAILURE); + } } + return IGRAPH_SUCCESS; } void igraph_i_attribute_destroy(igraph_t *graph) { - if (igraph_i_attribute_table) { + if (graph->attr && igraph_i_attribute_table) { igraph_i_attribute_table->destroy(graph); } graph->attr = NULL; @@ -52,15 +633,19 @@ void igraph_i_attribute_destroy(igraph_t *graph) { igraph_error_t igraph_i_attribute_copy(igraph_t *to, const igraph_t *from, igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea) { - to->attr = NULL; - if (igraph_i_attribute_table) { - return igraph_i_attribute_table->copy(to, from, ga, va, ea); - } else { - return IGRAPH_SUCCESS; + igraph_i_attribute_destroy(to); + if (from->attr && igraph_i_attribute_table) { + IGRAPH_CHECK(igraph_i_attribute_table->copy(to, from, ga, va, ea)); + if (to->attr == NULL) { + IGRAPH_ERROR("Attribute handler did not initialize attr pointer", IGRAPH_FAILURE); + } } + return IGRAPH_SUCCESS; } -igraph_error_t igraph_i_attribute_add_vertices(igraph_t *graph, igraph_integer_t nv, void *attr) { +igraph_error_t igraph_i_attribute_add_vertices( + igraph_t *graph, igraph_int_t nv, const igraph_attribute_record_list_t *attr +) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->add_vertices(graph, nv, attr); } else { @@ -98,8 +683,10 @@ igraph_error_t igraph_i_attribute_combine_vertices(const igraph_t *graph, } } -igraph_error_t igraph_i_attribute_add_edges(igraph_t *graph, - const igraph_vector_int_t *edges, void *attr) { +igraph_error_t igraph_i_attribute_add_edges( + igraph_t *graph, const igraph_vector_int_t *edges, + const igraph_attribute_record_list_t *attr +) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->add_edges(graph, edges, attr); } else { @@ -163,12 +750,12 @@ igraph_bool_t igraph_i_attribute_has_attr(const igraph_t *graph, } } -igraph_error_t igraph_i_attribute_gettype(const igraph_t *graph, +igraph_error_t igraph_i_attribute_get_type(const igraph_t *graph, igraph_attribute_type_t *type, igraph_attribute_elemtype_t elemtype, const char *name) { if (igraph_i_attribute_table) { - return igraph_i_attribute_table->gettype(graph, type, elemtype, name); + return igraph_i_attribute_table->get_type(graph, type, elemtype, name); } else { return IGRAPH_SUCCESS; } @@ -178,6 +765,7 @@ igraph_error_t igraph_i_attribute_gettype(const igraph_t *graph, igraph_error_t igraph_i_attribute_get_numeric_graph_attr(const igraph_t *graph, const char *name, igraph_vector_t *value) { + igraph_vector_clear(value); if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_numeric_graph_attr(graph, name, value); } else { @@ -189,6 +777,7 @@ igraph_error_t igraph_i_attribute_get_numeric_vertex_attr(const igraph_t *graph, const char *name, igraph_vs_t vs, igraph_vector_t *value) { + igraph_vector_clear(value); if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_numeric_vertex_attr(graph, name, vs, value); } else { @@ -200,6 +789,7 @@ igraph_error_t igraph_i_attribute_get_numeric_edge_attr(const igraph_t *graph, const char *name, igraph_es_t es, igraph_vector_t *value) { + igraph_vector_clear(value); if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_numeric_edge_attr(graph, name, es, value); } else { @@ -210,6 +800,7 @@ igraph_error_t igraph_i_attribute_get_numeric_edge_attr(const igraph_t *graph, igraph_error_t igraph_i_attribute_get_string_graph_attr(const igraph_t *graph, const char *name, igraph_strvector_t *value) { + igraph_strvector_clear(value); if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_string_graph_attr(graph, name, value); } else { @@ -221,6 +812,7 @@ igraph_error_t igraph_i_attribute_get_string_vertex_attr(const igraph_t *graph, const char *name, igraph_vs_t vs, igraph_strvector_t *value) { + igraph_strvector_clear(value); if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_string_vertex_attr(graph, name, vs, value); } else { @@ -232,6 +824,7 @@ igraph_error_t igraph_i_attribute_get_string_edge_attr(const igraph_t *graph, const char *name, igraph_es_t es, igraph_strvector_t *value) { + igraph_strvector_clear(value); if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_string_edge_attr(graph, name, es, value); } else { @@ -242,6 +835,7 @@ igraph_error_t igraph_i_attribute_get_string_edge_attr(const igraph_t *graph, igraph_error_t igraph_i_attribute_get_bool_graph_attr(const igraph_t *graph, const char *name, igraph_vector_bool_t *value) { + igraph_vector_bool_clear(value); if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_bool_graph_attr(graph, name, value); } else { @@ -253,6 +847,7 @@ igraph_error_t igraph_i_attribute_get_bool_vertex_attr(const igraph_t *graph, const char *name, igraph_vs_t vs, igraph_vector_bool_t *value) { + igraph_vector_bool_clear(value); if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_bool_vertex_attr(graph, name, vs, value); } else { @@ -264,6 +859,7 @@ igraph_error_t igraph_i_attribute_get_bool_edge_attr(const igraph_t *graph, const char *name, igraph_es_t es, igraph_vector_bool_t *value) { + igraph_vector_bool_clear(value); if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_bool_edge_attr(graph, name, es, value); } else { @@ -301,12 +897,6 @@ igraph_set_attribute_table(const igraph_attribute_table_t * table) { return old; } -igraph_attribute_table_t * -igraph_i_set_attribute_table(const igraph_attribute_table_t * table) { - IGRAPH_WARNING("igraph_i_set_attribute_table is deprecated, use igraph_set_attribute_table."); - return igraph_set_attribute_table(table); -} - igraph_bool_t igraph_has_attribute_table(void) { return igraph_i_attribute_table != NULL; } @@ -336,7 +926,7 @@ igraph_error_t igraph_attribute_combination_init(igraph_attribute_combination_t attribute combination list. */ void igraph_attribute_combination_destroy(igraph_attribute_combination_t *comb) { - igraph_integer_t i, n = igraph_vector_ptr_size(&comb->list); + igraph_int_t i, n = igraph_vector_ptr_size(&comb->list); for (i = 0; i < n; i++) { igraph_attribute_combination_record_t *rec = VECTOR(comb->list)[i]; if (rec->name) { @@ -375,7 +965,7 @@ igraph_error_t igraph_attribute_combination_add(igraph_attribute_combination_t * const char *name, igraph_attribute_combination_type_t type, igraph_function_pointer_t func) { - igraph_integer_t i, n = igraph_vector_ptr_size(&comb->list); + igraph_int_t i, n = igraph_vector_ptr_size(&comb->list); /* Search, in case it is already there */ for (i = 0; i < n; i++) { @@ -435,7 +1025,7 @@ igraph_error_t igraph_attribute_combination_add(igraph_attribute_combination_t * */ igraph_error_t igraph_attribute_combination_remove(igraph_attribute_combination_t *comb, const char *name) { - igraph_integer_t i, n = igraph_vector_ptr_size(&comb->list); + igraph_int_t i, n = igraph_vector_ptr_size(&comb->list); /* Search, in case it is already there */ for (i = 0; i < n; i++) { @@ -465,7 +1055,7 @@ igraph_error_t igraph_attribute_combination_query(const igraph_attribute_combina const char *name, igraph_attribute_combination_type_t *type, igraph_function_pointer_t *func) { - igraph_integer_t i, def = -1, len = igraph_vector_ptr_size(&comb->list); + igraph_int_t i, def = -1, len = igraph_vector_ptr_size(&comb->list); for (i = 0; i < len; i++) { igraph_attribute_combination_record_t *rec = VECTOR(comb->list)[i]; diff --git a/src/vendor/cigraph/src/graph/attributes.h b/src/vendor/cigraph/src/graph/attributes.h index c1ceb3e7a0f..91fdf48144c 100644 --- a/src/vendor/cigraph/src/graph/attributes.h +++ b/src/vendor/cigraph/src/graph/attributes.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -24,26 +24,20 @@ #include "igraph_strvector.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS -#define IGRAPH_I_ATTRIBUTE_DESTROY(graph) \ - do {if ((graph)->attr) igraph_i_attribute_destroy(graph);} while(0) -#define IGRAPH_I_ATTRIBUTE_COPY(to,from,ga,va,ea) do { \ - igraph_error_t igraph_i_ret2=IGRAPH_SUCCESS; \ - (to)->attr = NULL; \ - if ((from)->attr) { \ - IGRAPH_CHECK(igraph_i_ret2=igraph_i_attribute_copy((to),(from),(ga),(va),(ea))); \ - } \ - if (igraph_i_ret2 != IGRAPH_SUCCESS) { \ - IGRAPH_ERROR("", igraph_i_ret2); \ - } \ - } while(0) - -igraph_error_t igraph_i_attribute_init(igraph_t *graph, void *attr); +igraph_error_t igraph_i_attribute_init( + igraph_t *graph, const igraph_attribute_record_list_t *attr +); void igraph_i_attribute_destroy(igraph_t *graph); -igraph_error_t igraph_i_attribute_copy(igraph_t *to, const igraph_t *from, - igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea); -igraph_error_t igraph_i_attribute_add_vertices(igraph_t *graph, igraph_integer_t nv, void *attr); +igraph_error_t igraph_i_attribute_copy( + igraph_t *to, const igraph_t *from, + igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea +); +igraph_error_t igraph_i_attribute_add_vertices( + igraph_t *graph, igraph_int_t nv, + const igraph_attribute_record_list_t *attr +); igraph_error_t igraph_i_attribute_permute_vertices(const igraph_t *graph, igraph_t *newgraph, const igraph_vector_int_t *idx); @@ -51,8 +45,10 @@ igraph_error_t igraph_i_attribute_combine_vertices(const igraph_t *graph, igraph_t *newgraph, const igraph_vector_int_list_t *merges, const igraph_attribute_combination_t *comb); -igraph_error_t igraph_i_attribute_add_edges(igraph_t *graph, - const igraph_vector_int_t *edges, void *attr); +igraph_error_t igraph_i_attribute_add_edges( + igraph_t *graph, const igraph_vector_int_t *edges, + const igraph_attribute_record_list_t *attr +); igraph_error_t igraph_i_attribute_permute_edges(const igraph_t *graph, igraph_t *newgraph, const igraph_vector_int_t *idx); @@ -71,7 +67,7 @@ igraph_error_t igraph_i_attribute_get_info(const igraph_t *graph, igraph_bool_t igraph_i_attribute_has_attr(const igraph_t *graph, igraph_attribute_elemtype_t type, const char *name); -igraph_error_t igraph_i_attribute_gettype(const igraph_t *graph, +igraph_error_t igraph_i_attribute_get_type(const igraph_t *graph, igraph_attribute_type_t *type, igraph_attribute_elemtype_t elemtype, const char *name); @@ -110,6 +106,6 @@ igraph_error_t igraph_i_attribute_get_bool_edge_attr(const igraph_t *graph, igraph_es_t es, igraph_vector_bool_t *value); -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_GRAPH_ATTRIBUTES_H */ diff --git a/src/vendor/cigraph/src/graph/basic_query.c b/src/vendor/cigraph/src/graph/basic_query.c index 10dc66cdb4a..c58d19bd09e 100644 --- a/src/vendor/cigraph/src/graph/basic_query.c +++ b/src/vendor/cigraph/src/graph/basic_query.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -47,11 +46,11 @@ * d1 is the (out-)degree of \p v1 and d2 is the (in-)degree of \p v2. */ igraph_error_t igraph_are_adjacent(const igraph_t *graph, - igraph_integer_t v1, igraph_integer_t v2, + igraph_int_t v1, igraph_int_t v2, igraph_bool_t *res) { - igraph_integer_t nov = igraph_vcount(graph); - igraph_integer_t eid = -1; + igraph_int_t nov = igraph_vcount(graph); + igraph_int_t eid = -1; if (v1 < 0 || v2 < 0 || v1 > nov - 1 || v2 > nov - 1) { IGRAPH_ERROR("Invalid vertex ID when checking if two vertices are connected.", IGRAPH_EINVVID); @@ -62,32 +61,3 @@ igraph_error_t igraph_are_adjacent(const igraph_t *graph, return IGRAPH_SUCCESS; } - - -/** - * \ingroup structural - * \function igraph_are_connected - * \brief Decides whether two vertices are adjacent (deprecated alias). - * - * \deprecated-by igraph_are_adjacent 0.10.10 - * - * Decides whether there are any edges that have \p v1 and \p v2 - * as endpoints. This function is of course symmetric for undirected - * graphs. - * - * \param graph The graph object. - * \param v1 The first vertex. - * \param v2 The second vertex. - * \param res Boolean, \c true if there is an edge from - * \p v1 to \p v2, \c false otherwise. - * \return The error code \c IGRAPH_EINVVID is returned if an invalid - * vertex ID is given. - * - * Time complexity: O( min(log(d1), log(d2)) ), - * d1 is the (out-)degree of \p v1 and d2 is the (in-)degree of \p v2. - */ -igraph_error_t igraph_are_connected(const igraph_t *graph, - igraph_integer_t v1, igraph_integer_t v2, - igraph_bool_t *res) { - return igraph_are_adjacent(graph, v1, v2, res); -} diff --git a/src/vendor/cigraph/src/graph/caching.c b/src/vendor/cigraph/src/graph/caching.c index e7c4d9595c7..6710bf7d087 100644 --- a/src/vendor/cigraph/src/graph/caching.c +++ b/src/vendor/cigraph/src/graph/caching.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify diff --git a/src/vendor/cigraph/src/graph/caching.h b/src/vendor/cigraph/src/graph/caching.h index 3a3e1491ffa..d82c926493c 100644 --- a/src/vendor/cigraph/src/graph/caching.h +++ b/src/vendor/cigraph/src/graph/caching.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -28,7 +28,7 @@ #include /* memset */ -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS struct igraph_i_property_cache_t { igraph_bool_t value[IGRAPH_PROP_I_SIZE]; @@ -47,6 +47,6 @@ void igraph_i_property_cache_invalidate_conditionally( const igraph_t *graph, uint32_t keep_always, uint32_t keep_when_false, uint32_t keep_when_true ); -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_CACHING_H */ diff --git a/src/vendor/cigraph/src/graph/cattributes.c b/src/vendor/cigraph/src/graph/cattributes.c index f4242af7f70..70031f7beed 100644 --- a/src/vendor/cigraph/src/graph/cattributes.c +++ b/src/vendor/cigraph/src/graph/cattributes.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -9,7 +8,6 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -26,191 +24,193 @@ #include "igraph_interface.h" #include "igraph_random.h" -#include "internal/hacks.h" /* strdup */ - #include /* An attribute is either a numeric vector (vector_t), a boolean vector * (vector_bool_t) or a string vector (strvector_t). - * The attribute itself is stored in a struct igraph_attribute_record_t. - * There is one such object for each attribute. The igraph_t has a pointer - * to an igraph_i_cattribute_t, which contains three vector_ptr_t's, each - * holding pointers to igraph_attribute_record_t objects. */ + * The attribute itself is stored in a struct igraph_attribute_record_t. There + * is one such object for each attribute. The igraph_t has a pointer to an + * igraph_i_cattribute_t, which contains three igraph_attribute_vector_list_t's, + * each holding pointers to igraph_attribute_record_t objects. */ -/* This function is used for producing better error messages. */ -static const char *attribute_type_name(igraph_attribute_type_t type) { - switch (type) { - case IGRAPH_ATTRIBUTE_UNSPECIFIED: - return "unspecified"; /* TODO: should probably trigger a fatal error */ - case IGRAPH_ATTRIBUTE_NUMERIC: - return "numeric"; - case IGRAPH_ATTRIBUTE_BOOLEAN: - return "boolean"; - case IGRAPH_ATTRIBUTE_STRING: - return "string"; - case IGRAPH_ATTRIBUTE_OBJECT: - return "object"; +typedef struct igraph_i_cattributes_t { + igraph_attribute_record_list_t gal; + igraph_attribute_record_list_t val; + igraph_attribute_record_list_t eal; +} igraph_i_cattributes_t; + +/* + * Finds an attribute with the given name in an attribute record list, and + * returns the index of the record in the list, or -1 if there was no such + * attribute. + */ +static igraph_int_t igraph_i_cattribute_find_index( + const igraph_attribute_record_list_t *attrs, const char *name +) { + igraph_int_t n = igraph_attribute_record_list_size(attrs); + for (igraph_int_t i = 0; i < n; i++) { + const igraph_attribute_record_t *rec = igraph_attribute_record_list_get_ptr(attrs, i); + if (!strcmp(rec->name, name)) { + return i; + } } - /* The following line is intentionally not in a default switch label - * so that the compiler can warn about unhandled enum values, - * should additional attribute types ever be added in the future. */ - IGRAPH_FATALF("Invalid attribute type %d found.", (int) type); + return -1; } -static igraph_bool_t igraph_i_cattribute_find(const igraph_vector_ptr_t *ptrvec, - const char *name, igraph_integer_t *idx) { - igraph_integer_t i, n = igraph_vector_ptr_size(ptrvec); - igraph_bool_t l = false; - for (i = 0; !l && i < n; i++) { - igraph_attribute_record_t *rec = VECTOR(*ptrvec)[i]; - l = !strcmp(rec->name, name); - } - if (idx) { - *idx = i - 1; +/* + * Finds an attribute with the given name in an attribute record list, and + * returns the attribute record or NULL if there was no such attribute. + * Optionally, the type of the attribute can be enforced; use + * IGRAPH_ATTRIBUTE_UNSPECIFIED if you do not care about the type. + */ +static igraph_attribute_record_t* igraph_i_cattribute_find( + igraph_attribute_record_list_t *attrs, const char *name, + igraph_attribute_type_t type +) { + igraph_int_t index = igraph_i_cattribute_find_index(attrs, name); + igraph_attribute_record_t *rec; + + if (index >= 0) { + rec = igraph_attribute_record_list_get_ptr(attrs, index); + if (type == IGRAPH_ATTRIBUTE_UNSPECIFIED || type == rec->type) { + return rec; + } } - return l; + + return NULL; } /* - * Restores attribute vector lengths to their original size after a failure. - * This function assumes that none of the attribute vectors are shorter than origlen. - * Some may be longer due to a partially completed size extension: these will be - * shrunk to their original size. + * Same as igraph_i_cattribute_find(), but suitable for const attribute record + * lists. */ -static void igraph_i_cattribute_revert_attribute_vector_sizes( - igraph_vector_ptr_t *attrlist, igraph_integer_t origlen) { - - igraph_integer_t no_of_attrs = igraph_vector_ptr_size(attrlist); - for (igraph_integer_t i = 0; i < no_of_attrs; i++) { - igraph_attribute_record_t *rec = VECTOR(*attrlist)[i]; - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *nvec = (igraph_vector_t *) rec->value; - IGRAPH_ASSERT(igraph_vector_capacity(nvec) >= origlen); - igraph_vector_resize(nvec, origlen); /* shrinks */ - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *bvec = (igraph_vector_bool_t *) rec->value; - IGRAPH_ASSERT(igraph_vector_bool_capacity(bvec) >= origlen); - igraph_vector_bool_resize(bvec, origlen); /* shrinks */ - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *svec = (igraph_strvector_t *) rec->value; - IGRAPH_ASSERT(igraph_strvector_capacity(svec) >= origlen); - igraph_strvector_resize(svec, origlen); /* shrinks */ - } else { - /* Must never reach here */ - IGRAPH_FATAL("Unknown attribute type encountered."); +static const igraph_attribute_record_t* igraph_i_cattribute_find_const( + const igraph_attribute_record_list_t *attrs, const char *name, + igraph_attribute_type_t type +) { + igraph_int_t index = igraph_i_cattribute_find_index(attrs, name); + const igraph_attribute_record_t *rec; + + if (index >= 0) { + rec = igraph_attribute_record_list_get_ptr(attrs, index); + if (type == IGRAPH_ATTRIBUTE_UNSPECIFIED || type == rec->type) { + return rec; } } + + return NULL; } -typedef struct igraph_i_cattributes_t { - igraph_vector_ptr_t gal; - igraph_vector_ptr_t val; - igraph_vector_ptr_t eal; -} igraph_i_cattributes_t; +/* + * Finds an attribute with the given name in an attribute record list, and + * returns the attribute record in an output argument. Returns an error code + * if there is no such attribute. Optionally, the type of the attribute can be + * enforced; use IGRAPH_ATTRIBUTE_UNSPECIFIED if you do not care about the type. + */ +static igraph_error_t igraph_i_cattribute_find_or_return( + igraph_attribute_record_list_t *attrs, const char *name, + igraph_attribute_type_t type, igraph_attribute_record_t **ptr +) { + igraph_attribute_record_t *rec; -static igraph_error_t igraph_i_cattributes_copy_attribute_record(igraph_attribute_record_t **newrec, - const igraph_attribute_record_t *rec) { - igraph_vector_t *num, *newnum; - igraph_strvector_t *str, *newstr; + rec = igraph_i_cattribute_find(attrs, name, IGRAPH_ATTRIBUTE_UNSPECIFIED); + if (!rec) { + IGRAPH_ERRORF("Attribute '%s' does not exist.", IGRAPH_EINVAL, name); + } - *newrec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - if (!(*newrec)) { - IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ + if (type != IGRAPH_ATTRIBUTE_UNSPECIFIED) { + IGRAPH_CHECK(igraph_attribute_record_check_type(rec, type)); } - IGRAPH_FINALLY(igraph_free, *newrec); - (*newrec)->type = rec->type; - (*newrec)->name = strdup(rec->name); - if (!(*newrec)->name) { - IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ + + if (ptr) { + *ptr = rec; } - IGRAPH_FINALLY(igraph_free, (void*)(*newrec)->name); - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - num = (igraph_vector_t *)rec->value; - newnum = IGRAPH_CALLOC(1, igraph_vector_t); - if (!newnum) { - IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newnum); - IGRAPH_CHECK(igraph_vector_init_copy(newnum, num)); - IGRAPH_FINALLY(igraph_vector_destroy, newnum); - (*newrec)->value = newnum; - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - str = (igraph_strvector_t*)rec->value; - newstr = IGRAPH_CALLOC(1, igraph_strvector_t); - if (!newstr) { - IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newstr); - IGRAPH_CHECK(igraph_strvector_init_copy(newstr, str)); - IGRAPH_FINALLY(igraph_strvector_destroy, newstr); - (*newrec)->value = newstr; - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *log = (igraph_vector_bool_t*) rec->value; - igraph_vector_bool_t *newlog = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (!newlog) { - IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ + + return IGRAPH_SUCCESS; +} + +/* + * Finds an attribute with the given name in an attribute record list, and + * returns the attribute record in an output argument. Creates a new attribute + * with the given name if there is no such attribute. The type of the attribute + * needs to be specified so we can create the appropriate value vector if needed. + * You can specify a length; when the existing value vector for the attribute + * is shorter than this length, it will be extended to ensure that it has at + * least this many elements. You can pass 0 as the length if you do not want to + * expand value vectors. + */ +static igraph_error_t igraph_i_cattribute_find_or_create( + igraph_attribute_record_list_t *attrs, + const char *name, igraph_attribute_type_t type, + igraph_int_t length, + igraph_attribute_record_t **ptr +) { + igraph_attribute_record_t *rec; + + rec = igraph_i_cattribute_find(attrs, name, IGRAPH_ATTRIBUTE_UNSPECIFIED); + if (rec) { + if (type != IGRAPH_ATTRIBUTE_UNSPECIFIED) { + IGRAPH_CHECK(igraph_attribute_record_check_type(rec, type)); } - IGRAPH_FINALLY(igraph_free, newlog); - IGRAPH_CHECK(igraph_vector_bool_init_copy(newlog, log)); - IGRAPH_FINALLY(igraph_vector_bool_destroy, newlog); - (*newrec)->value = newlog; + } else { + IGRAPH_CHECK(igraph_attribute_record_list_push_back_new(attrs, &rec)); + IGRAPH_CHECK(igraph_attribute_record_set_name(rec, name)); + IGRAPH_CHECK(igraph_attribute_record_set_type(rec, type)); + } + + if (length > 0 && igraph_attribute_record_size(rec) < length) { + IGRAPH_CHECK(igraph_attribute_record_resize(rec, length)); + } + + if (ptr) { + *ptr = rec; } - IGRAPH_FINALLY_CLEAN(4); return IGRAPH_SUCCESS; } -static void igraph_i_attribute_list_destroy(igraph_vector_ptr_t *attrlist) { - igraph_integer_t i; - igraph_integer_t n = igraph_vector_ptr_size(attrlist); - for (i = 0; i < n; i++) { - igraph_attribute_record_t *rec = VECTOR(*attrlist)[i]; - if (rec) { - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *num = (igraph_vector_t *) rec->value; - igraph_vector_destroy(num); - IGRAPH_FREE(num); - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *str = (igraph_strvector_t *) rec->value; - igraph_strvector_destroy(str); - IGRAPH_FREE(str); - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *boolvec = (igraph_vector_bool_t *) rec->value; - igraph_vector_bool_destroy(boolvec); - IGRAPH_FREE(boolvec); - } - IGRAPH_FREE(rec->name); - IGRAPH_FREE(rec); +/* + * Restores attribute vector lengths to their original size after a failure. + * This function assumes that none of the attribute vectors are shorter than origlen. + * Some may be longer due to a partially completed size extension: these will be + * shrunk to their original size. + */ +static void igraph_i_cattribute_revert_attribute_vector_sizes( + igraph_attribute_record_list_t *attrlist, igraph_int_t origlen) { + + igraph_int_t no_of_attrs = igraph_attribute_record_list_size(attrlist); + for (igraph_int_t i = 0; i < no_of_attrs; i++) { + igraph_attribute_record_t *rec = igraph_attribute_record_list_get_ptr(attrlist, i); + IGRAPH_ASSERT(igraph_attribute_record_size(rec) >= origlen); + if (igraph_attribute_record_resize(rec, origlen) != IGRAPH_SUCCESS) { + /* We should have succeeded for known attribute types because we + * always shrink the vector so throw a fatal error if this happens */ + IGRAPH_FATAL("Unknown attribute type encountered."); } } - igraph_vector_ptr_destroy(attrlist); } -static igraph_error_t igraph_i_cattribute_init(igraph_t *graph, igraph_vector_ptr_t *attr) { - igraph_attribute_record_t *attr_rec; - igraph_integer_t i, n; +static igraph_error_t igraph_i_cattribute_init( + igraph_t *graph, const igraph_attribute_record_list_t *attr +) { igraph_i_cattributes_t *nattr; - n = attr ? igraph_vector_ptr_size(attr) : 0; - nattr = IGRAPH_CALLOC(1, igraph_i_cattributes_t); - if (!nattr) { - IGRAPH_ERROR("Can't init attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } + IGRAPH_CHECK_OOM(nattr, "Insufficient memory to allocate attribute storage."); IGRAPH_FINALLY(igraph_free, nattr); - IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->gal, n)); - IGRAPH_FINALLY(igraph_i_attribute_list_destroy, &nattr->gal); - IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->val, 0)); - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &nattr->val); - IGRAPH_CHECK(igraph_vector_ptr_init(&nattr->eal, 0)); - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &nattr->eal); - - for (i = 0; i < n; i++) { - IGRAPH_CHECK(igraph_i_cattributes_copy_attribute_record( - &attr_rec, VECTOR(*attr)[i])); - VECTOR(nattr->gal)[i] = attr_rec; + if (attr) { + IGRAPH_CHECK(igraph_attribute_record_list_init_copy(&nattr->gal, attr)); + } else { + IGRAPH_CHECK(igraph_attribute_record_list_init(&nattr->gal, 0)); } + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &nattr->gal); + + IGRAPH_CHECK(igraph_attribute_record_list_init(&nattr->val, 0)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &nattr->val); + + IGRAPH_CHECK(igraph_attribute_record_list_init(&nattr->eal, 0)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &nattr->eal); graph->attr = nattr; IGRAPH_FINALLY_CLEAN(4); @@ -220,260 +220,133 @@ static igraph_error_t igraph_i_cattribute_init(igraph_t *graph, igraph_vector_pt static void igraph_i_cattribute_destroy(igraph_t *graph) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *als[3] = { &attr->gal, &attr->val, &attr->eal }; - for (size_t a = 0; a < 3; a++) { - igraph_i_attribute_list_destroy(als[a]); - } + igraph_attribute_record_list_destroy(&attr->eal); + igraph_attribute_record_list_destroy(&attr->val); + igraph_attribute_record_list_destroy(&attr->gal); IGRAPH_FREE(graph->attr); /* sets to NULL */ } -/* Almost the same as destroy, but we might have null pointers */ - -static void igraph_i_cattribute_copy_free(igraph_i_cattributes_t *attr) { - igraph_vector_ptr_t *als[3] = { &attr->gal, &attr->val, &attr->eal }; - igraph_integer_t i, n; - igraph_vector_t *num; - igraph_strvector_t *str; - igraph_vector_bool_t *boolvec; - igraph_attribute_record_t *rec; - for (size_t a = 0; a < 3; a++) { - n = igraph_vector_ptr_size(als[a]); - for (i = 0; i < n; i++) { - rec = VECTOR(*als[a])[i]; - if (!rec) { - continue; - } - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - num = (igraph_vector_t*)rec->value; - igraph_vector_destroy(num); - IGRAPH_FREE(num); - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - boolvec = (igraph_vector_bool_t*)rec->value; - igraph_vector_bool_destroy(boolvec); - IGRAPH_FREE(boolvec); - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - str = (igraph_strvector_t*)rec->value; - igraph_strvector_destroy(str); - IGRAPH_FREE(str); - } - IGRAPH_FREE(rec->name); - IGRAPH_FREE(rec); - } - } -} - /* No reference counting here. If you use attributes in C you should know what you're doing. */ -static igraph_error_t igraph_i_cattribute_copy(igraph_t *to, const igraph_t *from, - igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea) { - igraph_i_cattributes_t *attrfrom = from->attr, *attrto; - igraph_vector_ptr_t *alto[3], *alfrom[3] = { &attrfrom->gal, &attrfrom->val, - &attrfrom->eal - }; - igraph_integer_t i, n; +static igraph_error_t igraph_i_cattribute_copy( + igraph_t *to, const igraph_t *from, + igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea +) { + igraph_i_cattributes_t *attrto, *attrfrom = from->attr; + igraph_attribute_record_list_t *alto[3], *alfrom[3] = { + &attrfrom->gal, &attrfrom->val, &attrfrom->eal + }; igraph_bool_t copy[3] = { ga, va, ea }; - to->attr = attrto = IGRAPH_CALLOC(1, igraph_i_cattributes_t); - if (!attrto) { - IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } + + attrto = IGRAPH_CALLOC(1, igraph_i_cattributes_t); + IGRAPH_CHECK_OOM(attrto, "Insufficient memory to copy attributes."); IGRAPH_FINALLY(igraph_free, attrto); - IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->gal, 0); - IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->val, 0); - IGRAPH_VECTOR_PTR_INIT_FINALLY(&attrto->eal, 0); - IGRAPH_FINALLY_CLEAN(3); - IGRAPH_FINALLY(igraph_i_cattribute_copy_free, attrto); - - alto[0] = &attrto->gal; alto[1] = &attrto->val; alto[2] = &attrto->eal; - for (size_t a = 0; a < 3; a++) { - if (copy[a]) { - n = igraph_vector_ptr_size(alfrom[a]); - IGRAPH_CHECK(igraph_vector_ptr_resize(alto[a], n)); - igraph_vector_ptr_null(alto[a]); - for (i = 0; i < n; i++) { - igraph_attribute_record_t *newrec; - IGRAPH_CHECK(igraph_i_cattributes_copy_attribute_record(&newrec, - VECTOR(*alfrom[a])[i])); - VECTOR(*alto[a])[i] = newrec; - } + + alto[0] = &attrto->gal; + alto[1] = &attrto->val; + alto[2] = &attrto->eal; + + for (igraph_int_t i = 0; i < 3; i++) { + if (copy[i]) { + IGRAPH_CHECK(igraph_attribute_record_list_init_copy(alto[i], alfrom[i])); + } else { + IGRAPH_CHECK(igraph_attribute_record_list_init(alto[i], 0)); } + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, alto[i]); } - IGRAPH_FINALLY_CLEAN(2); + to->attr = attrto; + IGRAPH_FINALLY_CLEAN(4); + return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattribute_add_vertices_inner(igraph_t *graph, igraph_integer_t nv, - igraph_vector_ptr_t *nattr) { +static igraph_error_t igraph_i_cattribute_add_vertices_or_edges_inner( + igraph_attribute_record_list_t *val, + igraph_int_t newlen, igraph_int_t nv, + const igraph_attribute_record_list_t *nattr +) { + igraph_int_t length; + igraph_int_t nattrno = nattr == NULL ? 0 : igraph_attribute_record_list_size(nattr); + igraph_int_t origlen = newlen - nv; - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t length = igraph_vector_ptr_size(val); - igraph_integer_t nattrno = nattr == NULL ? 0 : igraph_vector_ptr_size(nattr); - igraph_integer_t origlen = igraph_vcount(graph) - nv; - igraph_integer_t newattrs = 0, i; - igraph_vector_int_t news; - - /* First add the new attributes if any */ - newattrs = 0; - IGRAPH_VECTOR_INT_INIT_FINALLY(&news, 0); - for (i = 0; i < nattrno; i++) { - igraph_attribute_record_t *nattr_entry = VECTOR(*nattr)[i]; - const char *nname = nattr_entry->name; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(val, nname, &j); - if (!l) { - newattrs++; - IGRAPH_CHECK(igraph_vector_int_push_back(&news, i)); - } else { - /* check types */ - if (nattr_entry->type != - ((igraph_attribute_record_t*)VECTOR(*val)[j])->type) { - IGRAPH_ERROR("You cannot mix attribute types", IGRAPH_EINVAL); - } - } - } + IGRAPH_ASSERT(origlen >= 0); - /* Add NA/empty string vectors for the existing vertices */ - if (newattrs != 0) { - for (i = 0; i < newattrs; i++) { - igraph_attribute_record_t *tmp = VECTOR(*nattr)[VECTOR(news)[i]]; - igraph_attribute_record_t *newrec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_attribute_type_t type = tmp->type; - if (!newrec) { - IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newrec); - newrec->type = type; - newrec->name = strdup(tmp->name); - if (!newrec->name) { - IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)newrec->name); - if (type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *newnum = IGRAPH_CALLOC(1, igraph_vector_t); - if (!newnum) { - IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newnum); - IGRAPH_VECTOR_INIT_FINALLY(newnum, origlen); - newrec->value = newnum; - igraph_vector_fill(newnum, IGRAPH_NAN); - } else if (type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *newstr = IGRAPH_CALLOC(1, igraph_strvector_t); - if (!newstr) { - IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newstr); - IGRAPH_STRVECTOR_INIT_FINALLY(newstr, origlen); - newrec->value = newstr; - } else if (type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *newbool = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (!newbool) { - IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newbool); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newbool, origlen); - newrec->value = newbool; - igraph_vector_bool_fill(newbool, false); - } - IGRAPH_CHECK(igraph_vector_ptr_push_back(val, newrec)); - IGRAPH_FINALLY_CLEAN(4); - } - length = igraph_vector_ptr_size(val); + /* Find all the attributes that are newly added, and create new value vectors + * for them in the original graph */ + for (igraph_int_t i = 0; i < nattrno; i++) { + const igraph_attribute_record_t *nattr_entry = igraph_attribute_record_list_get_ptr(nattr, i); + const char *nname = nattr_entry->name; + IGRAPH_CHECK(igraph_i_cattribute_find_or_create(val, nname, nattr_entry->type, origlen, NULL)); } /* Now append the new values */ - for (i = 0; i < length; i++) { - igraph_attribute_record_t *oldrec = VECTOR(*val)[i]; - igraph_attribute_record_t *newrec = 0; - const char *name = oldrec->name; - igraph_integer_t j = -1; - igraph_bool_t l = false; - if (nattr) { - l = igraph_i_cattribute_find(nattr, name, &j); - } - if (l) { + length = igraph_attribute_record_list_size(val); + for (igraph_int_t i = 0; i < length; i++) { + igraph_attribute_record_t *oldrec = igraph_attribute_record_list_get_ptr(val, i); + const igraph_attribute_record_t *newrec = nattr + ? igraph_i_cattribute_find_const(nattr, oldrec->name, oldrec->type) + : NULL; + + IGRAPH_ASSERT(igraph_attribute_record_size(oldrec) == origlen); + + if (newrec) { /* This attribute is present in nattr */ - igraph_vector_t *oldnum, *newnum; - igraph_strvector_t *oldstr, *newstr; - igraph_vector_bool_t *oldbool, *newbool; - newrec = VECTOR(*nattr)[j]; - oldnum = (igraph_vector_t*)oldrec->value; - newnum = (igraph_vector_t*)newrec->value; - oldstr = (igraph_strvector_t*)oldrec->value; - newstr = (igraph_strvector_t*)newrec->value; - oldbool = (igraph_vector_bool_t*)oldrec->value; - newbool = (igraph_vector_bool_t*)newrec->value; - if (oldrec->type != newrec->type) { - IGRAPH_ERROR("Attribute types do not match.", IGRAPH_EINVAL); - } switch (oldrec->type) { case IGRAPH_ATTRIBUTE_NUMERIC: - if (nv != igraph_vector_size(newnum)) { + if (nv != igraph_vector_size(newrec->value.as_vector)) { IGRAPH_ERROR("Invalid numeric attribute length.", IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_vector_append(oldnum, newnum)); + IGRAPH_CHECK(igraph_vector_append( + oldrec->value.as_vector, newrec->value.as_vector + )); break; case IGRAPH_ATTRIBUTE_STRING: - if (nv != igraph_strvector_size(newstr)) { + if (nv != igraph_strvector_size(newrec->value.as_strvector)) { IGRAPH_ERROR("Invalid string attribute length.", IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_strvector_append(oldstr, newstr)); + IGRAPH_CHECK(igraph_strvector_append( + oldrec->value.as_strvector, newrec->value.as_strvector + )); break; case IGRAPH_ATTRIBUTE_BOOLEAN: - if (nv != igraph_vector_bool_size(newbool)) { + if (nv != igraph_vector_bool_size(newrec->value.as_vector_bool)) { IGRAPH_ERROR("Invalid boolean attribute length.", IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_vector_bool_append(oldbool, newbool)); + IGRAPH_CHECK(igraph_vector_bool_append( + oldrec->value.as_vector_bool, newrec->value.as_vector_bool + )); break; default: - IGRAPH_WARNING("Invalid attribute type."); + IGRAPH_WARNINGF( + "Attribute '%s' with unknown type %d ignored", + oldrec->name, (int) oldrec->type + ); break; } } else { - /* No such attribute, append NA's */ - igraph_vector_t *oldnum = (igraph_vector_t *)oldrec->value; - igraph_strvector_t *oldstr = (igraph_strvector_t*)oldrec->value; - igraph_vector_bool_t *oldbool = (igraph_vector_bool_t*)oldrec->value; - switch (oldrec->type) { - case IGRAPH_ATTRIBUTE_NUMERIC: - IGRAPH_CHECK(igraph_vector_resize(oldnum, origlen + nv)); - for (j = origlen; j < origlen + nv; j++) { - VECTOR(*oldnum)[j] = IGRAPH_NAN; - } - break; - case IGRAPH_ATTRIBUTE_STRING: - IGRAPH_CHECK(igraph_strvector_resize(oldstr, origlen + nv)); - break; - case IGRAPH_ATTRIBUTE_BOOLEAN: - IGRAPH_CHECK(igraph_vector_bool_resize(oldbool, origlen + nv)); - for (j = origlen; j < origlen + nv; j++) { - VECTOR(*oldbool)[j] = 0; - } - break; - default: - IGRAPH_WARNING("Invalid attribute type"); - break; - } + /* No such attribute among the new ones so just extend the length + * of the current record */ + IGRAPH_CHECK(igraph_attribute_record_resize(oldrec, newlen)); } - } - igraph_vector_int_destroy(&news); - IGRAPH_FINALLY_CLEAN(1); + IGRAPH_ASSERT(igraph_attribute_record_size(oldrec) == newlen); + } return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattribute_add_vertices(igraph_t *graph, igraph_integer_t nv, - igraph_vector_ptr_t *nattr) { - /* Record information needed to restore attribute vector sizes */ - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t origlen = igraph_vcount(graph) - nv; +static igraph_error_t igraph_i_cattribute_add_vertices_or_edges( + igraph_attribute_record_list_t *val, + igraph_int_t newlen, igraph_int_t nv, + const igraph_attribute_record_list_t *nattr +) { + igraph_int_t origlen = newlen - nv; + igraph_error_t err = igraph_i_cattribute_add_vertices_or_edges_inner( + val, newlen, nv, nattr + ); - /* Attempt adding attributes */ - igraph_error_t err = igraph_i_cattribute_add_vertices_inner(graph, nv, nattr); if (err != IGRAPH_SUCCESS) { /* If unsuccessful, revert attribute vector sizes. * The following function assumes that all attributes vectors that @@ -490,41 +363,27 @@ static igraph_error_t igraph_i_cattribute_add_vertices(igraph_t *graph, igraph_i */ igraph_i_cattribute_revert_attribute_vector_sizes(val, origlen); } + return err; } -static void igraph_i_cattribute_clear_attribute_container(igraph_vector_ptr_t *v) { - igraph_integer_t i, n = igraph_vector_ptr_size(v); - for (i = 0; i < n; i++) { - igraph_attribute_record_t *rec = VECTOR(*v)[i]; - IGRAPH_FREE(rec->name); - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *numv = (igraph_vector_t*) rec->value; - igraph_vector_destroy(numv); - IGRAPH_FREE(numv); - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *strv = (igraph_strvector_t*) rec->value; - igraph_strvector_destroy(strv); - IGRAPH_FREE(strv); - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *boolv = (igraph_vector_bool_t*) rec->value; - igraph_vector_bool_destroy(boolv); - IGRAPH_FREE(boolv); - } - IGRAPH_FREE(rec); - } - igraph_vector_ptr_clear(v); +static igraph_error_t igraph_i_cattribute_add_vertices( + igraph_t *graph, igraph_int_t nv, + const igraph_attribute_record_list_t *nattr +) { + igraph_i_cattributes_t *attr = graph->attr; + return igraph_i_cattribute_add_vertices_or_edges(&attr->val, igraph_vcount(graph), nv, nattr); } typedef struct { igraph_vector_t *numeric; igraph_vector_bool_t *boolean; igraph_vector_ptr_t *strings; - igraph_integer_t length; + igraph_int_t length; } igraph_i_attribute_permutation_work_area_t; static igraph_error_t igraph_i_attribute_permutation_work_area_init( - igraph_i_attribute_permutation_work_area_t *work_area, igraph_integer_t length + igraph_i_attribute_permutation_work_area_t *work_area, igraph_int_t length ) { work_area->length = length; work_area->numeric = NULL; @@ -566,7 +425,7 @@ static igraph_error_t igraph_i_attribute_permutation_work_area_alloc_for_numeric if (vec == NULL) { vec = IGRAPH_CALLOC(1, igraph_vector_t); - IGRAPH_CHECK_OOM(vec, "Cannot permute attributes"); + IGRAPH_CHECK_OOM(vec, "Cannot permute attributes."); IGRAPH_FINALLY(igraph_free, vec); IGRAPH_CHECK(igraph_vector_init(vec, work_area->length)); work_area->numeric = vec; @@ -583,7 +442,7 @@ static igraph_error_t igraph_i_attribute_permutation_work_area_alloc_for_boolean if (vec == NULL) { vec = IGRAPH_CALLOC(1, igraph_vector_bool_t); - IGRAPH_CHECK_OOM(vec, "Cannot permute attributes"); + IGRAPH_CHECK_OOM(vec, "Cannot permute attributes."); IGRAPH_FINALLY(igraph_free, vec); IGRAPH_CHECK(igraph_vector_bool_init(vec, work_area->length)); work_area->boolean = vec; @@ -600,7 +459,7 @@ static igraph_error_t igraph_i_attribute_permutation_work_area_alloc_for_strings if (vec == NULL) { vec = IGRAPH_CALLOC(1, igraph_vector_ptr_t); - IGRAPH_CHECK_OOM(vec, "Cannot permute attributes"); + IGRAPH_CHECK_OOM(vec, "Cannot permute attributes."); IGRAPH_FINALLY(igraph_free, vec); IGRAPH_CHECK(igraph_vector_ptr_init(vec, 0)); IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(vec, igraph_strvector_destroy); @@ -619,7 +478,7 @@ static igraph_error_t igraph_i_attribute_permutation_work_area_permute_and_store igraph_strvector_t *new_vec; new_vec = IGRAPH_CALLOC(1, igraph_strvector_t); - IGRAPH_CHECK_OOM(new_vec, "Cannot permute attributes"); + IGRAPH_CHECK_OOM(new_vec, "Cannot permute attributes."); IGRAPH_FINALLY(igraph_free, new_vec); IGRAPH_CHECK(igraph_strvector_init(new_vec, 0)); IGRAPH_FINALLY(igraph_strvector_destroy, new_vec); @@ -631,22 +490,74 @@ static igraph_error_t igraph_i_attribute_permutation_work_area_permute_and_store return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattribute_permute_vertices_in_place( - igraph_t *graph, const igraph_vector_int_t *idx +static igraph_error_t igraph_i_cattribute_permute_attribute_record_list( + igraph_attribute_record_list_t *attrs, + igraph_attribute_record_list_t *new_attrs, + const igraph_vector_int_t *idx ) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t valno = igraph_vector_ptr_size(val); - igraph_integer_t i, j; + igraph_int_t no_attrs, idxlen; + + no_attrs = igraph_attribute_record_list_size(attrs); + + /* When vertices or edges are permuted, we now assume that there are no + * attributes in the target attribute list yet */ + IGRAPH_ASSERT(igraph_attribute_record_list_empty(new_attrs)); + IGRAPH_FINALLY(igraph_attribute_record_list_clear, new_attrs); + + idxlen = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < no_attrs; i++) { + igraph_attribute_record_t *oldrec = igraph_attribute_record_list_get_ptr(attrs, i); + igraph_attribute_type_t type = oldrec->type; + + /* Create a record for the same attribute in the new graph */ + igraph_attribute_record_t *newrec; + IGRAPH_CHECK(igraph_i_cattribute_find_or_create( + new_attrs, oldrec->name, oldrec->type, idxlen, &newrec + )); + + /* The data */ + switch (type) { + case IGRAPH_ATTRIBUTE_NUMERIC: + IGRAPH_CHECK(igraph_vector_index( + oldrec->value.as_vector, newrec->value.as_vector, idx + )); + break; + case IGRAPH_ATTRIBUTE_BOOLEAN: + IGRAPH_CHECK(igraph_vector_bool_index( + oldrec->value.as_vector_bool, newrec->value.as_vector_bool, idx + )); + break; + case IGRAPH_ATTRIBUTE_STRING: + IGRAPH_CHECK(igraph_strvector_index( + oldrec->value.as_strvector, newrec->value.as_strvector, idx + )); + break; + default: + IGRAPH_WARNINGF( + "Attribute '%s' with unknown type %d ignored", + oldrec->name, (int) oldrec->type + ); + } + } + + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} + +static igraph_error_t igraph_i_cattribute_permute_attribute_record_list_in_place( + igraph_attribute_record_list_t *attrs, const igraph_vector_int_t *idx +) { + igraph_int_t no_attrs = igraph_attribute_record_list_size(attrs); igraph_attribute_record_t *oldrec; igraph_vector_t *num, *num_work; igraph_strvector_t *str, str_work; igraph_vector_bool_t *oldbool, *bool_work; igraph_i_attribute_permutation_work_area_t work_area; - igraph_integer_t idx_size = igraph_vector_int_size(idx); + igraph_int_t idx_size = igraph_vector_int_size(idx); /* shortcut: don't allocate anything if there are no attributes */ - if (valno == 0) { + if (no_attrs == 0) { return IGRAPH_SUCCESS; } @@ -655,29 +566,32 @@ static igraph_error_t igraph_i_cattribute_permute_vertices_in_place( * back out from a permutation once we've started it */ IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_init(&work_area, idx_size)); IGRAPH_FINALLY(igraph_i_attribute_permutation_work_area_destroy, &work_area); - for (i = 0; i < valno; i++) { - oldrec = VECTOR(*val)[i]; + for (igraph_int_t i = 0; i < no_attrs; i++) { + oldrec = igraph_attribute_record_list_get_ptr(attrs, i); switch (oldrec->type) { case IGRAPH_ATTRIBUTE_NUMERIC: - num = (igraph_vector_t*) oldrec->value; + num = oldrec->value.as_vector; IGRAPH_CHECK(igraph_vector_reserve(num, idx_size)); IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_alloc_for_numeric(&work_area)); break; case IGRAPH_ATTRIBUTE_BOOLEAN: - oldbool = (igraph_vector_bool_t*) oldrec->value; + oldbool = oldrec->value.as_vector_bool; IGRAPH_CHECK(igraph_vector_bool_reserve(oldbool, idx_size)); IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_alloc_for_boolean(&work_area)); break; case IGRAPH_ATTRIBUTE_STRING: - str = (igraph_strvector_t*) oldrec->value; + str = oldrec->value.as_strvector; IGRAPH_CHECK(igraph_strvector_reserve(str, idx_size)); IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_alloc_for_strings(&work_area)); break; default: - IGRAPH_WARNING("Unknown vertex attribute ignored"); + IGRAPH_WARNINGF( + "Vertex attribute '%s' with unknown type %d ignored", + oldrec->name, (int) oldrec->type + ); } } @@ -686,18 +600,16 @@ static igraph_error_t igraph_i_cattribute_permute_vertices_in_place( * instances for the permuted attributes and store them in an * igraph_vector_ptr_t until we are done with all of them. If any of the * allocations fail, we can destroy the igraph_vector_ptr_t safely */ - for (i = 0; i < valno; i++) { - oldrec = VECTOR(*val)[i]; - if (oldrec->type != IGRAPH_ATTRIBUTE_STRING) { - continue; + for (igraph_int_t i = 0; i < no_attrs; i++) { + oldrec = igraph_attribute_record_list_get_ptr(attrs, i); + if (oldrec->type == IGRAPH_ATTRIBUTE_STRING) { + str = oldrec->value.as_strvector; + IGRAPH_CHECK( + igraph_i_attribute_permutation_work_area_permute_and_store_strvector( + &work_area, str, idx + ) + ); } - - str = (igraph_strvector_t*) oldrec->value; - IGRAPH_CHECK( - igraph_i_attribute_permutation_work_area_permute_and_store_strvector( - &work_area, str, idx - ) - ); } /* strings are done, and now all vectors involved in the process are @@ -705,13 +617,13 @@ static igraph_error_t igraph_i_cattribute_permute_vertices_in_place( * supposed to fail. We can safely replace the original string attribute * vectors with the permuted ones, and then proceed to the remaining * attributes */ - for (i = 0, j = 0; i < valno; i++) { - oldrec = VECTOR(*val)[i]; + for (igraph_int_t i = 0, j = 0; i < no_attrs; i++) { + oldrec = igraph_attribute_record_list_get_ptr(attrs, i); if (oldrec->type != IGRAPH_ATTRIBUTE_STRING) { continue; } - str = (igraph_strvector_t*) oldrec->value; + str = oldrec->value.as_strvector; str_work = *((igraph_strvector_t*) VECTOR(*(work_area.strings))[j]); *((igraph_strvector_t*) VECTOR(*(work_area.strings))[j]) = *str; *str = str_work; @@ -719,24 +631,22 @@ static igraph_error_t igraph_i_cattribute_permute_vertices_in_place( } igraph_i_attribute_permutation_work_area_release_stored_strvectors(&work_area); - for (i = 0; i < valno; i++) { - oldrec = VECTOR(*val)[i]; + for (igraph_int_t i = 0; i < no_attrs; i++) { + oldrec = igraph_attribute_record_list_get_ptr(attrs, i); switch (oldrec->type) { case IGRAPH_ATTRIBUTE_NUMERIC: - num = (igraph_vector_t*) oldrec->value; + num = oldrec->value.as_vector; num_work = work_area.numeric; IGRAPH_ASSERT(num_work != NULL); IGRAPH_CHECK(igraph_vector_index(num, num_work, idx)); - work_area.numeric = num; - oldrec->value = num_work; + igraph_vector_swap(num, num_work); break; case IGRAPH_ATTRIBUTE_BOOLEAN: - oldbool = (igraph_vector_bool_t*) oldrec->value; + oldbool = oldrec->value.as_vector_bool; bool_work = work_area.boolean; IGRAPH_ASSERT(bool_work != NULL); IGRAPH_CHECK(igraph_vector_bool_index(oldbool, bool_work, idx)); - work_area.boolean = oldbool; - oldrec->value = bool_work; + igraph_vector_bool_swap(oldbool, bool_work); break; case IGRAPH_ATTRIBUTE_STRING: /* nothing to do */ @@ -757,88 +667,12 @@ static igraph_error_t igraph_i_cattribute_permute_vertices( const igraph_t *graph, igraph_t *newgraph, const igraph_vector_int_t *idx ) { igraph_i_cattributes_t *attr = graph->attr, *new_attr = newgraph->attr; - igraph_vector_ptr_t *val = &attr->val, *new_val = &new_attr->val; - igraph_integer_t i, valno; - - IGRAPH_ASSERT(graph == newgraph || igraph_vector_ptr_empty(new_val)); - - /* Handle in-place permutation separately */ + igraph_attribute_record_list_t *val = &attr->val, *new_val = &new_attr->val; if (graph == newgraph) { - return igraph_i_cattribute_permute_vertices_in_place(newgraph, idx); - } - - /* New vertex attributes */ - valno = igraph_vector_ptr_size(val); - IGRAPH_CHECK(igraph_vector_ptr_resize(new_val, valno)); - IGRAPH_FINALLY(igraph_i_cattribute_clear_attribute_container, new_val); - - for (i = 0; i < valno; i++) { - igraph_attribute_record_t *oldrec = VECTOR(*val)[i]; - igraph_attribute_type_t type = oldrec->type; - igraph_vector_t *num, *newnum; - igraph_strvector_t *str, *newstr; - igraph_vector_bool_t *oldbool, *newbool; - - /* The record itself */ - igraph_attribute_record_t *new_rec = - IGRAPH_CALLOC(1, igraph_attribute_record_t); - if (! new_rec) { - IGRAPH_ERROR("Cannot create vertex attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, new_rec); - new_rec->name = strdup(oldrec->name); - if (! new_rec->name) { - IGRAPH_ERROR("Cannot create vertex attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char *) new_rec->name); - new_rec->type = oldrec->type; - - /* The data */ - switch (type) { - case IGRAPH_ATTRIBUTE_NUMERIC: - num = (igraph_vector_t*)oldrec->value; - newnum = IGRAPH_CALLOC(1, igraph_vector_t); - if (!newnum) { - IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newnum); - IGRAPH_VECTOR_INIT_FINALLY(newnum, 0); - IGRAPH_CHECK(igraph_vector_index(num, newnum, idx)); - new_rec->value = newnum; - break; - case IGRAPH_ATTRIBUTE_BOOLEAN: - oldbool = (igraph_vector_bool_t*)oldrec->value; - newbool = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (!newbool) { - IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newbool); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newbool, 0); - IGRAPH_CHECK(igraph_vector_bool_index(oldbool, newbool, idx)); - new_rec->value = newbool; - break; - case IGRAPH_ATTRIBUTE_STRING: - str = (igraph_strvector_t*)oldrec->value; - newstr = IGRAPH_CALLOC(1, igraph_strvector_t); - if (!newstr) { - IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newstr); - IGRAPH_STRVECTOR_INIT_FINALLY(newstr, 0); - IGRAPH_CHECK(igraph_strvector_index(str, newstr, idx)); - new_rec->value = newstr; - break; - default: - IGRAPH_WARNING("Unknown vertex attribute ignored"); - } - - VECTOR(*new_val)[i] = new_rec; - IGRAPH_FINALLY_CLEAN(4); + return igraph_i_cattribute_permute_attribute_record_list_in_place(val, idx); + } else { + return igraph_i_cattribute_permute_attribute_record_list(val, new_val, idx); } - - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; } typedef igraph_error_t igraph_cattributes_combine_num_t(const igraph_vector_t *input, @@ -853,85 +687,58 @@ typedef igraph_error_t igraph_cattributes_combine_bool_t(const igraph_vector_boo static igraph_error_t igraph_i_cattributes_cn_sum(const igraph_attribute_record_t *oldrec, igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_t *oldv = oldrec->value; - igraph_vector_t *newv = IGRAPH_CALLOC(1, igraph_vector_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; - - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_INIT_FINALLY(newv, newlen); + const igraph_vector_t *oldv = oldrec->value.as_vector; + igraph_vector_t *newv = newrec->value.as_vector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - for (i = 0; i < newlen; i++) { + for (igraph_int_t i = 0; i < newlen; i++) { igraph_real_t s = 0.0; - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t j, n = igraph_vector_int_size(idx); - for (j = 0; j < n; j++) { - igraph_integer_t x = VECTOR(*idx)[j]; + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; s += VECTOR(*oldv)[x]; } VECTOR(*newv)[i] = s; } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } static igraph_error_t igraph_i_cattributes_cn_prod(const igraph_attribute_record_t *oldrec, igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_t *oldv = oldrec->value; - igraph_vector_t *newv = IGRAPH_CALLOC(1, igraph_vector_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; - - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_INIT_FINALLY(newv, newlen); + const igraph_vector_t *oldv = oldrec->value.as_vector; + igraph_vector_t *newv = newrec->value.as_vector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - for (i = 0; i < newlen; i++) { + for (igraph_int_t i = 0; i < newlen; i++) { igraph_real_t s = 1.0; - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t j, n = igraph_vector_int_size(idx); - for (j = 0; j < n; j++) { - igraph_integer_t x = VECTOR(*idx)[j]; + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; s *= VECTOR(*oldv)[x]; } VECTOR(*newv)[i] = s; } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } static igraph_error_t igraph_i_cattributes_cn_min(const igraph_attribute_record_t *oldrec, igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_t *oldv = oldrec->value; - igraph_vector_t *newv = IGRAPH_CALLOC(1, igraph_vector_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; - - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_INIT_FINALLY(newv, newlen); + const igraph_vector_t *oldv = oldrec->value.as_vector; + igraph_vector_t *newv = newrec->value.as_vector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t j, n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); igraph_real_t m = n > 0 ? VECTOR(*oldv)[ VECTOR(*idx)[0] ] : IGRAPH_NAN; - for (j = 1; j < n; j++) { - igraph_integer_t x = VECTOR(*idx)[j]; + for (igraph_int_t j = 1; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; igraph_real_t val = VECTOR(*oldv)[x]; if (val < m) { m = val; @@ -940,32 +747,22 @@ static igraph_error_t igraph_i_cattributes_cn_min(const igraph_attribute_record_ VECTOR(*newv)[i] = m; } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } static igraph_error_t igraph_i_cattributes_cn_max(const igraph_attribute_record_t *oldrec, igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_t *oldv = oldrec->value; - igraph_vector_t *newv = IGRAPH_CALLOC(1, igraph_vector_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; - - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_INIT_FINALLY(newv, newlen); + const igraph_vector_t *oldv = oldrec->value.as_vector; + igraph_vector_t *newv = newrec->value.as_vector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t j, n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); igraph_real_t m = n > 0 ? VECTOR(*oldv)[ VECTOR(*idx)[0] ] : IGRAPH_NAN; - for (j = 1; j < n; j++) { - igraph_integer_t x = VECTOR(*idx)[j]; + for (igraph_int_t j = 1; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; igraph_real_t val = VECTOR(*oldv)[x]; if (val > m) { m = val; @@ -974,9 +771,6 @@ static igraph_error_t igraph_i_cattributes_cn_max(const igraph_attribute_record_ VECTOR(*newv)[i] = m; } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } @@ -984,37 +778,23 @@ static igraph_error_t igraph_i_cattributes_cn_random(const igraph_attribute_reco igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_t *oldv = oldrec->value; - igraph_vector_t *newv = IGRAPH_CALLOC(1, igraph_vector_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; - - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_INIT_FINALLY(newv, newlen); - - RNG_BEGIN(); + const igraph_vector_t *oldv = oldrec->value.as_vector; + igraph_vector_t *newv = newrec->value.as_vector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); if (n == 0) { VECTOR(*newv)[i] = IGRAPH_NAN; } else if (n == 1) { VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[0] ]; } else { - igraph_integer_t r = RNG_INTEGER(0, n - 1); + igraph_int_t r = RNG_INTEGER(0, n - 1); VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[r] ]; } } - RNG_END(); - - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } @@ -1022,20 +802,13 @@ static igraph_error_t igraph_i_cattributes_cn_first(const igraph_attribute_recor igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_t *oldv = oldrec->value; - igraph_vector_t *newv = IGRAPH_CALLOC(1, igraph_vector_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; + const igraph_vector_t *oldv = oldrec->value.as_vector; + igraph_vector_t *newv = newrec->value.as_vector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_INIT_FINALLY(newv, newlen); - - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); if (n == 0) { VECTOR(*newv)[i] = IGRAPH_NAN; } else { @@ -1043,9 +816,6 @@ static igraph_error_t igraph_i_cattributes_cn_first(const igraph_attribute_recor } } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } @@ -1053,20 +823,13 @@ static igraph_error_t igraph_i_cattributes_cn_last(const igraph_attribute_record igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_t *oldv = oldrec->value; - igraph_vector_t *newv = IGRAPH_CALLOC(1, igraph_vector_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; + const igraph_vector_t *oldv = oldrec->value.as_vector; + igraph_vector_t *newv = newrec->value.as_vector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_INIT_FINALLY(newv, newlen); - - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); if (n == 0) { VECTOR(*newv)[i] = IGRAPH_NAN; } else { @@ -1074,32 +837,22 @@ static igraph_error_t igraph_i_cattributes_cn_last(const igraph_attribute_record } } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } static igraph_error_t igraph_i_cattributes_cn_mean(const igraph_attribute_record_t *oldrec, igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_t *oldv = oldrec->value; - igraph_vector_t *newv = IGRAPH_CALLOC(1, igraph_vector_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; + const igraph_vector_t *oldv = oldrec->value.as_vector; + igraph_vector_t *newv = newrec->value.as_vector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_INIT_FINALLY(newv, newlen); - - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t j, n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); igraph_real_t s = n > 0 ? 0.0 : IGRAPH_NAN; - for (j = 0; j < n; j++) { - igraph_integer_t x = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; s += VECTOR(*oldv)[x]; } if (n > 0) { @@ -1108,9 +861,6 @@ static igraph_error_t igraph_i_cattributes_cn_mean(const igraph_attribute_record VECTOR(*newv)[i] = s; } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } @@ -1119,24 +869,20 @@ static igraph_error_t igraph_i_cattributes_cn_func(const igraph_attribute_record const igraph_vector_int_list_t *merges, igraph_cattributes_combine_num_t *func) { - const igraph_vector_t *oldv = oldrec->value; - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - - igraph_vector_t *newv = IGRAPH_CALLOC(1, igraph_vector_t); - IGRAPH_CHECK_OOM(newv, "Cannot combine attributes."); - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_INIT_FINALLY(newv, newlen); + const igraph_vector_t *oldv = oldrec->value.as_vector; + igraph_vector_t *newv = newrec->value.as_vector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); igraph_vector_t values; IGRAPH_VECTOR_INIT_FINALLY(&values, 0); - for (igraph_integer_t i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); - igraph_integer_t n = igraph_vector_int_size(idx); + igraph_int_t n = igraph_vector_int_size(idx); IGRAPH_CHECK(igraph_vector_resize(&values, n)); - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t x = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; VECTOR(values)[j] = VECTOR(*oldv)[x]; } @@ -1146,8 +892,7 @@ static igraph_error_t igraph_i_cattributes_cn_func(const igraph_attribute_record } igraph_vector_destroy(&values); - IGRAPH_FINALLY_CLEAN(3); - newrec->value = newv; + IGRAPH_FINALLY_CLEAN(1); return IGRAPH_SUCCESS; } @@ -1156,37 +901,23 @@ static igraph_error_t igraph_i_cattributes_cb_random(const igraph_attribute_reco igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_bool_t *oldv = oldrec->value; - igraph_vector_bool_t *newv = IGRAPH_CALLOC(1, igraph_vector_bool_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; - - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newv, newlen); - - RNG_BEGIN(); + const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; + igraph_vector_bool_t *newv = newrec->value.as_vector_bool; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); if (n == 0) { VECTOR(*newv)[i] = 0; } else if (n == 1) { VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[0] ]; } else { - igraph_integer_t r = RNG_INTEGER(0, n - 1); + igraph_int_t r = RNG_INTEGER(0, n - 1); VECTOR(*newv)[i] = VECTOR(*oldv)[ VECTOR(*idx)[r] ]; } } - RNG_END(); - - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } @@ -1194,20 +925,13 @@ static igraph_error_t igraph_i_cattributes_cb_first(const igraph_attribute_recor igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_bool_t *oldv = oldrec->value; - igraph_vector_bool_t *newv = IGRAPH_CALLOC(1, igraph_vector_bool_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; + const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; + igraph_vector_bool_t *newv = newrec->value.as_vector_bool; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newv, newlen); - - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); if (n == 0) { VECTOR(*newv)[i] = 0; } else { @@ -1215,9 +939,6 @@ static igraph_error_t igraph_i_cattributes_cb_first(const igraph_attribute_recor } } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } @@ -1225,20 +946,13 @@ static igraph_error_t igraph_i_cattributes_cb_last(const igraph_attribute_record igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_bool_t *oldv = oldrec->value; - igraph_vector_bool_t *newv = IGRAPH_CALLOC(1, igraph_vector_bool_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; + const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; + igraph_vector_bool_t *newv = newrec->value.as_vector_bool; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newv, newlen); - - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); if (n == 0) { VECTOR(*newv)[i] = 0; } else { @@ -1246,9 +960,6 @@ static igraph_error_t igraph_i_cattributes_cb_last(const igraph_attribute_record } } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } @@ -1256,23 +967,16 @@ static igraph_error_t igraph_i_cattributes_cb_all_is_true(const igraph_attribute igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_bool_t *oldv = oldrec->value; - igraph_vector_bool_t *newv = IGRAPH_CALLOC(1, igraph_vector_bool_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i, j, n, x; + const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; + igraph_vector_bool_t *newv = newrec->value.as_vector_bool; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newv, newlen); - - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); VECTOR(*newv)[i] = 1; - for (j = 0; j < n; j++) { - x = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; if (!VECTOR(*oldv)[x]) { VECTOR(*newv)[i] = 0; break; @@ -1280,9 +984,6 @@ static igraph_error_t igraph_i_cattributes_cb_all_is_true(const igraph_attribute } } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } @@ -1290,23 +991,16 @@ static igraph_error_t igraph_i_cattributes_cb_any_is_true(const igraph_attribute igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_bool_t *oldv = oldrec->value; - igraph_vector_bool_t *newv = IGRAPH_CALLOC(1, igraph_vector_bool_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i, j, n, x; + const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; + igraph_vector_bool_t *newv = newrec->value.as_vector_bool; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newv, newlen); - - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); VECTOR(*newv)[i] = 0; - for (j = 0; j < n; j++) { - x = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; if (VECTOR(*oldv)[x]) { VECTOR(*newv)[i] = 1; break; @@ -1314,9 +1008,6 @@ static igraph_error_t igraph_i_cattributes_cb_any_is_true(const igraph_attribute } } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } @@ -1324,27 +1015,17 @@ static igraph_error_t igraph_i_cattributes_cb_majority(const igraph_attribute_re igraph_attribute_record_t * newrec, const igraph_vector_int_list_t *merges) { - const igraph_vector_bool_t *oldv = oldrec->value; - igraph_vector_bool_t *newv = IGRAPH_CALLOC(1, igraph_vector_bool_t); - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i, j, n, x, num_trues; - - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newv, newlen); - - RNG_BEGIN(); - - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; + const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; + igraph_vector_bool_t *newv = newrec->value.as_vector_bool; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); - num_trues = 0; - for (j = 0; j < n; j++) { - x = VECTOR(*idx)[j]; + igraph_int_t num_trues = 0; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; if (VECTOR(*oldv)[x]) { num_trues++; } @@ -1361,11 +1042,6 @@ static igraph_error_t igraph_i_cattributes_cb_majority(const igraph_attribute_re } } - RNG_END(); - - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } @@ -1374,24 +1050,20 @@ static igraph_error_t igraph_i_cattributes_cb_func(const igraph_attribute_record const igraph_vector_int_list_t *merges, igraph_cattributes_combine_bool_t *func) { - const igraph_vector_bool_t *oldv = oldrec->value; - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - - igraph_vector_bool_t *newv = IGRAPH_CALLOC(1, igraph_vector_bool_t); - IGRAPH_CHECK_OOM(newv, "Cannot combine attributes."); - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newv, newlen); + const igraph_vector_bool_t *oldv = oldrec->value.as_vector_bool; + igraph_vector_bool_t *newv = newrec->value.as_vector_bool; + igraph_int_t newlen = igraph_vector_int_list_size(merges); igraph_vector_bool_t values; IGRAPH_VECTOR_BOOL_INIT_FINALLY(&values, 0); - for (igraph_integer_t i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); - igraph_integer_t n = igraph_vector_int_size(idx); + igraph_int_t n = igraph_vector_int_size(idx); IGRAPH_CHECK(igraph_vector_bool_resize(&values, n)); - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t x = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; VECTOR(values)[j] = VECTOR(*oldv)[x]; } @@ -1401,8 +1073,7 @@ static igraph_error_t igraph_i_cattributes_cb_func(const igraph_attribute_record } igraph_vector_bool_destroy(&values); - IGRAPH_FINALLY_CLEAN(3); - newrec->value = newv; + IGRAPH_FINALLY_CLEAN(1); return IGRAPH_SUCCESS; } @@ -1411,22 +1082,13 @@ static igraph_error_t igraph_i_cattributes_sn_random(const igraph_attribute_reco igraph_attribute_record_t *newrec, const igraph_vector_int_list_t *merges) { - const igraph_strvector_t *oldv = oldrec->value; - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - igraph_integer_t i; - igraph_strvector_t *newv = IGRAPH_CALLOC(1, igraph_strvector_t); - - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_STRVECTOR_INIT_FINALLY(newv, newlen); - - RNG_BEGIN(); + const igraph_strvector_t *oldv = oldrec->value.as_strvector; + igraph_strvector_t *newv = newrec->value.as_strvector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); const char *tmp; if (n == 0) { IGRAPH_CHECK(igraph_strvector_set(newv, i, "")); @@ -1434,37 +1096,26 @@ static igraph_error_t igraph_i_cattributes_sn_random(const igraph_attribute_reco tmp = igraph_strvector_get(oldv, 0); IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp)); } else { - igraph_integer_t r = RNG_INTEGER(0, n - 1); + igraph_int_t r = RNG_INTEGER(0, n - 1); tmp = igraph_strvector_get(oldv, r); IGRAPH_CHECK(igraph_strvector_set(newv, i, tmp)); } } - RNG_END(); - - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattributes_sn_first(const igraph_attribute_record_t *oldrec, +static igraph_error_t igraph_i_cattributes_cs_first(const igraph_attribute_record_t *oldrec, igraph_attribute_record_t *newrec, const igraph_vector_int_list_t *merges) { - const igraph_strvector_t *oldv = oldrec->value; - igraph_integer_t i, newlen = igraph_vector_int_list_size(merges); - igraph_strvector_t *newv = IGRAPH_CALLOC(1, igraph_strvector_t); + const igraph_strvector_t *oldv = oldrec->value.as_strvector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); + igraph_strvector_t *newv = newrec->value.as_strvector; - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_STRVECTOR_INIT_FINALLY(newv, newlen); - - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); if (n == 0) { IGRAPH_CHECK(igraph_strvector_set(newv, i, "")); } else { @@ -1473,29 +1124,20 @@ static igraph_error_t igraph_i_cattributes_sn_first(const igraph_attribute_recor } } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattributes_sn_last(const igraph_attribute_record_t *oldrec, +static igraph_error_t igraph_i_cattributes_cs_last(const igraph_attribute_record_t *oldrec, igraph_attribute_record_t *newrec, const igraph_vector_int_list_t *merges) { - const igraph_strvector_t *oldv = oldrec->value; - igraph_integer_t i, newlen = igraph_vector_int_list_size(merges); - igraph_strvector_t *newv = IGRAPH_CALLOC(1, igraph_strvector_t); - - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_STRVECTOR_INIT_FINALLY(newv, newlen); + const igraph_strvector_t *oldv = oldrec->value.as_strvector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); + igraph_strvector_t *newv = newrec->value.as_strvector; - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); if (n == 0) { IGRAPH_CHECK(igraph_strvector_set(newv, i, "")); } else { @@ -1504,43 +1146,32 @@ static igraph_error_t igraph_i_cattributes_sn_last(const igraph_attribute_record } } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattributes_sn_concat(const igraph_attribute_record_t *oldrec, +static igraph_error_t igraph_i_cattributes_cs_concat(const igraph_attribute_record_t *oldrec, igraph_attribute_record_t *newrec, const igraph_vector_int_list_t *merges) { - const igraph_strvector_t *oldv = oldrec->value; - igraph_integer_t i, newlen = igraph_vector_int_list_size(merges); - igraph_strvector_t *newv = IGRAPH_CALLOC(1, igraph_strvector_t); + const igraph_strvector_t *oldv = oldrec->value.as_strvector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); + igraph_strvector_t *newv = newrec->value.as_strvector; - if (!newv) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_STRVECTOR_INIT_FINALLY(newv, newlen); - - for (i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; - igraph_integer_t j, n = igraph_vector_int_size(idx); + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); + igraph_int_t n = igraph_vector_int_size(idx); size_t len = 0; const char *tmp; char *tmp2; - for (j = 0; j < n; j++) { + for (igraph_int_t j = 0; j < n; j++) { tmp = igraph_strvector_get(oldv, j); len += strlen(tmp); } tmp2 = IGRAPH_CALLOC(len + 1, char); - if (!tmp2) { - IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } + IGRAPH_CHECK_OOM(tmp2, "Cannot combine attributes."); IGRAPH_FINALLY(igraph_free, tmp2); len = 0; - for (j = 0; j < n; j++) { + for (igraph_int_t j = 0; j < n; j++) { tmp = igraph_strvector_get(oldv, j); strcpy(tmp2 + len, tmp); len += strlen(tmp); @@ -1551,35 +1182,28 @@ static igraph_error_t igraph_i_cattributes_sn_concat(const igraph_attribute_reco IGRAPH_FINALLY_CLEAN(1); } - IGRAPH_FINALLY_CLEAN(2); - newrec->value = newv; - return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattributes_sn_func(const igraph_attribute_record_t *oldrec, +static igraph_error_t igraph_i_cattributes_cs_func(const igraph_attribute_record_t *oldrec, igraph_attribute_record_t *newrec, const igraph_vector_int_list_t *merges, igraph_cattributes_combine_str_t *func) { - const igraph_strvector_t *oldv = oldrec->value; - igraph_integer_t newlen = igraph_vector_int_list_size(merges); - - igraph_strvector_t *newv = IGRAPH_CALLOC(1, igraph_strvector_t); - IGRAPH_CHECK_OOM(newv, "Cannot combine attributes."); - IGRAPH_FINALLY(igraph_free, newv); - IGRAPH_STRVECTOR_INIT_FINALLY(newv, newlen); + const igraph_strvector_t *oldv = oldrec->value.as_strvector; + igraph_strvector_t *newv = newrec->value.as_strvector; + igraph_int_t newlen = igraph_vector_int_list_size(merges); igraph_strvector_t values; IGRAPH_STRVECTOR_INIT_FINALLY(&values, 0); - for (igraph_integer_t i = 0; i < newlen; i++) { - igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i);; + for (igraph_int_t i = 0; i < newlen; i++) { + const igraph_vector_int_t *idx = igraph_vector_int_list_get_ptr(merges, i); - igraph_integer_t n = igraph_vector_int_size(idx); + igraph_int_t n = igraph_vector_int_size(idx); IGRAPH_CHECK(igraph_strvector_resize(&values, n)); - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t x = VECTOR(*idx)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t x = VECTOR(*idx)[j]; const char *elem = igraph_strvector_get(oldv, x); IGRAPH_CHECK(igraph_strvector_set(newv, j, elem)); } @@ -1595,8 +1219,7 @@ static igraph_error_t igraph_i_cattributes_sn_func(const igraph_attribute_record } igraph_strvector_destroy(&values); - IGRAPH_FINALLY_CLEAN(3); - newrec->value = newv; + IGRAPH_FINALLY_CLEAN(1); return IGRAPH_SUCCESS; } @@ -1641,650 +1264,35 @@ typedef struct { } func; } igraph_attribute_combination_todo_item_t; -static igraph_error_t igraph_i_cattribute_combine_vertices(const igraph_t *graph, - igraph_t *newgraph, - const igraph_vector_int_list_t *merges, - const igraph_attribute_combination_t *comb) { - - igraph_i_cattributes_t *attr = graph->attr; - igraph_i_cattributes_t *toattr = newgraph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_vector_ptr_t *new_val = &toattr->val; - igraph_integer_t valno = igraph_vector_ptr_size(val); - igraph_integer_t i, j, keepno = 0; - igraph_attribute_combination_todo_item_t *todo_items; - - IGRAPH_ASSERT(graph != newgraph); - IGRAPH_ASSERT(igraph_vector_ptr_empty(new_val)); - - todo_items = IGRAPH_CALLOC(valno, igraph_attribute_combination_todo_item_t); - if (!todo_items) { - IGRAPH_ERROR("Cannot combine vertex attributes", - IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, todo_items); - - for (i = 0; i < valno; i++) { - igraph_attribute_record_t *oldrec = VECTOR(*val)[i]; - const char *name = oldrec->name; - igraph_attribute_combination_type_t type; - igraph_function_pointer_t voidfunc; - IGRAPH_CHECK(igraph_attribute_combination_query(comb, name, &type, &voidfunc)); - todo_items[i].type = type; - todo_items[i].func.as_void = voidfunc; - if (type != IGRAPH_ATTRIBUTE_COMBINE_IGNORE) { - keepno++; - } - } - - IGRAPH_CHECK(igraph_vector_ptr_resize(new_val, keepno)); - IGRAPH_FINALLY(igraph_i_cattribute_clear_attribute_container, new_val); - - for (i = 0, j = 0; i < valno; i++) { - igraph_attribute_record_t *newrec, *oldrec = VECTOR(*val)[i]; - const char *name = oldrec->name; - igraph_attribute_combination_todo_item_t todo_item = todo_items[i]; - igraph_attribute_type_t attr_type = oldrec->type; - - if (todo_item.type == IGRAPH_ATTRIBUTE_COMBINE_DEFAULT || - todo_item.type == IGRAPH_ATTRIBUTE_COMBINE_IGNORE) { - continue; - } - - newrec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - if (!newrec) { - IGRAPH_ERROR("Cannot combine vertex attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newrec); - newrec->name = strdup(name); - if (!newrec->name) { - IGRAPH_ERROR("Cannot combine vertex attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char *) newrec->name); - newrec->type = attr_type; - - if (attr_type == IGRAPH_ATTRIBUTE_NUMERIC) { - switch (todo_item.type) { - case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION: - IGRAPH_CHECK(igraph_i_cattributes_cn_func(oldrec, newrec, merges, - todo_item.func.as_num)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_SUM: - IGRAPH_CHECK(igraph_i_cattributes_cn_sum(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_PROD: - IGRAPH_CHECK(igraph_i_cattributes_cn_prod(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_MIN: - IGRAPH_CHECK(igraph_i_cattributes_cn_min(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_MAX: - IGRAPH_CHECK(igraph_i_cattributes_cn_max(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_RANDOM: - IGRAPH_CHECK(igraph_i_cattributes_cn_random(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_FIRST: - IGRAPH_CHECK(igraph_i_cattributes_cn_first(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_LAST: - IGRAPH_CHECK(igraph_i_cattributes_cn_last(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_MEAN: - IGRAPH_CHECK(igraph_i_cattributes_cn_mean(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN: - IGRAPH_ERROR("Median calculation not implemented", - IGRAPH_UNIMPLEMENTED); - break; - case IGRAPH_ATTRIBUTE_COMBINE_CONCAT: - IGRAPH_ERROR("Cannot concatenate numeric attributes", - IGRAPH_EATTRCOMBINE); - break; - default: - IGRAPH_ERROR("Unknown attribute_combination", - IGRAPH_UNIMPLEMENTED); - break; - } - } else if (attr_type == IGRAPH_ATTRIBUTE_BOOLEAN) { - switch (todo_item.type) { - case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION: - IGRAPH_CHECK(igraph_i_cattributes_cb_func(oldrec, newrec, merges, - todo_item.func.as_bool)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_SUM: - case IGRAPH_ATTRIBUTE_COMBINE_MAX: - IGRAPH_CHECK(igraph_i_cattributes_cb_any_is_true(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_PROD: - case IGRAPH_ATTRIBUTE_COMBINE_MIN: - IGRAPH_CHECK(igraph_i_cattributes_cb_all_is_true(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_MEAN: - case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN: - IGRAPH_CHECK(igraph_i_cattributes_cb_majority(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_RANDOM: - IGRAPH_CHECK(igraph_i_cattributes_cb_random(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_FIRST: - IGRAPH_CHECK(igraph_i_cattributes_cb_first(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_LAST: - IGRAPH_CHECK(igraph_i_cattributes_cb_last(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_CONCAT: - IGRAPH_ERROR("Cannot calculate concatenation of Booleans", - IGRAPH_EATTRCOMBINE); - break; - default: - IGRAPH_ERROR("Unknown attribute_combination", - IGRAPH_UNIMPLEMENTED); - break; - } - } else if (attr_type == IGRAPH_ATTRIBUTE_STRING) { - switch (todo_item.type) { - case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION: - IGRAPH_CHECK(igraph_i_cattributes_sn_func(oldrec, newrec, merges, - todo_item.func.as_str)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_SUM: - IGRAPH_ERROR("Cannot sum strings", IGRAPH_EATTRCOMBINE); - break; - case IGRAPH_ATTRIBUTE_COMBINE_PROD: - IGRAPH_ERROR("Cannot multiply strings", IGRAPH_EATTRCOMBINE); - break; - case IGRAPH_ATTRIBUTE_COMBINE_MIN: - IGRAPH_ERROR("Cannot find minimum of strings", - IGRAPH_EATTRCOMBINE); - break; - case IGRAPH_ATTRIBUTE_COMBINE_MAX: - IGRAPH_ERROR("Cannot find maximum of strings", - IGRAPH_EATTRCOMBINE); - break; - case IGRAPH_ATTRIBUTE_COMBINE_MEAN: - IGRAPH_ERROR("Cannot calculate mean of strings", - IGRAPH_EATTRCOMBINE); - break; - case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN: - IGRAPH_ERROR("Cannot calculate median of strings", - IGRAPH_EATTRCOMBINE); - break; - case IGRAPH_ATTRIBUTE_COMBINE_RANDOM: - IGRAPH_CHECK(igraph_i_cattributes_sn_random(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_FIRST: - IGRAPH_CHECK(igraph_i_cattributes_sn_first(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_LAST: - IGRAPH_CHECK(igraph_i_cattributes_sn_last(oldrec, newrec, merges)); - break; - case IGRAPH_ATTRIBUTE_COMBINE_CONCAT: - IGRAPH_CHECK(igraph_i_cattributes_sn_concat(oldrec, newrec, merges)); - break; - default: - IGRAPH_ERROR("Unknown attribute_combination", - IGRAPH_UNIMPLEMENTED); - break; - } - } else { - IGRAPH_ERROR("Unknown attribute type, this should not happen", - IGRAPH_UNIMPLEMENTED); - } - - VECTOR(*new_val)[j] = newrec; - IGRAPH_FINALLY_CLEAN(2); /* newrec->name and newrec */ - - j++; - } - - IGRAPH_FREE(todo_items); - IGRAPH_FINALLY_CLEAN(2); - - return IGRAPH_SUCCESS; -} - -static igraph_error_t igraph_i_cattribute_add_edges_inner(igraph_t *graph, const igraph_vector_int_t *edges, - igraph_vector_ptr_t *nattr) { - - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t ealno = igraph_vector_ptr_size(eal); - igraph_integer_t ne = igraph_vector_int_size(edges) / 2; - igraph_integer_t origlen = igraph_ecount(graph) - ne; - igraph_integer_t nattrno = nattr == 0 ? 0 : igraph_vector_ptr_size(nattr); - igraph_vector_int_t news; - igraph_integer_t newattrs, i; - - /* First add the new attributes if any */ - newattrs = 0; - IGRAPH_VECTOR_INT_INIT_FINALLY(&news, 0); - for (i = 0; i < nattrno; i++) { - igraph_attribute_record_t *nattr_entry = VECTOR(*nattr)[i]; - const char *nname = nattr_entry->name; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(eal, nname, &j); - if (!l) { - newattrs++; - IGRAPH_CHECK(igraph_vector_int_push_back(&news, i)); - } else { - /* check types */ - if (nattr_entry->type != - ((igraph_attribute_record_t*)VECTOR(*eal)[j])->type) { - IGRAPH_ERROR("You cannot mix attribute types", IGRAPH_EINVAL); - } - } - } - - /* Add NaN/false/"" for the existing vertices for numeric, boolean and string attributes. */ - if (newattrs != 0) { - for (i = 0; i < newattrs; i++) { - igraph_attribute_record_t *tmp = VECTOR(*nattr)[ VECTOR(news)[i] ]; - igraph_attribute_record_t *newrec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_attribute_type_t type = tmp->type; - if (!newrec) { - IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newrec); - newrec->type = type; - newrec->name = strdup(tmp->name); - if (!newrec->name) { - IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)newrec->name); - if (type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *newnum = IGRAPH_CALLOC(1, igraph_vector_t); - if (!newnum) { - IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newnum); - IGRAPH_VECTOR_INIT_FINALLY(newnum, origlen); - newrec->value = newnum; - igraph_vector_fill(newnum, IGRAPH_NAN); - } else if (type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *newbool = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (!newbool) { - IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newbool); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newbool, origlen); - newrec->value = newbool; - igraph_vector_bool_fill(newbool, false); - } else if (type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *newstr = IGRAPH_CALLOC(1, igraph_strvector_t); - if (!newstr) { - IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newstr); - IGRAPH_STRVECTOR_INIT_FINALLY(newstr, origlen); - newrec->value = newstr; - } - IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, newrec)); - IGRAPH_FINALLY_CLEAN(4); - } - ealno = igraph_vector_ptr_size(eal); - } - - /* Now append the new values */ - for (i = 0; i < ealno; i++) { - igraph_attribute_record_t *oldrec = VECTOR(*eal)[i]; - igraph_attribute_record_t *newrec = NULL; - const char *name = oldrec->name; - igraph_integer_t j = -1; - igraph_bool_t l = false; - if (nattr) { - l = igraph_i_cattribute_find(nattr, name, &j); - } - if (l) { - /* This attribute is present in nattr */ - igraph_vector_t *oldnum, *newnum; - igraph_strvector_t *oldstr, *newstr; - igraph_vector_bool_t *oldbool, *newbool; - newrec = VECTOR(*nattr)[j]; - oldnum = (igraph_vector_t*)oldrec->value; - newnum = (igraph_vector_t*)newrec->value; - oldstr = (igraph_strvector_t*)oldrec->value; - newstr = (igraph_strvector_t*)newrec->value; - oldbool = (igraph_vector_bool_t*)oldrec->value; - newbool = (igraph_vector_bool_t*)newrec->value; - if (oldrec->type != newrec->type) { - IGRAPH_ERROR("Attribute types do not match.", IGRAPH_EINVAL); - } - switch (oldrec->type) { - case IGRAPH_ATTRIBUTE_NUMERIC: - if (ne != igraph_vector_size(newnum)) { - IGRAPH_ERROR("Invalid numeric attribute length.", IGRAPH_EINVAL); - } - IGRAPH_CHECK(igraph_vector_append(oldnum, newnum)); - break; - case IGRAPH_ATTRIBUTE_STRING: - if (ne != igraph_strvector_size(newstr)) { - IGRAPH_ERROR("Invalid string attribute length.", IGRAPH_EINVAL); - } - IGRAPH_CHECK(igraph_strvector_append(oldstr, newstr)); - break; - case IGRAPH_ATTRIBUTE_BOOLEAN: - if (ne != igraph_vector_bool_size(newbool)) { - IGRAPH_ERROR("Invalid boolean attribute length.", IGRAPH_EINVAL); - } - IGRAPH_CHECK(igraph_vector_bool_append(oldbool, newbool)); - break; - default: - IGRAPH_WARNING("Invalid attribute type."); - break; - } - } else { - /* No such attribute, append NaN/false/"". */ - igraph_vector_t *oldnum = (igraph_vector_t *)oldrec->value; - igraph_strvector_t *oldstr = (igraph_strvector_t*)oldrec->value; - igraph_vector_bool_t *oldbool = (igraph_vector_bool_t *)oldrec->value; - switch (oldrec->type) { - case IGRAPH_ATTRIBUTE_NUMERIC: - IGRAPH_CHECK(igraph_vector_resize(oldnum, origlen + ne)); - for (j = origlen; j < origlen + ne; j++) { - VECTOR(*oldnum)[j] = IGRAPH_NAN; - } - break; - case IGRAPH_ATTRIBUTE_STRING: - IGRAPH_CHECK(igraph_strvector_resize(oldstr, origlen + ne)); - break; - case IGRAPH_ATTRIBUTE_BOOLEAN: - IGRAPH_CHECK(igraph_vector_bool_resize(oldbool, origlen + ne)); - for (j = origlen; j < origlen + ne; j++) { - VECTOR(*oldbool)[j] = 0; - } - break; - default: - IGRAPH_WARNING("Invalid attribute type"); - break; - } - } - } - - igraph_vector_int_destroy(&news); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} - -static igraph_error_t igraph_i_cattribute_add_edges(igraph_t *graph, const igraph_vector_int_t *edges, - igraph_vector_ptr_t *nattr) { - /* Record information needed to restore attribute vector sizes */ - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t ne = igraph_vector_int_size(edges) / 2; - igraph_integer_t origlen = igraph_ecount(graph) - ne; - - /* Attempt adding attributes */ - igraph_error_t err = igraph_i_cattribute_add_edges_inner(graph, edges, nattr); - if (err != IGRAPH_SUCCESS) { - /* If unsuccessful, revert attribute vector sizes. - * The following function assumes that all attributes vectors that - * are present have a length at least as great as origlen. - * This is true at the moment because any new attributes that are - * added to the graph are created directly at 'origlen' instead of - * being created at smaller sizes and resized later. - * - * NOTE: While this ensures that all attribute vector lengths are - * correct, it does not ensure that no extra attributes have - * been added to the graph. However, the presence of extra - * attributes does not make the attribute table inconsistent - * like the incorrect attribute vector lengths would. - */ - igraph_i_cattribute_revert_attribute_vector_sizes(eal, origlen); - } - return err; -} - -static igraph_error_t igraph_i_cattribute_permute_edges_in_place( - igraph_t *graph, const igraph_vector_int_t *idx +static igraph_error_t igraph_i_cattribute_combine_attribute_record_lists( + igraph_attribute_record_list_t *attrs, igraph_attribute_record_list_t *new_attrs, + const igraph_vector_int_list_t *merges, const igraph_attribute_combination_t *comb ) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t ealno = igraph_vector_ptr_size(eal); - igraph_integer_t i, j; - igraph_attribute_record_t *oldrec; - igraph_vector_t *num, *num_work; - igraph_strvector_t *str, str_work; - igraph_vector_bool_t *oldbool, *bool_work; - igraph_i_attribute_permutation_work_area_t work_area; - igraph_integer_t idx_size = igraph_vector_int_size(idx); - - /* shortcut: don't allocate anything if there are no attributes */ - if (ealno == 0) { - return IGRAPH_SUCCESS; - } - - IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_init(&work_area, idx_size)); - IGRAPH_FINALLY(igraph_i_attribute_permutation_work_area_destroy, &work_area); - for (i = 0; i < ealno; i++) { - oldrec = VECTOR(*eal)[i]; - switch (oldrec->type) { - case IGRAPH_ATTRIBUTE_NUMERIC: - num = (igraph_vector_t*) oldrec->value; - IGRAPH_CHECK(igraph_vector_reserve(num, idx_size)); - IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_alloc_for_numeric(&work_area)); - break; - - case IGRAPH_ATTRIBUTE_BOOLEAN: - oldbool = (igraph_vector_bool_t*) oldrec->value; - IGRAPH_CHECK(igraph_vector_bool_reserve(oldbool, idx_size)); - IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_alloc_for_boolean(&work_area)); - break; - - case IGRAPH_ATTRIBUTE_STRING: - str = (igraph_strvector_t*) oldrec->value; - IGRAPH_CHECK(igraph_strvector_reserve(str, idx_size)); - IGRAPH_CHECK(igraph_i_attribute_permutation_work_area_alloc_for_strings(&work_area)); - break; - - default: - IGRAPH_WARNING("Unknown edge attribute ignored"); - } - } - - /* let's do string attributes first because these might need extra - * allocations that can fail. The strategy is to build new igraph_strvector_t - * instances for the permuted attributes and store them in an - * igraph_vector_ptr_t until we are done with all of them. If any of the - * allocations fail, we can destroy the igraph_vector_ptr_t safely */ - for (i = 0; i < ealno; i++) { - oldrec = VECTOR(*eal)[i]; - if (oldrec->type != IGRAPH_ATTRIBUTE_STRING) { - continue; - } - - str = (igraph_strvector_t*) oldrec->value; - IGRAPH_CHECK( - igraph_i_attribute_permutation_work_area_permute_and_store_strvector( - &work_area, str, idx - ) - ); - } - - /* strings are done, and now all vectors involved in the process are - * as large as they should be (or larger) so the operations below are not - * supposed to fail. We can safely replace the original string attribute - * vectors with the permuted ones, and then proceed to the remaining - * attributes */ - for (i = 0, j = 0; i < ealno; i++) { - oldrec = VECTOR(*eal)[i]; - if (oldrec->type != IGRAPH_ATTRIBUTE_STRING) { - continue; - } - - str = (igraph_strvector_t*) oldrec->value; - str_work = *((igraph_strvector_t*) VECTOR(*(work_area.strings))[j]); - *((igraph_strvector_t*) VECTOR(*(work_area.strings))[j]) = *str; - *str = str_work; - j++; - } - igraph_i_attribute_permutation_work_area_release_stored_strvectors(&work_area); - - /* now all vectors involved in the process are as large as they should be - * (or larger) so the operations below are not supposed to fail -- except - * for string operations that still do some extra allocations and we are - * not prepared for the failures of those. This must still be fixed. */ - for (i = 0; i < ealno; i++) { - oldrec = VECTOR(*eal)[i]; - switch (oldrec->type) { - case IGRAPH_ATTRIBUTE_NUMERIC: - num = (igraph_vector_t*) oldrec->value; - num_work = work_area.numeric; - IGRAPH_ASSERT(num_work != NULL); - IGRAPH_CHECK(igraph_vector_index(num, num_work, idx)); - work_area.numeric = num; - oldrec->value = num_work; - break; - case IGRAPH_ATTRIBUTE_BOOLEAN: - oldbool = (igraph_vector_bool_t*) oldrec->value; - bool_work = work_area.boolean; - IGRAPH_ASSERT(bool_work != NULL); - IGRAPH_CHECK(igraph_vector_bool_index(oldbool, bool_work, idx)); - work_area.boolean = oldbool; - oldrec->value = bool_work; - break; - case IGRAPH_ATTRIBUTE_STRING: - /* nothing to do */ - break; - default: - /* already warned */ - break; - } - } - - igraph_i_attribute_permutation_work_area_destroy(&work_area); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} - -static igraph_error_t igraph_i_cattribute_permute_edges(const igraph_t *graph, - igraph_t *newgraph, - const igraph_vector_int_t *idx) { - - igraph_i_cattributes_t *attr = graph->attr, *new_attr = newgraph->attr; - igraph_vector_ptr_t *eal = &attr->eal, *new_eal = &new_attr->eal; - igraph_integer_t i, ealno; - - IGRAPH_ASSERT(graph == newgraph || igraph_vector_ptr_empty(new_eal)); - - if (graph == newgraph) { - return igraph_i_cattribute_permute_edges_in_place(newgraph, idx); - } - - /* New edge attributes */ - ealno = igraph_vector_ptr_size(eal); - IGRAPH_ASSERT(igraph_vector_ptr_empty(new_eal)); - IGRAPH_CHECK(igraph_vector_ptr_resize(new_eal, ealno)); - IGRAPH_FINALLY(igraph_i_cattribute_clear_attribute_container, new_eal); - - for (i = 0; i < ealno; i++) { - igraph_attribute_record_t *oldrec = VECTOR(*eal)[i]; - igraph_attribute_type_t type = oldrec->type; - igraph_vector_t *num, *newnum; - igraph_strvector_t *str, *newstr; - igraph_vector_bool_t *oldbool, *newbool; - - /* The record itself */ - igraph_attribute_record_t *new_rec = - IGRAPH_CALLOC(1, igraph_attribute_record_t); - if (!new_rec) { - IGRAPH_ERROR("Cannot create edge attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, new_rec); - new_rec->name = strdup(oldrec->name); - if (! new_rec->name) { - IGRAPH_ERROR("Cannot create edge attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char *) new_rec->name); - new_rec->type = oldrec->type; - - switch (type) { - case IGRAPH_ATTRIBUTE_NUMERIC: - num = (igraph_vector_t*) oldrec->value; - newnum = IGRAPH_CALLOC(1, igraph_vector_t); - if (!newnum) { - IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newnum); - IGRAPH_VECTOR_INIT_FINALLY(newnum, 0); - IGRAPH_CHECK(igraph_vector_index(num, newnum, idx)); - new_rec->value = newnum; - break; - case IGRAPH_ATTRIBUTE_STRING: - str = (igraph_strvector_t*)oldrec->value; - newstr = IGRAPH_CALLOC(1, igraph_strvector_t); - if (!newstr) { - IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newstr); - IGRAPH_STRVECTOR_INIT_FINALLY(newstr, 0); - IGRAPH_CHECK(igraph_strvector_index(str, newstr, idx)); - new_rec->value = newstr; - break; - case IGRAPH_ATTRIBUTE_BOOLEAN: - oldbool = (igraph_vector_bool_t*) oldrec->value; - newbool = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (!newbool) { - IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newbool); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(newbool, 0); - IGRAPH_CHECK(igraph_vector_bool_index(oldbool, newbool, idx)); - new_rec->value = newbool; - break; - default: - IGRAPH_WARNING("Unknown edge attribute ignored"); - } - VECTOR(*new_eal)[i] = new_rec; - IGRAPH_FINALLY_CLEAN(4); - } - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} - -static igraph_error_t igraph_i_cattribute_combine_edges(const igraph_t *graph, - igraph_t *newgraph, - const igraph_vector_int_list_t *merges, - const igraph_attribute_combination_t *comb) { - - igraph_i_cattributes_t *attr = graph->attr; - igraph_i_cattributes_t *toattr = newgraph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_vector_ptr_t *new_eal = &toattr->eal; - igraph_integer_t ealno = igraph_vector_ptr_size(eal); - igraph_integer_t i, j, keepno = 0; + igraph_int_t no_attrs = igraph_attribute_record_list_size(attrs); igraph_attribute_combination_todo_item_t *todo_items; - IGRAPH_ASSERT(graph != newgraph); - IGRAPH_ASSERT(igraph_vector_ptr_empty(new_eal)); + IGRAPH_ASSERT(attrs != new_attrs); + IGRAPH_ASSERT(igraph_attribute_record_list_empty(new_attrs)); - todo_items = IGRAPH_CALLOC(ealno, igraph_attribute_combination_todo_item_t); - if (!todo_items) { - IGRAPH_ERROR("Cannot combine edge attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } + todo_items = IGRAPH_CALLOC(no_attrs, igraph_attribute_combination_todo_item_t); + IGRAPH_CHECK_OOM(todo_items, "Cannot combine attributes."); IGRAPH_FINALLY(igraph_free, todo_items); - for (i = 0; i < ealno; i++) { - igraph_attribute_record_t *oldrec = VECTOR(*eal)[i]; + for (igraph_int_t i = 0; i < no_attrs; i++) { + const igraph_attribute_record_t *oldrec = igraph_attribute_record_list_get_ptr(attrs, i); const char *name = oldrec->name; - igraph_attribute_combination_type_t todo; + igraph_attribute_combination_type_t type; igraph_function_pointer_t voidfunc; - IGRAPH_CHECK(igraph_attribute_combination_query(comb, name, &todo, &voidfunc)); - todo_items[i].type = todo; + IGRAPH_CHECK(igraph_attribute_combination_query(comb, name, &type, &voidfunc)); + todo_items[i].type = type; todo_items[i].func.as_void = voidfunc; - if (todo != IGRAPH_ATTRIBUTE_COMBINE_IGNORE) { - keepno++; - } } - IGRAPH_CHECK(igraph_vector_ptr_resize(new_eal, keepno)); - IGRAPH_FINALLY(igraph_i_cattribute_clear_attribute_container, new_eal); + IGRAPH_FINALLY(igraph_attribute_record_list_clear, new_attrs); - for (i = 0, j = 0; i < ealno; i++) { - igraph_attribute_record_t *newrec, *oldrec = VECTOR(*eal)[i]; + for (igraph_int_t i = 0; i < no_attrs; i++) { + const igraph_attribute_record_t *oldrec = igraph_attribute_record_list_get_ptr(attrs, i); + igraph_attribute_record_t newrec; const char *name = oldrec->name; igraph_attribute_combination_todo_item_t todo_item = todo_items[i]; igraph_attribute_type_t attr_type = oldrec->type; @@ -2294,151 +1302,142 @@ static igraph_error_t igraph_i_cattribute_combine_edges(const igraph_t *graph, continue; } - newrec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - if (!newrec) { - IGRAPH_ERROR("Cannot combine edge attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, newrec); - newrec->name = strdup(name); - if (! newrec->name) { - IGRAPH_ERROR("Cannot combine edge attributes", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char *) newrec->name); - newrec->type = attr_type; + IGRAPH_CHECK(igraph_attribute_record_init(&newrec, name, attr_type)); + IGRAPH_FINALLY(igraph_attribute_record_destroy, &newrec); + + IGRAPH_CHECK(igraph_attribute_record_resize(&newrec, igraph_vector_int_list_size(merges))); if (attr_type == IGRAPH_ATTRIBUTE_NUMERIC) { switch (todo_item.type) { case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION: - IGRAPH_CHECK(igraph_i_cattributes_cn_func(oldrec, newrec, merges, + IGRAPH_CHECK(igraph_i_cattributes_cn_func(oldrec, &newrec, merges, todo_item.func.as_num)); break; case IGRAPH_ATTRIBUTE_COMBINE_SUM: - IGRAPH_CHECK(igraph_i_cattributes_cn_sum(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cn_sum(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_PROD: - IGRAPH_CHECK(igraph_i_cattributes_cn_prod(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cn_prod(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_MIN: - IGRAPH_CHECK(igraph_i_cattributes_cn_min(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cn_min(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_MAX: - IGRAPH_CHECK(igraph_i_cattributes_cn_max(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cn_max(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_RANDOM: - IGRAPH_CHECK(igraph_i_cattributes_cn_random(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cn_random(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_FIRST: - IGRAPH_CHECK(igraph_i_cattributes_cn_first(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cn_first(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_LAST: - IGRAPH_CHECK(igraph_i_cattributes_cn_last(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cn_last(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_MEAN: - IGRAPH_CHECK(igraph_i_cattributes_cn_mean(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cn_mean(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN: - IGRAPH_ERROR("Median calculation not implemented", + IGRAPH_ERROR("Median calculation not implemented.", IGRAPH_UNIMPLEMENTED); break; case IGRAPH_ATTRIBUTE_COMBINE_CONCAT: - IGRAPH_ERROR("Cannot concatenate numeric attributes", + IGRAPH_ERROR("Cannot concatenate numeric attributes.", IGRAPH_EATTRCOMBINE); break; default: - IGRAPH_ERROR("Unknown attribute_combination", + IGRAPH_ERROR("Unknown attribute combination.", IGRAPH_UNIMPLEMENTED); break; } } else if (attr_type == IGRAPH_ATTRIBUTE_BOOLEAN) { switch (todo_item.type) { case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION: - IGRAPH_CHECK(igraph_i_cattributes_cb_func(oldrec, newrec, merges, + IGRAPH_CHECK(igraph_i_cattributes_cb_func(oldrec, &newrec, merges, todo_item.func.as_bool)); break; case IGRAPH_ATTRIBUTE_COMBINE_SUM: case IGRAPH_ATTRIBUTE_COMBINE_MAX: - IGRAPH_CHECK(igraph_i_cattributes_cb_any_is_true(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cb_any_is_true(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_PROD: case IGRAPH_ATTRIBUTE_COMBINE_MIN: - IGRAPH_CHECK(igraph_i_cattributes_cb_all_is_true(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cb_all_is_true(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_MEAN: case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN: - IGRAPH_CHECK(igraph_i_cattributes_cb_majority(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cb_majority(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_RANDOM: - IGRAPH_CHECK(igraph_i_cattributes_cb_random(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cb_random(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_FIRST: - IGRAPH_CHECK(igraph_i_cattributes_cb_first(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cb_first(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_LAST: - IGRAPH_CHECK(igraph_i_cattributes_cb_last(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cb_last(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_CONCAT: - IGRAPH_ERROR("Cannot calculate concatenation of Booleans", + IGRAPH_ERROR("Cannot calculate concatenation of Booleans.", IGRAPH_EATTRCOMBINE); break; default: - IGRAPH_ERROR("Unknown attribute_combination", + IGRAPH_ERROR("Unknown attribute combination.", IGRAPH_UNIMPLEMENTED); break; } } else if (attr_type == IGRAPH_ATTRIBUTE_STRING) { switch (todo_item.type) { case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION: - IGRAPH_CHECK(igraph_i_cattributes_sn_func(oldrec, newrec, merges, + IGRAPH_CHECK(igraph_i_cattributes_cs_func(oldrec, &newrec, merges, todo_item.func.as_str)); break; case IGRAPH_ATTRIBUTE_COMBINE_SUM: - IGRAPH_ERROR("Cannot sum strings", IGRAPH_EATTRCOMBINE); + IGRAPH_ERROR("Cannot sum strings.", IGRAPH_EATTRCOMBINE); break; case IGRAPH_ATTRIBUTE_COMBINE_PROD: - IGRAPH_ERROR("Cannot multiply strings", IGRAPH_EATTRCOMBINE); + IGRAPH_ERROR("Cannot multiply strings.", IGRAPH_EATTRCOMBINE); break; case IGRAPH_ATTRIBUTE_COMBINE_MIN: - IGRAPH_ERROR("Cannot find minimum of strings", + IGRAPH_ERROR("Cannot find minimum of strings.", IGRAPH_EATTRCOMBINE); break; case IGRAPH_ATTRIBUTE_COMBINE_MAX: - IGRAPH_ERROR("Cannot find maximum of strings", + IGRAPH_ERROR("Cannot find maximum of strings.", IGRAPH_EATTRCOMBINE); break; case IGRAPH_ATTRIBUTE_COMBINE_MEAN: - IGRAPH_ERROR("Cannot calculate mean of strings", + IGRAPH_ERROR("Cannot calculate mean of strings.", IGRAPH_EATTRCOMBINE); break; case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN: - IGRAPH_ERROR("Cannot calculate median of strings", + IGRAPH_ERROR("Cannot calculate median of strings.", IGRAPH_EATTRCOMBINE); break; case IGRAPH_ATTRIBUTE_COMBINE_RANDOM: - IGRAPH_CHECK(igraph_i_cattributes_sn_random(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_sn_random(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_FIRST: - IGRAPH_CHECK(igraph_i_cattributes_sn_first(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cs_first(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_LAST: - IGRAPH_CHECK(igraph_i_cattributes_sn_last(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cs_last(oldrec, &newrec, merges)); break; case IGRAPH_ATTRIBUTE_COMBINE_CONCAT: - IGRAPH_CHECK(igraph_i_cattributes_sn_concat(oldrec, newrec, merges)); + IGRAPH_CHECK(igraph_i_cattributes_cs_concat(oldrec, &newrec, merges)); break; default: - IGRAPH_ERROR("Unknown attribute_combination", + IGRAPH_ERROR("Unknown attribute combination.", IGRAPH_UNIMPLEMENTED); break; } } else { - IGRAPH_ERROR("Unknown attribute type, this should not happen", + IGRAPH_ERROR("Unknown attribute type, this should not happen.", IGRAPH_UNIMPLEMENTED); } - VECTOR(*new_eal)[j] = newrec; - IGRAPH_FINALLY_CLEAN(2); /* newrec and newrc->name */ - - j++; + IGRAPH_CHECK(igraph_attribute_record_list_push_back(new_attrs, &newrec)); + IGRAPH_FINALLY_CLEAN(1); /* ownership of newrec transferred */ } IGRAPH_FREE(todo_items); @@ -2447,6 +1446,49 @@ static igraph_error_t igraph_i_cattribute_combine_edges(const igraph_t *graph, return IGRAPH_SUCCESS; } +static igraph_error_t igraph_i_cattribute_combine_vertices( + const igraph_t *graph, igraph_t *newgraph, + const igraph_vector_int_list_t *merges, const igraph_attribute_combination_t *comb +) { + igraph_i_cattributes_t *attr = graph->attr; + igraph_i_cattributes_t *toattr = newgraph->attr; + return igraph_i_cattribute_combine_attribute_record_lists( + &attr->val, &toattr->val, merges, comb + ); +} + +static igraph_error_t igraph_i_cattribute_add_edges( + igraph_t *graph, const igraph_vector_int_t *edges, + const igraph_attribute_record_list_t *nattr +) { + igraph_int_t ne = igraph_vector_int_size(edges) / 2; + igraph_i_cattributes_t *attr = graph->attr; + return igraph_i_cattribute_add_vertices_or_edges(&attr->eal, igraph_ecount(graph), ne, nattr); +} + +static igraph_error_t igraph_i_cattribute_permute_edges(const igraph_t *graph, + igraph_t *newgraph, + const igraph_vector_int_t *idx) { + igraph_i_cattributes_t *attr = graph->attr, *new_attr = newgraph->attr; + igraph_attribute_record_list_t *eal = &attr->eal, *new_eal = &new_attr->eal; + if (graph == newgraph) { + return igraph_i_cattribute_permute_attribute_record_list_in_place(eal, idx); + } else { + return igraph_i_cattribute_permute_attribute_record_list(eal, new_eal, idx); + } +} + +static igraph_error_t igraph_i_cattribute_combine_edges( + const igraph_t *graph, igraph_t *newgraph, + const igraph_vector_int_list_t *merges, const igraph_attribute_combination_t *comb +) { + igraph_i_cattributes_t *attr = graph->attr; + igraph_i_cattributes_t *toattr = newgraph->attr; + return igraph_i_cattribute_combine_attribute_record_lists( + &attr->eal, &toattr->eal, merges, comb + ); +} + static igraph_error_t igraph_i_cattribute_get_info(const igraph_t *graph, igraph_strvector_t *gnames, igraph_vector_int_t *gtypes, @@ -2458,14 +1500,13 @@ static igraph_error_t igraph_i_cattribute_get_info(const igraph_t *graph, igraph_strvector_t *names[3] = { gnames, vnames, enames }; igraph_vector_int_t *types[3] = { gtypes, vtypes, etypes }; igraph_i_cattributes_t *at = graph->attr; - igraph_vector_ptr_t *attr[3] = { &at->gal, &at->val, &at->eal }; - igraph_integer_t i, j; + igraph_attribute_record_list_t *attr[3] = { &at->gal, &at->val, &at->eal }; - for (i = 0; i < 3; i++) { + for (igraph_int_t i = 0; i < 3; i++) { igraph_strvector_t *n = names[i]; igraph_vector_int_t *t = types[i]; - igraph_vector_ptr_t *al = attr[i]; - igraph_integer_t len = igraph_vector_ptr_size(al); + const igraph_attribute_record_list_t *al = attr[i]; + igraph_int_t len = igraph_attribute_record_list_size(al); if (n) { IGRAPH_CHECK(igraph_strvector_resize(n, len)); @@ -2474,8 +1515,8 @@ static igraph_error_t igraph_i_cattribute_get_info(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_resize(t, len)); } - for (j = 0; j < len; j++) { - igraph_attribute_record_t *rec = VECTOR(*al)[j]; + for (igraph_int_t j = 0; j < len; j++) { + const igraph_attribute_record_t *rec = igraph_attribute_record_list_get_ptr(al, j); const char *name = rec->name; igraph_attribute_type_t type = rec->type; if (n) { @@ -2493,137 +1534,86 @@ static igraph_error_t igraph_i_cattribute_get_info(const igraph_t *graph, static igraph_bool_t igraph_i_cattribute_has_attr(const igraph_t *graph, igraph_attribute_elemtype_t type, const char *name) { - igraph_i_cattributes_t *at = graph->attr; - igraph_vector_ptr_t *attr[3] = { &at->gal, &at->val, &at->eal }; - igraph_integer_t attrnum; - + const igraph_i_cattributes_t *at = graph->attr; switch (type) { case IGRAPH_ATTRIBUTE_GRAPH: - attrnum = 0; - break; + return igraph_i_cattribute_find_index(&at->gal, name) >= 0; case IGRAPH_ATTRIBUTE_VERTEX: - attrnum = 1; - break; + return igraph_i_cattribute_find_index(&at->val, name) >= 0; case IGRAPH_ATTRIBUTE_EDGE: - attrnum = 2; - break; + return igraph_i_cattribute_find_index(&at->eal, name) >= 0; default: - IGRAPH_ERROR("Unknown attribute element type", IGRAPH_EINVAL); + IGRAPH_ERROR("Unknown attribute element type.", IGRAPH_EINVAL); break; } - return igraph_i_cattribute_find(attr[attrnum], name, 0); + return false; } -static igraph_error_t igraph_i_cattribute_gettype(const igraph_t *graph, +static igraph_error_t igraph_i_cattribute_get_type(const igraph_t *graph, igraph_attribute_type_t *type, igraph_attribute_elemtype_t elemtype, const char *name) { - igraph_integer_t attrnum; igraph_attribute_record_t *rec; igraph_i_cattributes_t *at = graph->attr; - igraph_vector_ptr_t *attr[3] = { &at->gal, &at->val, &at->eal }; - igraph_vector_ptr_t *al; - igraph_integer_t j; - igraph_bool_t l = false; + igraph_attribute_record_list_t *al; switch (elemtype) { case IGRAPH_ATTRIBUTE_GRAPH: - attrnum = 0; + al = &at->gal; break; case IGRAPH_ATTRIBUTE_VERTEX: - attrnum = 1; + al = &at->val; break; case IGRAPH_ATTRIBUTE_EDGE: - attrnum = 2; + al = &at->eal; break; default: - IGRAPH_ERROR("Unknown attribute element type", IGRAPH_EINVAL); + IGRAPH_ERROR("Unknown attribute element type.", IGRAPH_EINVAL); break; } - al = attr[attrnum]; - l = igraph_i_cattribute_find(al, name, &j); - if (!l) { - IGRAPH_ERROR("Unknown attribute", IGRAPH_EINVAL); - } - rec = VECTOR(*al)[j]; + IGRAPH_CHECK(igraph_i_cattribute_find_or_return(al, name, IGRAPH_ATTRIBUTE_UNSPECIFIED, &rec)); *type = rec->type; return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattribute_get_numeric_graph_attr(const igraph_t *graph, - const char *name, - igraph_vector_t *value) { +static igraph_error_t igraph_i_cattribute_get_numeric_graph_attr( + const igraph_t *graph, const char *name, igraph_vector_t *value +) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t j; + igraph_attribute_record_list_t *gal = &attr->gal; igraph_attribute_record_t *rec; - igraph_vector_t *num; - igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j); - - if (!l) { - IGRAPH_ERRORF("The graph attribute '%s' does not exist.", IGRAPH_EINVAL, name); - } - rec = VECTOR(*gal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) { - IGRAPH_ERRORF("Numeric graph attribute '%s' expected, got %s.", IGRAPH_EINVAL, name, attribute_type_name(rec->type)); - } - num = (igraph_vector_t*)rec->value; - IGRAPH_CHECK(igraph_vector_resize(value, 1)); - VECTOR(*value)[0] = VECTOR(*num)[0]; + IGRAPH_CHECK(igraph_i_cattribute_find_or_return(gal, name, IGRAPH_ATTRIBUTE_NUMERIC, &rec)); + IGRAPH_CHECK(igraph_vector_push_back(value, VECTOR(*rec->value.as_vector)[0])); return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattribute_get_bool_graph_attr(const igraph_t *graph, - const char *name, - igraph_vector_bool_t *value) { +static igraph_error_t igraph_i_cattribute_get_bool_graph_attr( + const igraph_t *graph, const char *name, igraph_vector_bool_t *value +) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t j; + igraph_attribute_record_list_t *gal = &attr->gal; igraph_attribute_record_t *rec; - igraph_vector_bool_t *log; - igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j); - - if (!l) { - IGRAPH_ERRORF("The graph attribute '%s' does not exist.", IGRAPH_EINVAL, name); - } - rec = VECTOR(*gal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) { - IGRAPH_ERRORF("Boolean graph attribute '%s' expected, got %s.", IGRAPH_EINVAL, name, attribute_type_name(rec->type)); - } - log = (igraph_vector_bool_t*)rec->value; - IGRAPH_CHECK(igraph_vector_bool_resize(value, 1)); - VECTOR(*value)[0] = VECTOR(*log)[0]; + IGRAPH_CHECK(igraph_i_cattribute_find_or_return(gal, name, IGRAPH_ATTRIBUTE_BOOLEAN, &rec)); + IGRAPH_CHECK(igraph_vector_bool_push_back(value, VECTOR(*rec->value.as_vector_bool)[0])); return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattribute_get_string_graph_attr(const igraph_t *graph, - const char *name, - igraph_strvector_t *value) { +static igraph_error_t igraph_i_cattribute_get_string_graph_attr( + const igraph_t *graph, const char *name, igraph_strvector_t *value +) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t j; + igraph_attribute_record_list_t *gal = &attr->gal; igraph_attribute_record_t *rec; - igraph_strvector_t *str; - igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j); - - if (!l) { - IGRAPH_ERRORF("The graph attribute '%s' does not exist.", IGRAPH_EINVAL, name); - } - rec = VECTOR(*gal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_STRING) { - IGRAPH_ERRORF("String graph attribute '%s' expected, got %s.", IGRAPH_EINVAL, name, attribute_type_name(rec->type)); - } - str = (igraph_strvector_t*)rec->value; - IGRAPH_CHECK(igraph_strvector_resize(value, 1)); - IGRAPH_CHECK(igraph_strvector_set(value, 0, igraph_strvector_get(str, 0))); + IGRAPH_CHECK(igraph_i_cattribute_find_or_return(gal, name, IGRAPH_ATTRIBUTE_STRING, &rec)); + IGRAPH_CHECK(igraph_strvector_push_back(value, igraph_strvector_get(rec->value.as_strvector, 0))); return IGRAPH_SUCCESS; } @@ -2633,32 +1623,23 @@ static igraph_error_t igraph_i_cattribute_get_numeric_vertex_attr(const igraph_t igraph_vs_t vs, igraph_vector_t *value) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; + igraph_attribute_record_list_t *val = &attr->val; igraph_attribute_record_t *rec; - igraph_vector_t *num; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); + const igraph_vector_t *num; - if (!l) { - IGRAPH_ERRORF("The vertex attribute '%s' does not exist.", IGRAPH_EINVAL, name); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_return(val, name, IGRAPH_ATTRIBUTE_NUMERIC, &rec)); - rec = VECTOR(*val)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) { - IGRAPH_ERRORF("Numeric vertex attribute '%s' expected, got %s.", IGRAPH_EINVAL, name, attribute_type_name(rec->type)); - } - num = (igraph_vector_t*)rec->value; + num = rec->value.as_vector; if (igraph_vs_is_all(&vs)) { - igraph_vector_clear(value); IGRAPH_CHECK(igraph_vector_append(value, num)); } else { igraph_vit_t it; - igraph_integer_t i = 0; + igraph_int_t i = igraph_vector_size(value); IGRAPH_CHECK(igraph_vit_create(graph, vs, &it)); IGRAPH_FINALLY(igraph_vit_destroy, &it); - IGRAPH_CHECK(igraph_vector_resize(value, IGRAPH_VIT_SIZE(it))); + IGRAPH_CHECK(igraph_vector_resize(value, i + IGRAPH_VIT_SIZE(it))); for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) { - igraph_integer_t v = IGRAPH_VIT_GET(it); + igraph_int_t v = IGRAPH_VIT_GET(it); VECTOR(*value)[i] = VECTOR(*num)[v]; } igraph_vit_destroy(&it); @@ -2673,31 +1654,23 @@ static igraph_error_t igraph_i_cattribute_get_bool_vertex_attr(const igraph_t *g igraph_vs_t vs, igraph_vector_bool_t *value) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_vit_t it; - igraph_integer_t i, j, v; + igraph_attribute_record_list_t *val = &attr->val; igraph_attribute_record_t *rec; - igraph_vector_bool_t *log; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); + const igraph_vector_bool_t *log; - if (!l) { - IGRAPH_ERRORF("The vertex attribute '%s' does not exist.", IGRAPH_EINVAL, name); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_return(val, name, IGRAPH_ATTRIBUTE_BOOLEAN, &rec)); - rec = VECTOR(*val)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) { - IGRAPH_ERRORF("Boolean vertex attribute '%s' expected, got %s.", IGRAPH_EINVAL, name, attribute_type_name(rec->type)); - } - log = (igraph_vector_bool_t*)rec->value; + log = rec->value.as_vector_bool; if (igraph_vs_is_all(&vs)) { - igraph_vector_bool_clear(value); IGRAPH_CHECK(igraph_vector_bool_append(value, log)); } else { + igraph_vit_t it; + igraph_int_t i = igraph_vector_bool_size(value); IGRAPH_CHECK(igraph_vit_create(graph, vs, &it)); IGRAPH_FINALLY(igraph_vit_destroy, &it); - IGRAPH_CHECK(igraph_vector_bool_resize(value, IGRAPH_VIT_SIZE(it))); - for (i = 0; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) { - v = IGRAPH_VIT_GET(it); + IGRAPH_CHECK(igraph_vector_bool_resize(value, i + IGRAPH_VIT_SIZE(it))); + for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) { + igraph_int_t v = IGRAPH_VIT_GET(it); VECTOR(*value)[i] = VECTOR(*log)[v]; } igraph_vit_destroy(&it); @@ -2712,34 +1685,25 @@ static igraph_error_t igraph_i_cattribute_get_string_vertex_attr(const igraph_t igraph_vs_t vs, igraph_strvector_t *value) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; + igraph_attribute_record_list_t *val = &attr->val; igraph_attribute_record_t *rec; - igraph_strvector_t *str; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); + const igraph_strvector_t *str; - if (!l) { - IGRAPH_ERRORF("The vertex attribute '%s' does not exist.", IGRAPH_EINVAL, name); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_return(val, name, IGRAPH_ATTRIBUTE_STRING, &rec)); - rec = VECTOR(*val)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_STRING) { - IGRAPH_ERRORF("String vertex attribute '%s' expected, got %s.", IGRAPH_EINVAL, name, attribute_type_name(rec->type)); - } - str = (igraph_strvector_t*)rec->value; + str = rec->value.as_strvector; if (igraph_vs_is_all(&vs)) { igraph_strvector_clear(value); IGRAPH_CHECK(igraph_strvector_append(value, str)); } else { igraph_vit_t it; - igraph_integer_t i = 0; + igraph_int_t i = igraph_strvector_size(value); IGRAPH_CHECK(igraph_vit_create(graph, vs, &it)); IGRAPH_FINALLY(igraph_vit_destroy, &it); - IGRAPH_CHECK(igraph_strvector_resize(value, IGRAPH_VIT_SIZE(it))); + IGRAPH_CHECK(igraph_strvector_resize(value, i + IGRAPH_VIT_SIZE(it))); for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) { - igraph_integer_t v = IGRAPH_VIT_GET(it); - const char *s = igraph_strvector_get(str, v); - IGRAPH_CHECK(igraph_strvector_set(value, i, s)); + igraph_int_t v = IGRAPH_VIT_GET(it); + IGRAPH_CHECK(igraph_strvector_set(value, i, igraph_strvector_get(str, v))); } igraph_vit_destroy(&it); IGRAPH_FINALLY_CLEAN(1); @@ -2748,37 +1712,27 @@ static igraph_error_t igraph_i_cattribute_get_string_vertex_attr(const igraph_t return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattribute_get_numeric_edge_attr(const igraph_t *graph, - const char *name, - igraph_es_t es, - igraph_vector_t *value) { +static igraph_error_t igraph_i_cattribute_get_numeric_edge_attr( + const igraph_t *graph, const char *name, igraph_es_t es, igraph_vector_t *value +) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; + igraph_attribute_record_list_t *eal = &attr->eal; igraph_attribute_record_t *rec; - igraph_vector_t *num; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); + const igraph_vector_t *num; - if (!l) { - IGRAPH_ERRORF("The edge attribute '%s' does not exist.", IGRAPH_EINVAL, name); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_return(eal, name, IGRAPH_ATTRIBUTE_NUMERIC, &rec)); - rec = VECTOR(*eal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) { - IGRAPH_ERRORF("Numeric edge attribute '%s' expected, got %s.", IGRAPH_EINVAL, name, attribute_type_name(rec->type)); - } - num = (igraph_vector_t*)rec->value; + num = rec->value.as_vector; if (igraph_es_is_all(&es)) { - igraph_vector_clear(value); IGRAPH_CHECK(igraph_vector_append(value, num)); } else { igraph_eit_t it; - igraph_integer_t i = 0; + igraph_int_t i = igraph_vector_size(value); IGRAPH_CHECK(igraph_eit_create(graph, es, &it)); IGRAPH_FINALLY(igraph_eit_destroy, &it); - IGRAPH_CHECK(igraph_vector_resize(value, IGRAPH_EIT_SIZE(it))); + IGRAPH_CHECK(igraph_vector_resize(value, i + IGRAPH_EIT_SIZE(it))); for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) { - igraph_integer_t e = IGRAPH_EIT_GET(it); + igraph_int_t e = IGRAPH_EIT_GET(it); VECTOR(*value)[i] = VECTOR(*num)[e]; } igraph_eit_destroy(&it); @@ -2788,39 +1742,29 @@ static igraph_error_t igraph_i_cattribute_get_numeric_edge_attr(const igraph_t * return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattribute_get_string_edge_attr(const igraph_t *graph, - const char *name, - igraph_es_t es, - igraph_strvector_t *value) { +static igraph_error_t igraph_i_cattribute_get_string_edge_attr( + const igraph_t *graph, const char *name, igraph_es_t es, + igraph_strvector_t *value +) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; + igraph_attribute_record_list_t *eal = &attr->eal; igraph_attribute_record_t *rec; - igraph_strvector_t *str; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); + const igraph_strvector_t *str; - if (!l) { - IGRAPH_ERRORF("The edge attribute '%s' does not exist.", IGRAPH_EINVAL, name); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_return(eal, name, IGRAPH_ATTRIBUTE_STRING, &rec)); - rec = VECTOR(*eal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_STRING) { - IGRAPH_ERRORF("String edge attribute '%s' expected, got %s.", IGRAPH_EINVAL, name, attribute_type_name(rec->type)); - } - str = (igraph_strvector_t*)rec->value; + str = rec->value.as_strvector; if (igraph_es_is_all(&es)) { - igraph_strvector_clear(value); IGRAPH_CHECK(igraph_strvector_append(value, str)); } else { igraph_eit_t it; - igraph_integer_t i = 0; + igraph_int_t i = igraph_strvector_size(value); IGRAPH_CHECK(igraph_eit_create(graph, es, &it)); IGRAPH_FINALLY(igraph_eit_destroy, &it); - IGRAPH_CHECK(igraph_strvector_resize(value, IGRAPH_EIT_SIZE(it))); + IGRAPH_CHECK(igraph_strvector_resize(value, i + IGRAPH_EIT_SIZE(it))); for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) { - igraph_integer_t e = IGRAPH_EIT_GET(it); - const char *s = igraph_strvector_get(str, e); - IGRAPH_CHECK(igraph_strvector_set(value, i, s)); + igraph_int_t e = IGRAPH_EIT_GET(it); + IGRAPH_CHECK(igraph_strvector_set(value, i, igraph_strvector_get(str, e))); } igraph_eit_destroy(&it); IGRAPH_FINALLY_CLEAN(1); @@ -2829,37 +1773,28 @@ static igraph_error_t igraph_i_cattribute_get_string_edge_attr(const igraph_t *g return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_cattribute_get_bool_edge_attr(const igraph_t *graph, - const char *name, - igraph_es_t es, - igraph_vector_bool_t *value) { +static igraph_error_t igraph_i_cattribute_get_bool_edge_attr( + const igraph_t *graph, const char *name, igraph_es_t es, + igraph_vector_bool_t *value +) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; + igraph_attribute_record_list_t *eal = &attr->eal; igraph_attribute_record_t *rec; - igraph_vector_bool_t *log; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); + const igraph_vector_bool_t *log; - if (!l) { - IGRAPH_ERRORF("The edge attribute '%s' does not exist.", IGRAPH_EINVAL, name); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_return(eal, name, IGRAPH_ATTRIBUTE_BOOLEAN, &rec)); - rec = VECTOR(*eal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) { - IGRAPH_ERRORF("Boolean edge attribute '%s' expected, got %s.", IGRAPH_EINVAL, name, attribute_type_name(rec->type)); - } - log = (igraph_vector_bool_t*)rec->value; + log = rec->value.as_vector_bool; if (igraph_es_is_all(&es)) { - igraph_vector_bool_clear(value); IGRAPH_CHECK(igraph_vector_bool_append(value, log)); } else { igraph_eit_t it; - igraph_integer_t i = 0; + igraph_int_t i = igraph_vector_bool_size(value); IGRAPH_CHECK(igraph_eit_create(graph, es, &it)); IGRAPH_FINALLY(igraph_eit_destroy, &it); - IGRAPH_CHECK(igraph_vector_bool_resize(value, IGRAPH_EIT_SIZE(it))); + IGRAPH_CHECK(igraph_vector_bool_resize(value, i + IGRAPH_EIT_SIZE(it))); for (; !IGRAPH_EIT_END(it); IGRAPH_EIT_NEXT(it), i++) { - igraph_integer_t e = IGRAPH_EIT_GET(it); + igraph_int_t e = IGRAPH_EIT_GET(it); VECTOR(*value)[i] = VECTOR(*log)[e]; } igraph_eit_destroy(&it); @@ -2883,7 +1818,7 @@ const igraph_attribute_table_t igraph_cattribute_table = { &igraph_i_cattribute_combine_edges, &igraph_i_cattribute_get_info, &igraph_i_cattribute_has_attr, - &igraph_i_cattribute_gettype, + &igraph_i_cattribute_get_type, &igraph_i_cattribute_get_numeric_graph_attr, &igraph_i_cattribute_get_string_graph_attr, &igraph_i_cattribute_get_bool_graph_attr, @@ -2954,21 +1889,17 @@ const igraph_attribute_table_t igraph_cattribute_table = { * Time complexity: O(Ag), the number of graph attributes. */ igraph_real_t igraph_cattribute_GAN(const igraph_t *graph, const char *name) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t j; - igraph_attribute_record_t *rec; - igraph_vector_t *num; - igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j); + const igraph_attribute_record_t *rec; + const igraph_vector_t *num; - if (!l) { + rec = igraph_i_cattribute_find(&attr->gal, name, IGRAPH_ATTRIBUTE_NUMERIC); + if (!rec) { IGRAPH_WARNINGF("Graph attribute '%s' does not exist, returning default numeric attribute value.", name); return IGRAPH_NAN; } - rec = VECTOR(*gal)[j]; - num = (igraph_vector_t*)rec->value; + num = rec->value.as_vector; return VECTOR(*num)[0]; } @@ -2989,21 +1920,17 @@ igraph_real_t igraph_cattribute_GAN(const igraph_t *graph, const char *name) { * Time complexity: O(Ag), the number of graph attributes. */ igraph_bool_t igraph_cattribute_GAB(const igraph_t *graph, const char *name) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t j; - igraph_attribute_record_t *rec; - igraph_vector_bool_t *log; - igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j); + const igraph_attribute_record_t *rec; + const igraph_vector_bool_t *log; - if (!l) { + rec = igraph_i_cattribute_find(&attr->gal, name, IGRAPH_ATTRIBUTE_BOOLEAN); + if (!rec) { IGRAPH_WARNINGF("Graph attribute '%s' does not exist, returning default boolean attribute value.", name); return false; } - rec = VECTOR(*gal)[j]; - log = (igraph_vector_bool_t*)rec->value; + log = rec->value.as_vector_bool; return VECTOR(*log)[0]; } @@ -3025,21 +1952,17 @@ igraph_bool_t igraph_cattribute_GAB(const igraph_t *graph, const char *name) { * Time complexity: O(Ag), the number of graph attributes. */ const char *igraph_cattribute_GAS(const igraph_t *graph, const char *name) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t j; - igraph_attribute_record_t *rec; - igraph_strvector_t *str; - igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j); + const igraph_attribute_record_t *rec; + const igraph_strvector_t *str; - if (!l) { + rec = igraph_i_cattribute_find(&attr->gal, name, IGRAPH_ATTRIBUTE_STRING); + if (!rec) { IGRAPH_WARNINGF("Graph attribute '%s' does not exist, returning default string attribute value.", name); return ""; } - rec = VECTOR(*gal)[j]; - str = (igraph_strvector_t*)rec->value; + str = rec->value.as_strvector; return igraph_strvector_get(str, 0); } @@ -3061,21 +1984,18 @@ const char *igraph_cattribute_GAS(const igraph_t *graph, const char *name) { * Time complexity: O(Av), the number of vertex attributes. */ igraph_real_t igraph_cattribute_VAN(const igraph_t *graph, const char *name, - igraph_integer_t vid) { + igraph_int_t vid) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; - igraph_attribute_record_t *rec; - igraph_vector_t *num; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); + const igraph_attribute_record_t *rec; + const igraph_vector_t *num; - if (!l) { + rec = igraph_i_cattribute_find(&attr->val, name, IGRAPH_ATTRIBUTE_NUMERIC); + if (!rec) { IGRAPH_WARNINGF("Vertex attribute '%s' does not exist, returning default numeric attribute value.", name); return IGRAPH_NAN; } - rec = VECTOR(*val)[j]; - num = (igraph_vector_t*)rec->value; + num = rec->value.as_vector; return VECTOR(*num)[vid]; } @@ -3097,21 +2017,18 @@ igraph_real_t igraph_cattribute_VAN(const igraph_t *graph, const char *name, * Time complexity: O(Av), the number of vertex attributes. */ igraph_bool_t igraph_cattribute_VAB(const igraph_t *graph, const char *name, - igraph_integer_t vid) { + igraph_int_t vid) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; - igraph_attribute_record_t *rec; - igraph_vector_bool_t *log; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); + const igraph_attribute_record_t *rec; + const igraph_vector_bool_t *log; - if (!l) { + rec = igraph_i_cattribute_find(&attr->val, name, IGRAPH_ATTRIBUTE_BOOLEAN); + if (!rec) { IGRAPH_WARNINGF("Vertex attribute '%s' does not exist, returning default boolean attribute value.", name); return false; } - rec = VECTOR(*val)[j]; - log = (igraph_vector_bool_t*)rec->value; + log = rec->value.as_vector_bool; return VECTOR(*log)[vid]; } @@ -3135,21 +2052,18 @@ igraph_bool_t igraph_cattribute_VAB(const igraph_t *graph, const char *name, * Time complexity: O(Av), the number of vertex attributes. */ const char *igraph_cattribute_VAS(const igraph_t *graph, const char *name, - igraph_integer_t vid) { + igraph_int_t vid) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; - igraph_attribute_record_t *rec; - igraph_strvector_t *str; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); + const igraph_attribute_record_t *rec; + const igraph_strvector_t *str; - if (!l) { + rec = igraph_i_cattribute_find(&attr->val, name, IGRAPH_ATTRIBUTE_STRING); + if (!rec) { IGRAPH_WARNINGF("Vertex attribute '%s' does not exist, returning default string attribute value.", name); return ""; } - rec = VECTOR(*val)[j]; - str = (igraph_strvector_t*)rec->value; + str = rec->value.as_strvector; return igraph_strvector_get(str, vid); } @@ -3171,21 +2085,18 @@ const char *igraph_cattribute_VAS(const igraph_t *graph, const char *name, * Time complexity: O(Ae), the number of edge attributes. */ igraph_real_t igraph_cattribute_EAN(const igraph_t *graph, const char *name, - igraph_integer_t eid) { + igraph_int_t eid) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; - igraph_attribute_record_t *rec; - igraph_vector_t *num; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); + const igraph_attribute_record_t *rec; + const igraph_vector_t *num; - if (!l) { + rec = igraph_i_cattribute_find(&attr->eal, name, IGRAPH_ATTRIBUTE_NUMERIC); + if (!rec) { IGRAPH_WARNINGF("Edge attribute '%s' does not exist, returning default numeric attribute value.", name); return IGRAPH_NAN; } - rec = VECTOR(*eal)[j]; - num = (igraph_vector_t*)rec->value; + num = rec->value.as_vector; return VECTOR(*num)[eid]; } @@ -3207,21 +2118,18 @@ igraph_real_t igraph_cattribute_EAN(const igraph_t *graph, const char *name, * Time complexity: O(Ae), the number of edge attributes. */ igraph_bool_t igraph_cattribute_EAB(const igraph_t *graph, const char *name, - igraph_integer_t eid) { + igraph_int_t eid) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; - igraph_attribute_record_t *rec; - igraph_vector_bool_t *log; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); + const igraph_attribute_record_t *rec; + const igraph_vector_bool_t *log; - if (!l) { + rec = igraph_i_cattribute_find(&attr->eal, name, IGRAPH_ATTRIBUTE_BOOLEAN); + if (!rec) { IGRAPH_WARNINGF("Edge attribute '%s' does not exist, returning default boolean attribute value.", name); return false; } - rec = VECTOR(*eal)[j]; - log = (igraph_vector_bool_t*)rec->value; + log = rec->value.as_vector_bool; return VECTOR(*log)[eid]; } @@ -3245,21 +2153,18 @@ igraph_bool_t igraph_cattribute_EAB(const igraph_t *graph, const char *name, * Time complexity: O(Ae), the number of edge attributes. */ const char *igraph_cattribute_EAS(const igraph_t *graph, const char *name, - igraph_integer_t eid) { + igraph_int_t eid) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; - igraph_attribute_record_t *rec; - igraph_strvector_t *str; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); + const igraph_attribute_record_t *rec; + const igraph_strvector_t *str; - if (!l) { + rec = igraph_i_cattribute_find(&attr->eal, name, IGRAPH_ATTRIBUTE_STRING); + if (!rec) { IGRAPH_WARNINGF("Edge attribute '%s' does not exist, returning default string attribute value.", name); return ""; } - rec = VECTOR(*eal)[j]; - str = (igraph_strvector_t*)rec->value; + str = rec->value.as_strvector; return igraph_strvector_get(str, eid); } @@ -3279,9 +2184,8 @@ const char *igraph_cattribute_EAS(const igraph_t *graph, const char *name, igraph_error_t igraph_cattribute_VANV(const igraph_t *graph, const char *name, igraph_vs_t vids, igraph_vector_t *result) { - - return igraph_i_cattribute_get_numeric_vertex_attr(graph, name, vids, - result); + igraph_vector_clear(result); + return igraph_i_cattribute_get_numeric_vertex_attr(graph, name, vids, result); } /** @@ -3300,9 +2204,8 @@ igraph_error_t igraph_cattribute_VANV(const igraph_t *graph, const char *name, igraph_error_t igraph_cattribute_VABV(const igraph_t *graph, const char *name, igraph_vs_t vids, igraph_vector_bool_t *result) { - - return igraph_i_cattribute_get_bool_vertex_attr(graph, name, vids, - result); + igraph_vector_bool_clear(result); + return igraph_i_cattribute_get_bool_vertex_attr(graph, name, vids, result); } /** @@ -3321,9 +2224,8 @@ igraph_error_t igraph_cattribute_VABV(const igraph_t *graph, const char *name, igraph_error_t igraph_cattribute_EANV(const igraph_t *graph, const char *name, igraph_es_t eids, igraph_vector_t *result) { - - return igraph_i_cattribute_get_numeric_edge_attr(graph, name, eids, - result); + igraph_vector_clear(result); + return igraph_i_cattribute_get_numeric_edge_attr(graph, name, eids, result); } /** @@ -3342,9 +2244,8 @@ igraph_error_t igraph_cattribute_EANV(const igraph_t *graph, const char *name, igraph_error_t igraph_cattribute_EABV(const igraph_t *graph, const char *name, igraph_es_t eids, igraph_vector_bool_t *result) { - - return igraph_i_cattribute_get_bool_edge_attr(graph, name, eids, - result); + igraph_vector_bool_clear(result); + return igraph_i_cattribute_get_bool_edge_attr(graph, name, eids, result); } /** @@ -3364,9 +2265,8 @@ igraph_error_t igraph_cattribute_EABV(const igraph_t *graph, const char *name, igraph_error_t igraph_cattribute_VASV(const igraph_t *graph, const char *name, igraph_vs_t vids, igraph_strvector_t *result) { - - return igraph_i_cattribute_get_string_vertex_attr(graph, name, vids, - result); + igraph_strvector_clear(result); + return igraph_i_cattribute_get_string_vertex_attr(graph, name, vids, result); } /** @@ -3386,9 +2286,8 @@ igraph_error_t igraph_cattribute_VASV(const igraph_t *graph, const char *name, igraph_error_t igraph_cattribute_EASV(const igraph_t *graph, const char *name, igraph_es_t eids, igraph_strvector_t *result) { - - return igraph_i_cattribute_get_string_edge_attr(graph, name, eids, - result); + igraph_strvector_clear(result); + return igraph_i_cattribute_get_string_edge_attr(graph, name, eids, result); } /** @@ -3454,44 +2353,16 @@ igraph_bool_t igraph_cattribute_has_attr(const igraph_t *graph, */ igraph_error_t igraph_cattribute_GAN_set(igraph_t *graph, const char *name, igraph_real_t value) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j); - - if (l) { - igraph_attribute_record_t *rec = VECTOR(*gal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) { - IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL); - } else { - igraph_vector_t *num = (igraph_vector_t *)rec->value; - VECTOR(*num)[0] = value; - } - } else { - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_vector_t *num; - if (!rec) { - IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - rec->type = IGRAPH_ATTRIBUTE_NUMERIC; - num = IGRAPH_CALLOC(1, igraph_vector_t); - if (!num) { - IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, num); - IGRAPH_VECTOR_INIT_FINALLY(num, 1); - VECTOR(*num)[0] = value; - rec->value = num; - IGRAPH_CHECK(igraph_vector_ptr_push_back(gal, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + igraph_attribute_record_t *rec; + igraph_vector_t *num; + + IGRAPH_CHECK(igraph_i_cattribute_find_or_create( + &attr->gal, name, IGRAPH_ATTRIBUTE_NUMERIC, 1, &rec + )); + + num = rec->value.as_vector; + VECTOR(*num)[0] = value; return IGRAPH_SUCCESS; } @@ -3512,44 +2383,16 @@ igraph_error_t igraph_cattribute_GAN_set(igraph_t *graph, const char *name, */ igraph_error_t igraph_cattribute_GAB_set(igraph_t *graph, const char *name, igraph_bool_t value) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j); - - if (l) { - igraph_attribute_record_t *rec = VECTOR(*gal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) { - IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL); - } else { - igraph_vector_bool_t *log = (igraph_vector_bool_t *)rec->value; - VECTOR(*log)[0] = value; - } - } else { - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_vector_bool_t *log; - if (!rec) { - IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - rec->type = IGRAPH_ATTRIBUTE_BOOLEAN; - log = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (!log) { - IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, log); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(log, 1); - VECTOR(*log)[0] = value; - rec->value = log; - IGRAPH_CHECK(igraph_vector_ptr_push_back(gal, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + igraph_attribute_record_t *rec; + igraph_vector_bool_t *log; + + IGRAPH_CHECK(igraph_i_cattribute_find_or_create( + &attr->gal, name, IGRAPH_ATTRIBUTE_BOOLEAN, 1, &rec + )); + + log = rec->value.as_vector_bool; + VECTOR(*log)[0] = value; return IGRAPH_SUCCESS; } @@ -3571,44 +2414,16 @@ igraph_error_t igraph_cattribute_GAB_set(igraph_t *graph, const char *name, */ igraph_error_t igraph_cattribute_GAS_set(igraph_t *graph, const char *name, const char *value) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j); - - if (l) { - igraph_attribute_record_t *rec = VECTOR(*gal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_STRING) { - IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL); - } else { - igraph_strvector_t *str = (igraph_strvector_t*)rec->value; - IGRAPH_CHECK(igraph_strvector_set(str, 0, value)); - } - } else { - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_strvector_t *str; - if (!rec) { - IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - rec->type = IGRAPH_ATTRIBUTE_STRING; - str = IGRAPH_CALLOC(1, igraph_strvector_t); - if (!str) { - IGRAPH_ERROR("Cannot add graph attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, str); - IGRAPH_STRVECTOR_INIT_FINALLY(str, 1); - IGRAPH_CHECK(igraph_strvector_set(str, 0, value)); - rec->value = str; - IGRAPH_CHECK(igraph_vector_ptr_push_back(gal, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + igraph_attribute_record_t *rec; + igraph_strvector_t *str; + + IGRAPH_CHECK(igraph_i_cattribute_find_or_create( + &attr->gal, name, IGRAPH_ATTRIBUTE_STRING, 1, &rec + )); + + str = rec->value.as_strvector; + IGRAPH_CHECK(igraph_strvector_set(str, 0, value)); return IGRAPH_SUCCESS; } @@ -3632,46 +2447,14 @@ igraph_error_t igraph_cattribute_GAS_set(igraph_t *graph, const char *name, * new, O(|vid|) otherwise. */ igraph_error_t igraph_cattribute_VAN_set(igraph_t *graph, const char *name, - igraph_integer_t vid, igraph_real_t value) { - + igraph_int_t vid, igraph_real_t value) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); - - if (l) { - igraph_attribute_record_t *rec = VECTOR(*val)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) { - IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL); - } else { - igraph_vector_t *num = (igraph_vector_t*)rec->value; - VECTOR(*num)[vid] = value; - } - } else { - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_vector_t *num; - if (!rec) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - rec->type = IGRAPH_ATTRIBUTE_NUMERIC; - num = IGRAPH_CALLOC(1, igraph_vector_t); - if (!num) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, num); - IGRAPH_VECTOR_INIT_FINALLY(num, igraph_vcount(graph)); - igraph_vector_fill(num, IGRAPH_NAN); - VECTOR(*num)[vid] = value; - rec->value = num; - IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + igraph_attribute_record_t *rec; + + IGRAPH_CHECK(igraph_i_cattribute_find_or_create( + &attr->val, name, IGRAPH_ATTRIBUTE_NUMERIC, igraph_vcount(graph), &rec + )); + VECTOR(*rec->value.as_vector)[vid] = value; return IGRAPH_SUCCESS; } @@ -3695,46 +2478,14 @@ igraph_error_t igraph_cattribute_VAN_set(igraph_t *graph, const char *name, * new, O(|vid|) otherwise. */ igraph_error_t igraph_cattribute_VAB_set(igraph_t *graph, const char *name, - igraph_integer_t vid, igraph_bool_t value) { - + igraph_int_t vid, igraph_bool_t value) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); - - if (l) { - igraph_attribute_record_t *rec = VECTOR(*val)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) { - IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL); - } else { - igraph_vector_bool_t *log = (igraph_vector_bool_t*)rec->value; - VECTOR(*log)[vid] = value; - } - } else { - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_vector_bool_t *log; - if (!rec) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - rec->type = IGRAPH_ATTRIBUTE_BOOLEAN; - log = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (!log) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, log); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(log, igraph_vcount(graph)); - igraph_vector_bool_fill(log, false); - VECTOR(*log)[vid] = value; - rec->value = log; - IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + igraph_attribute_record_t *rec; + + IGRAPH_CHECK(igraph_i_cattribute_find_or_create( + &attr->val, name, IGRAPH_ATTRIBUTE_BOOLEAN, igraph_vcount(graph), &rec + )); + VECTOR(*rec->value.as_vector_bool)[vid] = value; return IGRAPH_SUCCESS; } @@ -3759,45 +2510,14 @@ igraph_error_t igraph_cattribute_VAB_set(igraph_t *graph, const char *name, * O(|vid|*l). */ igraph_error_t igraph_cattribute_VAS_set(igraph_t *graph, const char *name, - igraph_integer_t vid, const char *value) { - + igraph_int_t vid, const char *value) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); - - if (l) { - igraph_attribute_record_t *rec = VECTOR(*val)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_STRING) { - IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL); - } else { - igraph_strvector_t *str = (igraph_strvector_t*)rec->value; - IGRAPH_CHECK(igraph_strvector_set(str, vid, value)); - } - } else { - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_strvector_t *str; - if (!rec) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - rec->type = IGRAPH_ATTRIBUTE_STRING; - str = IGRAPH_CALLOC(1, igraph_strvector_t); - if (!str) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, str); - IGRAPH_STRVECTOR_INIT_FINALLY(str, igraph_vcount(graph)); - IGRAPH_CHECK(igraph_strvector_set(str, vid, value)); - rec->value = str; - IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + igraph_attribute_record_t *rec; + + IGRAPH_CHECK(igraph_i_cattribute_find_or_create( + &attr->val, name, IGRAPH_ATTRIBUTE_STRING, igraph_vcount(graph), &rec + )); + IGRAPH_CHECK(igraph_strvector_set(rec->value.as_strvector, vid, value)); return IGRAPH_SUCCESS; } @@ -3821,46 +2541,14 @@ igraph_error_t igraph_cattribute_VAS_set(igraph_t *graph, const char *name, * new, O(|eid|) otherwise. */ igraph_error_t igraph_cattribute_EAN_set(igraph_t *graph, const char *name, - igraph_integer_t eid, igraph_real_t value) { - + igraph_int_t eid, igraph_real_t value) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); - - if (l) { - igraph_attribute_record_t *rec = VECTOR(*eal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) { - IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL); - } else { - igraph_vector_t *num = (igraph_vector_t*)rec->value; - VECTOR(*num)[eid] = value; - } - } else { - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_vector_t *num; - if (!rec) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - rec->type = IGRAPH_ATTRIBUTE_NUMERIC; - num = IGRAPH_CALLOC(1, igraph_vector_t); - if (!num) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, num); - IGRAPH_VECTOR_INIT_FINALLY(num, igraph_ecount(graph)); - igraph_vector_fill(num, IGRAPH_NAN); - VECTOR(*num)[eid] = value; - rec->value = num; - IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + igraph_attribute_record_t *rec; + + IGRAPH_CHECK(igraph_i_cattribute_find_or_create( + &attr->eal, name, IGRAPH_ATTRIBUTE_NUMERIC, igraph_ecount(graph), &rec + )); + VECTOR(*rec->value.as_vector)[eid] = value; return IGRAPH_SUCCESS; } @@ -3884,46 +2572,14 @@ igraph_error_t igraph_cattribute_EAN_set(igraph_t *graph, const char *name, * new, O(|eid|) otherwise. */ igraph_error_t igraph_cattribute_EAB_set(igraph_t *graph, const char *name, - igraph_integer_t eid, igraph_bool_t value) { - + igraph_int_t eid, igraph_bool_t value) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); - - if (l) { - igraph_attribute_record_t *rec = VECTOR(*eal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) { - IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL); - } else { - igraph_vector_bool_t *log = (igraph_vector_bool_t*)rec->value; - VECTOR(*log)[eid] = value; - } - } else { - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_vector_bool_t *log; - if (!rec) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - rec->type = IGRAPH_ATTRIBUTE_BOOLEAN; - log = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (!log) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, log); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(log, igraph_ecount(graph)); - igraph_vector_bool_fill(log, false); - VECTOR(*log)[eid] = value; - rec->value = log; - IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + igraph_attribute_record_t *rec; + + IGRAPH_CHECK(igraph_i_cattribute_find_or_create( + &attr->eal, name, IGRAPH_ATTRIBUTE_BOOLEAN, igraph_ecount(graph), &rec + )); + VECTOR(*rec->value.as_vector_bool)[eid] = value; return IGRAPH_SUCCESS; } @@ -3948,45 +2604,14 @@ igraph_error_t igraph_cattribute_EAB_set(igraph_t *graph, const char *name, * O(|eid|*l). */ igraph_error_t igraph_cattribute_EAS_set(igraph_t *graph, const char *name, - igraph_integer_t eid, const char *value) { - + igraph_int_t eid, const char *value) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); - - if (l) { - igraph_attribute_record_t *rec = VECTOR(*eal)[j]; - if (rec->type != IGRAPH_ATTRIBUTE_STRING) { - IGRAPH_ERROR("Invalid attribute type", IGRAPH_EINVAL); - } else { - igraph_strvector_t *str = (igraph_strvector_t*)rec->value; - IGRAPH_CHECK(igraph_strvector_set(str, eid, value)); - } - } else { - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_strvector_t *str; - if (!rec) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - rec->type = IGRAPH_ATTRIBUTE_STRING; - str = IGRAPH_CALLOC(1, igraph_strvector_t); - if (!str) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, str); - IGRAPH_STRVECTOR_INIT_FINALLY(str, igraph_ecount(graph)); - IGRAPH_CHECK(igraph_strvector_set(str, eid, value)); - rec->value = str; - IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + igraph_attribute_record_t *rec; + + IGRAPH_CHECK(igraph_i_cattribute_find_or_create( + &attr->eal, name, IGRAPH_ATTRIBUTE_STRING, igraph_ecount(graph), &rec + )); + IGRAPH_CHECK(igraph_strvector_set(rec->value.as_strvector, eid, value)); return IGRAPH_SUCCESS; } @@ -4010,52 +2635,20 @@ igraph_error_t igraph_cattribute_EAS_set(igraph_t *graph, const char *name, igraph_error_t igraph_cattribute_VAN_setv(igraph_t *graph, const char *name, const igraph_vector_t *v) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); + igraph_attribute_record_t *rec; + igraph_int_t nv = igraph_vcount(graph); /* Check length first */ - if (igraph_vector_size(v) != igraph_vcount(graph)) { - IGRAPH_ERROR("Invalid vertex attribute vector length", IGRAPH_EINVAL); + if (igraph_vector_size(v) != nv) { + IGRAPH_ERROR("Invalid vertex attribute vector length.", IGRAPH_EINVAL); } - if (l) { - /* Already present, check type */ - igraph_attribute_record_t *rec = VECTOR(*val)[j]; - igraph_vector_t *num = (igraph_vector_t *)rec->value; - if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) { - IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL); - } - igraph_vector_clear(num); - IGRAPH_CHECK(igraph_vector_append(num, v)); - } else { - /* Add it */ - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_vector_t *num; - if (!rec) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->type = IGRAPH_ATTRIBUTE_NUMERIC; - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - num = IGRAPH_CALLOC(1, igraph_vector_t); - if (!num) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, num); - rec->value = num; - IGRAPH_CHECK(igraph_vector_init_copy(num, v)); - IGRAPH_FINALLY(igraph_vector_destroy, num); - IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->val, name, IGRAPH_ATTRIBUTE_NUMERIC, nv, &rec)); + IGRAPH_CHECK(igraph_vector_update(rec->value.as_vector, v)); return IGRAPH_SUCCESS; } + /** * \function igraph_cattribute_VAB_setv * \brief Set a boolean vertex attribute for all vertices. @@ -4075,49 +2668,16 @@ igraph_error_t igraph_cattribute_VAN_setv(igraph_t *graph, const char *name, igraph_error_t igraph_cattribute_VAB_setv(igraph_t *graph, const char *name, const igraph_vector_bool_t *v) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); + igraph_attribute_record_t *rec; + igraph_int_t nv = igraph_vcount(graph); /* Check length first */ - if (igraph_vector_bool_size(v) != igraph_vcount(graph)) { - IGRAPH_ERROR("Invalid vertex attribute vector length", IGRAPH_EINVAL); + if (igraph_vector_bool_size(v) != nv) { + IGRAPH_ERROR("Invalid vertex attribute vector length.", IGRAPH_EINVAL); } - if (l) { - /* Already present, check type */ - igraph_attribute_record_t *rec = VECTOR(*val)[j]; - igraph_vector_bool_t *log = (igraph_vector_bool_t *)rec->value; - if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) { - IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL); - } - igraph_vector_bool_clear(log); - IGRAPH_CHECK(igraph_vector_bool_append(log, v)); - } else { - /* Add it */ - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_vector_bool_t *log; - if (!rec) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->type = IGRAPH_ATTRIBUTE_BOOLEAN; - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - log = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (!log) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, log); - rec->value = log; - IGRAPH_CHECK(igraph_vector_bool_init_copy(log, v)); - IGRAPH_FINALLY(igraph_vector_bool_destroy, log); - IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->val, name, IGRAPH_ATTRIBUTE_BOOLEAN, nv, &rec)); + IGRAPH_CHECK(igraph_vector_bool_update(rec->value.as_vector_bool, v)); return IGRAPH_SUCCESS; } @@ -4140,51 +2700,17 @@ igraph_error_t igraph_cattribute_VAB_setv(igraph_t *graph, const char *name, */ igraph_error_t igraph_cattribute_VAS_setv(igraph_t *graph, const char *name, const igraph_strvector_t *sv) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); + igraph_attribute_record_t *rec; + igraph_int_t nv = igraph_vcount(graph); /* Check length first */ - if (igraph_strvector_size(sv) != igraph_vcount(graph)) { - IGRAPH_ERROR("Invalid vertex attribute vector length", IGRAPH_EINVAL); + if (igraph_strvector_size(sv) != nv) { + IGRAPH_ERROR("Invalid vertex attribute vector length.", IGRAPH_EINVAL); } - if (l) { - /* Already present, check type */ - igraph_attribute_record_t *rec = VECTOR(*val)[j]; - igraph_strvector_t *str = (igraph_strvector_t *)rec->value; - if (rec->type != IGRAPH_ATTRIBUTE_STRING) { - IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL); - } - igraph_strvector_clear(str); - IGRAPH_CHECK(igraph_strvector_append(str, sv)); - } else { - /* Add it */ - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_strvector_t *str; - if (!rec) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->type = IGRAPH_ATTRIBUTE_STRING; - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - str = IGRAPH_CALLOC(1, igraph_strvector_t); - if (!str) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, str); - rec->value = str; - IGRAPH_CHECK(igraph_strvector_init_copy(str, sv)); - IGRAPH_FINALLY(igraph_strvector_destroy, str); - IGRAPH_CHECK(igraph_vector_ptr_push_back(val, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->val, name, IGRAPH_ATTRIBUTE_STRING, nv, &rec)); + IGRAPH_CHECK(igraph_strvector_update(rec->value.as_strvector, sv)); return IGRAPH_SUCCESS; } @@ -4206,51 +2732,17 @@ igraph_error_t igraph_cattribute_VAS_setv(igraph_t *graph, const char *name, */ igraph_error_t igraph_cattribute_EAN_setv(igraph_t *graph, const char *name, const igraph_vector_t *v) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); + igraph_attribute_record_t *rec; + igraph_int_t ne = igraph_ecount(graph); /* Check length first */ - if (igraph_vector_size(v) != igraph_ecount(graph)) { - IGRAPH_ERROR("Invalid edge attribute vector length", IGRAPH_EINVAL); + if (igraph_vector_size(v) != ne) { + IGRAPH_ERROR("Invalid edge attribute vector length.", IGRAPH_EINVAL); } - if (l) { - /* Already present, check type */ - igraph_attribute_record_t *rec = VECTOR(*eal)[j]; - igraph_vector_t *num = (igraph_vector_t *)rec->value; - if (rec->type != IGRAPH_ATTRIBUTE_NUMERIC) { - IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL); - } - igraph_vector_clear(num); - IGRAPH_CHECK(igraph_vector_append(num, v)); - } else { - /* Add it */ - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_vector_t *num; - if (!rec) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->type = IGRAPH_ATTRIBUTE_NUMERIC; - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - num = IGRAPH_CALLOC(1, igraph_vector_t); - if (!num) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, num); - rec->value = num; - IGRAPH_CHECK(igraph_vector_init_copy(num, v)); - IGRAPH_FINALLY(igraph_vector_destroy, num); - IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->eal, name, IGRAPH_ATTRIBUTE_NUMERIC, ne, &rec)); + IGRAPH_CHECK(igraph_vector_update(rec->value.as_vector, v)); return IGRAPH_SUCCESS; } @@ -4272,51 +2764,17 @@ igraph_error_t igraph_cattribute_EAN_setv(igraph_t *graph, const char *name, */ igraph_error_t igraph_cattribute_EAB_setv(igraph_t *graph, const char *name, const igraph_vector_bool_t *v) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); + igraph_attribute_record_t *rec; + igraph_int_t ne = igraph_ecount(graph); /* Check length first */ - if (igraph_vector_bool_size(v) != igraph_ecount(graph)) { - IGRAPH_ERROR("Invalid edge attribute vector length", IGRAPH_EINVAL); + if (igraph_vector_bool_size(v) != ne) { + IGRAPH_ERROR("Invalid edge attribute vector length.", IGRAPH_EINVAL); } - if (l) { - /* Already present, check type */ - igraph_attribute_record_t *rec = VECTOR(*eal)[j]; - igraph_vector_bool_t *log = (igraph_vector_bool_t *)rec->value; - if (rec->type != IGRAPH_ATTRIBUTE_BOOLEAN) { - IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL); - } - igraph_vector_bool_clear(log); - IGRAPH_CHECK(igraph_vector_bool_append(log, v)); - } else { - /* Add it */ - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_vector_bool_t *log; - if (!rec) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->type = IGRAPH_ATTRIBUTE_BOOLEAN; - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - log = IGRAPH_CALLOC(1, igraph_vector_bool_t); - if (!log) { - IGRAPH_ERROR("Cannot add edge attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, log); - rec->value = log; - IGRAPH_CHECK(igraph_vector_bool_init_copy(log, v)); - IGRAPH_FINALLY(igraph_vector_bool_destroy, log); - IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->eal, name, IGRAPH_ATTRIBUTE_BOOLEAN, ne, &rec)); + IGRAPH_CHECK(igraph_vector_bool_update(rec->value.as_vector_bool, v)); return IGRAPH_SUCCESS; } @@ -4339,72 +2797,21 @@ igraph_error_t igraph_cattribute_EAB_setv(igraph_t *graph, const char *name, */ igraph_error_t igraph_cattribute_EAS_setv(igraph_t *graph, const char *name, const igraph_strvector_t *sv) { - igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); + igraph_attribute_record_t *rec; + igraph_int_t ne = igraph_ecount(graph); /* Check length first */ - if (igraph_strvector_size(sv) != igraph_ecount(graph)) { - IGRAPH_ERROR("Invalid edge attribute vector length", IGRAPH_EINVAL); + if (igraph_strvector_size(sv) != ne) { + IGRAPH_ERROR("Invalid edge attribute vector length.", IGRAPH_EINVAL); } - if (l) { - /* Already present, check type */ - igraph_attribute_record_t *rec = VECTOR(*eal)[j]; - igraph_strvector_t *str = (igraph_strvector_t *)rec->value; - if (rec->type != IGRAPH_ATTRIBUTE_STRING) { - IGRAPH_ERROR("Attribute type mismatch", IGRAPH_EINVAL); - } - igraph_strvector_clear(str); - IGRAPH_CHECK(igraph_strvector_append(str, sv)); - } else { - /* Add it */ - igraph_attribute_record_t *rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - igraph_strvector_t *str; - if (!rec) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, rec); - rec->type = IGRAPH_ATTRIBUTE_STRING; - rec->name = strdup(name); - if (!rec->name) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, (char*)rec->name); - str = IGRAPH_CALLOC(1, igraph_strvector_t); - if (!str) { - IGRAPH_ERROR("Cannot add vertex attribute", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } - IGRAPH_FINALLY(igraph_free, str); - rec->value = str; - IGRAPH_CHECK(igraph_strvector_init_copy(str, sv)); - IGRAPH_FINALLY(igraph_strvector_destroy, str); - IGRAPH_CHECK(igraph_vector_ptr_push_back(eal, rec)); - IGRAPH_FINALLY_CLEAN(4); - } + IGRAPH_CHECK(igraph_i_cattribute_find_or_create(&attr->eal, name, IGRAPH_ATTRIBUTE_STRING, ne, &rec)); + IGRAPH_CHECK(igraph_strvector_update(rec->value.as_strvector, sv)); return IGRAPH_SUCCESS; } -static void igraph_i_cattribute_free_rec(igraph_attribute_record_t *rec) { - - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *num = (igraph_vector_t*)rec->value; - igraph_vector_destroy(num); - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *str = (igraph_strvector_t*)rec->value; - igraph_strvector_destroy(str); - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *boolvec = (igraph_vector_bool_t*)rec->value; - igraph_vector_bool_destroy(boolvec); - } - IGRAPH_FREE(rec->name); - IGRAPH_FREE(rec->value); - IGRAPH_FREE(rec); -} - /** * \function igraph_cattribute_remove_g * \brief Remove a graph attribute. @@ -4418,13 +2825,11 @@ static void igraph_i_cattribute_free_rec(igraph_attribute_record_t *rec) { void igraph_cattribute_remove_g(igraph_t *graph, const char *name) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(gal, name, &j); + igraph_attribute_record_list_t *gal = &attr->gal; + igraph_int_t j = igraph_i_cattribute_find_index(gal, name); - if (l) { - igraph_i_cattribute_free_rec(VECTOR(*gal)[j]); - igraph_vector_ptr_remove(gal, j); + if (j >= 0) { + igraph_attribute_record_list_discard(gal, j); } else { IGRAPH_WARNING("Cannot remove non-existent graph attribute"); } @@ -4443,13 +2848,11 @@ void igraph_cattribute_remove_g(igraph_t *graph, const char *name) { void igraph_cattribute_remove_v(igraph_t *graph, const char *name) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(val, name, &j); + igraph_attribute_record_list_t *val = &attr->val; + igraph_int_t j = igraph_i_cattribute_find_index(val, name); - if (l) { - igraph_i_cattribute_free_rec(VECTOR(*val)[j]); - igraph_vector_ptr_remove(val, j); + if (j >= 0) { + igraph_attribute_record_list_discard(val, j); } else { IGRAPH_WARNING("Cannot remove non-existent graph attribute"); } @@ -4463,18 +2866,15 @@ void igraph_cattribute_remove_v(igraph_t *graph, const char *name) { * \param name Name of the edge attribute to remove. * * \sa \ref DELEA for a simpler way. - * */ void igraph_cattribute_remove_e(igraph_t *graph, const char *name) { igraph_i_cattributes_t *attr = graph->attr; - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t j; - igraph_bool_t l = igraph_i_cattribute_find(eal, name, &j); + igraph_attribute_record_list_t *eal = &attr->eal; + igraph_int_t j = igraph_i_cattribute_find_index(eal, name); - if (l) { - igraph_i_cattribute_free_rec(VECTOR(*eal)[j]); - igraph_vector_ptr_remove(eal, j); + if (j >= 0) { + igraph_attribute_record_list_discard(eal, j); } else { IGRAPH_WARNING("Cannot remove non-existent graph attribute"); } @@ -4498,27 +2898,12 @@ void igraph_cattribute_remove_all(igraph_t *graph, igraph_bool_t g, igraph_i_cattributes_t *attr = graph->attr; if (g) { - igraph_vector_ptr_t *gal = &attr->gal; - igraph_integer_t i, n = igraph_vector_ptr_size(gal); - for (i = 0; i < n; i++) { - igraph_i_cattribute_free_rec(VECTOR(*gal)[i]); - } - igraph_vector_ptr_clear(gal); + igraph_attribute_record_list_clear(&attr->gal); } if (v) { - igraph_vector_ptr_t *val = &attr->val; - igraph_integer_t i, n = igraph_vector_ptr_size(val); - for (i = 0; i < n; i++) { - igraph_i_cattribute_free_rec(VECTOR(*val)[i]); - } - igraph_vector_ptr_clear(val); + igraph_attribute_record_list_clear(&attr->val); } if (e) { - igraph_vector_ptr_t *eal = &attr->eal; - igraph_integer_t i, n = igraph_vector_ptr_size(eal); - for (i = 0; i < n; i++) { - igraph_i_cattribute_free_rec(VECTOR(*eal)[i]); - } - igraph_vector_ptr_clear(eal); + igraph_attribute_record_list_clear(&attr->eal); } } diff --git a/src/vendor/cigraph/src/graph/graph_list.c b/src/vendor/cigraph/src/graph/graph_list.c index 9d82ec2901a..a96ae6b92bb 100644 --- a/src/vendor/cigraph/src/graph/graph_list.c +++ b/src/vendor/cigraph/src/graph/graph_list.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/graph/internal.h b/src/vendor/cigraph/src/graph/internal.h index 1e5d2620c1b..7acea1f9014 100644 --- a/src/vendor/cigraph/src/graph/internal.h +++ b/src/vendor/cigraph/src/graph/internal.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -21,22 +21,12 @@ #include "igraph_datatype.h" #include "igraph_decls.h" -#include "igraph_constants.h" #include "igraph_error.h" -#include "igraph_vector.h" -__BEGIN_DECLS - -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_neighbors( - const igraph_t *graph, igraph_vector_int_t *neis, igraph_integer_t pnode, - igraph_neimode_t mode, igraph_loops_t loops, igraph_multiple_t multiple); - -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_incident( - const igraph_t *graph, igraph_vector_int_t *eids, igraph_integer_t pnode, - igraph_neimode_t mode, igraph_loops_t loops); +IGRAPH_BEGIN_C_DECLS igraph_error_t igraph_i_reverse(igraph_t *graph); -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_GRAPH_INTERNAL_H */ diff --git a/src/vendor/cigraph/src/graph/iterators.c b/src/vendor/cigraph/src/graph/iterators.c index 79a2abbdb0f..d557b309344 100644 --- a/src/vendor/cigraph/src/graph/iterators.c +++ b/src/vendor/cigraph/src/graph/iterators.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -145,17 +144,32 @@ igraph_vs_t igraph_vss_all(void) { * from/to \c vid. That is, all the neighbors of \c vid considered * as if the graph is undirected. * \endclist + * \param loops Whether to include the vertex itself in the neighborhood if the + * vertex has a loop edge. If \c IGRAPH_NO_LOOPS, loop edges are + * excluded. If \c IGRAPH_LOOPS_ONCE, the vertex is included in its own + * neighborhood once for every loop edge that it has. If + * \c IGRAPH_LOOPS_TWICE, the vertex is included twice in its own + * neighborhood for every loop edge that it has, but only if the graph is + * undirected or \p mode is set to \c IGRAPH_ALL. + * \param multiple Whether to include multiple edges. If \c IGRAPH_NO_MULTIPLE, + * multiple edges are not included in the neighborhood. If + * \c IGRAPH_MULTIPLE, multiple edges are included in the neighborhood. + * * \return Error code. * \sa \ref igraph_vs_destroy() * * Time complexity: O(1). */ -igraph_error_t igraph_vs_adj(igraph_vs_t *vs, - igraph_integer_t vid, igraph_neimode_t mode) { +igraph_error_t igraph_vs_adj( + igraph_vs_t *vs, igraph_int_t vid, igraph_neimode_t mode, + igraph_loops_t loops, igraph_bool_t multiple +) { vs->type = IGRAPH_VS_ADJ; vs->data.adj.vid = vid; vs->data.adj.mode = mode; + vs->data.adj.loops = loops; + vs->data.adj.multiple = multiple; return IGRAPH_SUCCESS; } @@ -196,11 +210,13 @@ igraph_error_t igraph_vs_adj(igraph_vs_t *vs, * \example examples/simple/igraph_vs_nonadj.c */ -igraph_error_t igraph_vs_nonadj(igraph_vs_t *vs, igraph_integer_t vid, +igraph_error_t igraph_vs_nonadj(igraph_vs_t *vs, igraph_int_t vid, igraph_neimode_t mode) { vs->type = IGRAPH_VS_NONADJ; vs->data.adj.vid = vid; vs->data.adj.mode = mode; + vs->data.adj.loops = IGRAPH_LOOPS; + vs->data.adj.multiple = IGRAPH_MULTIPLE; return IGRAPH_SUCCESS; } @@ -254,7 +270,7 @@ igraph_vs_t igraph_vss_none(void) { * Time complexity: O(1). */ -igraph_error_t igraph_vs_1(igraph_vs_t *vs, igraph_integer_t vid) { +igraph_error_t igraph_vs_1(igraph_vs_t *vs, igraph_int_t vid) { vs->type = IGRAPH_VS_1; vs->data.vid = vid; return IGRAPH_SUCCESS; @@ -273,7 +289,7 @@ igraph_error_t igraph_vs_1(igraph_vs_t *vs, igraph_integer_t vid) { * Time complexity: O(1). */ -igraph_vs_t igraph_vss_1(igraph_integer_t vid) { +igraph_vs_t igraph_vss_1(igraph_int_t vid) { igraph_vs_t onevs; onevs.type = IGRAPH_VS_1; onevs.data.vid = vid; @@ -358,7 +374,7 @@ igraph_vs_t igraph_vss_vector(const igraph_vector_int_t *v) { igraph_error_t igraph_vs_vector_small(igraph_vs_t *vs, ...) { va_list ap; - igraph_integer_t i, n = 0; + igraph_int_t i, n = 0; igraph_vector_int_t* vec; vec = IGRAPH_CALLOC(1, igraph_vector_int_t); @@ -447,7 +463,7 @@ igraph_error_t igraph_vs_vector_copy(igraph_vs_t *vs, const igraph_vector_int_t * \example examples/simple/igraph_vs_range.c */ -igraph_error_t igraph_vs_range(igraph_vs_t *vs, igraph_integer_t start, igraph_integer_t end) { +igraph_error_t igraph_vs_range(igraph_vs_t *vs, igraph_int_t start, igraph_int_t end) { *vs = igraph_vss_range(start, end); return IGRAPH_SUCCESS; } @@ -466,7 +482,7 @@ igraph_error_t igraph_vs_range(igraph_vs_t *vs, igraph_integer_t start, igraph_i * Time complexity: O(1). */ -igraph_vs_t igraph_vss_range(igraph_integer_t start, igraph_integer_t end) { +igraph_vs_t igraph_vss_range(igraph_int_t start, igraph_int_t end) { igraph_vs_t vs; vs.type = IGRAPH_VS_RANGE; vs.data.range.start = start; @@ -474,52 +490,6 @@ igraph_vs_t igraph_vss_range(igraph_integer_t start, igraph_integer_t end) { return vs; } -/** - * \function igraph_vs_seq - * \brief Vertex set, an interval of vertices with inclusive endpoints (deprecated). - * - * Creates a vertex selector containing all vertices with vertex ID - * equal to or bigger than \p from and equal to or smaller than \p to. - * Note that both endpoints are inclusive, contrary to C conventions. - * - * \deprecated-by igraph_vs_range 0.10.0 - * - * \param vs Pointer to an uninitialized vertex selector object. - * \param from The first vertex ID to be included in the vertex selector. - * \param to The last vertex ID to be included in the vertex selector. - * \return Error code. - * \sa \ref igraph_vs_range(), \ref igraph_vss_seq(), \ref igraph_vs_destroy() - * - * Time complexity: O(1). - * - * \example examples/simple/igraph_vs_range.c - */ - -igraph_error_t igraph_vs_seq(igraph_vs_t *vs, igraph_integer_t from, igraph_integer_t to) { - *vs = igraph_vss_range(from, to + 1); - return IGRAPH_SUCCESS; -} - -/** - * \function igraph_vss_seq - * \brief An interval of vertices with inclusive endpoints (immediate version, deprecated). - * - * The immediate version of \ref igraph_vs_seq(). - * - * \deprecated-by igraph_vss_range 0.10.0 - * - * \param from The first vertex ID to be included in the vertex selector. - * \param to The last vertex ID to be included in the vertex selector. - * \return Error code. - * \sa \ref igraph_vss_range(), \ref igraph_vs_seq() - * - * Time complexity: O(1). - */ - -igraph_vs_t igraph_vss_seq(igraph_integer_t from, igraph_integer_t to) { - return igraph_vss_range(from, to + 1); -} - /** * \function igraph_vs_destroy * \brief Destroy a vertex set. @@ -638,11 +608,11 @@ igraph_vs_type_t igraph_vs_type(const igraph_vs_t *vs) { * \return Error code. */ igraph_error_t igraph_vs_size(const igraph_t *graph, const igraph_vs_t *vs, - igraph_integer_t *result) { + igraph_int_t *result) { igraph_vector_int_t vec; igraph_bool_t *seen; - igraph_integer_t i; - igraph_integer_t vec_len; + igraph_int_t i; + igraph_int_t vec_len; switch (vs->type) { case IGRAPH_VS_NONE: @@ -664,7 +634,10 @@ igraph_error_t igraph_vs_size(const igraph_t *graph, const igraph_vs_t *vs, case IGRAPH_VS_ADJ: IGRAPH_VECTOR_INT_INIT_FINALLY(&vec, 0); - IGRAPH_CHECK(igraph_neighbors(graph, &vec, vs->data.adj.vid, vs->data.adj.mode)); + IGRAPH_CHECK(igraph_neighbors( + graph, &vec, vs->data.adj.vid, vs->data.adj.mode, + vs->data.adj.loops, vs->data.adj.multiple + )); *result = igraph_vector_int_size(&vec); igraph_vector_int_destroy(&vec); IGRAPH_FINALLY_CLEAN(1); @@ -672,7 +645,10 @@ igraph_error_t igraph_vs_size(const igraph_t *graph, const igraph_vs_t *vs, case IGRAPH_VS_NONADJ: IGRAPH_VECTOR_INT_INIT_FINALLY(&vec, 0); - IGRAPH_CHECK(igraph_neighbors(graph, &vec, vs->data.adj.vid, vs->data.adj.mode)); + IGRAPH_CHECK(igraph_neighbors( + graph, &vec, vs->data.adj.vid, vs->data.adj.mode, + vs->data.adj.loops, vs->data.adj.multiple + )); vec_len = igraph_vector_int_size(&vec); *result = igraph_vcount(graph); seen = IGRAPH_CALLOC(*result, igraph_bool_t); @@ -737,8 +713,8 @@ igraph_error_t igraph_vit_create(const igraph_t *graph, igraph_vs_t vs, igraph_v igraph_vector_int_t vec; igraph_vector_int_t *vec_int; igraph_bool_t *seen; - igraph_integer_t i, j, n; - igraph_integer_t vec_len; + igraph_int_t i, j, n; + igraph_int_t vec_len; switch (vs.type) { case IGRAPH_VS_ALL: @@ -753,7 +729,10 @@ igraph_error_t igraph_vit_create(const igraph_t *graph, igraph_vs_t vs, igraph_v IGRAPH_FINALLY(igraph_free, vec_int); IGRAPH_VECTOR_INT_INIT_FINALLY(vec_int, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&vec, 0); - IGRAPH_CHECK(igraph_neighbors(graph, &vec, vs.data.adj.vid, vs.data.adj.mode)); + IGRAPH_CHECK(igraph_neighbors( + graph, &vec, vs.data.adj.vid, vs.data.adj.mode, + vs.data.adj.loops, vs.data.adj.multiple + )); n = igraph_vector_int_size(&vec); IGRAPH_CHECK(igraph_vector_int_resize(vec_int, n)); for (i = 0; i < n; i++) { @@ -776,7 +755,10 @@ igraph_error_t igraph_vit_create(const igraph_t *graph, igraph_vs_t vs, igraph_v IGRAPH_FINALLY(igraph_free, vec_int); IGRAPH_VECTOR_INT_INIT_FINALLY(vec_int, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&vec, 0); - IGRAPH_CHECK(igraph_neighbors(graph, &vec, vs.data.adj.vid, vs.data.adj.mode)); + IGRAPH_CHECK(igraph_neighbors( + graph, &vec, vs.data.adj.vid, vs.data.adj.mode, + vs.data.adj.loops, vs.data.adj.multiple + )); vec_len = igraph_vector_int_size(&vec); n = igraph_vcount(graph); seen = IGRAPH_CALLOC(n, igraph_bool_t); @@ -833,7 +815,7 @@ igraph_error_t igraph_vit_create(const igraph_t *graph, igraph_vs_t vs, igraph_v break; case IGRAPH_VS_RANGE: { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (vs.data.range.start < 0 || vs.data.range.start > no_of_nodes || (no_of_nodes > 0 && vs.data.range.start == no_of_nodes)) { @@ -884,7 +866,7 @@ void igraph_vit_destroy(const igraph_vit_t *vit) { } igraph_error_t igraph_vit_as_vector(const igraph_vit_t *vit, igraph_vector_int_t *v) { - igraph_integer_t i; + igraph_int_t i; IGRAPH_CHECK(igraph_vector_int_resize(v, IGRAPH_VIT_SIZE(*vit))); @@ -986,17 +968,25 @@ igraph_es_t igraph_ess_all(igraph_edgeorder_type_t order) { * \c IGRAPH_OUT, outgoing edges; * \c IGRAPH_IN, incoming edges; * \c IGRAPH_ALL, all edges. + * \param loops Whether to include loop edges in the result. If + * \c IGRAPH_NO_LOOPS, loop edges are excluded. If \c IGRAPH_LOOPS_ONCE, + * loop edges are included once. If \c IGRAPH_LOOPS_TWICE, loop edges + * are included twice, but only if the graph is undirected or \p mode is + * set to \c IGRAPH_ALL. * \return Error code. * \sa \ref igraph_es_destroy() * * Time complexity: O(1). */ -igraph_error_t igraph_es_incident(igraph_es_t *es, - igraph_integer_t vid, igraph_neimode_t mode) { +igraph_error_t igraph_es_incident( + igraph_es_t *es, igraph_int_t vid, igraph_neimode_t mode, + igraph_loops_t loops +) { es->type = IGRAPH_ES_INCIDENT; es->data.incident.vid = vid; es->data.incident.mode = mode; + es->data.incident.loops = loops; return IGRAPH_SUCCESS; } @@ -1048,7 +1038,7 @@ igraph_es_t igraph_ess_none(void) { * Time complexity: O(1). */ -igraph_error_t igraph_es_1(igraph_es_t *es, igraph_integer_t eid) { +igraph_error_t igraph_es_1(igraph_es_t *es, igraph_int_t eid) { es->type = IGRAPH_ES_1; es->data.eid = eid; return IGRAPH_SUCCESS; @@ -1065,7 +1055,7 @@ igraph_error_t igraph_es_1(igraph_es_t *es, igraph_integer_t eid) { * Time complexity: O(1). */ -igraph_es_t igraph_ess_1(igraph_integer_t eid) { +igraph_es_t igraph_ess_1(igraph_int_t eid) { igraph_es_t es; es.type = IGRAPH_ES_1; es.data.eid = eid; @@ -1171,7 +1161,7 @@ igraph_es_t igraph_ess_vector(const igraph_vector_int_t *v) { * Time complexity: O(1). */ -igraph_error_t igraph_es_range(igraph_es_t *es, igraph_integer_t start, igraph_integer_t end) { +igraph_error_t igraph_es_range(igraph_es_t *es, igraph_int_t start, igraph_int_t end) { *es = igraph_ess_range(start, end); return IGRAPH_SUCCESS; } @@ -1188,7 +1178,7 @@ igraph_error_t igraph_es_range(igraph_es_t *es, igraph_integer_t start, igraph_i * Time complexity: O(1). */ -igraph_es_t igraph_ess_range(igraph_integer_t start, igraph_integer_t end) { +igraph_es_t igraph_ess_range(igraph_int_t start, igraph_int_t end) { igraph_es_t es; es.type = IGRAPH_ES_RANGE; es.data.range.start = start; @@ -1196,47 +1186,6 @@ igraph_es_t igraph_ess_range(igraph_integer_t start, igraph_integer_t end) { return es; } -/** - * \function igraph_es_seq - * \brief Edge selector, a sequence of edge IDs, with inclusive endpoints (deprecated). - * - * All edge IDs between \p from and \p to (inclusive) will be - * included in the edge selection. - * - * \deprecated-by igraph_es_range 0.10.0 - * - * \param es Pointer to an uninitialized edge selector object. - * \param from The first edge ID to be included. - * \param to The last edge ID to be included. - * \return Error code. - * \sa \ref igraph_ess_seq(), \ref igraph_es_destroy() - * - * Time complexity: O(1). - */ - -igraph_error_t igraph_es_seq(igraph_es_t *es, igraph_integer_t from, igraph_integer_t to) { - *es = igraph_ess_range(from, to + 1); - return IGRAPH_SUCCESS; -} - -/** - * \function igraph_ess_seq - * \brief Immediate version of the sequence edge selector, with inclusive endpoints. - * - * \deprecated-by igraph_ess_range 0.10.0 - * - * \param from The first edge ID to include. - * \param to The last edge ID to include. - * \return The initialized edge selector. - * \sa \ref igraph_es_seq() - * - * Time complexity: O(1). - */ - -igraph_es_t igraph_ess_seq(igraph_integer_t from, igraph_integer_t to) { - return igraph_ess_range(from, to + 1); -} - /** * \function igraph_es_pairs * \brief Edge selector, multiple edges defined by their endpoints in a vector. @@ -1306,7 +1255,7 @@ igraph_error_t igraph_es_pairs(igraph_es_t *es, const igraph_vector_int_t *v, igraph_error_t igraph_es_pairs_small(igraph_es_t *es, igraph_bool_t directed, int first, ...) { va_list ap; - igraph_integer_t i, n = 0; + igraph_int_t i, n = 0; igraph_vector_int_t *vec; int num; @@ -1379,7 +1328,7 @@ igraph_error_t igraph_es_path(igraph_es_t *es, const igraph_vector_int_t *v, igraph_error_t igraph_es_path_small(igraph_es_t *es, igraph_bool_t directed, int first, ...) { va_list ap; - igraph_integer_t i, n = 0; + igraph_int_t i, n = 0; igraph_vector_int_t *vec; int num; @@ -1433,7 +1382,7 @@ igraph_error_t igraph_es_path_small(igraph_es_t *es, igraph_bool_t directed, int * Time complexity: O(1). */ igraph_error_t igraph_es_all_between( - igraph_es_t *es, igraph_integer_t from, igraph_integer_t to, + igraph_es_t *es, igraph_int_t from, igraph_int_t to, igraph_bool_t directed ) { es->type = IGRAPH_ES_ALL_BETWEEN; @@ -1573,11 +1522,11 @@ igraph_es_type_t igraph_es_type(const igraph_es_t *es) { } static igraph_error_t igraph_i_es_pairs_size(const igraph_t *graph, - const igraph_es_t *es, igraph_integer_t *result); + const igraph_es_t *es, igraph_int_t *result); static igraph_error_t igraph_i_es_path_size(const igraph_t *graph, - const igraph_es_t *es, igraph_integer_t *result); + const igraph_es_t *es, igraph_int_t *result); static igraph_error_t igraph_i_es_all_between_size(const igraph_t *graph, - const igraph_es_t *es, igraph_integer_t *result); + const igraph_es_t *es, igraph_int_t *result); /** * \function igraph_es_size @@ -1592,7 +1541,7 @@ static igraph_error_t igraph_i_es_all_between_size(const igraph_t *graph, * \return Error code. */ igraph_error_t igraph_es_size(const igraph_t *graph, const igraph_es_t *es, - igraph_integer_t *result) { + igraph_int_t *result) { igraph_vector_int_t v; switch (es->type) { @@ -1610,8 +1559,10 @@ igraph_error_t igraph_es_size(const igraph_t *graph, const igraph_es_t *es, case IGRAPH_ES_INCIDENT: IGRAPH_VECTOR_INT_INIT_FINALLY(&v, 0); - IGRAPH_CHECK(igraph_incident(graph, &v, - es->data.incident.vid, es->data.incident.mode)); + IGRAPH_CHECK(igraph_incident( + graph, &v, es->data.incident.vid, es->data.incident.mode, + es->data.incident.loops + )); *result = igraph_vector_int_size(&v); igraph_vector_int_destroy(&v); IGRAPH_FINALLY_CLEAN(1); @@ -1657,9 +1608,9 @@ igraph_error_t igraph_es_size(const igraph_t *graph, const igraph_es_t *es, } static igraph_error_t igraph_i_es_pairs_size(const igraph_t *graph, - const igraph_es_t *es, igraph_integer_t *result) { - igraph_integer_t i, n = igraph_vector_int_size(es->data.path.ptr); - igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_es_t *es, igraph_int_t *result) { + igraph_int_t i, n = igraph_vector_int_size(es->data.path.ptr); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (n % 2 != 0) { IGRAPH_ERROR("Cannot calculate edge selector length from odd number of vertices.", @@ -1672,9 +1623,9 @@ static igraph_error_t igraph_i_es_pairs_size(const igraph_t *graph, *result = n / 2; /* Check for the existence of all edges */ for (i = 0; i < *result; i++) { - igraph_integer_t from = VECTOR(*es->data.path.ptr)[2 * i]; - igraph_integer_t to = VECTOR(*es->data.path.ptr)[2 * i + 1]; - igraph_integer_t eid; + igraph_int_t from = VECTOR(*es->data.path.ptr)[2 * i]; + igraph_int_t to = VECTOR(*es->data.path.ptr)[2 * i + 1]; + igraph_int_t eid; IGRAPH_CHECK(igraph_get_eid(graph, &eid, from, to, es->data.path.mode, /*error=*/ 1)); } @@ -1683,9 +1634,9 @@ static igraph_error_t igraph_i_es_pairs_size(const igraph_t *graph, } static igraph_error_t igraph_i_es_path_size(const igraph_t *graph, - const igraph_es_t *es, igraph_integer_t *result) { - igraph_integer_t i, n = igraph_vector_int_size(es->data.path.ptr); - igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_es_t *es, igraph_int_t *result) { + igraph_int_t i, n = igraph_vector_int_size(es->data.path.ptr); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (!igraph_vector_int_isininterval(es->data.path.ptr, 0, no_of_nodes - 1)) { IGRAPH_ERROR("Cannot calculate selector length.", IGRAPH_EINVVID); @@ -1697,9 +1648,9 @@ static igraph_error_t igraph_i_es_path_size(const igraph_t *graph, *result = n - 1; } for (i = 0; i < *result; i++) { - igraph_integer_t from = VECTOR(*es->data.path.ptr)[i]; - igraph_integer_t to = VECTOR(*es->data.path.ptr)[i + 1]; - igraph_integer_t eid; + igraph_int_t from = VECTOR(*es->data.path.ptr)[i]; + igraph_int_t to = VECTOR(*es->data.path.ptr)[i + 1]; + igraph_int_t eid; IGRAPH_CHECK(igraph_get_eid(graph, &eid, from, to, es->data.path.mode, /*error=*/ 1)); } @@ -1708,10 +1659,10 @@ static igraph_error_t igraph_i_es_path_size(const igraph_t *graph, } static igraph_error_t igraph_i_es_all_between_size(const igraph_t *graph, - const igraph_es_t *es, igraph_integer_t *result) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t from = es->data.between.from; - igraph_integer_t to = es->data.between.to; + const igraph_es_t *es, igraph_int_t *result) { + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t from = es->data.between.from; + igraph_int_t to = es->data.between.to; igraph_bool_t directed = es->data.between.directed; igraph_vector_int_t vec; @@ -1744,8 +1695,8 @@ static igraph_error_t igraph_i_eit_create_allfromto(const igraph_t *graph, igraph_eit_t *eit, igraph_neimode_t mode) { igraph_vector_int_t *vec; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); vec = IGRAPH_CALLOC(1, igraph_vector_int_t); IGRAPH_CHECK_OOM(vec, "Cannot create edge iterator."); @@ -1757,8 +1708,8 @@ static igraph_error_t igraph_i_eit_create_allfromto(const igraph_t *graph, if (igraph_is_directed(graph)) { igraph_vector_int_t adj; IGRAPH_VECTOR_INT_INIT_FINALLY(&adj, 0); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - IGRAPH_CHECK(igraph_incident(graph, &adj, i, mode)); + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + IGRAPH_CHECK(igraph_incident(graph, &adj, i, mode, IGRAPH_LOOPS)); igraph_vector_int_append(vec, &adj); /* reserved */ } igraph_vector_int_destroy(&adj); @@ -1770,10 +1721,10 @@ static igraph_error_t igraph_i_eit_create_allfromto(const igraph_t *graph, added = IGRAPH_CALLOC(no_of_edges, igraph_bool_t); IGRAPH_CHECK_OOM(added, "Cannot create edge iterator."); IGRAPH_FINALLY(igraph_free, added); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - IGRAPH_CHECK(igraph_incident(graph, &adj, i, IGRAPH_ALL)); - const igraph_integer_t length = igraph_vector_int_size(&adj); - for (igraph_integer_t j = 0; j < length; j++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + IGRAPH_CHECK(igraph_incident(graph, &adj, i, IGRAPH_ALL, IGRAPH_LOOPS)); + const igraph_int_t length = igraph_vector_int_size(&adj); + for (igraph_int_t j = 0; j < length; j++) { if (!added[ VECTOR(adj)[j] ]) { igraph_vector_int_push_back(vec, VECTOR(adj)[j]); /* reserved */ added[ VECTOR(adj)[j] ] = true; @@ -1799,10 +1750,13 @@ static igraph_error_t igraph_i_eit_create_incident(const igraph_t* graph, igraph_es_t es, igraph_eit_t *eit) { igraph_vector_int_t vec; igraph_vector_int_t* vec_int; - igraph_integer_t i, n; + igraph_int_t i, n; IGRAPH_VECTOR_INT_INIT_FINALLY(&vec, 0); - IGRAPH_CHECK(igraph_incident(graph, &vec, es.data.incident.vid, es.data.incident.mode)); + IGRAPH_CHECK(igraph_incident( + graph, &vec, es.data.incident.vid, es.data.incident.mode, + es.data.incident.loops + )); vec_int = IGRAPH_CALLOC(1, igraph_vector_int_t); IGRAPH_CHECK_OOM(vec_int, "Cannot create edge iterator."); @@ -1829,9 +1783,9 @@ static igraph_error_t igraph_i_eit_create_incident(const igraph_t* graph, static igraph_error_t igraph_i_eit_pairs(const igraph_t *graph, igraph_es_t es, igraph_eit_t *eit) { - igraph_integer_t n = igraph_vector_int_size(es.data.path.ptr); - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t i; + igraph_int_t n = igraph_vector_int_size(es.data.path.ptr); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i; igraph_vector_int_t* vec; if (n % 2 != 0) { @@ -1848,9 +1802,9 @@ static igraph_error_t igraph_i_eit_pairs(const igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(vec, n / 2); for (i = 0; i < n / 2; i++) { - igraph_integer_t from = VECTOR(*es.data.path.ptr)[2 * i]; - igraph_integer_t to = VECTOR(*es.data.path.ptr)[2 * i + 1]; - igraph_integer_t eid; + igraph_int_t from = VECTOR(*es.data.path.ptr)[2 * i]; + igraph_int_t to = VECTOR(*es.data.path.ptr)[2 * i + 1]; + igraph_int_t eid; IGRAPH_CHECK(igraph_get_eid(graph, &eid, from, to, es.data.path.mode, /*error=*/ 1)); VECTOR(*vec)[i] = eid; @@ -1869,9 +1823,9 @@ static igraph_error_t igraph_i_eit_pairs(const igraph_t *graph, static igraph_error_t igraph_i_eit_path(const igraph_t *graph, igraph_es_t es, igraph_eit_t *eit) { - igraph_integer_t n = igraph_vector_int_size(es.data.path.ptr); - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t i, len; + igraph_int_t n = igraph_vector_int_size(es.data.path.ptr); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i, len; igraph_vector_int_t* vec; if (!igraph_vector_int_isininterval(es.data.path.ptr, 0, no_of_nodes - 1)) { @@ -1891,9 +1845,9 @@ static igraph_error_t igraph_i_eit_path(const igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(vec, len); for (i = 0; i < len; i++) { - igraph_integer_t from = VECTOR(*es.data.path.ptr)[i]; - igraph_integer_t to = VECTOR(*es.data.path.ptr)[i + 1]; - igraph_integer_t eid; + igraph_int_t from = VECTOR(*es.data.path.ptr)[i]; + igraph_int_t to = VECTOR(*es.data.path.ptr)[i + 1]; + igraph_int_t eid; IGRAPH_CHECK(igraph_get_eid(graph, &eid, from, to, es.data.path.mode, /*error=*/ 1)); VECTOR(*vec)[i] = eid; @@ -1913,10 +1867,10 @@ static igraph_error_t igraph_i_eit_path(const igraph_t *graph, static igraph_error_t igraph_i_eit_all_between( const igraph_t *graph, igraph_es_t es, igraph_eit_t *eit ) { - igraph_integer_t from = es.data.between.from; - igraph_integer_t to = es.data.between.to; + igraph_int_t from = es.data.between.from; + igraph_int_t to = es.data.between.to; igraph_bool_t directed = es.data.between.directed; - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t* vec; if (from < 0 || from >= no_of_nodes || to < 0 || to >= no_of_nodes) { @@ -1994,7 +1948,7 @@ igraph_error_t igraph_eit_create(const igraph_t *graph, igraph_es_t es, igraph_e eit->start = es.data.eid; eit->end = es.data.eid + 1; if (eit->pos >= igraph_ecount(graph)) { - IGRAPH_ERROR("Cannot create iterator, invalid edge ID.", IGRAPH_EINVAL); + IGRAPH_ERROR("Cannot create iterator.", IGRAPH_EINVEID); } break; case IGRAPH_ES_VECTOR: @@ -2005,19 +1959,19 @@ igraph_error_t igraph_eit_create(const igraph_t *graph, igraph_es_t es, igraph_e eit->vec = es.data.vecptr; eit->end = igraph_vector_int_size(eit->vec); if (!igraph_vector_int_isininterval(eit->vec, 0, igraph_ecount(graph) - 1)) { - IGRAPH_ERROR("Cannot create iterator, invalid edge ID.", IGRAPH_EINVAL); + IGRAPH_ERROR("Cannot create iterator.", IGRAPH_EINVEID); } break; case IGRAPH_ES_RANGE: { - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); if (es.data.range.start < 0 || es.data.range.start > no_of_edges || (no_of_edges > 0 && es.data.range.start == no_of_edges)) { - IGRAPH_ERROR("Cannot create range iterator, starting edge ID out of range.", IGRAPH_EINVAL); + IGRAPH_ERROR("Cannot create range iterator, starting edge ID out of range.", IGRAPH_EINVEID); } if (es.data.range.end < 0 || es.data.range.end > no_of_edges) { - IGRAPH_ERROR("Cannot create range iterator, ending edge ID out of range.", IGRAPH_EINVAL); + IGRAPH_ERROR("Cannot create range iterator, ending edge ID out of range.", IGRAPH_EINVEID); } } eit->type = IGRAPH_EIT_RANGE; @@ -2068,7 +2022,7 @@ void igraph_eit_destroy(const igraph_eit_t *eit) { igraph_error_t igraph_eit_as_vector(const igraph_eit_t *eit, igraph_vector_int_t *v) { - igraph_integer_t i; + igraph_int_t i; IGRAPH_CHECK(igraph_vector_int_resize(v, IGRAPH_EIT_SIZE(*eit))); diff --git a/src/vendor/cigraph/src/graph/type_common.c b/src/vendor/cigraph/src/graph/type_common.c index a2d5f47b7d7..44bf27ac903 100644 --- a/src/vendor/cigraph/src/graph/type_common.c +++ b/src/vendor/cigraph/src/graph/type_common.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -62,7 +61,7 @@ * * \example examples/simple/creation.c */ -igraph_error_t igraph_empty(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed) { +igraph_error_t igraph_empty(igraph_t *graph, igraph_int_t n, igraph_bool_t directed) { return igraph_empty_attrs(graph, n, directed, 0); } @@ -90,7 +89,20 @@ igraph_error_t igraph_empty(igraph_t *graph, igraph_integer_t n, igraph_bool_t d * \example examples/simple/igraph_delete_vertices.c */ igraph_error_t igraph_delete_vertices(igraph_t *graph, const igraph_vs_t vertices) { - return igraph_delete_vertices_idx(graph, vertices, /* idx= */ 0, /* invidx= */ 0); + return igraph_delete_vertices_map(graph, vertices, /* idx= */ 0, /* invidx= */ 0); +} + +/** + * \function igraph_delete_vertices_idx + * \brief Removes some vertices (with all their edges) from the graph (deprecated alias). + * + * \deprecated-by igraph_delete_vertices_map 0.11.0 + */ +igraph_error_t igraph_delete_vertices_idx( + igraph_t *graph, const igraph_vs_t vertices, igraph_vector_int_t *idx, + igraph_vector_int_t *invidx +) { + return igraph_delete_vertices_map(graph, vertices, idx, invidx); } /** @@ -99,9 +111,9 @@ igraph_error_t igraph_delete_vertices(igraph_t *graph, const igraph_vs_t vertice * * \param graph The graph object. * \param eid The edge ID. - * \param from Pointer to an \type igraph_integer_t. The tail (source) of + * \param from Pointer to an \type igraph_int_t. The tail (source) of * the edge will be placed here. - * \param to Pointer to an \type igraph_integer_t. The head (target) of the + * \param to Pointer to an \type igraph_int_t. The head (target) of the * edge will be placed here. * \return Error code. * @@ -115,12 +127,12 @@ igraph_error_t igraph_delete_vertices(igraph_t *graph, const igraph_vs_t vertice * Time complexity: O(1). */ igraph_error_t igraph_edge( - const igraph_t *graph, igraph_integer_t eid, - igraph_integer_t *from, igraph_integer_t *to + const igraph_t *graph, igraph_int_t eid, + igraph_int_t *from, igraph_int_t *to ) { if (eid < 0 || eid >= igraph_ecount(graph)) { - IGRAPH_ERROR("Invalid edge ID when retrieving edge endpoints.", IGRAPH_EINVAL); + IGRAPH_ERROR("Cannot retrieve edge endpoints.", IGRAPH_EINVEID); } if (igraph_is_directed(graph)) { @@ -142,35 +154,59 @@ igraph_error_t igraph_edge( * \param eids Edge selector, the series of edges. * \param edges Pointer to an initialized vector. The start and endpoints of * each edge will be placed here. + * \param bycol Boolean constant. If true, the edges will be returned + * columnwise, e.g. the first edge is + * res[0]->res[|E|], the second is + * res[1]->res[|E|+1], etc. Supply false to get + * the edge list in a format compatible with \ref igraph_add_edges(). * \return Error code. - * \sa \ref igraph_get_edgelist() to get the endpoints of all edges; - * \ref igraph_get_eids() for the opposite operation; + * \sa \ref igraph_get_eids() for the opposite operation; * \ref igraph_edge() for getting the endpoints of a single edge; * \ref IGRAPH_TO(), \ref IGRAPH_FROM() and \ref IGRAPH_OTHER() for * a faster but non-error-checked method. * * Time complexity: O(k) where k is the number of edges in the selector. */ -igraph_error_t igraph_edges(const igraph_t *graph, igraph_es_t eids, igraph_vector_int_t *edges) { +igraph_error_t igraph_edges( + const igraph_t *graph, igraph_es_t eids, igraph_vector_int_t *edges, + igraph_bool_t bycol +) { igraph_eit_t eit; - igraph_integer_t n, ptr = 0; + igraph_int_t n, ptr = 0, ptr2; IGRAPH_CHECK(igraph_eit_create(graph, eids, &eit)); IGRAPH_FINALLY(igraph_eit_destroy, &eit); n = IGRAPH_EIT_SIZE(eit); IGRAPH_CHECK(igraph_vector_int_resize(edges, n * 2)); - if (igraph_is_directed(graph)) { - for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t e = IGRAPH_EIT_GET(eit); - VECTOR(*edges)[ptr++] = IGRAPH_FROM(graph, e); - VECTOR(*edges)[ptr++] = IGRAPH_TO(graph, e); + if (bycol) { + ptr2 = n; + if (igraph_is_directed(graph)) { + for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { + igraph_int_t e = IGRAPH_EIT_GET(eit); + VECTOR(*edges)[ptr++] = IGRAPH_FROM(graph, e); + VECTOR(*edges)[ptr2++] = IGRAPH_TO(graph, e); + } + } else { + for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { + igraph_int_t e = IGRAPH_EIT_GET(eit); + VECTOR(*edges)[ptr++] = IGRAPH_TO(graph, e); + VECTOR(*edges)[ptr2++] = IGRAPH_FROM(graph, e); + } } } else { - for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t e = IGRAPH_EIT_GET(eit); - VECTOR(*edges)[ptr++] = IGRAPH_TO(graph, e); - VECTOR(*edges)[ptr++] = IGRAPH_FROM(graph, e); + if (igraph_is_directed(graph)) { + for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { + igraph_int_t e = IGRAPH_EIT_GET(eit); + VECTOR(*edges)[ptr++] = IGRAPH_FROM(graph, e); + VECTOR(*edges)[ptr++] = IGRAPH_TO(graph, e); + } + } else { + for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { + igraph_int_t e = IGRAPH_EIT_GET(eit); + VECTOR(*edges)[ptr++] = IGRAPH_TO(graph, e); + VECTOR(*edges)[ptr++] = IGRAPH_FROM(graph, e); + } } } diff --git a/src/vendor/cigraph/src/graph/type_indexededgelist.c b/src/vendor/cigraph/src/graph/type_indexededgelist.c index 5421e9c69f3..b8c42070ccc 100644 --- a/src/vendor/cigraph/src/graph/type_indexededgelist.c +++ b/src/vendor/cigraph/src/graph/type_indexededgelist.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team 334 Harvard street, Cambridge, MA 02139 USA @@ -34,7 +33,7 @@ static igraph_error_t igraph_i_create_start_vectors( igraph_vector_int_t *res, igraph_vector_int_t *el, - igraph_vector_int_t *index, igraph_integer_t nodes); + igraph_vector_int_t *index, igraph_int_t nodes); /** * \section about_basic_interface @@ -95,12 +94,17 @@ static igraph_error_t igraph_i_create_start_vectors( * Time complexity: O(|V|) for a graph with * |V| vertices (and no edges). */ -igraph_error_t igraph_empty_attrs(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, void *attr) { +igraph_error_t igraph_empty_attrs( + igraph_t *graph, igraph_int_t n, igraph_bool_t directed, + const igraph_attribute_record_list_t *attr +) { if (n < 0) { IGRAPH_ERROR("Number of vertices must not be negative.", IGRAPH_EINVAL); } + memset(graph, 0, sizeof(igraph_t)); + graph->n = 0; graph->directed = directed; IGRAPH_VECTOR_INT_INIT_FINALLY(&graph->from, 0); @@ -121,7 +125,6 @@ igraph_error_t igraph_empty_attrs(igraph_t *graph, igraph_integer_t n, igraph_bo VECTOR(graph->is)[0] = 0; /* init attributes */ - graph->attr = 0; IGRAPH_CHECK(igraph_i_attribute_init(graph, attr)); /* add the vertices */ @@ -148,8 +151,7 @@ igraph_error_t igraph_empty_attrs(igraph_t *graph, igraph_integer_t n, igraph_bo * Time complexity: operating system specific. */ void igraph_destroy(igraph_t *graph) { - - IGRAPH_I_ATTRIBUTE_DESTROY(graph); + igraph_i_attribute_destroy(graph); igraph_i_property_cache_destroy(graph->cache); IGRAPH_FREE(graph->cache); @@ -189,6 +191,8 @@ void igraph_destroy(igraph_t *graph) { */ igraph_error_t igraph_copy(igraph_t *to, const igraph_t *from) { + memset(to, 0, sizeof(igraph_t)); + to->n = from->n; to->directed = from->directed; IGRAPH_CHECK(igraph_vector_int_init_copy(&to->from, &from->from)); @@ -210,7 +214,7 @@ igraph_error_t igraph_copy(igraph_t *to, const igraph_t *from) { IGRAPH_CHECK(igraph_i_property_cache_copy(to->cache, from->cache)); IGRAPH_FINALLY(igraph_i_property_cache_destroy, to->cache); - IGRAPH_I_ATTRIBUTE_COPY(to, from, true, true, true); /* does IGRAPH_CHECK */ + IGRAPH_CHECK(igraph_i_attribute_copy(to, from, true, true, true)); IGRAPH_FINALLY_CLEAN(8); return IGRAPH_SUCCESS; @@ -234,7 +238,7 @@ igraph_error_t igraph_copy(igraph_t *to, const igraph_t *from) { * \param attr The attributes of the new edges. You can supply a null pointer * here if you do not need edge attributes. * \return Error code: - * \c IGRAPH_EINVEVECTOR: invalid (odd) edges vector length, + * \c IGRAPH_EINVAL: invalid (odd) edges vector length, * \c IGRAPH_EINVVID: invalid vertex ID in edges vector. * * This function invalidates all iterators. @@ -245,17 +249,19 @@ igraph_error_t igraph_copy(igraph_t *to, const igraph_t *from) { * * \example examples/simple/creation.c */ -igraph_error_t igraph_add_edges(igraph_t *graph, const igraph_vector_int_t *edges, - void *attr) { - igraph_integer_t no_of_edges = igraph_vector_int_size(&graph->from); - igraph_integer_t edges_to_add = igraph_vector_int_size(edges) / 2; - igraph_integer_t new_no_of_edges; - igraph_integer_t i = 0; +igraph_error_t igraph_add_edges( + igraph_t *graph, const igraph_vector_int_t *edges, + const igraph_attribute_record_list_t *attr +) { + igraph_int_t no_of_edges = igraph_vector_int_size(&graph->from); + igraph_int_t edges_to_add = igraph_vector_int_size(edges) / 2; + igraph_int_t new_no_of_edges; + igraph_int_t i = 0; igraph_vector_int_t newoi, newii; igraph_bool_t directed = igraph_is_directed(graph); if (igraph_vector_int_size(edges) % 2 != 0) { - IGRAPH_ERROR("Invalid (odd) length of edges vector.", IGRAPH_EINVEVECTOR); + IGRAPH_ERROR("Invalid (odd) length of edges vector.", IGRAPH_EINVAL); } if (!igraph_vector_int_isininterval(edges, 0, igraph_vcount(graph) - 1)) { IGRAPH_ERROR("Out-of-range vertex IDs when adding edges.", IGRAPH_EINVVID); @@ -378,11 +384,13 @@ igraph_error_t igraph_add_edges(igraph_t *graph, const igraph_vector_int_t *edge * * \example examples/simple/creation.c */ -igraph_error_t igraph_add_vertices(igraph_t *graph, igraph_integer_t nv, void *attr) { - igraph_integer_t ec = igraph_ecount(graph); - igraph_integer_t vc = igraph_vcount(graph); - igraph_integer_t new_vc; - igraph_integer_t i; +igraph_error_t igraph_add_vertices( + igraph_t *graph, igraph_int_t nv, const igraph_attribute_record_list_t *attr +) { + igraph_int_t ec = igraph_ecount(graph); + igraph_int_t vc = igraph_vcount(graph); + igraph_int_t new_vc; + igraph_int_t i; if (nv < 0) { IGRAPH_ERROR("Cannot add negative number of vertices.", IGRAPH_EINVAL); @@ -407,7 +415,7 @@ igraph_error_t igraph_add_vertices(igraph_t *graph, igraph_integer_t nv, void *a /* Add attributes if necessary. This section is protected with * FINALLY_ENTER/EXIT so that the graph would not be accidentally - * free upon error until it could be restored to a consistant state. */ + * free upon error until it could be restored to a consistent state. */ if (graph->attr) { igraph_error_t err; @@ -488,17 +496,17 @@ igraph_error_t igraph_add_vertices(igraph_t *graph, igraph_integer_t nv, void *a * \example examples/simple/igraph_delete_edges.c */ igraph_error_t igraph_delete_edges(igraph_t *graph, igraph_es_t edges) { - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t edges_to_remove = 0; - igraph_integer_t remaining_edges; + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t edges_to_remove = 0; + igraph_int_t remaining_edges; igraph_eit_t eit; igraph_vector_int_t newfrom, newto; igraph_vector_int_t newoi, newii; igraph_bool_t *mark; - igraph_integer_t i, j; + igraph_int_t i, j; mark = IGRAPH_CALLOC(no_of_edges, igraph_bool_t); IGRAPH_CHECK_OOM(mark, "Cannot delete edges."); @@ -508,7 +516,7 @@ igraph_error_t igraph_delete_edges(igraph_t *graph, igraph_es_t edges) { IGRAPH_FINALLY(igraph_eit_destroy, &eit); for (IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t e = IGRAPH_EIT_GET(eit); + igraph_int_t e = IGRAPH_EIT_GET(eit); if (! mark[e]) { edges_to_remove++; mark[e] = true; @@ -605,14 +613,14 @@ igraph_error_t igraph_delete_edges(igraph_t *graph, igraph_es_t edges) { /** * \ingroup interface - * \function igraph_delete_vertices_idx + * \function igraph_delete_vertices_map * \brief Removes some vertices (with all their edges) from the graph. * * * This function changes the IDs of the vertices (except in some very * special cases, but these should not be relied on anyway). You can use the - * \c idx argument to obtain the mapping from old vertex IDs to the new ones, - * and the \c newidx argument to obtain the reverse mapping. + * \p map argument to obtain the mapping from old vertex IDs to the new ones, + * and the \p newmap argument to obtain the reverse mapping. * * * This function invalidates all iterators. @@ -620,12 +628,10 @@ igraph_error_t igraph_delete_edges(igraph_t *graph, igraph_es_t edges) { * \param graph The graph to work on. * \param vertices The IDs of the vertices to remove, in a vector. The vector * may contain the same ID more than once. - * \param idx An optional pointer to a vector that provides the mapping from + * \param map An optional pointer to a vector that provides the mapping from * the vertex IDs \em before the removal to the vertex IDs \em after - * the removal, \em plus one. Zero is used to represent vertices that were - * removed during the operation. You can supply \c NULL here if you are not - * interested. - * \param invidx An optional pointer to a vector that provides the mapping from + * the removal. You can supply \c NULL here if you are not interested. + * \param invmap An optional pointer to a vector that provides the mapping from * the vertex IDs \em after the removal to the vertex IDs \em before * the removal. You can supply \c NULL here if you are not interested. * \return Error code: @@ -633,26 +639,24 @@ igraph_error_t igraph_delete_edges(igraph_t *graph, igraph_es_t edges) { * * Time complexity: O(|V|+|E|), |V| and |E| are the number of vertices and * edges in the original graph. - * - * \example examples/simple/igraph_delete_vertices.c */ -igraph_error_t igraph_delete_vertices_idx( - igraph_t *graph, const igraph_vs_t vertices, igraph_vector_int_t *idx, - igraph_vector_int_t *invidx +igraph_error_t igraph_delete_vertices_map( + igraph_t *graph, const igraph_vs_t vertices, igraph_vector_int_t *map, + igraph_vector_int_t *invmap ) { - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t edge_recoding, vertex_recoding; igraph_vector_int_t *my_vertex_recoding = &vertex_recoding; igraph_vit_t vit; igraph_t newgraph; - igraph_integer_t i, j; - igraph_integer_t remaining_vertices, remaining_edges; + igraph_int_t i, j; + igraph_int_t remaining_vertices, remaining_edges; - if (idx) { - my_vertex_recoding = idx; - IGRAPH_CHECK(igraph_vector_int_resize(idx, no_of_nodes)); - igraph_vector_int_null(idx); + if (map) { + my_vertex_recoding = map; + IGRAPH_CHECK(igraph_vector_int_resize(map, no_of_nodes)); + igraph_vector_int_null(map); } else { IGRAPH_VECTOR_INT_INIT_FINALLY(&vertex_recoding, no_of_nodes); } @@ -664,33 +668,34 @@ igraph_error_t igraph_delete_vertices_idx( /* mark the vertices to delete */ for (; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit) ) { - igraph_integer_t vertex = IGRAPH_VIT_GET(vit); + igraph_int_t vertex = IGRAPH_VIT_GET(vit); if (vertex < 0 || vertex >= no_of_nodes) { - IGRAPH_ERROR("Cannot delete vertices", IGRAPH_EINVVID); + IGRAPH_ERROR("Cannot delete vertices.", IGRAPH_EINVVID); } VECTOR(*my_vertex_recoding)[vertex] = 1; } /* create vertex recoding vector */ for (remaining_vertices = 0, i = 0; i < no_of_nodes; i++) { if (VECTOR(*my_vertex_recoding)[i] == 0) { - VECTOR(*my_vertex_recoding)[i] = remaining_vertices + 1; + VECTOR(*my_vertex_recoding)[i] = remaining_vertices; remaining_vertices++; } else { - VECTOR(*my_vertex_recoding)[i] = 0; + VECTOR(*my_vertex_recoding)[i] = -1; } } /* create edge recoding vector */ for (remaining_edges = 0, i = 0; i < no_of_edges; i++) { - igraph_integer_t from = VECTOR(graph->from)[i]; - igraph_integer_t to = VECTOR(graph->to)[i]; - if (VECTOR(*my_vertex_recoding)[from] != 0 && - VECTOR(*my_vertex_recoding)[to ] != 0) { + igraph_int_t from = VECTOR(graph->from)[i]; + igraph_int_t to = VECTOR(graph->to)[i]; + if (VECTOR(*my_vertex_recoding)[from] >= 0 && + VECTOR(*my_vertex_recoding)[to ] >= 0) { VECTOR(edge_recoding)[i] = remaining_edges + 1; remaining_edges++; } } /* start creating the graph */ + memset(&newgraph, 0, sizeof(igraph_t)); newgraph.n = remaining_vertices; newgraph.directed = graph->directed; @@ -705,10 +710,10 @@ igraph_error_t igraph_delete_vertices_idx( /* Add the edges */ for (i = 0, j = 0; j < remaining_edges; i++) { if (VECTOR(edge_recoding)[i] > 0) { - igraph_integer_t from = VECTOR(graph->from)[i]; - igraph_integer_t to = VECTOR(graph->to )[i]; - VECTOR(newgraph.from)[j] = VECTOR(*my_vertex_recoding)[from] - 1; - VECTOR(newgraph.to )[j] = VECTOR(*my_vertex_recoding)[to] - 1; + igraph_int_t from = VECTOR(graph->from)[i]; + igraph_int_t to = VECTOR(graph->to )[i]; + VECTOR(newgraph.from)[j] = VECTOR(*my_vertex_recoding)[from]; + VECTOR(newgraph.to )[j] = VECTOR(*my_vertex_recoding)[to]; j++; } } @@ -731,8 +736,9 @@ igraph_error_t igraph_delete_vertices_idx( IGRAPH_FINALLY(igraph_i_property_cache_destroy, newgraph.cache); /* attributes */ - IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, - /*graph=*/ 1, /*vertex=*/0, /*edge=*/0); + IGRAPH_CHECK(igraph_i_attribute_copy( + &newgraph, graph, /* graph= */ true, /* vertex= */ false, /* edge= */ false + )); /* at this point igraph_destroy can take over the responsibility of * deallocating the graph */ @@ -743,17 +749,15 @@ igraph_error_t igraph_delete_vertices_idx( igraph_vector_int_t iidx; IGRAPH_VECTOR_INT_INIT_FINALLY(&iidx, remaining_vertices); for (i = 0; i < no_of_nodes; i++) { - igraph_integer_t jj = VECTOR(*my_vertex_recoding)[i]; - if (jj != 0) { - VECTOR(iidx)[ jj - 1 ] = i; + igraph_int_t jj = VECTOR(*my_vertex_recoding)[i]; + if (jj >= 0) { + VECTOR(iidx)[ jj ] = i; } } - IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, - &newgraph, - &iidx)); + IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, &newgraph, &iidx)); IGRAPH_CHECK(igraph_vector_int_resize(&iidx, remaining_edges)); for (i = 0; i < no_of_edges; i++) { - igraph_integer_t jj = VECTOR(edge_recoding)[i]; + igraph_int_t jj = VECTOR(edge_recoding)[i]; if (jj != 0) { VECTOR(iidx)[ jj - 1 ] = i; } @@ -770,18 +774,17 @@ igraph_error_t igraph_delete_vertices_idx( IGRAPH_FINALLY_CLEAN(3); - /* TODO: this is duplicate */ - if (invidx) { - IGRAPH_CHECK(igraph_vector_int_resize(invidx, remaining_vertices)); + if (invmap) { + IGRAPH_CHECK(igraph_vector_int_resize(invmap, remaining_vertices)); for (i = 0; i < no_of_nodes; i++) { - igraph_integer_t newid = VECTOR(*my_vertex_recoding)[i]; - if (newid != 0) { - VECTOR(*invidx)[newid - 1] = i; + igraph_int_t newid = VECTOR(*my_vertex_recoding)[i]; + if (newid >= 0) { + VECTOR(*invmap)[newid] = i; } } } - if (!idx) { + if (!map) { igraph_vector_int_destroy(my_vertex_recoding); IGRAPH_FINALLY_CLEAN(1); } @@ -821,7 +824,7 @@ igraph_error_t igraph_delete_vertices_idx( * * Time complexity: O(1) */ -igraph_integer_t igraph_vcount(const igraph_t *graph) { +igraph_int_t igraph_vcount(const igraph_t *graph) { return graph->n; } @@ -835,7 +838,7 @@ igraph_integer_t igraph_vcount(const igraph_t *graph) { * * Time complexity: O(1) */ -igraph_integer_t igraph_ecount(const igraph_t *graph) { +igraph_int_t igraph_ecount(const igraph_t *graph) { return igraph_vector_int_size(&graph->from); } @@ -861,28 +864,32 @@ igraph_integer_t igraph_ecount(const igraph_t *graph) { * \c IGRAPH_ALL, both kinds of vertices are * searched. * This parameter is ignored for undirected graphs. + * \param loops Specifies how to treat loop edges. \c IGRAPH_NO_LOOPS + * removes loop edges from the result. \c IGRAPH_LOOPS_ONCE + * makes each loop edge appear only once in the result. + * \c IGRAPH_LOOPS_TWICE makes loop edges appear \em twice in the + * result if the graph is undirected or \p mode is set to \c IGRAPH_ALL + * (and once otherwise as returning them twice does not make sense for + * directed graphs). + * \param multiple Specifies how to treat multiple (parallel) edges. + * \c IGRAPH_NO_MULTIPLE collapses parallel edges into a single one; + * \c IGRAPH_MULTIPLE keeps the multiplicities of parallel edges + * so the same neighbor will appear as many times in the result as the + * number of parallel edges going between the two vertices. * \return Error code: * \c IGRAPH_EINVVID: invalid vertex ID. * \c IGRAPH_EINVMODE: invalid mode argument. * \c IGRAPH_ENOMEM: not enough memory. * - * Time complexity: O(d), - * d is the number - * of adjacent vertices to the queried vertex. + * Time complexity: O(d), d is the number of adjacent vertices to the queried + * vertex. * * \example examples/simple/igraph_neighbors.c */ -igraph_error_t igraph_neighbors(const igraph_t *graph, igraph_vector_int_t *neis, igraph_integer_t pnode, - igraph_neimode_t mode) { - if (!igraph_is_directed(graph) || mode == IGRAPH_ALL) { - return igraph_i_neighbors(graph, neis, pnode, mode, IGRAPH_LOOPS_TWICE, IGRAPH_MULTIPLE); - } else { - return igraph_i_neighbors(graph, neis, pnode, mode, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE); - } -} - -igraph_error_t igraph_i_neighbors(const igraph_t *graph, igraph_vector_int_t *neis, igraph_integer_t pnode, - igraph_neimode_t mode, igraph_loops_t loops, igraph_multiple_t multiple) { +igraph_error_t igraph_neighbors( + const igraph_t *graph, igraph_vector_int_t *neis, igraph_int_t pnode, + igraph_neimode_t mode, igraph_loops_t loops, igraph_bool_t multiple +) { #define DEDUPLICATE_IF_NEEDED(vertex, n) \ if (should_filter_duplicates) { \ if (vertex == pnode) { \ @@ -918,11 +925,11 @@ igraph_error_t igraph_i_neighbors(const igraph_t *graph, igraph_vector_int_t *ne } - igraph_integer_t length = 0, idx = 0; - igraph_integer_t i, j; + igraph_int_t length = 0, idx = 0; + igraph_int_t i, j; - igraph_integer_t node = pnode; - igraph_integer_t last_added = -1; + igraph_int_t node = pnode; + igraph_int_t last_added = -1; igraph_bool_t should_filter_duplicates; /* seen_loop stores whether we have already seen at least one full loop @@ -944,8 +951,11 @@ igraph_error_t igraph_i_neighbors(const igraph_t *graph, igraph_vector_int_t *ne } if (mode != IGRAPH_ALL && loops == IGRAPH_LOOPS_TWICE) { + /* IGRAPH_ERROR("For a directed graph (with directions not ignored), " "IGRAPH_LOOPS_TWICE does not make sense.", IGRAPH_EINVAL); + */ + loops = IGRAPH_LOOPS_ONCE; } /* Calculate needed space first & allocate it */ @@ -980,7 +990,7 @@ igraph_error_t igraph_i_neighbors(const igraph_t *graph, igraph_vector_int_t *ne if (mode & IGRAPH_OUT) { j = VECTOR(graph->os)[node + 1]; for (i = VECTOR(graph->os)[node]; i < j; i++) { - igraph_integer_t to = VECTOR(graph->to)[ VECTOR(graph->oi)[i] ]; + igraph_int_t to = VECTOR(graph->to)[ VECTOR(graph->oi)[i] ]; DEDUPLICATE_IF_NEEDED(to, 1); VECTOR(*neis)[idx++] = to; } @@ -989,7 +999,7 @@ igraph_error_t igraph_i_neighbors(const igraph_t *graph, igraph_vector_int_t *ne if (mode & IGRAPH_IN) { j = VECTOR(graph->is)[node + 1]; for (i = VECTOR(graph->is)[node]; i < j; i++) { - igraph_integer_t from = VECTOR(graph->from)[ VECTOR(graph->ii)[i] ]; + igraph_int_t from = VECTOR(graph->from)[ VECTOR(graph->ii)[i] ]; DEDUPLICATE_IF_NEEDED(from, 1); VECTOR(*neis)[idx++] = from; } @@ -998,12 +1008,12 @@ igraph_error_t igraph_i_neighbors(const igraph_t *graph, igraph_vector_int_t *ne /* Both in- and out- neighbors in a directed graph, we need to merge the two 'vectors' so the result is correctly ordered. */ - igraph_integer_t j1 = VECTOR(graph->os)[node + 1]; - igraph_integer_t j2 = VECTOR(graph->is)[node + 1]; - igraph_integer_t i1 = VECTOR(graph->os)[node]; - igraph_integer_t i2 = VECTOR(graph->is)[node]; - igraph_integer_t eid1, eid2; - igraph_integer_t n1, n2; + igraph_int_t j1 = VECTOR(graph->os)[node + 1]; + igraph_int_t j2 = VECTOR(graph->is)[node + 1]; + igraph_int_t i1 = VECTOR(graph->os)[node]; + igraph_int_t i2 = VECTOR(graph->is)[node]; + igraph_int_t eid1, eid2; + igraph_int_t n1, n2; should_filter_duplicates = !(multiple == IGRAPH_MULTIPLE && loops == IGRAPH_LOOPS_TWICE); @@ -1033,14 +1043,14 @@ igraph_error_t igraph_i_neighbors(const igraph_t *graph, igraph_vector_int_t *ne while (i1 < j1) { eid1 = VECTOR(graph->oi)[i1++]; - igraph_integer_t to = VECTOR(graph->to)[eid1]; + igraph_int_t to = VECTOR(graph->to)[eid1]; DEDUPLICATE_IF_NEEDED(to, 1); VECTOR(*neis)[idx++] = to; } while (i2 < j2) { eid2 = VECTOR(graph->ii)[i2++]; - igraph_integer_t from = VECTOR(graph->from)[eid2]; + igraph_int_t from = VECTOR(graph->from)[eid2]; DEDUPLICATE_IF_NEEDED(from, 1); VECTOR(*neis)[idx++] = from; } @@ -1058,13 +1068,13 @@ igraph_error_t igraph_i_neighbors(const igraph_t *graph, igraph_vector_int_t *ne static igraph_error_t igraph_i_create_start_vectors( igraph_vector_int_t *res, igraph_vector_int_t *el, - igraph_vector_int_t *iindex, igraph_integer_t nodes) { + igraph_vector_int_t *iindex, igraph_int_t nodes) { # define EDGE(i) (VECTOR(*el)[ VECTOR(*iindex)[(i)] ]) - igraph_integer_t no_of_nodes; - igraph_integer_t no_of_edges; - igraph_integer_t i, j, idx; + igraph_int_t no_of_nodes; + igraph_int_t no_of_edges; + igraph_int_t i, j, idx; no_of_nodes = nodes; no_of_edges = igraph_vector_int_size(el); @@ -1084,7 +1094,7 @@ static igraph_error_t igraph_i_create_start_vectors( idx++; VECTOR(*res)[idx] = 0; } for (i = 1; i < no_of_edges; i++) { - igraph_integer_t n = EDGE(i) - EDGE(VECTOR(*res)[idx]); + igraph_int_t n = EDGE(i) - EDGE(VECTOR(*res)[idx]); for (j = 0; j < n; j++) { idx++; VECTOR(*res)[idx] = i; } @@ -1144,13 +1154,25 @@ igraph_bool_t igraph_is_directed(const igraph_t *graph) { * Time complexity: O(1) if \p loops is \c true, and * O(d) otherwise, where d is the degree. */ -igraph_error_t igraph_degree_1(const igraph_t *graph, igraph_integer_t *deg, - igraph_integer_t vid, igraph_neimode_t mode, igraph_bool_t loops) { +igraph_error_t igraph_degree_1( + const igraph_t *graph, igraph_int_t *deg, igraph_int_t vid, + igraph_neimode_t mode, igraph_loops_t loops +) { + igraph_int_t loop_counter; if (!igraph_is_directed(graph)) { mode = IGRAPH_ALL; } + if (loops != IGRAPH_NO_LOOPS && loops != IGRAPH_LOOPS_ONCE && + loops != IGRAPH_LOOPS_TWICE) { + IGRAPH_ERROR("Invalid loops argument.", IGRAPH_EINVAL); + } + + if (loops == IGRAPH_LOOPS_ONCE && (mode & IGRAPH_ALL) != IGRAPH_ALL) { + loops = IGRAPH_LOOPS_TWICE; + } + *deg = 0; if (mode & IGRAPH_OUT) { *deg += (VECTOR(graph->os)[vid + 1] - VECTOR(graph->os)[vid]); @@ -1158,23 +1180,32 @@ igraph_error_t igraph_degree_1(const igraph_t *graph, igraph_integer_t *deg, if (mode & IGRAPH_IN) { *deg += (VECTOR(graph->is)[vid + 1] - VECTOR(graph->is)[vid]); } - if (! loops) { + + if (loops != IGRAPH_LOOPS_TWICE) { /* When loops should not be counted, we remove their contribution from the * previously computed degree. */ + loop_counter = 0; if (mode & IGRAPH_OUT) { - for (igraph_integer_t i = VECTOR(graph->os)[vid]; i < VECTOR(graph->os)[vid + 1]; i++) { + for (igraph_int_t i = VECTOR(graph->os)[vid]; i < VECTOR(graph->os)[vid + 1]; i++) { if (VECTOR(graph->to)[ VECTOR(graph->oi)[i] ] == vid) { - *deg -= 1; + loop_counter++; } } } if (mode & IGRAPH_IN) { - for (igraph_integer_t i = VECTOR(graph->is)[vid]; i < VECTOR(graph->is)[vid + 1]; i++) { + for (igraph_int_t i = VECTOR(graph->is)[vid]; i < VECTOR(graph->is)[vid + 1]; i++) { if (VECTOR(graph->from)[ VECTOR(graph->ii)[i] ] == vid) { - *deg -= 1; + loop_counter++; } } } + + if (loops == IGRAPH_NO_LOOPS || mode != IGRAPH_ALL) { + *deg -= loop_counter; + } else { + /* loops == IGRAPH_LOOPS_ONCE && mode == IGRAPH_ALL */ + *deg -= loop_counter / 2; + } } return IGRAPH_SUCCESS; @@ -1190,7 +1221,7 @@ igraph_error_t igraph_degree_1(const igraph_t *graph, igraph_integer_t *deg, * specified vertices. * * - * This function returns the result as a vector of \c igraph_integer_t + * This function returns the result as a vector of \c igraph_int_t * values. In applications where \c igraph_real_t is desired, use * \ref igraph_strength() with \c NULL weights. * @@ -1205,8 +1236,11 @@ igraph_error_t igraph_degree_1(const igraph_t *graph, igraph_integer_t *deg, * \c IGRAPH_ALL, total degree (sum of the * in- and out-degree). * This parameter is ignored for undirected graphs. - * \param loops Boolean, gives whether the self-loops should be - * counted. + * \param loops Constant of type \ref igraph_loops_t, specifies how to treat + * loop edges when calculating the degree. \c IGRAPH_NO_LOOPS ignores + * loop edges; \c IGRAPH_LOOPS_ONCE counts each loop edge only once; + * \c IGRAPH_LOOPS_TWICE counts each loop edge twice in undirected + * graphs and once in directed graphs. * \return Error code: * \c IGRAPH_EINVVID: invalid vertex ID. * \c IGRAPH_EINVMODE: invalid mode argument. @@ -1223,12 +1257,13 @@ igraph_error_t igraph_degree_1(const igraph_t *graph, igraph_integer_t *deg, * * \example examples/simple/igraph_degree.c */ -igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res, - const igraph_vs_t vids, - igraph_neimode_t mode, igraph_bool_t loops) { +igraph_error_t igraph_degree( + const igraph_t *graph, igraph_vector_int_t *res, const igraph_vs_t vids, + igraph_neimode_t mode, igraph_loops_t loops +) { - igraph_integer_t nodes_to_calc; - igraph_integer_t i, j; + igraph_int_t nodes_to_calc; + igraph_int_t i, j; igraph_vit_t vit; IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); @@ -1238,15 +1273,21 @@ igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res, IGRAPH_ERROR("Invalid mode for degree calculation.", IGRAPH_EINVMODE); } - if (! loops) { + if (loops == IGRAPH_NO_LOOPS || loops == IGRAPH_LOOPS_ONCE) { /* If the graph is known not to have loops, we can use the faster - * loops == true code path, which has O(1) complexity instead of of O(d). */ + * loops == IGRAPH_LOOPS_TWICE code path, which has O(1) complexity + * instead of of O(d). */ if (igraph_i_property_cache_has(graph, IGRAPH_PROP_HAS_LOOP) && !igraph_i_property_cache_get_bool(graph, IGRAPH_PROP_HAS_LOOP)) { - loops = true; + loops = IGRAPH_LOOPS_TWICE; } } + if (loops == IGRAPH_LOOPS_ONCE && mode != IGRAPH_ALL) { + /* We can use the faster loops == IGRAPH_LOOPS_TWICE path again */ + loops = IGRAPH_LOOPS_TWICE; + } + nodes_to_calc = IGRAPH_VIT_SIZE(vit); if (!igraph_is_directed(graph)) { mode = IGRAPH_ALL; @@ -1255,12 +1296,12 @@ igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res, IGRAPH_CHECK(igraph_vector_int_resize(res, nodes_to_calc)); igraph_vector_int_null(res); - if (loops) { + if (loops == IGRAPH_LOOPS_TWICE) { if (mode & IGRAPH_OUT) { for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t vid = IGRAPH_VIT_GET(vit); + igraph_int_t vid = IGRAPH_VIT_GET(vit); VECTOR(*res)[i] += (VECTOR(graph->os)[vid + 1] - VECTOR(graph->os)[vid]); } } @@ -1268,60 +1309,109 @@ igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res, for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t vid = IGRAPH_VIT_GET(vit); + igraph_int_t vid = IGRAPH_VIT_GET(vit); VECTOR(*res)[i] += (VECTOR(graph->is)[vid + 1] - VECTOR(graph->is)[vid]); } } - } else if (igraph_vs_is_all(&vids)) { /* no loops, calculating degree for all vertices */ - // When calculating degree for all vertices, iterating over edges is faster - igraph_integer_t no_of_edges = igraph_ecount(graph); + } else if (loops == IGRAPH_LOOPS_ONCE) { + IGRAPH_ASSERT((mode & IGRAPH_ALL) == IGRAPH_ALL); - if (mode & IGRAPH_OUT) { - for (igraph_integer_t edge = 0; edge < no_of_edges; ++edge) { - igraph_integer_t from = IGRAPH_FROM(graph, edge); - if (from != IGRAPH_TO(graph, edge)) { - VECTOR(*res)[from]++; - } + /* We arbitrarily count loop edges in the (mode & IGRAPH_OUT) branch but + * not in the (mode & IGRAPH_IN) branch */ + + if (igraph_vs_is_all(&vids)) { + // When calculating degree for all vertices, iterating over edges is faster + igraph_int_t no_of_edges = igraph_ecount(graph); + + /* mode & IGRAPH_OUT branch */ + for (igraph_int_t edge = 0; edge < no_of_edges; ++edge) { + igraph_int_t from = IGRAPH_FROM(graph, edge); + VECTOR(*res)[from]++; } - } - if (mode & IGRAPH_IN) { - for (igraph_integer_t edge = 0; edge < no_of_edges; ++edge) { - igraph_integer_t to = IGRAPH_TO(graph, edge); + + /* mode & IGRAPH_IN branch */ + for (igraph_int_t edge = 0; edge < no_of_edges; ++edge) { + igraph_int_t to = IGRAPH_TO(graph, edge); if (IGRAPH_FROM(graph, edge) != to) { VECTOR(*res)[to]++; } } - } - } else { /* no loops */ - if (mode & IGRAPH_OUT) { + } else { + /* mode & IGRAPH_OUT branch */ for (IGRAPH_VIT_RESET(vit), i = 0; - !IGRAPH_VIT_END(vit); - IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t vid = IGRAPH_VIT_GET(vit); + !IGRAPH_VIT_END(vit); + IGRAPH_VIT_NEXT(vit), i++) { + igraph_int_t vid = IGRAPH_VIT_GET(vit); VECTOR(*res)[i] += (VECTOR(graph->os)[vid + 1] - VECTOR(graph->os)[vid]); - for (j = VECTOR(graph->os)[vid]; - j < VECTOR(graph->os)[vid + 1]; j++) { - if (VECTOR(graph->to)[ VECTOR(graph->oi)[j] ] == vid) { - VECTOR(*res)[i] -= 1; - } - } } - } - if (mode & IGRAPH_IN) { + + /* mode & IGRAPH_IN branch */ for (IGRAPH_VIT_RESET(vit), i = 0; - !IGRAPH_VIT_END(vit); - IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t vid = IGRAPH_VIT_GET(vit); + !IGRAPH_VIT_END(vit); + IGRAPH_VIT_NEXT(vit), i++) { + igraph_int_t vid = IGRAPH_VIT_GET(vit); VECTOR(*res)[i] += (VECTOR(graph->is)[vid + 1] - VECTOR(graph->is)[vid]); for (j = VECTOR(graph->is)[vid]; - j < VECTOR(graph->is)[vid + 1]; j++) { + j < VECTOR(graph->is)[vid + 1]; j++) { if (VECTOR(graph->from)[ VECTOR(graph->ii)[j] ] == vid) { VECTOR(*res)[i] -= 1; } } } } - } /* loops */ + } else { + /* no loops should be counted */ + if (igraph_vs_is_all(&vids)) { + // When calculating degree for all vertices, iterating over edges is faster + igraph_int_t no_of_edges = igraph_ecount(graph); + + if (mode & IGRAPH_OUT) { + for (igraph_int_t edge = 0; edge < no_of_edges; ++edge) { + igraph_int_t from = IGRAPH_FROM(graph, edge); + if (from != IGRAPH_TO(graph, edge)) { + VECTOR(*res)[from]++; + } + } + } + if (mode & IGRAPH_IN) { + for (igraph_int_t edge = 0; edge < no_of_edges; ++edge) { + igraph_int_t to = IGRAPH_TO(graph, edge); + if (IGRAPH_FROM(graph, edge) != to) { + VECTOR(*res)[to]++; + } + } + } + } else { + if (mode & IGRAPH_OUT) { + for (IGRAPH_VIT_RESET(vit), i = 0; + !IGRAPH_VIT_END(vit); + IGRAPH_VIT_NEXT(vit), i++) { + igraph_int_t vid = IGRAPH_VIT_GET(vit); + VECTOR(*res)[i] += (VECTOR(graph->os)[vid + 1] - VECTOR(graph->os)[vid]); + for (j = VECTOR(graph->os)[vid]; + j < VECTOR(graph->os)[vid + 1]; j++) { + if (VECTOR(graph->to)[ VECTOR(graph->oi)[j] ] == vid) { + VECTOR(*res)[i] -= 1; + } + } + } + } + if (mode & IGRAPH_IN) { + for (IGRAPH_VIT_RESET(vit), i = 0; + !IGRAPH_VIT_END(vit); + IGRAPH_VIT_NEXT(vit), i++) { + igraph_int_t vid = IGRAPH_VIT_GET(vit); + VECTOR(*res)[i] += (VECTOR(graph->is)[vid + 1] - VECTOR(graph->is)[vid]); + for (j = VECTOR(graph->is)[vid]; + j < VECTOR(graph->is)[vid + 1]; j++) { + if (VECTOR(graph->from)[ VECTOR(graph->ii)[j] ] == vid) { + VECTOR(*res)[i] -= 1; + } + } + } + } + } + } igraph_vit_destroy(&vit); IGRAPH_FINALLY_CLEAN(1); @@ -1353,8 +1443,8 @@ igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res, #define BINSEARCH(start, end, value, iindex, edgelist, N, result, result_pos) \ do { \ while ((start) < (end)) { \ - igraph_integer_t mid =(start)+((end)-(start))/2; \ - igraph_integer_t e = VECTOR((iindex))[mid]; \ + igraph_int_t mid =(start)+((end)-(start))/2; \ + igraph_int_t e = VECTOR((iindex))[mid]; \ if (VECTOR((edgelist))[e] < (value)) { \ (start) = mid+1; \ } else { \ @@ -1362,7 +1452,7 @@ igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res, } \ } \ if ((start) < (N)) { \ - igraph_integer_t e = VECTOR((iindex))[(start)]; \ + igraph_int_t e = VECTOR((iindex))[(start)]; \ if (VECTOR((edgelist))[e] == (value)) { \ *(result) = e; \ if (result_pos != 0) { *(result_pos) = start; } \ @@ -1372,13 +1462,13 @@ igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res, #define FIND_DIRECTED_EDGE(graph,xfrom,xto,eid) \ do { \ - igraph_integer_t start = VECTOR(graph->os)[xfrom]; \ - igraph_integer_t end = VECTOR(graph->os)[xfrom+1]; \ - igraph_integer_t N = end; \ - igraph_integer_t start2 = VECTOR(graph->is)[xto]; \ - igraph_integer_t end2 = VECTOR(graph->is)[xto+1]; \ - igraph_integer_t N2 = end2; \ - igraph_integer_t *nullpointer = NULL; \ + igraph_int_t start = VECTOR(graph->os)[xfrom]; \ + igraph_int_t end = VECTOR(graph->os)[xfrom+1]; \ + igraph_int_t N = end; \ + igraph_int_t start2 = VECTOR(graph->is)[xto]; \ + igraph_int_t end2 = VECTOR(graph->is)[xto+1]; \ + igraph_int_t N2 = end2; \ + igraph_int_t *nullpointer = NULL; \ if (end-start < end2-start2) { \ BINSEARCH(start, end, xto, graph->oi, graph->to, N, eid, nullpointer); \ } else { \ @@ -1388,8 +1478,8 @@ igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res, #define FIND_UNDIRECTED_EDGE(graph, from, to, eid) \ do { \ - igraph_integer_t xfrom1 = from > to ? from : to; \ - igraph_integer_t xto1 = from > to ? to : from; \ + igraph_int_t xfrom1 = from > to ? from : to; \ + igraph_int_t xto1 = from > to ? to : from; \ FIND_DIRECTED_EDGE(graph, xfrom1, xto1, eid); \ } while (0) @@ -1422,15 +1512,13 @@ igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res, * d2 is the minimum of the out-degree of \c to and the in-degree of \c from. * * \example examples/simple/igraph_get_eid.c - * - * Added in version 0.2. */ -igraph_error_t igraph_get_eid(const igraph_t *graph, igraph_integer_t *eid, - igraph_integer_t from, igraph_integer_t to, +igraph_error_t igraph_get_eid(const igraph_t *graph, igraph_int_t *eid, + igraph_int_t from, igraph_int_t to, igraph_bool_t directed, igraph_bool_t error) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (from < 0 || to < 0 || from >= no_of_nodes || to >= no_of_nodes) { IGRAPH_ERROR("Cannot get edge ID.", IGRAPH_EINVVID); @@ -1454,7 +1542,7 @@ igraph_error_t igraph_get_eid(const igraph_t *graph, igraph_integer_t *eid, if (*eid < 0) { if (error) { - IGRAPH_ERROR("Cannot get edge ID, no such edge", IGRAPH_EINVAL); + IGRAPH_ERROR("Cannot get edge ID, no such edge.", IGRAPH_EINVAL); } } @@ -1508,10 +1596,10 @@ igraph_error_t igraph_get_eids(const igraph_t *graph, igraph_vector_int_t *eids, const igraph_vector_int_t *pairs, igraph_bool_t directed, igraph_bool_t error) { - igraph_integer_t n = pairs ? igraph_vector_int_size(pairs) : 0; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t i; - igraph_integer_t eid = -1; + igraph_int_t n = pairs ? igraph_vector_int_size(pairs) : 0; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i; + igraph_int_t eid = -1; if (n == 0) { igraph_vector_int_clear(eids); @@ -1519,20 +1607,20 @@ igraph_error_t igraph_get_eids(const igraph_t *graph, igraph_vector_int_t *eids, } if (n % 2 != 0) { - IGRAPH_ERROR("Cannot get edge IDs, invalid length of edge IDs", + IGRAPH_ERROR("Cannot get edge IDs, invalid length of vertex pair vector.", IGRAPH_EINVAL); } if (!igraph_vector_int_isininterval(pairs, 0, no_of_nodes - 1)) { - IGRAPH_ERROR("Cannot get edge IDs, invalid vertex ID", IGRAPH_EINVVID); + IGRAPH_ERROR("Cannot get edge IDs, invalid vertex ID.", IGRAPH_EINVVID); } IGRAPH_CHECK(igraph_vector_int_resize(eids, n / 2)); if (igraph_is_directed(graph)) { for (i = 0; i < n / 2; i++) { - igraph_integer_t from = VECTOR(*pairs)[2 * i]; - igraph_integer_t to = VECTOR(*pairs)[2 * i + 1]; + igraph_int_t from = VECTOR(*pairs)[2 * i]; + igraph_int_t to = VECTOR(*pairs)[2 * i + 1]; eid = -1; FIND_DIRECTED_EDGE(graph, from, to, &eid); @@ -1542,19 +1630,19 @@ igraph_error_t igraph_get_eids(const igraph_t *graph, igraph_vector_int_t *eids, VECTOR(*eids)[i] = eid; if (eid < 0 && error) { - IGRAPH_ERROR("Cannot get edge ID, no such edge", IGRAPH_EINVAL); + IGRAPH_ERROR("Cannot get edge ID, no such edge.", IGRAPH_EINVAL); } } } else { for (i = 0; i < n / 2; i++) { - igraph_integer_t from = VECTOR(*pairs)[2 * i]; - igraph_integer_t to = VECTOR(*pairs)[2 * i + 1]; + igraph_int_t from = VECTOR(*pairs)[2 * i]; + igraph_int_t to = VECTOR(*pairs)[2 * i + 1]; eid = -1; FIND_UNDIRECTED_EDGE(graph, from, to, &eid); VECTOR(*eids)[i] = eid; if (eid < 0 && error) { - IGRAPH_ERROR("Cannot get edge ID, no such edge", IGRAPH_EINVAL); + IGRAPH_ERROR("Cannot get edge ID, no such edge.", IGRAPH_EINVAL); } } } @@ -1567,14 +1655,14 @@ igraph_error_t igraph_get_eids(const igraph_t *graph, igraph_vector_int_t *eids, #define FIND_ALL_DIRECTED_EDGES(graph, xfrom, xto, eidvec) \ do { \ - igraph_integer_t start = VECTOR(graph->os)[xfrom]; \ - igraph_integer_t end = VECTOR(graph->os)[xfrom+1]; \ - igraph_integer_t N = end; \ - igraph_integer_t start2 = VECTOR(graph->is)[xto]; \ - igraph_integer_t end2 = VECTOR(graph->is)[xto+1]; \ - igraph_integer_t N2 = end2; \ - igraph_integer_t eid = -1; \ - igraph_integer_t pos = -1; \ + igraph_int_t start = VECTOR(graph->os)[xfrom]; \ + igraph_int_t end = VECTOR(graph->os)[xfrom+1]; \ + igraph_int_t N = end; \ + igraph_int_t start2 = VECTOR(graph->is)[xto]; \ + igraph_int_t end2 = VECTOR(graph->is)[xto+1]; \ + igraph_int_t N2 = end2; \ + igraph_int_t eid = -1; \ + igraph_int_t pos = -1; \ if (end-start < end2-start2) { \ BINSEARCH(start, end, xto, graph->oi, graph->to, N, &eid, &pos); \ while (pos >= 0 && pos < N) { \ @@ -1594,8 +1682,8 @@ igraph_error_t igraph_get_eids(const igraph_t *graph, igraph_vector_int_t *eids, #define FIND_ALL_UNDIRECTED_EDGES(graph, from, to, eidvec) \ do { \ - igraph_integer_t xfrom1 = from > to ? from : to; \ - igraph_integer_t xto1 = from > to ? to : from; \ + igraph_int_t xfrom1 = from > to ? from : to; \ + igraph_int_t xto1 = from > to ? to : from; \ FIND_ALL_DIRECTED_EDGES(graph, xfrom1, xto1, eidvec); \ } while (0) @@ -1621,16 +1709,16 @@ igraph_error_t igraph_get_eids(const igraph_t *graph, igraph_vector_int_t *eids, */ igraph_error_t igraph_get_all_eids_between( const igraph_t *graph, igraph_vector_int_t *eids, - igraph_integer_t source, igraph_integer_t target, igraph_bool_t directed + igraph_int_t source, igraph_int_t target, igraph_bool_t directed ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (source < 0 || source >= no_of_nodes) { - IGRAPH_ERROR("Cannot get edge IDs, invalid source vertex ID", IGRAPH_EINVVID); + IGRAPH_ERROR("Cannot get edge IDs, invalid source vertex ID.", IGRAPH_EINVVID); } if (target < 0 || target >= no_of_nodes) { - IGRAPH_ERROR("Cannot get edge IDs, invalid target vertex ID", IGRAPH_EINVVID); + IGRAPH_ERROR("Cannot get edge IDs, invalid target vertex ID.", IGRAPH_EINVVID); } igraph_vector_int_clear(eids); @@ -1658,39 +1746,38 @@ igraph_error_t igraph_get_all_eids_between( * \brief Gives the incident edges of a vertex. * * \param graph The graph object. - * \param eids An initialized vector. It will be resized - * to hold the result. + * \param eids An initialized vector. It will be resized to hold the result. * \param pnode A vertex ID. * \param mode Specifies what kind of edges to include for directed - * graphs. \c IGRAPH_OUT means only outgoing edges, \c IGRAPH_IN only - * incoming edges, \c IGRAPH_ALL both. This parameter is ignored for - * undirected graphs. - * \return Error code. \c IGRAPH_EINVVID: invalid \p pnode argument, - * \c IGRAPH_EINVMODE: invalid \p mode argument. - * - * Added in version 0.2. + * graphs. \c IGRAPH_OUT means only outgoing edges, \c IGRAPH_IN means + * only incoming edges, \c IGRAPH_ALL means both. This parameter is + * ignored for undirected graphs. + * \param loops Specifies how to treat loop edges. \c IGRAPH_NO_LOOPS + * removes loop edges from the result. \c IGRAPH_LOOPS_ONCE + * makes each loop edge appear only once in the result. + * \c IGRAPH_LOOPS_TWICE makes loop edges appear \em twice in the + * result if the graph is undirected or \p mode is set to \c IGRAPH_ALL + * (and once otherwise as returning them twice does not make sense for + * directed graphs). + * \return Error code: + * \c IGRAPH_EINVVID: invalid vertex ID. + * \c IGRAPH_EINVMODE: invalid mode argument. + * \c IGRAPH_ENOMEM: not enough memory. * * Time complexity: O(d), the number of incident edges to \p pnode. */ -igraph_error_t igraph_incident(const igraph_t *graph, igraph_vector_int_t *eids, igraph_integer_t pnode, - igraph_neimode_t mode) { - if (!igraph_is_directed(graph) || mode == IGRAPH_ALL) { - return igraph_i_incident(graph, eids, pnode, mode, IGRAPH_LOOPS_TWICE); - } else { - return igraph_i_incident(graph, eids, pnode, mode, IGRAPH_LOOPS_ONCE); - } -} - -igraph_error_t igraph_i_incident(const igraph_t *graph, igraph_vector_int_t *eids, igraph_integer_t pnode, - igraph_neimode_t mode, igraph_loops_t loops) { - igraph_integer_t length = 0, idx = 0; - igraph_integer_t i, j; - igraph_integer_t node = pnode; +igraph_error_t igraph_incident( + const igraph_t *graph, igraph_vector_int_t *eids, igraph_int_t pnode, + igraph_neimode_t mode, igraph_loops_t loops +) { + igraph_int_t length = 0, idx = 0; + igraph_int_t i, j; + igraph_int_t node = pnode; igraph_bool_t directed = igraph_is_directed(graph); if (node < 0 || node > igraph_vcount(graph) - 1) { - IGRAPH_ERROR("Given vertex is not in the graph.", IGRAPH_EINVVID); + IGRAPH_ERRORF("Vertex %" IGRAPH_PRId " is not in the graph.", IGRAPH_EINVVID, node); } if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) { @@ -1702,8 +1789,11 @@ igraph_error_t igraph_i_incident(const igraph_t *graph, igraph_vector_int_t *eid } if (mode != IGRAPH_ALL && loops == IGRAPH_LOOPS_TWICE) { + /* IGRAPH_ERROR("For a directed graph (with directions not ignored), " - "IGRAPH_LOOPS_TWICE does not make sense.\n", IGRAPH_EINVAL); + "IGRAPH_LOOPS_TWICE does not make sense.", IGRAPH_EINVAL); + */ + loops = IGRAPH_LOOPS_ONCE; } /* Calculate needed space first & allocate it */ @@ -1731,8 +1821,8 @@ igraph_error_t igraph_i_incident(const igraph_t *graph, igraph_vector_int_t *eid if (mode & IGRAPH_OUT) { j = VECTOR(graph->os)[node + 1]; for (i = VECTOR(graph->os)[node]; i < j; i++) { - igraph_integer_t edge = VECTOR(graph->oi)[i]; - igraph_integer_t other = VECTOR(graph->to)[edge]; + igraph_int_t edge = VECTOR(graph->oi)[i]; + igraph_int_t other = VECTOR(graph->to)[edge]; if (loops == IGRAPH_NO_LOOPS && other == pnode) { length--; } else { @@ -1744,8 +1834,8 @@ igraph_error_t igraph_i_incident(const igraph_t *graph, igraph_vector_int_t *eid if (mode & IGRAPH_IN) { j = VECTOR(graph->is)[node + 1]; for (i = VECTOR(graph->is)[node]; i < j; i++) { - igraph_integer_t edge = VECTOR(graph->ii)[i]; - igraph_integer_t other = VECTOR(graph->from)[edge]; + igraph_int_t edge = VECTOR(graph->ii)[i]; + igraph_int_t other = VECTOR(graph->from)[edge]; if ((loops == IGRAPH_NO_LOOPS || (loops == IGRAPH_LOOPS_ONCE && !directed)) && other == pnode) { length--; } else { @@ -1756,12 +1846,12 @@ igraph_error_t igraph_i_incident(const igraph_t *graph, igraph_vector_int_t *eid } else { /* both in- and out- neighbors in a directed graph, we need to merge the two 'vectors' */ - igraph_integer_t j1 = VECTOR(graph->os)[node + 1]; - igraph_integer_t j2 = VECTOR(graph->is)[node + 1]; - igraph_integer_t i1 = VECTOR(graph->os)[node]; - igraph_integer_t i2 = VECTOR(graph->is)[node]; - igraph_integer_t eid1, eid2; - igraph_integer_t n1, n2; + igraph_int_t j1 = VECTOR(graph->os)[node + 1]; + igraph_int_t j2 = VECTOR(graph->is)[node + 1]; + igraph_int_t i1 = VECTOR(graph->os)[node]; + igraph_int_t i2 = VECTOR(graph->is)[node]; + igraph_int_t eid1, eid2; + igraph_int_t n1, n2; igraph_bool_t seen_loop_edge = false; while (i1 < j1 && i2 < j2) { @@ -1814,7 +1904,6 @@ igraph_error_t igraph_i_incident(const igraph_t *graph, igraph_vector_int_t *eid } IGRAPH_CHECK(igraph_vector_int_resize(eids, length)); return IGRAPH_SUCCESS; -#undef DEDUPLICATE_IF_NEEDED } @@ -1851,11 +1940,11 @@ igraph_error_t igraph_i_incident(const igraph_t *graph, igraph_vector_int_t *eid */ igraph_error_t igraph_is_same_graph(const igraph_t *graph1, const igraph_t *graph2, igraph_bool_t *res) { - igraph_integer_t nv1 = igraph_vcount(graph1); - igraph_integer_t nv2 = igraph_vcount(graph2); - igraph_integer_t ne1 = igraph_ecount(graph1); - igraph_integer_t ne2 = igraph_ecount(graph2); - igraph_integer_t i, eid1, eid2; + igraph_int_t nv1 = igraph_vcount(graph1); + igraph_int_t nv2 = igraph_vcount(graph2); + igraph_int_t ne1 = igraph_ecount(graph1); + igraph_int_t ne2 = igraph_ecount(graph2); + igraph_int_t i, eid1, eid2; *res = false; /* Assume that the graphs differ */ diff --git a/src/vendor/cigraph/src/graph/visitors.c b/src/vendor/cigraph/src/graph/visitors.c index f373c09932b..1520d4b021d 100644 --- a/src/vendor/cigraph/src/graph/visitors.c +++ b/src/vendor/cigraph/src/graph/visitors.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -102,7 +102,7 @@ * \example examples/simple/igraph_bfs_callback.c */ igraph_error_t igraph_bfs(const igraph_t *graph, - igraph_integer_t root, const igraph_vector_int_t *roots, + igraph_int_t root, const igraph_vector_int_t *roots, igraph_neimode_t mode, igraph_bool_t unreachable, const igraph_vector_int_t *restricted, igraph_vector_int_t *order, igraph_vector_int_t *rank, @@ -111,21 +111,21 @@ igraph_error_t igraph_bfs(const igraph_t *graph, igraph_vector_int_t *dist, igraph_bfshandler_t *callback, void *extra) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_error_t ret; igraph_dqueue_int_t Q; - igraph_integer_t actroot = 0; + igraph_int_t actroot = 0; igraph_bitset_t added; igraph_lazy_adjlist_t adjlist; - igraph_integer_t act_rank = 0; - igraph_integer_t pred_vec = -1; + igraph_int_t act_rank = 0; + igraph_int_t pred_vec = -1; - igraph_integer_t rootpos = 0; - igraph_integer_t noroots = roots ? igraph_vector_int_size(roots) : 1; + igraph_int_t rootpos = 0; + igraph_int_t noroots = roots ? igraph_vector_int_size(roots) : 1; if (!roots && (root < 0 || root >= no_of_nodes)) { IGRAPH_ERROR("Invalid root vertex in BFS.", IGRAPH_EINVVID); @@ -158,10 +158,10 @@ igraph_error_t igraph_bfs(const igraph_t *graph, found. Special care must be taken for vertices that are not in the restricted set, but are to be used as 'root' vertices. */ if (restricted) { - igraph_integer_t i, n = igraph_vector_int_size(restricted); + igraph_int_t i, n = igraph_vector_int_size(restricted); igraph_bitset_fill(&added, true); for (i = 0; i < n; i++) { - igraph_integer_t v = VECTOR(*restricted)[i]; + igraph_int_t v = VECTOR(*restricted)[i]; IGRAPH_BIT_CLEAR(added, v); } } @@ -220,13 +220,13 @@ igraph_error_t igraph_bfs(const igraph_t *graph, pred_vec = -1; while (!igraph_dqueue_int_empty(&Q)) { - igraph_integer_t actvect = igraph_dqueue_int_pop(&Q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&Q); - igraph_integer_t succ_vec; + igraph_int_t actvect = igraph_dqueue_int_pop(&Q); + igraph_int_t actdist = igraph_dqueue_int_pop(&Q); + igraph_int_t succ_vec; igraph_vector_int_t *neis = igraph_lazy_adjlist_get(&adjlist, actvect); IGRAPH_CHECK_OOM(neis, "Failed to query neighbors."); - const igraph_integer_t n = igraph_vector_int_size(neis); + const igraph_int_t n = igraph_vector_int_size(neis); if (pred) { VECTOR(*pred)[actvect] = pred_vec; @@ -241,8 +241,8 @@ igraph_error_t igraph_bfs(const igraph_t *graph, VECTOR(*dist)[actvect] = actdist; } - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t nei = VECTOR(*neis)[i]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t nei = VECTOR(*neis)[i]; if (! IGRAPH_BIT_TEST(added, nei)) { IGRAPH_BIT_SET(added, nei); IGRAPH_CHECK(igraph_dqueue_int_push(&Q, nei)); @@ -326,17 +326,17 @@ igraph_error_t igraph_bfs(const igraph_t *graph, * \example examples/simple/igraph_bfs_simple.c */ igraph_error_t igraph_bfs_simple( - const igraph_t *graph, igraph_integer_t root, igraph_neimode_t mode, + const igraph_t *graph, igraph_int_t root, igraph_neimode_t mode, igraph_vector_int_t *order, igraph_vector_int_t *layers, igraph_vector_int_t *parents ) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_dqueue_int_t q; - igraph_integer_t num_visited = 0; + igraph_int_t num_visited = 0; igraph_vector_int_t neis; igraph_bitset_t added; - igraph_integer_t lastlayer = -1; + igraph_int_t lastlayer = -1; if (!igraph_is_directed(graph)) { mode = IGRAPH_ALL; @@ -382,13 +382,14 @@ igraph_error_t igraph_bfs_simple( IGRAPH_BIT_SET(added, root); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actvect = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, actvect, - mode)); - igraph_integer_t nei_count = igraph_vector_int_size(&neis); - for (igraph_integer_t i = 0; i < nei_count; i++) { - const igraph_integer_t neighbor = VECTOR(neis)[i]; + igraph_int_t actvect = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, actvect, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); + igraph_int_t nei_count = igraph_vector_int_size(&neis); + for (igraph_int_t i = 0; i < nei_count; i++) { + const igraph_int_t neighbor = VECTOR(neis)[i]; if (! IGRAPH_BIT_TEST(added, neighbor)) { IGRAPH_BIT_SET(added, neighbor); if (parents) { @@ -475,7 +476,7 @@ igraph_error_t igraph_bfs_simple( * edges. */ -igraph_error_t igraph_dfs(const igraph_t *graph, igraph_integer_t root, +igraph_error_t igraph_dfs(const igraph_t *graph, igraph_int_t root, igraph_neimode_t mode, igraph_bool_t unreachable, igraph_vector_int_t *order, igraph_vector_int_t *order_out, igraph_vector_int_t *parents, @@ -483,15 +484,15 @@ igraph_error_t igraph_dfs(const igraph_t *graph, igraph_integer_t root, igraph_dfshandler_t *out_callback, void *extra) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_lazy_adjlist_t adjlist; igraph_stack_int_t stack; igraph_bitset_t added; igraph_vector_int_t nptr; igraph_error_t ret; - igraph_integer_t act_rank = 0; - igraph_integer_t rank_out = 0; - igraph_integer_t act_dist = 0; + igraph_int_t act_rank = 0; + igraph_int_t rank_out = 0; + igraph_int_t act_dist = 0; if (root < 0 || root >= no_of_nodes) { IGRAPH_ERROR("Invalid root vertex for DFS.", IGRAPH_EINVAL); @@ -553,7 +554,7 @@ igraph_error_t igraph_dfs(const igraph_t *graph, igraph_integer_t root, } } - for (igraph_integer_t actroot = 0; actroot < no_of_nodes; ) { + for (igraph_int_t actroot = 0; actroot < no_of_nodes; ) { /* 'root' first, then all other vertices */ if (igraph_stack_int_empty(&stack)) { @@ -588,17 +589,17 @@ igraph_error_t igraph_dfs(const igraph_t *graph, igraph_integer_t root, } while (!igraph_stack_int_empty(&stack)) { - igraph_integer_t actvect = igraph_stack_int_top(&stack); - igraph_integer_t *ptr = igraph_vector_int_get_ptr(&nptr, actvect); + igraph_int_t actvect = igraph_stack_int_top(&stack); + igraph_int_t *ptr = igraph_vector_int_get_ptr(&nptr, actvect); igraph_vector_int_t *neis = igraph_lazy_adjlist_get(&adjlist, actvect); IGRAPH_CHECK_OOM(neis, "Failed to query neighbors."); - const igraph_integer_t n = igraph_vector_int_size(neis); + const igraph_int_t n = igraph_vector_int_size(neis); /* Search for a neighbor that was not yet visited */ igraph_bool_t any = false; - igraph_integer_t nei = 0; + igraph_int_t nei = 0; while (!any && (*ptr) < n) { nei = VECTOR(*neis)[(*ptr)]; any = !IGRAPH_BIT_TEST(added, nei); diff --git a/src/vendor/cigraph/src/hrg/dendro.h b/src/vendor/cigraph/src/hrg/dendro.h index 7b66331e816..77d4003a028 100644 --- a/src/vendor/cigraph/src/hrg/dendro.h +++ b/src/vendor/cigraph/src/hrg/dendro.h @@ -1,6 +1,6 @@ /* -*- mode: C++ -*- */ /* - IGraph library. + igraph library. Copyright (C) 2011-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/hrg/graph.h b/src/vendor/cigraph/src/hrg/graph.h index 4e72b24746e..09f379d1f82 100644 --- a/src/vendor/cigraph/src/hrg/graph.h +++ b/src/vendor/cigraph/src/hrg/graph.h @@ -1,6 +1,6 @@ /* -*- mode: C++ -*- */ /* - IGraph library. + igraph library. Copyright (C) 2011-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -133,7 +133,7 @@ class graph { // clear all links from graph void resetLinks(); // allocate edge histograms - void setAdjacencyHistograms(igraph_integer_t); + void setAdjacencyHistograms(igraph_int_t); // set name of vertex i bool setName(int, const std::string &); diff --git a/src/vendor/cigraph/src/hrg/graph_simp.h b/src/vendor/cigraph/src/hrg/graph_simp.h index 4ba56824fcd..2d658c425e3 100644 --- a/src/vendor/cigraph/src/hrg/graph_simp.h +++ b/src/vendor/cigraph/src/hrg/graph_simp.h @@ -1,6 +1,6 @@ /* -*- mode: C++ -*- */ /* - IGraph library. + igraph library. Copyright (C) 2011-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/hrg/hrg.cc b/src/vendor/cigraph/src/hrg/hrg.cc index 374bde6977c..a430d7f0334 100644 --- a/src/vendor/cigraph/src/hrg/hrg.cc +++ b/src/vendor/cigraph/src/hrg/hrg.cc @@ -1,6 +1,6 @@ /* -*- mode: C++ -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -84,7 +84,7 @@ struct pblock { }; } -static void markovChainMonteCarlo(dendro &d, const igraph_integer_t period, +static void markovChainMonteCarlo(dendro &d, const igraph_int_t period, igraph_hrg_t *hrg) { igraph_real_t bestL = d.getLikelihood(); @@ -103,7 +103,7 @@ static void markovChainMonteCarlo(dendro &d, const igraph_integer_t period, // model averaging sense), you'll need to code that yourself. // do 'period' MCMC moves before doing anything else - for (igraph_integer_t i = 0; i < period; i++) { + for (igraph_int_t i = 0; i < period; i++) { // make a MCMC move d.monteCarloMove(dL, flag_taken, 1.0); @@ -125,7 +125,7 @@ static void markovChainMonteCarlo2(dendro &d, const int num_samples) { bool flag_taken; double dL; const double ptest = 1.0 / (50.0 * static_cast(d.getGraph()->numNodes())); - igraph_integer_t sample_num = 0; + igraph_int_t sample_num = 0; int t = 1; const int thresh = 200 * d.getGraph()->numNodes(); @@ -186,8 +186,8 @@ static void MCMCEquilibrium_Find(dendro &d, igraph_hrg_t *hrg) { } igraph_error_t dendro::setGraph(const igraph_t *igraph) { - igraph_integer_t no_of_nodes = igraph_vcount(igraph); - igraph_integer_t no_of_edges = igraph_ecount(igraph); + igraph_int_t no_of_nodes = igraph_vcount(igraph); + igraph_int_t no_of_edges = igraph_ecount(igraph); if (no_of_nodes > INT_MAX) { IGRAPH_ERROR("Graph too large for the HRG module.", IGRAPH_EOVERFLOW); @@ -203,7 +203,7 @@ igraph_error_t dendro::setGraph(const igraph_t *igraph) { g = new graph(no_of_nodes); // Add edges - for (igraph_integer_t i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { int from = IGRAPH_FROM(igraph, i); int to = IGRAPH_TO(igraph, i); if (from == to) { @@ -224,10 +224,10 @@ igraph_error_t dendro::setGraph(const igraph_t *igraph) { static std::unique_ptr igraph_i_hrg_getsimplegraph(const igraph_t *igraph, dendro &d, - igraph_integer_t num_bins) { + igraph_int_t num_bins) { - const igraph_integer_t no_of_nodes = igraph_vcount(igraph); - const igraph_integer_t no_of_edges = igraph_ecount(igraph); + const igraph_int_t no_of_nodes = igraph_vcount(igraph); + const igraph_int_t no_of_edges = igraph_ecount(igraph); // TODO replace the following throw's with IGRAPH_ERROR @@ -247,7 +247,7 @@ static std::unique_ptr igraph_i_hrg_getsimplegraph(const igraph_t * std::unique_ptr sg(new simpleGraph(no_of_nodes)); - for (igraph_integer_t i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { int from = (int) IGRAPH_FROM(igraph, i); int to = (int) IGRAPH_TO(igraph, i); if (from == to) { @@ -288,7 +288,7 @@ static std::unique_ptr igraph_i_hrg_getsimplegraph(const igraph_t * * Time complexity: O(n), the number of vertices in the graph. */ -igraph_error_t igraph_hrg_init(igraph_hrg_t *hrg, igraph_integer_t n) { +igraph_error_t igraph_hrg_init(igraph_hrg_t *hrg, igraph_int_t n) { if (n < 0) { IGRAPH_ERRORF("Number of vertices should not be negative, got %" IGRAPH_PRId ".", IGRAPH_EINVAL, n); } @@ -334,7 +334,7 @@ void igraph_hrg_destroy(igraph_hrg_t *hrg) { * Time complexity: O(1). */ -igraph_integer_t igraph_hrg_size(const igraph_hrg_t *hrg) { +igraph_int_t igraph_hrg_size(const igraph_hrg_t *hrg) { return igraph_vector_int_size(&hrg->left) + 1; } @@ -350,8 +350,8 @@ igraph_integer_t igraph_hrg_size(const igraph_hrg_t *hrg) { * Time complexity: O(n), n is the new size. */ -igraph_error_t igraph_hrg_resize(igraph_hrg_t *hrg, igraph_integer_t newsize) { - igraph_integer_t origsize = igraph_hrg_size(hrg); +igraph_error_t igraph_hrg_resize(igraph_hrg_t *hrg, igraph_int_t newsize) { + igraph_int_t origsize = igraph_hrg_size(hrg); /* The data structure must be left in a consistent state if resizing fails. */ @@ -407,13 +407,11 @@ igraph_error_t igraph_hrg_resize(igraph_hrg_t *hrg, igraph_integer_t newsize) { igraph_error_t igraph_hrg_fit(const igraph_t *graph, igraph_hrg_t *hrg, igraph_bool_t start, - igraph_integer_t steps) { + igraph_int_t steps) { IGRAPH_HANDLE_EXCEPTIONS_BEGIN - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - - RNG_BEGIN(); + const igraph_int_t no_of_nodes = igraph_vcount(graph); dendro d; @@ -439,8 +437,6 @@ igraph_error_t igraph_hrg_fit(const igraph_t *graph, MCMCEquilibrium_Find(d, hrg); } - RNG_END(); - return IGRAPH_SUCCESS; IGRAPH_HANDLE_EXCEPTIONS_END @@ -465,15 +461,11 @@ igraph_error_t igraph_hrg_sample(const igraph_hrg_t *hrg, igraph_t *sample) { // TODO: error handling - RNG_BEGIN(); - d.clearDendrograph(); d.importDendrogramStructure(hrg); d.makeRandomGraph(); IGRAPH_CHECK(d.recordGraphStructure(sample)); - RNG_END(); - return IGRAPH_SUCCESS; IGRAPH_HANDLE_EXCEPTIONS_END } @@ -498,7 +490,7 @@ igraph_error_t igraph_hrg_sample(const igraph_hrg_t *hrg, igraph_t *sample) { igraph_error_t igraph_hrg_sample_many( const igraph_hrg_t *hrg, igraph_graph_list_t *samples, - igraph_integer_t num_samples + igraph_int_t num_samples ) { IGRAPH_HANDLE_EXCEPTIONS_BEGIN igraph_t g; @@ -512,8 +504,6 @@ igraph_error_t igraph_hrg_sample_many( return IGRAPH_SUCCESS; } - RNG_BEGIN(); - d.clearDendrograph(); d.importDendrogramStructure(hrg); while (num_samples-- > 0) { @@ -524,8 +514,6 @@ igraph_error_t igraph_hrg_sample_many( IGRAPH_FINALLY_CLEAN(1); } - RNG_END(); - return IGRAPH_SUCCESS; IGRAPH_HANDLE_EXCEPTIONS_END } @@ -574,11 +562,11 @@ igraph_error_t igraph_hrg_game(igraph_t *graph, igraph_error_t igraph_from_hrg_dendrogram( igraph_t *graph, const igraph_hrg_t *hrg, igraph_vector_t *prob ) { - const igraph_integer_t orig_nodes = igraph_hrg_size(hrg); - const igraph_integer_t no_of_nodes = orig_nodes * 2 - 1; - const igraph_integer_t no_of_edges = no_of_nodes > 0 ? no_of_nodes - 1 : 0; + const igraph_int_t orig_nodes = igraph_hrg_size(hrg); + const igraph_int_t no_of_nodes = orig_nodes * 2 - 1; + const igraph_int_t no_of_edges = no_of_nodes > 0 ? no_of_nodes - 1 : 0; igraph_vector_int_t edges; - igraph_integer_t i, idx = 0; + igraph_int_t i, idx = 0; // Probability labels, for leaf nodes they are IGRAPH_NAN if (prob) { @@ -594,8 +582,8 @@ igraph_error_t igraph_from_hrg_dendrogram( IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges * 2); for (i = 0; i < orig_nodes - 1; i++) { - igraph_integer_t left = VECTOR(hrg->left)[i]; - igraph_integer_t right = VECTOR(hrg->right)[i]; + igraph_int_t left = VECTOR(hrg->left)[i]; + igraph_int_t right = VECTOR(hrg->right)[i]; VECTOR(edges)[idx++] = orig_nodes + i; VECTOR(edges)[idx++] = left < 0 ? orig_nodes - left - 1 : left; @@ -631,17 +619,14 @@ igraph_error_t igraph_from_hrg_dendrogram( * \deprecated-by igraph_from_hrg_dendrogram 0.10.5 */ igraph_error_t igraph_hrg_dendrogram(igraph_t *graph, const igraph_hrg_t *hrg) { - const igraph_integer_t orig_nodes = igraph_hrg_size(hrg); - const igraph_integer_t no_of_nodes = orig_nodes * 2 - 1; - const igraph_integer_t no_of_edges = no_of_nodes > 0 ? no_of_nodes - 1 : 0; + const igraph_int_t orig_nodes = igraph_hrg_size(hrg); + const igraph_int_t no_of_nodes = orig_nodes * 2 - 1; + const igraph_int_t no_of_edges = no_of_nodes > 0 ? no_of_nodes - 1 : 0; igraph_vector_int_t edges; - igraph_integer_t i, idx = 0; - igraph_vector_ptr_t vattrs; + igraph_int_t i, idx = 0; + igraph_attribute_record_list_t vattrs; igraph_vector_t prob; - igraph_attribute_record_t rec = { "probability", - IGRAPH_ATTRIBUTE_NUMERIC, - &prob - }; + igraph_attribute_record_t* rec; // Probability labels, for leaf nodes they are IGRAPH_NAN IGRAPH_VECTOR_INIT_FINALLY(&prob, no_of_nodes); @@ -653,13 +638,17 @@ igraph_error_t igraph_hrg_dendrogram(igraph_t *graph, const igraph_hrg_t *hrg) { } IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges * 2); - IGRAPH_CHECK(igraph_vector_ptr_init(&vattrs, 1)); - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vattrs); - VECTOR(vattrs)[0] = &rec; + IGRAPH_CHECK(igraph_attribute_record_list_init(&vattrs, 1)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &vattrs); + + rec = igraph_attribute_record_list_get_ptr(&vattrs, 1); + IGRAPH_CHECK(igraph_attribute_record_set_name(rec, "probability")); + IGRAPH_CHECK(igraph_attribute_record_set_type(rec, IGRAPH_ATTRIBUTE_NUMERIC)); + igraph_vector_swap(rec->value.as_vector, &prob); for (i = 0; i < orig_nodes - 1; i++) { - igraph_integer_t left = VECTOR(hrg->left)[i]; - igraph_integer_t right = VECTOR(hrg->right)[i]; + igraph_int_t left = VECTOR(hrg->left)[i]; + igraph_int_t right = VECTOR(hrg->right)[i]; VECTOR(edges)[idx++] = orig_nodes + i; VECTOR(edges)[idx++] = left < 0 ? orig_nodes - left - 1 : left; @@ -672,7 +661,7 @@ igraph_error_t igraph_hrg_dendrogram(igraph_t *graph, const igraph_hrg_t *hrg) { IGRAPH_CHECK(igraph_add_vertices(graph, no_of_nodes, &vattrs)); IGRAPH_CHECK(igraph_add_edges(graph, &edges, NULL)); - igraph_vector_ptr_destroy(&vattrs); + igraph_attribute_record_list_destroy(&vattrs); igraph_vector_int_destroy(&edges); igraph_vector_destroy(&prob); IGRAPH_FINALLY_CLEAN(4); // + 1 for graph @@ -713,15 +702,13 @@ igraph_error_t igraph_hrg_consensus(const igraph_t *graph, igraph_vector_t *weights, igraph_hrg_t *hrg, igraph_bool_t start, - igraph_integer_t num_samples) { + igraph_int_t num_samples) { IGRAPH_HANDLE_EXCEPTIONS_BEGIN if (start && !hrg) { IGRAPH_ERROR("`hrg' must be given if `start' is true.", IGRAPH_EINVAL); } - RNG_BEGIN(); - dendro d; if (start) { @@ -740,14 +727,12 @@ igraph_error_t igraph_hrg_consensus(const igraph_t *graph, d.recordConsensusTree(parents, weights); - RNG_END(); - return IGRAPH_SUCCESS; IGRAPH_HANDLE_EXCEPTIONS_END } -static void MCMCEquilibrium_Sample(dendro &d, igraph_integer_t num_samples) { +static void MCMCEquilibrium_Sample(dendro &d, igraph_int_t num_samples) { // Because moves in the dendrogram space are chosen (Monte // Carlo) so that we sample dendrograms with probability @@ -762,8 +747,8 @@ static void MCMCEquilibrium_Sample(dendro &d, igraph_integer_t num_samples) { double dL; bool flag_taken; - igraph_integer_t sample_num = 0; - igraph_integer_t t = 1, thresh = 100 * d.getGraph()->numNodes(); + igraph_int_t sample_num = 0; + igraph_int_t t = 1, thresh = 100 * d.getGraph()->numNodes(); double ptest = 1.0 / 10.0 / d.getGraph()->numNodes(); while (sample_num < num_samples) { @@ -777,13 +762,13 @@ static void MCMCEquilibrium_Sample(dendro &d, igraph_integer_t num_samples) { } } -static igraph_integer_t QsortPartition (pblock* array, igraph_integer_t left, igraph_integer_t right, igraph_integer_t index) { +static igraph_int_t QsortPartition (pblock* array, igraph_int_t left, igraph_int_t right, igraph_int_t index) { pblock p_value = array[index]; std::swap(array[right], array[index]); - igraph_integer_t stored = left; - for (igraph_integer_t i = left; i < right; i++) { + igraph_int_t stored = left; + for (igraph_int_t i = left; i < right; i++) { if (array[i].L <= p_value.L) { std::swap(array[i], array[stored]); stored++; @@ -794,10 +779,10 @@ static igraph_integer_t QsortPartition (pblock* array, igraph_integer_t left, ig return stored; } -static void QsortMain (pblock* array, igraph_integer_t left, igraph_integer_t right) { +static void QsortMain (pblock* array, igraph_int_t left, igraph_int_t right) { if (right > left) { - igraph_integer_t pivot = left; - igraph_integer_t part = QsortPartition(array, left, right, pivot); + igraph_int_t pivot = left; + igraph_int_t part = QsortPartition(array, left, right, pivot); QsortMain(array, left, part - 1); QsortMain(array, part + 1, right ); } @@ -867,16 +852,14 @@ igraph_error_t igraph_hrg_predict(const igraph_t *graph, igraph_vector_t *prob, igraph_hrg_t *hrg, igraph_bool_t start, - igraph_integer_t num_samples, - igraph_integer_t num_bins) { + igraph_int_t num_samples, + igraph_int_t num_bins) { IGRAPH_HANDLE_EXCEPTIONS_BEGIN if (start && !hrg) { IGRAPH_ERROR("`hrg' must be given when `start' is true", IGRAPH_EINVAL); } - RNG_BEGIN(); - dendro d; std::unique_ptr sg = igraph_i_hrg_getsimplegraph(graph, d, num_bins); @@ -903,8 +886,6 @@ igraph_error_t igraph_hrg_predict(const igraph_t *graph, rankCandidatesByProbability(*sg, d, br_list.get(), mk); IGRAPH_CHECK(recordPredictions(br_list.get(), edges, prob, mk)); - RNG_END(); - return IGRAPH_SUCCESS; IGRAPH_HANDLE_EXCEPTIONS_END @@ -930,12 +911,12 @@ igraph_error_t igraph_hrg_create(igraph_hrg_t *hrg, const igraph_t *graph, const igraph_vector_t *prob) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_internal = no_of_nodes > 0 ? (no_of_nodes - 1) / 2 : 0; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_internal = no_of_nodes > 0 ? (no_of_nodes - 1) / 2 : 0; igraph_vector_int_t deg, idx; - igraph_integer_t root = 0; - igraph_integer_t d0 = 0, d1 = 0, d2 = 0; - igraph_integer_t ii = 0, il = 0; + igraph_int_t root = 0; + igraph_int_t d0 = 0, d1 = 0, d2 = 0; + igraph_int_t ii = 0, il = 0; igraph_vector_int_t neis; igraph_vector_int_t path; igraph_bool_t simple; @@ -974,7 +955,7 @@ igraph_error_t igraph_hrg_create(igraph_hrg_t *hrg, IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_is_simple(graph, &simple)); + IGRAPH_CHECK(igraph_is_simple(graph, &simple, IGRAPH_DIRECTED)); if (!simple) { IGRAPH_ERROR("HRG graph must be a simple graph.", IGRAPH_EINVAL); } @@ -984,8 +965,8 @@ igraph_error_t igraph_hrg_create(igraph_hrg_t *hrg, // Every vertex, except for the root must have in-degree one. IGRAPH_CHECK(igraph_degree(graph, °, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t d = VECTOR(deg)[i]; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t d = VECTOR(deg)[i]; switch (d) { case 0: d0++; root = i; break; case 1: d1++; break; @@ -1005,7 +986,7 @@ igraph_error_t igraph_hrg_create(igraph_hrg_t *hrg, IGRAPH_CHECK(igraph_degree(graph, °, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS)); for (int i = 0; i < no_of_nodes; i++) { - igraph_integer_t d = VECTOR(deg)[i]; + igraph_int_t d = VECTOR(deg)[i]; switch (d) { case 0: d0++; break; case 2: d2++; break; @@ -1030,8 +1011,8 @@ igraph_error_t igraph_hrg_create(igraph_hrg_t *hrg, // the internal nodes, then the leaf nodes IGRAPH_VECTOR_INT_INIT_FINALLY(&idx, no_of_nodes); VECTOR(idx)[root] = - (ii++) - 1; - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t d = VECTOR(deg)[i]; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t d = VECTOR(deg)[i]; if (i == root) { continue; } @@ -1045,12 +1026,12 @@ igraph_error_t igraph_hrg_create(igraph_hrg_t *hrg, IGRAPH_CHECK(igraph_hrg_resize(hrg, no_of_internal + 1)); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t ri = VECTOR(idx)[i]; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t ri = VECTOR(idx)[i]; if (ri >= 0) { continue; } - IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, IGRAPH_OUT, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); VECTOR(hrg->left )[-ri - 1] = VECTOR(idx)[ VECTOR(neis)[0] ]; VECTOR(hrg->right)[-ri - 1] = VECTOR(idx)[ VECTOR(neis)[1] ]; VECTOR(hrg->prob )[-ri - 1] = VECTOR(*prob)[i]; @@ -1062,9 +1043,9 @@ igraph_error_t igraph_hrg_create(igraph_hrg_t *hrg, IGRAPH_VECTOR_INT_INIT_FINALLY(&path, 0); IGRAPH_CHECK(igraph_vector_int_push_back(&path, VECTOR(idx)[root])); while (!igraph_vector_int_empty(&path)) { - igraph_integer_t ri = igraph_vector_int_tail(&path); - igraph_integer_t lc = VECTOR(hrg->left)[-ri - 1]; - igraph_integer_t rc = VECTOR(hrg->right)[-ri - 1]; + igraph_int_t ri = igraph_vector_int_tail(&path); + igraph_int_t lc = VECTOR(hrg->left)[-ri - 1]; + igraph_int_t rc = VECTOR(hrg->right)[-ri - 1]; if (lc < 0 && VECTOR(hrg->vertices)[-lc - 1] == 0) { // Go left IGRAPH_CHECK(igraph_vector_int_push_back(&path, lc)); diff --git a/src/vendor/cigraph/src/hrg/hrg_types.cc b/src/vendor/cigraph/src/hrg/hrg_types.cc index e1bbd34dada..0c736af372a 100644 --- a/src/vendor/cigraph/src/hrg/hrg_types.cc +++ b/src/vendor/cigraph/src/hrg/hrg_types.cc @@ -1386,7 +1386,7 @@ double dendro::getSplitTotalWeight() const { // *********************************************************************** bool dendro::importDendrogramStructure(const igraph_hrg_t *hrg) { - igraph_integer_t size = igraph_hrg_size(hrg); + igraph_int_t size = igraph_hrg_size(hrg); if (size > INT_MAX) { throw std::range_error("Hierarchical random graph too large for the HRG module"); @@ -2530,7 +2530,7 @@ void graph::resetLinks() { // ********************************************************************** -void graph::setAdjacencyHistograms(const igraph_integer_t bin_count) { +void graph::setAdjacencyHistograms(const igraph_int_t bin_count) { // For all possible adjacencies, setup an edge histograms num_bins = bin_count + 1; bin_resolution = 1.0 / (double)(bin_count); diff --git a/src/vendor/cigraph/src/hrg/rbtree.h b/src/vendor/cigraph/src/hrg/rbtree.h index 222eba8d31a..309db8fce12 100644 --- a/src/vendor/cigraph/src/hrg/rbtree.h +++ b/src/vendor/cigraph/src/hrg/rbtree.h @@ -1,6 +1,6 @@ /* -*- mode: C++ -*- */ /* - IGraph library. + igraph library. Copyright (C) 2011-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/hrg/splittree_eq.h b/src/vendor/cigraph/src/hrg/splittree_eq.h index 0c83f853395..28d03b20661 100644 --- a/src/vendor/cigraph/src/hrg/splittree_eq.h +++ b/src/vendor/cigraph/src/hrg/splittree_eq.h @@ -1,6 +1,6 @@ /* -*- mode: C++ -*- */ /* - IGraph library. + igraph library. Copyright (C) 2011-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/internal/glpk_support.c b/src/vendor/cigraph/src/internal/glpk_support.c index 384390e737d..ab0f61ce3da 100644 --- a/src/vendor/cigraph/src/internal/glpk_support.c +++ b/src/vendor/cigraph/src/internal/glpk_support.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2011-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -49,7 +47,7 @@ int igraph_i_glpk_terminal_hook(void *info, const char *s) { if (igraph_i_interruption_handler && !igraph_i_glpk_error_info.is_interrupted && - igraph_allow_interruption(NULL) != IGRAPH_SUCCESS) { + igraph_allow_interruption() != IGRAPH_SUCCESS) { /* If an interruption has already occurred, do not set another error, to avoid an infinite loop between the term_hook (this function) and the error_hook. */ @@ -90,7 +88,7 @@ void igraph_i_glpk_interruption_hook(glp_tree *tree, void *info) { with the code GLP_ESTOP. */ if (igraph_i_interruption_handler) { - if (igraph_allow_interruption(NULL) != IGRAPH_SUCCESS) { + if (igraph_allow_interruption() != IGRAPH_SUCCESS) { glp_ios_terminate(tree); } } @@ -128,9 +126,8 @@ igraph_error_t igraph_i_glpk_check(int retval, const char* message) { } /* handle errors */ -#define HANDLE_CODE(c) case c: code = #c; ret = IGRAPH_##c; break; -#define HANDLE_CODE2(c) case c: code = #c; ret = IGRAPH_FAILURE; break; -#define HANDLE_CODE3(c) case c: code = #c; ret = IGRAPH_INTERRUPTED; break; +#define HANDLE_CODE(c) case c: code = #c; ret = IGRAPH_FAILURE; break; +#define HANDLE_CODE2(c) case c: code = #c; ret = IGRAPH_INTERRUPTED; break; switch (retval) { HANDLE_CODE(GLP_EBOUND); HANDLE_CODE(GLP_EROOT); @@ -140,14 +137,14 @@ igraph_error_t igraph_i_glpk_check(int retval, const char* message) { HANDLE_CODE(GLP_EMIPGAP); HANDLE_CODE(GLP_ETMLIM); - HANDLE_CODE3(GLP_ESTOP); + HANDLE_CODE2(GLP_ESTOP); - HANDLE_CODE2(GLP_EBADB); - HANDLE_CODE2(GLP_ESING); - HANDLE_CODE2(GLP_ECOND); - HANDLE_CODE2(GLP_EOBJLL); - HANDLE_CODE2(GLP_EOBJUL); - HANDLE_CODE2(GLP_EITLIM); + HANDLE_CODE(GLP_EBADB); + HANDLE_CODE(GLP_ESING); + HANDLE_CODE(GLP_ECOND); + HANDLE_CODE(GLP_EOBJLL); + HANDLE_CODE(GLP_EOBJUL); + HANDLE_CODE(GLP_EITLIM); default: IGRAPH_ERROR("Unknown GLPK error.", IGRAPH_FAILURE); diff --git a/src/vendor/cigraph/src/internal/glpk_support.h b/src/vendor/cigraph/src/internal/glpk_support.h index 973b6dad61e..3f05fa7bbfb 100644 --- a/src/vendor/cigraph/src/internal/glpk_support.h +++ b/src/vendor/cigraph/src/internal/glpk_support.h @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -40,9 +38,9 @@ #include #include -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS -typedef struct igraph_i_glpk_error_info_s { +typedef struct { jmp_buf jmp; /* used for bailing when there is a GLPK error */ bool is_interrupted; /* Boolean; true if there was an interruption */ bool is_error; /* Boolean; true if the error hook was called */ @@ -131,18 +129,18 @@ void igraph_i_glp_delete_prob(glp_prob *p); igraph_i_glpk_error_info.msg_ptr--; \ } \ *igraph_i_glpk_error_info.msg_ptr = '\0'; \ - igraph_error(igraph_i_glpk_error_info.msg, IGRAPH_FILE_BASENAME, __LINE__, IGRAPH_EGLP); \ + igraph_error(igraph_i_glpk_error_info.msg, IGRAPH_FILE_BASENAME, __LINE__, IGRAPH_FAILURE); \ } else if (igraph_i_glpk_error_info.is_error) { \ /* This branch can never be reached unless compiled with USING_R and using */ \ /* the hack to support pre-4.57 GLPK versions. See comments in glpk_support.c. */ \ - igraph_error("Error while running GLPK solver.", IGRAPH_FILE_BASENAME, __LINE__, IGRAPH_EGLP); \ + igraph_error("Error while running GLPK solver.", IGRAPH_FILE_BASENAME, __LINE__, IGRAPH_FAILURE); \ } \ - return IGRAPH_EGLP; \ + return IGRAPH_FAILURE; \ } \ } \ } while (0) -__END_DECLS +IGRAPH_END_C_DECLS #endif /* HAVE_GLPK */ diff --git a/src/vendor/cigraph/src/internal/gmp_internal.h b/src/vendor/cigraph/src/internal/gmp_internal.h index 5cc0b9910ad..e36970bc70e 100644 --- a/src/vendor/cigraph/src/internal/gmp_internal.h +++ b/src/vendor/cigraph/src/internal/gmp_internal.h @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2020 The igraph development team it under the terms of the GNU General Public License as published by diff --git a/src/vendor/cigraph/src/internal/hacks.c b/src/vendor/cigraph/src/internal/hacks.c index 09f42206b62..18c7ef6a648 100644 --- a/src/vendor/cigraph/src/internal/hacks.c +++ b/src/vendor/cigraph/src/internal/hacks.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA diff --git a/src/vendor/cigraph/src/internal/hacks.h b/src/vendor/cigraph/src/internal/hacks.h index b38bfce873c..270c073624e 100644 --- a/src/vendor/cigraph/src/internal/hacks.h +++ b/src/vendor/cigraph/src/internal/hacks.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2003-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -35,7 +34,7 @@ #include -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS #ifndef HAVE_STRDUP #define strdup igraph_i_strdup @@ -68,6 +67,6 @@ __BEGIN_DECLS */ #define IGRAPH_STATIC_ASSERT(condition) ((void)sizeof(char[1 - 2*!(condition)])) -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/internal/lsap.c b/src/vendor/cigraph/src/internal/lsap.c index 23eb1a08d8e..7494419ef36 100644 --- a/src/vendor/cigraph/src/internal/lsap.c +++ b/src/vendor/cigraph/src/internal/lsap.c @@ -31,25 +31,25 @@ typedef enum reduce_t { } reduce_t; typedef struct { - igraph_integer_t n; /* order of problem */ + igraph_int_t n; /* order of problem */ double **C; /* cost matrix */ double **c; /* reduced cost matrix */ - igraph_integer_t *s; /* assignment */ - igraph_integer_t *f; /* column i is assigned to f[i] */ - igraph_integer_t na; /* number of assigned items; */ - igraph_integer_t runs; /* number of iterations */ + igraph_int_t *s; /* assignment */ + igraph_int_t *f; /* column i is assigned to f[i] */ + igraph_int_t na; /* number of assigned items; */ + igraph_int_t runs; /* number of iterations */ double cost; /* minimum cost */ } AP; /* public interface */ /* constructors and destructor */ -static igraph_error_t ap_create_problem(AP **problem, const double *t, const igraph_integer_t n); +static igraph_error_t ap_create_problem(AP **problem, const double *t, const igraph_int_t n); /* static AP *ap_create_problem_from_matrix(double **t, int n); */ /* static AP *ap_read_problem(char *file); */ static void ap_free(AP *p); -static igraph_integer_t ap_get_result(AP *p, igraph_integer_t *res); +static igraph_int_t ap_get_result(AP *p, igraph_int_t *res); /* static int ap_costmatrix(AP *p, double **m); */ /* static int ap_datamatrix(AP *p, double **m); */ /* static int ap_iterations(AP *p); */ @@ -76,15 +76,15 @@ igraph_error_t ap_hungarian(AP *p) { covered_t *ri; /* covered rows */ covered_t *ci; /* covered columns */ - const igraph_integer_t n = p->n; /* size of problem */ + const igraph_int_t n = p->n; /* size of problem */ p->runs = 0; /* allocate memory */ /* Note: p is already on the finally stack here. */ - p->s = IGRAPH_CALLOC(1 + n, igraph_integer_t); + p->s = IGRAPH_CALLOC(1 + n, igraph_int_t); IGRAPH_CHECK_OOM(p->s, memerr); - p->f = IGRAPH_CALLOC(1 + n, igraph_integer_t); + p->f = IGRAPH_CALLOC(1 + n, igraph_int_t); IGRAPH_CHECK_OOM(p->f, memerr); ri = IGRAPH_CALLOC(1 + n, covered_t); @@ -108,9 +108,9 @@ igraph_error_t ap_hungarian(AP *p) { } /* check if assignment is a permutation of (1..n) */ - for (igraph_integer_t i = 1; i <= n; i++) { - igraph_integer_t ok = 0; - for (igraph_integer_t j = 1; j <= n; j++) + for (igraph_int_t i = 1; i <= n; i++) { + igraph_int_t ok = 0; + for (igraph_int_t j = 1; j <= n; j++) if (p->s[j] == i) { ++ok; } @@ -121,12 +121,12 @@ igraph_error_t ap_hungarian(AP *p) { /* calculate cost of assignment */ p->cost = 0; - for (igraph_integer_t i = 1; i <= n; i++) { + for (igraph_int_t i = 1; i <= n; i++) { p->cost += p->C[i][p->s[i]]; } /* reset result back to base-0 indexing */ - for (igraph_integer_t i = 1; i <= n; i++) { + for (igraph_int_t i = 1; i <= n; i++) { p->s[i - 1] = p->s[i] - 1; } @@ -140,8 +140,8 @@ igraph_error_t ap_hungarian(AP *p) { } /* abbreviated interface */ -igraph_integer_t ap_get_result(AP *p, igraph_integer_t *res) { - for (igraph_integer_t i = 0; i < p->n; i++) { +igraph_int_t ap_get_result(AP *p, igraph_int_t *res) { + for (igraph_int_t i = 0; i < p->n; i++) { res[i] = p->s[i]; } @@ -284,7 +284,7 @@ AP *ap_create_problem_from_matrix(double **t, int n) { #endif /* read data from vector */ -igraph_error_t ap_create_problem(AP **problem, const double *t, const igraph_integer_t n) { +igraph_error_t ap_create_problem(AP **problem, const double *t, const igraph_int_t n) { *problem = IGRAPH_CALLOC(1, AP); IGRAPH_CHECK_OOM(*problem, memerr); IGRAPH_FINALLY(ap_free, *problem); @@ -299,15 +299,15 @@ igraph_error_t ap_create_problem(AP **problem, const double *t, const igraph_int p->c = IGRAPH_CALLOC(n+1, double *); IGRAPH_CHECK_OOM(p->c, memerr); - for (igraph_integer_t i = 1; i <= n; i++) { + for (igraph_int_t i = 1; i <= n; i++) { p->C[i] = IGRAPH_CALLOC(n+1, double); IGRAPH_CHECK_OOM(p->C[i], memerr); p->c[i] = IGRAPH_CALLOC(n+1, double); IGRAPH_CHECK_OOM(p->c[i], memerr); } - for (igraph_integer_t i = 1; i <= n; i++) { - for (igraph_integer_t j = 1; j <= n; j++) { + for (igraph_int_t i = 1; i <= n; i++) { + for (igraph_int_t j = 1; j <= n; j++) { p->C[i][j] = t[n * (j - 1) + i - 1]; p->c[i][j] = t[n * (j - 1) + i - 1]; } @@ -326,7 +326,7 @@ void ap_free(AP *p) { IGRAPH_FREE(p->s); IGRAPH_FREE(p->f); - for (igraph_integer_t i = 1; i <= p->n; i++) { + for (igraph_int_t i = 1; i <= p->n; i++) { IGRAPH_FREE(p->C[i]); IGRAPH_FREE(p->c[i]); } @@ -341,7 +341,7 @@ void ap_free(AP *p) { /* void ap_show_data(AP *p) { - igraph_integer_t i, j; + igraph_int_t i, j; for(i = 1; i <= p->n; i++){ for(j = 1; j <= p->n; j++) @@ -358,7 +358,7 @@ double ap_mincost(AP *p) { return p->cost; } -igraph_integer_t ap_size(AP *p) { +igraph_int_t ap_size(AP *p) { return p->n; } @@ -372,7 +372,7 @@ int ap_iterations(AP *p) { void ap_print_solution(AP *p) { - igraph_integer_t i; + igraph_int_t i; printf("%d itertations, %d secs.\n",p->runs, (int)p->rtime); printf("Min Cost: %10.4f\n",p->cost); @@ -383,7 +383,7 @@ void ap_print_solution(AP *p) } int ap_costmatrix(AP *p, double **m) { - igraph_integer_t i, j; + igraph_int_t i, j; for (i = 0; i < p->n; i++) for (j = 0; j < p->n; j++) { @@ -394,7 +394,7 @@ int ap_costmatrix(AP *p, double **m) { } int ap_datamatrix(AP *p, double **m) { - igraph_integer_t i, j; + igraph_int_t i, j; for (i = 0; i < p->n; i++) for (j = 0; j < p->n; j++) { @@ -422,15 +422,15 @@ void ap_error(char *message) igraph_error_t cover(AP *p, covered_t *ri, covered_t *ci, reduce_t *res) { marked_t *mr; - igraph_integer_t r; + igraph_int_t r; - const igraph_integer_t n = p->n; + const igraph_int_t n = p->n; mr = IGRAPH_CALLOC(1 + p->n, marked_t); IGRAPH_CHECK_OOM(mr, memerr); /* reset cover indices */ - for (igraph_integer_t i = 1; i <= n; i++) { + for (igraph_int_t i = 1; i <= n; i++) { if (p->s[i] == UNASSIGNED) { ri[i] = UNCOVERED; mr[i] = MARKED; @@ -443,7 +443,7 @@ igraph_error_t cover(AP *p, covered_t *ri, covered_t *ci, reduce_t *res) { while (true) { /* find marked row */ r = 0; - for (igraph_integer_t i = 1; i <= n; i++) + for (igraph_int_t i = 1; i <= n; i++) if (mr[i] == MARKED) { r = i; break; @@ -452,7 +452,7 @@ igraph_error_t cover(AP *p, covered_t *ri, covered_t *ci, reduce_t *res) { if (r == 0) { break; } - for (igraph_integer_t i = 1; i <= n; i++) + for (igraph_int_t i = 1; i <= n; i++) if (p->c[r][i] == 0 && ci[i] == UNCOVERED) { if (p->f[i]) { ri[p->f[i]] = UNCOVERED; @@ -482,12 +482,12 @@ igraph_error_t cover(AP *p, covered_t *ri, covered_t *ci, reduce_t *res) { void reduce(AP *p, const covered_t *ri, const covered_t *ci) { double min; - const igraph_integer_t n = p->n; + const igraph_int_t n = p->n; /* find minimum in uncovered c-matrix */ min = DBL_MAX; - for (igraph_integer_t i = 1; i <= n; i++) - for (igraph_integer_t j = 1; j <= n; j++) + for (igraph_int_t i = 1; i <= n; i++) + for (igraph_int_t j = 1; j <= n; j++) if (ri[i] == UNCOVERED && ci[j] == UNCOVERED) { if (p->c[i][j] < min) { min = p->c[i][j]; @@ -496,8 +496,8 @@ void reduce(AP *p, const covered_t *ri, const covered_t *ci) { /* subtract min from each uncovered element and add it to each element */ /* which is covered twice */ - for (igraph_integer_t i = 1; i <= n; i++) - for (igraph_integer_t j = 1; j <= n; j++) { + for (igraph_int_t i = 1; i <= n; i++) + for (igraph_int_t j = 1; j <= n; j++) { if (ri[i] == UNCOVERED && ci[j] == UNCOVERED) { p->c[i][j] -= min; } @@ -508,9 +508,9 @@ void reduce(AP *p, const covered_t *ri, const covered_t *ci) { } igraph_error_t preassign(AP *p) { - igraph_integer_t min, r, c, n, count; + igraph_int_t min, r, c, n, count; assigned_t *ri, *ci; - igraph_integer_t *rz, *cz; + igraph_int_t *rz, *cz; n = p->n; p->na = 0; @@ -525,26 +525,26 @@ igraph_error_t preassign(AP *p) { IGRAPH_FINALLY(igraph_free, ci); /* row and column counts of zeroes */ - rz = IGRAPH_CALLOC(1 + n, igraph_integer_t); + rz = IGRAPH_CALLOC(1 + n, igraph_int_t); IGRAPH_CHECK_OOM(rz, memerr); IGRAPH_FINALLY(igraph_free, rz); - cz = IGRAPH_CALLOC(1 + n, igraph_integer_t); + cz = IGRAPH_CALLOC(1 + n, igraph_int_t); IGRAPH_CHECK_OOM(cz, memerr); IGRAPH_FINALLY(igraph_free, cz); - for (igraph_integer_t i = 1; i <= n; i++) { + for (igraph_int_t i = 1; i <= n; i++) { count = 0; - for (igraph_integer_t j = 1; j <= n; j++) + for (igraph_int_t j = 1; j <= n; j++) if (p->c[i][j] == 0) { ++count; } rz[i] = count; } - for (igraph_integer_t i = 1; i <= n; i++) { + for (igraph_int_t i = 1; i <= n; i++) { count = 0; - for (igraph_integer_t j = 1; j <= n; j++) + for (igraph_int_t j = 1; j <= n; j++) if (p->c[j][i] == 0) { ++count; } @@ -555,7 +555,7 @@ igraph_error_t preassign(AP *p) { /* find unassigned row with least number of zeroes > 0 */ min = IGRAPH_INTEGER_MAX; r = 0; - for (igraph_integer_t i = 1; i <= n; i++) + for (igraph_int_t i = 1; i <= n; i++) if (rz[i] > 0 && rz[i] < min && ri[i] == UNASSIGNED) { min = rz[i]; r = i; @@ -568,7 +568,7 @@ igraph_error_t preassign(AP *p) { /* find unassigned column in row r with least number of zeroes */ c = 0; min = IGRAPH_INTEGER_MAX; - for (igraph_integer_t i = 1; i <= n; i++) + for (igraph_int_t i = 1; i <= n; i++) if (p->c[r][i] == 0 && cz[i] < min && ci[i] == UNASSIGNED) { min = cz[i]; c = i; @@ -584,7 +584,7 @@ igraph_error_t preassign(AP *p) { /* adjust zero counts */ cz[c] = 0; - for (igraph_integer_t i = 1; i <= n; i++) + for (igraph_int_t i = 1; i <= n; i++) if (p->c[i][c] == 0) { --rz[i]; } @@ -603,28 +603,28 @@ igraph_error_t preassign(AP *p) { void preprocess(AP *p) { double min; - const igraph_integer_t n = p->n; + const igraph_int_t n = p->n; /* subtract column minima in each row */ - for (igraph_integer_t i = 1; i <= n; i++) { + for (igraph_int_t i = 1; i <= n; i++) { min = p->c[i][1]; - for (igraph_integer_t j = 2; j <= n; j++) + for (igraph_int_t j = 2; j <= n; j++) if (p->c[i][j] < min) { min = p->c[i][j]; } - for (igraph_integer_t j = 1; j <= n; j++) { + for (igraph_int_t j = 1; j <= n; j++) { p->c[i][j] -= min; } } /* subtract row minima in each column */ - for (igraph_integer_t i = 1; i <= n; i++) { + for (igraph_int_t i = 1; i <= n; i++) { min = p->c[1][i]; - for (igraph_integer_t j = 2; j <= n; j++) + for (igraph_int_t j = 2; j <= n; j++) if (p->c[j][i] < min) { min = p->c[j][i]; } - for (igraph_integer_t j = 1; j <= n; j++) { + for (igraph_int_t j = 1; j <= n; j++) { p->c[j][i] -= min; } } @@ -661,7 +661,7 @@ void preprocess(AP *p) { * * Time complexity: O(n^3), where n is the number of agents. */ -igraph_error_t igraph_solve_lsap(const igraph_matrix_t *c, igraph_integer_t n, +igraph_error_t igraph_solve_lsap(const igraph_matrix_t *c, igraph_int_t n, igraph_vector_int_t *p) { AP *ap; diff --git a/src/vendor/cigraph/src/internal/utils.c b/src/vendor/cigraph/src/internal/utils.c index 0698e47dfc8..058bd12fe87 100644 --- a/src/vendor/cigraph/src/internal/utils.c +++ b/src/vendor/cigraph/src/internal/utils.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -17,6 +17,8 @@ */ #include "igraph_interface.h" +#include "igraph_qsort.h" +#include "igraph_random.h" #include "internal/utils.h" @@ -51,9 +53,9 @@ igraph_error_t igraph_i_matrix_subset_vertices( /* Assertion: the size of 'm' agrees with 'graph': */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t ncol = igraph_matrix_ncol(m); - igraph_integer_t nrow = igraph_matrix_nrow(m); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t ncol = igraph_matrix_ncol(m); + igraph_int_t nrow = igraph_matrix_nrow(m); IGRAPH_ASSERT(nrow == no_of_nodes && nrow == ncol); @@ -76,15 +78,15 @@ igraph_error_t igraph_i_matrix_subset_vertices( IGRAPH_MATRIX_INIT_FINALLY(&tmp, IGRAPH_VIT_SIZE(fromvit), IGRAPH_VIT_SIZE(tovit)); - for (igraph_integer_t j=0; ! IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit), j++) { - igraph_integer_t i; + for (igraph_int_t j=0; ! IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit), j++) { + igraph_int_t i; for (IGRAPH_VIT_RESET(fromvit), i=0; ! IGRAPH_VIT_END(fromvit); IGRAPH_VIT_NEXT(fromvit), i++) { MATRIX(tmp, i, j) = MATRIX(*m, IGRAPH_VIT_GET(fromvit), IGRAPH_VIT_GET(tovit)); } } /* This is O(1) time */ - IGRAPH_CHECK(igraph_matrix_swap(m, &tmp)); + igraph_matrix_swap(m, &tmp); igraph_matrix_destroy(&tmp); igraph_vit_destroy(&tovit); @@ -93,3 +95,130 @@ igraph_error_t igraph_i_matrix_subset_vertices( return IGRAPH_SUCCESS; } + + +/* Lexicographic edge comparator, used with igraph_qsort() in igraph_i_simplify_edge_list() */ +static int edge_comparator(const void *a, const void *b) { + igraph_int_t *A = (igraph_int_t *) a; + igraph_int_t *B = (igraph_int_t *) b; + + if (A[0] < B[0]) { + return -1; + } + if (A[0] > B[0]) { + return 1; + } + + /* first are equal */ + if (A[1] < B[1]) { + return -1; + } + if (A[1] > B[1]) { + return 1; + } + + /* second are equal, so the edges must be equal */ + return 0; +} + +/** + * Simplify an edge list in-place. Edges may be reordered by this function. + * + * TODO: Refactor this to take the number of vertices as input and use linear-time radix sort. + * + * \param edges The edge list vector, as a consecutive list of pairs. It will be modified in-place. + * \param self_loops Set to \c false to remove self-loops. + * \param multi_edges Set to \c false to eliminate multi-edges. + * \param directed Whether to treat edges as directed. + */ +void igraph_i_simplify_edge_list( + igraph_vector_int_t *edges, + igraph_bool_t remove_loops, igraph_bool_t remove_multiple, + igraph_bool_t directed) { + + igraph_int_t size = igraph_vector_int_size(edges); + + if (size == 0 || (!remove_loops && !remove_multiple)) { + return; + } + + /* Canonicalize undirected edges. */ + if (!directed) { + for (igraph_int_t i = 0; i < size; i += 2) { + if (VECTOR(*edges)[i] > VECTOR(*edges)[i + 1]) { + igraph_int_t temp = VECTOR(*edges)[i]; + VECTOR(*edges)[i] = VECTOR(*edges)[i + 1]; + VECTOR(*edges)[i + 1] = temp; + } + } + } + + /* Sort edge list. Not needed if multi edges are allowed. */ + if (remove_multiple) { + igraph_qsort(VECTOR(*edges), size / 2, 2 * sizeof(igraph_int_t), + &edge_comparator); + } + + /* Remove self-loops and duplicate edges from the sorted edge list, in place. + * i points to the current edge being examined, j points to the last edge copied. */ + + igraph_int_t j = -2; + for (igraph_int_t i = 0 ; i < size; i += 2) { + if (remove_multiple && + /* If we've already copied some edges, */ + j != -2 && + /* and the current edge is equal to the previously copied one: */ + VECTOR(*edges)[i] == VECTOR(*edges)[j] && + VECTOR(*edges)[i + 1] == VECTOR(*edges)[j + 1]) + { + /* This edge is a duplicate, and should be skipped */ + continue; + } + + if (remove_loops && + VECTOR(*edges)[i] == VECTOR(*edges)[i + 1]) + { + /* This edge is a self loop, and should be skipped */ + continue; + } + + j += 2; + VECTOR(*edges)[j] = VECTOR(*edges)[i]; + VECTOR(*edges)[j + 1] = VECTOR(*edges)[i + 1]; + } + + igraph_vector_int_resize(edges, j + 2); /* shrinks */ +} + +/** + * Shuffle a list of pairs, such as an edge list. + * + * \param pairs Vector of pairs, will be modified in-place. + * \return Error code, when the input is not of even length. + */ +igraph_error_t igraph_i_vector_int_shuffle_pairs(igraph_vector_int_t *pairs) { + igraph_int_t pair_count = igraph_vector_int_size(pairs); + + if (pair_count % 2 == 1) { + IGRAPH_ERROR("A vector of pairs must have an even length.", IGRAPH_EINVAL); + } + + pair_count /= 2; + while (pair_count > 1) { + igraph_int_t dummy, k; + + pair_count--; + k = RNG_INTEGER(0, pair_count); + + dummy = VECTOR(*pairs)[pair_count * 2]; + VECTOR(*pairs)[pair_count * 2] = VECTOR(*pairs)[k * 2]; + + VECTOR(*pairs)[k * 2] = dummy; + dummy = VECTOR(*pairs)[pair_count * 2 + 1]; + + VECTOR(*pairs)[pair_count * 2] = VECTOR(*pairs)[k * 2 + 1]; + VECTOR(*pairs)[k * 2 + 1] = dummy; + } + + return IGRAPH_SUCCESS; +} diff --git a/src/vendor/cigraph/src/internal/utils.h b/src/vendor/cigraph/src/internal/utils.h index 94be451fc3a..f3be6b2877e 100644 --- a/src/vendor/cigraph/src/internal/utils.h +++ b/src/vendor/cigraph/src/internal/utils.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2008-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -29,4 +29,11 @@ igraph_error_t igraph_i_matrix_subset_vertices( igraph_vs_t from, igraph_vs_t to); +void igraph_i_simplify_edge_list( + igraph_vector_int_t *edges, + igraph_bool_t self_loops, igraph_bool_t multi_edges, + igraph_bool_t directed); + +igraph_error_t igraph_i_vector_int_shuffle_pairs(igraph_vector_int_t *pairs); + #endif /* IGRAPH_INTERNAL_UTILS_H */ diff --git a/src/vendor/cigraph/src/internal/zeroin.c b/src/vendor/cigraph/src/internal/zeroin.c deleted file mode 100644 index 89ade546255..00000000000 --- a/src/vendor/cigraph/src/internal/zeroin.c +++ /dev/null @@ -1,201 +0,0 @@ -/* -*- mode: C -*- */ -/* - IGraph library. - Copyright (C) 2007-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - -*/ - -/* from GNU R's zeroin.c, minor modifications by Gabor Csardi */ - -/* from NETLIB c/brent.shar with max.iter, add'l info and convergence - details hacked in by Peter Dalgaard */ - -/************************************************************************* - * C math library - * function ZEROIN - obtain a function zero within the given range - * - * Input - * double zeroin(ax,bx,f,info,Tol,Maxit) - * double ax; Root will be seeked for within - * double bx; a range [ax,bx] - * double (*f)(double x, void *info); Name of the function whose zero - * will be seeked for - * void *info; Add'l info passed to f - * double *Tol; Acceptable tolerance for the root - * value. - * May be specified as 0.0 to cause - * the program to find the root as - * accurate as possible - * - * int *Maxit; Max. iterations - * - * - * Output - * Zeroin returns an estimate for the root with accuracy - * 4*EPSILON*abs(x) + tol - * *Tol returns estimated precision - * *Maxit returns actual # of iterations, or -1 if maxit was - * reached without convergence. - * - * Algorithm - * G.Forsythe, M.Malcolm, C.Moler, Computer methods for mathematical - * computations. M., Mir, 1980, p.180 of the Russian edition - * - * The function makes use of the bisection procedure combined with - * the linear or quadric inverse interpolation. - * At every step program operates on three abscissae - a, b, and c. - * b - the last and the best approximation to the root - * a - the last but one approximation - * c - the last but one or even earlier approximation than a that - * 1) |f(b)| <= |f(c)| - * 2) f(b) and f(c) have opposite signs, i.e. b and c confine - * the root - * At every step Zeroin selects one of the two new approximations, the - * former being obtained by the bisection procedure and the latter - * resulting in the interpolation (if a,b, and c are all different - * the quadric interpolation is utilized, otherwise the linear one). - * If the latter (i.e. obtained by the interpolation) point is - * reasonable (i.e. lies within the current interval [b,c] not being - * too close to the boundaries) it is accepted. The bisection result - * is used in the other case. Therefore, the range of uncertainty is - * ensured to be reduced at least by the factor 1.6 - * - ************************************************************************ - */ - -#include "igraph_nongraph.h" -#include "igraph_types.h" - -#include "core/interruption.h" - -#include -#include - -#define EPSILON DBL_EPSILON - -igraph_error_t igraph_zeroin( /* An estimate of the root */ - igraph_real_t *ax, /* Left border | of the range */ - igraph_real_t *bx, /* Right border| the root is seeked*/ - igraph_real_t (*f)(igraph_real_t x, void *info), /* Function under investigation */ - void *info, /* Add'l info passed on to f */ - igraph_real_t *Tol, /* Acceptable tolerance */ - int *Maxit, /* Max # of iterations */ - igraph_real_t *res) { /* Result is stored here */ - igraph_real_t a, b, c, /* Abscissae, descr. see above */ - fa, fb, fc; /* f(a), f(b), f(c) */ - igraph_real_t tol; - int maxit; - - a = *ax; b = *bx; fa = (*f)(a, info); fb = (*f)(b, info); - c = a; fc = fa; - maxit = *Maxit + 1; tol = * Tol; - - /* First test if we have found a root at an endpoint */ - if (fa == 0.0) { - *Tol = 0.0; - *Maxit = 0; - *res = a; - return IGRAPH_SUCCESS; - } - if (fb == 0.0) { - *Tol = 0.0; - *Maxit = 0; - *res = b; - return IGRAPH_SUCCESS; - } - - while (maxit--) { /* Main iteration loop */ - igraph_real_t prev_step = b - a; /* Distance from the last but one to the last approximation */ - igraph_real_t tol_act; /* Actual tolerance */ - igraph_real_t p; /* Interpolation step is calculated in the form p/q; */ - igraph_real_t q; /* division operations are delayed until the last moment */ - igraph_real_t new_step; /* Step at this iteration */ - - IGRAPH_ALLOW_INTERRUPTION(); - - if ( fabs(fc) < fabs(fb) ) { - /* Swap data for b to be the best approximation */ - a = b; b = c; c = a; - fa = fb; fb = fc; fc = fa; - } - tol_act = 2 * EPSILON * fabs(b) + tol / 2; - new_step = (c - b) / 2; - - if ( fabs(new_step) <= tol_act || fb == (igraph_real_t)0 ) { - *Maxit -= maxit; - *Tol = fabs(c - b); - *res = b; - return IGRAPH_SUCCESS; /* Acceptable approx. is found */ - } - - /* Decide if the interpolation can be tried */ - if ( fabs(prev_step) >= tol_act /* If prev_step was large enough*/ - && fabs(fa) > fabs(fb) ) { - /* and was in true direction, - * Interpolation may be tried */ - register igraph_real_t t1, cb, t2; - cb = c - b; - if ( a == c ) { /* If we have only two distinct */ - /* points linear interpolation */ - t1 = fb / fa; /* can only be applied */ - p = cb * t1; - q = 1.0 - t1; - } else { /* Quadric inverse interpolation*/ - - q = fa / fc; t1 = fb / fc; t2 = fb / fa; - p = t2 * ( cb * q * (q - t1) - (b - a) * (t1 - 1.0) ); - q = (q - 1.0) * (t1 - 1.0) * (t2 - 1.0); - } - if ( p > (igraph_real_t)0 ) { /* p was calculated with the */ - q = -q; /* opposite sign; make p positive */ - } else { /* and assign possible minus to */ - p = -p; /* q */ - } - - if ( p < (0.75 * cb * q - fabs(tol_act * q) / 2) /* If b+p/q falls in [b,c]*/ - && p < fabs(prev_step * q / 2) ) { /* and isn't too large */ - new_step = p / q; - } /* it is accepted - * If p/q is too large then the - * bisection procedure can - * reduce [b,c] range to more - * extent */ - } - - if ( fabs(new_step) < tol_act) { /* Adjust the step to be not less*/ - if ( new_step > (igraph_real_t)0 ) { /* than tolerance */ - new_step = tol_act; - } else { - new_step = -tol_act; - } - } - a = b; fa = fb; /* Save the previous approx. */ - b += new_step; fb = (*f)(b, info); /* Do step to a new approxim. */ - if ( (fb > 0 && fc > 0) || (fb < 0 && fc < 0) ) { - /* Adjust c for it to have a sign opposite to that of b */ - c = a; fc = fa; - } - - } - /* failed! */ - *Tol = fabs(c - b); - *Maxit = -1; - *res = b; - return IGRAPH_DIVERGED; -} diff --git a/src/vendor/cigraph/src/io/dimacs.c b/src/vendor/cigraph/src/io/dimacs.c index 4de4f40ff21..31543514e37 100644 --- a/src/vendor/cigraph/src/io/dimacs.c +++ b/src/vendor/cigraph/src/io/dimacs.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -39,24 +38,6 @@ #define IGRAPH_DIMACS_MAX_EDGE_COUNT INT32_MAX #endif -/** - * \function igraph_read_graph_dimacs - * \brief Read a graph in DIMACS format (deprecated alias). - * - * \deprecated-by igraph_read_graph_dimacs_flow 0.10.0 - */ -igraph_error_t igraph_read_graph_dimacs(igraph_t *graph, FILE *instream, - igraph_strvector_t *problem, - igraph_vector_int_t *label, - igraph_integer_t *source, - igraph_integer_t *target, - igraph_vector_t *capacity, - igraph_bool_t directed) { - return igraph_read_graph_dimacs_flow( - graph, instream, problem, label, source, target, capacity, directed - ); -} - #define EXPECT(actual, expected) \ do { \ if ((actual) != (expected)) { \ @@ -126,16 +107,16 @@ igraph_error_t igraph_read_graph_dimacs_flow( igraph_t *graph, FILE *instream, igraph_strvector_t *problem, igraph_vector_int_t *label, - igraph_integer_t *source, - igraph_integer_t *target, + igraph_int_t *source, + igraph_int_t *target, igraph_vector_t *capacity, igraph_bool_t directed) { igraph_vector_int_t edges; - igraph_integer_t no_of_nodes = -1; - igraph_integer_t no_of_edges = -1; - igraph_integer_t tsource = -1; - igraph_integer_t ttarget = -1; + igraph_int_t no_of_nodes = -1; + igraph_int_t no_of_edges = -1; + igraph_int_t tsource = -1; + igraph_int_t ttarget = -1; char prob[21]; enum { PROBLEM_NONE, @@ -160,8 +141,8 @@ igraph_error_t igraph_read_graph_dimacs_flow( } EXPECT(read, 1); switch (str[0]) { - igraph_integer_t tmp, tmp2; - igraph_integer_t from, to; + igraph_int_t tmp, tmp2; + igraph_int_t from, to; igraph_real_t cap; case 'c': @@ -305,18 +286,6 @@ igraph_error_t igraph_read_graph_dimacs_flow( return IGRAPH_SUCCESS; } -/** - * \function igraph_write_graph_dimacs - * \brief Write a graph in DIMACS format (deprecated alias). - * - * \deprecated-by igraph_write_graph_dimacs_flow 0.10.0 - */ -igraph_error_t igraph_write_graph_dimacs(const igraph_t *graph, FILE *outstream, - igraph_integer_t source, igraph_integer_t target, - const igraph_vector_t *capacity) { - return igraph_write_graph_dimacs_flow(graph, outstream, source, target, capacity); -} - /** * \function igraph_write_graph_dimacs_flow * \brief Write a graph in DIMACS format. @@ -343,13 +312,13 @@ igraph_error_t igraph_write_graph_dimacs(const igraph_t *graph, FILE *outstream, * \sa \ref igraph_read_graph_dimacs_flow() */ igraph_error_t igraph_write_graph_dimacs_flow(const igraph_t *graph, FILE *outstream, - igraph_integer_t source, igraph_integer_t target, + igraph_int_t source, igraph_int_t target, const igraph_vector_t *capacity) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_eit_t it; - igraph_integer_t i = 0; + igraph_int_t i = 0; int ret, ret1, ret2, ret3; if (igraph_vector_size(capacity) != no_of_edges) { @@ -373,7 +342,7 @@ igraph_error_t igraph_write_graph_dimacs_flow(const igraph_t *graph, FILE *outst } while (!IGRAPH_EIT_END(it)) { - igraph_integer_t from, to; + igraph_int_t from, to; igraph_real_t cap; igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to); cap = VECTOR(*capacity)[i++]; diff --git a/src/vendor/cigraph/src/io/dl-header.h b/src/vendor/cigraph/src/io/dl-header.h index b34910957aa..1da687e9241 100644 --- a/src/vendor/cigraph/src/io/dl-header.h +++ b/src/vendor/cigraph/src/io/dl-header.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2009-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -43,8 +43,8 @@ typedef struct { char errmsg[300]; igraph_error_t igraph_errno; int mode; - igraph_integer_t n; - igraph_integer_t from, to; + igraph_int_t n; + igraph_int_t from, to; igraph_vector_int_t edges; igraph_vector_t weights; igraph_strvector_t labels; diff --git a/src/vendor/cigraph/src/io/dl-lexer.l b/src/vendor/cigraph/src/io/dl-lexer.l index e34d8e29db5..8cf0b21af7b 100644 --- a/src/vendor/cigraph/src/io/dl-lexer.l +++ b/src/vendor/cigraph/src/io/dl-lexer.l @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -23,7 +23,7 @@ %{ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA diff --git a/src/vendor/cigraph/src/io/dl-parser.y b/src/vendor/cigraph/src/io/dl-parser.y index d166f889aff..22923effcbf 100644 --- a/src/vendor/cigraph/src/io/dl-parser.y +++ b/src/vendor/cigraph/src/io/dl-parser.y @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2009-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -23,7 +23,7 @@ %{ /* - IGraph library. + igraph library. Copyright (C) 2009-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -54,12 +54,12 @@ int igraph_dl_yyerror(YYLTYPE* locp, igraph_i_dl_parsedata_t* context, const char *s); static igraph_error_t igraph_i_dl_add_str(char *newstr, yy_size_t length, igraph_i_dl_parsedata_t *context); -static igraph_error_t igraph_i_dl_add_edge(igraph_integer_t from, igraph_integer_t to, +static igraph_error_t igraph_i_dl_add_edge(igraph_int_t from, igraph_int_t to, igraph_i_dl_parsedata_t *context); -static igraph_error_t igraph_i_dl_add_edge_w(igraph_integer_t from, igraph_integer_t to, +static igraph_error_t igraph_i_dl_add_edge_w(igraph_int_t from, igraph_int_t to, igraph_real_t weight, igraph_i_dl_parsedata_t *context); -static igraph_error_t igraph_i_dl_check_vid(igraph_integer_t dl_vid); +static igraph_error_t igraph_i_dl_check_vid(igraph_int_t dl_vid); #define scanner context->scanner @@ -76,7 +76,7 @@ static igraph_error_t igraph_i_dl_check_vid(igraph_integer_t dl_vid); %lex-param { void* scanner } %union { - igraph_integer_t integer; + igraph_int_t integer; igraph_real_t real; }; @@ -195,19 +195,19 @@ edgelist1data: {} /* nothing, empty graph */ ; edgelist1dataline: integer integer weight NEWLINE { - igraph_integer_t from = $1, to = $2; + igraph_int_t from = $1, to = $2; IGRAPH_YY_CHECK(igraph_i_dl_check_vid(from)); IGRAPH_YY_CHECK(igraph_i_dl_check_vid(to)); IGRAPH_YY_CHECK(igraph_i_dl_add_edge_w(from-1, to-1, $3, context)); } | integer integer NEWLINE { - igraph_integer_t from = $1, to = $2; + igraph_int_t from = $1, to = $2; IGRAPH_YY_CHECK(igraph_i_dl_check_vid(from)); IGRAPH_YY_CHECK(igraph_i_dl_check_vid(to)); IGRAPH_YY_CHECK(igraph_i_dl_add_edge(from-1, to-1, context)); } ; integer: NUM { - igraph_integer_t val; + igraph_int_t val; IGRAPH_YY_CHECK(igraph_i_parse_integer(igraph_dl_yyget_text(scanner), igraph_dl_yyget_leng(scanner), &val)); @@ -233,11 +233,11 @@ weight: NUM { }; elabel: LABEL { - igraph_integer_t trie_id; + igraph_int_t trie_id; /* Copy label list to trie, if needed */ if (igraph_strvector_size(&context->labels) != 0) { - igraph_integer_t i, id, n=igraph_strvector_size(&context->labels); + igraph_int_t i, id, n=igraph_strvector_size(&context->labels); for (i=0; itrie, igraph_strvector_get(&context->labels, i), &id)); } @@ -274,7 +274,7 @@ from: NUM { } ; tolist: {} | tolist integer { - igraph_integer_t to = $2; + igraph_int_t to = $2; IGRAPH_YY_CHECK(igraph_i_dl_check_vid(to)); IGRAPH_YY_CHECK(igraph_vector_int_push_back(&context->edges, context->from-1)); @@ -314,7 +314,7 @@ static igraph_error_t igraph_i_dl_add_str(char *newstr, yy_size_t length, return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_dl_add_edge(igraph_integer_t from, igraph_integer_t to, +static igraph_error_t igraph_i_dl_add_edge(igraph_int_t from, igraph_int_t to, igraph_i_dl_parsedata_t *context) { //IGRAPH_CHECK(igraph_i_dl_check_vid(from+1)); //IGRAPH_CHECK(igraph_i_dl_check_vid(to+1)); @@ -323,11 +323,11 @@ static igraph_error_t igraph_i_dl_add_edge(igraph_integer_t from, igraph_integer return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_dl_add_edge_w(igraph_integer_t from, igraph_integer_t to, +static igraph_error_t igraph_i_dl_add_edge_w(igraph_int_t from, igraph_int_t to, igraph_real_t weight, igraph_i_dl_parsedata_t *context) { - igraph_integer_t n=igraph_vector_size(&context->weights); - igraph_integer_t n2=igraph_vector_int_size(&context->edges)/2; + igraph_int_t n=igraph_vector_size(&context->weights); + igraph_int_t n2=igraph_vector_int_size(&context->edges)/2; if (n != n2) { IGRAPH_CHECK(igraph_vector_resize(&context->weights, n2)); for (; nvalue.as_strvector, namevec)); + pname = &name; - namerec.name = namestr; - namerec.type = IGRAPH_ATTRIBUTE_STRING; - namerec.value = namevec; - VECTOR(name)[0] = &namerec; } /* Weights */ if (igraph_vector_size(&context.weights) != 0) { - IGRAPH_CHECK(igraph_vector_ptr_init(&weight, 1)); - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &weight); + IGRAPH_CHECK(igraph_attribute_record_list_init(&weight, 1)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &weight); + + weightrec = igraph_attribute_record_list_get_ptr(&weight, 0); + IGRAPH_CHECK(igraph_attribute_record_set_name(weightrec, weightstr)); + IGRAPH_CHECK(igraph_attribute_record_set_type(weightrec, IGRAPH_ATTRIBUTE_NUMERIC)); + igraph_vector_swap(weightrec->value.as_vector, &context.weights); + pweight = &weight; - weightrec.name = weightstr; - weightrec.type = IGRAPH_ATTRIBUTE_NUMERIC; - weightrec.value = &context.weights; - VECTOR(weight)[0] = &weightrec; } /* Create graph */ @@ -180,12 +184,12 @@ igraph_error_t igraph_read_graph_dl(igraph_t *graph, FILE *instream, IGRAPH_CHECK(igraph_add_edges(graph, &context.edges, pweight)); if (pweight) { - igraph_vector_ptr_destroy(pweight); + igraph_attribute_record_list_destroy(pweight); IGRAPH_FINALLY_CLEAN(1); } if (pname) { - igraph_vector_ptr_destroy(pname); + igraph_attribute_record_list_destroy(pname); IGRAPH_FINALLY_CLEAN(1); } diff --git a/src/vendor/cigraph/src/io/dot.c b/src/vendor/cigraph/src/io/dot.c index 88b8c5f732b..899dbd9b380 100644 --- a/src/vendor/cigraph/src/io/dot.c +++ b/src/vendor/cigraph/src/io/dot.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -39,7 +38,7 @@ static igraph_error_t dot_escape(const char *orig, igraph_vector_char_t* result) { /* do we have to escape the string at all? */ - igraph_integer_t i, j, len = strlen(orig), newlen = 0; + igraph_int_t i, j, len = strlen(orig), newlen = 0; igraph_bool_t need_quote = false, is_number = true; /* first, check whether the string is equal to some reserved word, or empty */ @@ -159,8 +158,8 @@ static igraph_error_t fprint_integral_or_precise(FILE *file, igraph_real_t x, ig * \example examples/simple/dot.c */ igraph_error_t igraph_write_graph_dot(const igraph_t *graph, FILE* outstream) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); const igraph_bool_t directed = igraph_is_directed(graph); const char *edgeop = directed ? "->" : "--"; igraph_strvector_t gnames, vnames, enames; @@ -199,7 +198,7 @@ igraph_error_t igraph_write_graph_dot(const igraph_t *graph, FILE* outstream) { /* Write the graph attributes */ if (igraph_vector_int_size(>ypes) > 0) { CHECK(fprintf(outstream, " graph [\n")); - for (igraph_integer_t i = 0; i < igraph_vector_int_size(>ypes); i++) { + for (igraph_int_t i = 0; i < igraph_vector_int_size(>ypes); i++) { const char *name; name = igraph_strvector_get(&gnames, i); IGRAPH_CHECK(dot_escape(name, &buf)); @@ -227,9 +226,9 @@ igraph_error_t igraph_write_graph_dot(const igraph_t *graph, FILE* outstream) { /* Write the vertices */ if (igraph_vector_int_size(&vtypes) > 0) { - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { CHECK(fprintf(outstream, " %" IGRAPH_PRId " [\n", i)); - for (igraph_integer_t j = 0; j < igraph_vector_int_size(&vtypes); j++) { + for (igraph_int_t j = 0; j < igraph_vector_int_size(&vtypes); j++) { const char *name; name = igraph_strvector_get(&vnames, j); IGRAPH_CHECK(dot_escape(name, &buf)); @@ -255,7 +254,7 @@ igraph_error_t igraph_write_graph_dot(const igraph_t *graph, FILE* outstream) { CHECK(fprintf(outstream, " ];\n")); } } else { - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { CHECK(fprintf(outstream, " %" IGRAPH_PRId ";\n", i)); } } @@ -263,11 +262,11 @@ igraph_error_t igraph_write_graph_dot(const igraph_t *graph, FILE* outstream) { /* Write the edges */ if (igraph_vector_int_size(&etypes) > 0) { - for (igraph_integer_t i = 0; i < no_of_edges; i++) { - igraph_integer_t from = IGRAPH_FROM(graph, i); - igraph_integer_t to = IGRAPH_TO(graph, i); + for (igraph_int_t i = 0; i < no_of_edges; i++) { + igraph_int_t from = IGRAPH_FROM(graph, i); + igraph_int_t to = IGRAPH_TO(graph, i); CHECK(fprintf(outstream, " %" IGRAPH_PRId " %s %" IGRAPH_PRId " [\n", from, edgeop, to)); - for (igraph_integer_t j = 0; j < igraph_vector_int_size(&etypes); j++) { + for (igraph_int_t j = 0; j < igraph_vector_int_size(&etypes); j++) { const char *name; name = igraph_strvector_get(&enames, j); IGRAPH_CHECK(dot_escape(name, &buf)); @@ -296,9 +295,9 @@ igraph_error_t igraph_write_graph_dot(const igraph_t *graph, FILE* outstream) { CHECK(fprintf(outstream, " ];\n")); } } else { - for (igraph_integer_t i = 0; i < no_of_edges; i++) { - igraph_integer_t from = IGRAPH_FROM(graph, i); - igraph_integer_t to = IGRAPH_TO(graph, i); + for (igraph_int_t i = 0; i < no_of_edges; i++) { + igraph_int_t from = IGRAPH_FROM(graph, i); + igraph_int_t to = IGRAPH_TO(graph, i); CHECK(fprintf(outstream, " %" IGRAPH_PRId " %s %" IGRAPH_PRId ";\n", from, edgeop, to)); } } diff --git a/src/vendor/cigraph/src/io/edgelist.c b/src/vendor/cigraph/src/io/edgelist.c index ccd3b09a7b2..d0bb089af7c 100644 --- a/src/vendor/cigraph/src/io/edgelist.c +++ b/src/vendor/cigraph/src/io/edgelist.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -76,10 +75,10 @@ * reading an integer requires O(1) time. */ igraph_error_t igraph_read_graph_edgelist(igraph_t *graph, FILE *instream, - igraph_integer_t n, igraph_bool_t directed) { + igraph_int_t n, igraph_bool_t directed) { igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; - igraph_integer_t from, to; + igraph_int_t from, to; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, 100)); @@ -143,7 +142,7 @@ igraph_error_t igraph_write_graph_edgelist(const igraph_t *graph, FILE *outstrea IGRAPH_FINALLY(igraph_eit_destroy, &it); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t from, to; + igraph_int_t from, to; int ret; igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to); ret = fprintf(outstream, "%" IGRAPH_PRId " %" IGRAPH_PRId "\n", diff --git a/src/vendor/cigraph/src/io/gml-header.h b/src/vendor/cigraph/src/io/gml-header.h index b8d590d8068..ef9b5d3f928 100644 --- a/src/vendor/cigraph/src/io/gml-header.h +++ b/src/vendor/cigraph/src/io/gml-header.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2011-2021 The igraph development team This program is free software; you can redistribute it and/or modify diff --git a/src/vendor/cigraph/src/io/gml-lexer.l b/src/vendor/cigraph/src/io/gml-lexer.l index 375dc6fbca0..7e9c5c6042d 100644 --- a/src/vendor/cigraph/src/io/gml-lexer.l +++ b/src/vendor/cigraph/src/io/gml-lexer.l @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2007-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -21,7 +21,7 @@ %{ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA diff --git a/src/vendor/cigraph/src/io/gml-parser.y b/src/vendor/cigraph/src/io/gml-parser.y index c9ee9454b7c..d11fc4da30b 100644 --- a/src/vendor/cigraph/src/io/gml-parser.y +++ b/src/vendor/cigraph/src/io/gml-parser.y @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2009-2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -21,7 +21,7 @@ %{ /* - IGraph library. + igraph library. Copyright (C) 2009-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -186,7 +186,7 @@ static igraph_error_t igraph_i_gml_make_numeric(const char *name, IGRAPH_FINALLY(igraph_free, t); /* The GML spec only requires support for 32-bit signed integers, - * but igraph tries to support the same range as igraph_integer_t, + * but igraph tries to support the same range as igraph_int_t, * so that it can read/write all graphs it can represent. * We treat anything out of that range as real. These values end * up as igraph_real_t anyway, as igraph does not currently support diff --git a/src/vendor/cigraph/src/io/gml-tree.c b/src/vendor/cigraph/src/io/gml-tree.c index 59b08077836..05b1d1d6c84 100644 --- a/src/vendor/cigraph/src/io/gml-tree.c +++ b/src/vendor/cigraph/src/io/gml-tree.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2007-2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -27,10 +27,10 @@ igraph_error_t igraph_gml_tree_init_integer(igraph_gml_tree_t *t, const char *name, - igraph_integer_t line, - igraph_integer_t value) { + igraph_int_t line, + igraph_int_t value) { - igraph_integer_t *p; + igraph_int_t *p; IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->names, 1); IGRAPH_VECTOR_CHAR_INIT_FINALLY(&t->types, 1); @@ -47,7 +47,7 @@ igraph_error_t igraph_gml_tree_init_integer(igraph_gml_tree_t *t, VECTOR(t->types)[0] = IGRAPH_I_GML_TREE_INTEGER; /* children */ - p = IGRAPH_CALLOC(1, igraph_integer_t); + p = IGRAPH_CALLOC(1, igraph_int_t); IGRAPH_CHECK_OOM(p, "Cannot create integer GML tree node."); *p = value; VECTOR(t->children)[0] = p; @@ -58,7 +58,7 @@ igraph_error_t igraph_gml_tree_init_integer(igraph_gml_tree_t *t, igraph_error_t igraph_gml_tree_init_real(igraph_gml_tree_t *t, const char *name, - igraph_integer_t line, + igraph_int_t line, igraph_real_t value) { igraph_real_t *p; @@ -89,7 +89,7 @@ igraph_error_t igraph_gml_tree_init_real(igraph_gml_tree_t *t, igraph_error_t igraph_gml_tree_init_string(igraph_gml_tree_t *t, const char *name, - igraph_integer_t line, + igraph_int_t line, const char *value) { IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->names, 1); @@ -115,7 +115,7 @@ igraph_error_t igraph_gml_tree_init_string(igraph_gml_tree_t *t, igraph_error_t igraph_gml_tree_init_tree(igraph_gml_tree_t *t, const char *name, - igraph_integer_t line, + igraph_int_t line, igraph_gml_tree_t *value) { IGRAPH_VECTOR_PTR_INIT_FINALLY(&t->names, 1); @@ -151,7 +151,7 @@ igraph_error_t igraph_gml_tree_init_empty(igraph_gml_tree_t *t) { /* merge is destructive, the _second_ tree is destroyed */ igraph_error_t igraph_gml_tree_mergedest(igraph_gml_tree_t *t1, igraph_gml_tree_t *t2) { - igraph_integer_t i, n = igraph_vector_ptr_size(&t2->children); + igraph_int_t i, n = igraph_vector_ptr_size(&t2->children); for (i = 0; i < n; i++) { IGRAPH_CHECK(igraph_vector_ptr_push_back(&t1->names, VECTOR(t2->names)[i])); @@ -170,7 +170,7 @@ igraph_error_t igraph_gml_tree_mergedest(igraph_gml_tree_t *t1, igraph_gml_tree_ void igraph_gml_tree_destroy(igraph_gml_tree_t *t) { - igraph_integer_t i, n = igraph_vector_ptr_size(&t->children); + igraph_int_t i, n = igraph_vector_ptr_size(&t->children); for (i = 0; i < n; i++) { igraph_i_gml_tree_type_t type = (igraph_i_gml_tree_type_t) VECTOR(t->types)[i]; switch (type) { @@ -201,14 +201,14 @@ void igraph_gml_tree_destroy(igraph_gml_tree_t *t) { IGRAPH_FREE(t); } -igraph_integer_t igraph_gml_tree_length(const igraph_gml_tree_t *t) { +igraph_int_t igraph_gml_tree_length(const igraph_gml_tree_t *t) { return igraph_vector_ptr_size(&t->names); } -igraph_integer_t igraph_gml_tree_find( - const igraph_gml_tree_t *t, const char *name, igraph_integer_t from +igraph_int_t igraph_gml_tree_find( + const igraph_gml_tree_t *t, const char *name, igraph_int_t from ) { - igraph_integer_t size = igraph_vector_ptr_size(&t->names); + igraph_int_t size = igraph_vector_ptr_size(&t->names); while ( from < size && (! VECTOR(t->names)[from] || strcmp(VECTOR(t->names)[from], name)) ) { from++; @@ -220,8 +220,8 @@ igraph_integer_t igraph_gml_tree_find( return from; } -igraph_integer_t igraph_gml_tree_findback( - const igraph_gml_tree_t *t, const char *name, igraph_integer_t from +igraph_int_t igraph_gml_tree_findback( + const igraph_gml_tree_t *t, const char *name, igraph_int_t from ) { while ( from >= 0 && (! VECTOR(t->names)[from] || strcmp(VECTOR(t->names)[from], name)) ) { @@ -231,43 +231,43 @@ igraph_integer_t igraph_gml_tree_findback( return from; } -igraph_i_gml_tree_type_t igraph_gml_tree_type(const igraph_gml_tree_t *t, igraph_integer_t pos) { +igraph_i_gml_tree_type_t igraph_gml_tree_type(const igraph_gml_tree_t *t, igraph_int_t pos) { return (igraph_i_gml_tree_type_t) VECTOR(t->types)[pos]; } -const char *igraph_gml_tree_name(const igraph_gml_tree_t *t, igraph_integer_t pos) { +const char *igraph_gml_tree_name(const igraph_gml_tree_t *t, igraph_int_t pos) { return VECTOR(t->names)[pos]; } -igraph_integer_t igraph_gml_tree_line(const igraph_gml_tree_t *t, igraph_integer_t pos) { +igraph_int_t igraph_gml_tree_line(const igraph_gml_tree_t *t, igraph_int_t pos) { return VECTOR(t->lines)[pos]; } -igraph_integer_t igraph_gml_tree_get_integer(const igraph_gml_tree_t *t, - igraph_integer_t pos) { - igraph_integer_t *i = VECTOR(t->children)[pos]; +igraph_int_t igraph_gml_tree_get_integer(const igraph_gml_tree_t *t, + igraph_int_t pos) { + igraph_int_t *i = VECTOR(t->children)[pos]; return *i; } igraph_real_t igraph_gml_tree_get_real(const igraph_gml_tree_t *t, - igraph_integer_t pos) { + igraph_int_t pos) { igraph_real_t *d = VECTOR(t->children)[pos]; return *d; } const char *igraph_gml_tree_get_string(const igraph_gml_tree_t *t, - igraph_integer_t pos) { + igraph_int_t pos) { const char *s = VECTOR(t->children)[pos]; return s; } igraph_gml_tree_t *igraph_gml_tree_get_tree(const igraph_gml_tree_t *t, - igraph_integer_t pos) { + igraph_int_t pos) { igraph_gml_tree_t *tree = VECTOR(t->children)[pos]; return tree; } -void igraph_gml_tree_delete(igraph_gml_tree_t *t, igraph_integer_t pos) { +void igraph_gml_tree_delete(igraph_gml_tree_t *t, igraph_int_t pos) { if (VECTOR(t->types)[pos] == IGRAPH_I_GML_TREE_TREE) { igraph_gml_tree_destroy(VECTOR(t->children)[pos]); } diff --git a/src/vendor/cigraph/src/io/gml-tree.h b/src/vendor/cigraph/src/io/gml-tree.h index 26e9308f1ff..fbae24a7b0b 100644 --- a/src/vendor/cigraph/src/io/gml-tree.h +++ b/src/vendor/cigraph/src/io/gml-tree.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2007-2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ #include "igraph_vector.h" #include "igraph_vector_ptr.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS typedef enum { IGRAPH_I_GML_TREE_TREE = 0, IGRAPH_I_GML_TREE_INTEGER, @@ -44,44 +44,44 @@ typedef struct igraph_gml_tree_t { igraph_error_t igraph_gml_tree_init_integer(igraph_gml_tree_t *t, const char *name, - igraph_integer_t line, - igraph_integer_t value); + igraph_int_t line, + igraph_int_t value); igraph_error_t igraph_gml_tree_init_real(igraph_gml_tree_t *t, const char *name, - igraph_integer_t line, + igraph_int_t line, igraph_real_t value); igraph_error_t igraph_gml_tree_init_string(igraph_gml_tree_t *t, const char *name, - igraph_integer_t line, + igraph_int_t line, const char *value); igraph_error_t igraph_gml_tree_init_tree(igraph_gml_tree_t *t, const char *name, - igraph_integer_t line, + igraph_int_t line, igraph_gml_tree_t *value); igraph_error_t igraph_gml_tree_init_empty(igraph_gml_tree_t *t); void igraph_gml_tree_destroy(igraph_gml_tree_t *t); -void igraph_gml_tree_delete(igraph_gml_tree_t *t, igraph_integer_t pos); +void igraph_gml_tree_delete(igraph_gml_tree_t *t, igraph_int_t pos); igraph_error_t igraph_gml_tree_mergedest(igraph_gml_tree_t *t1, igraph_gml_tree_t *t2); -IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_gml_tree_length(const igraph_gml_tree_t *t); -IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_gml_tree_find(const igraph_gml_tree_t *t, - const char *name, igraph_integer_t from); -IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_gml_tree_findback(const igraph_gml_tree_t *t, - const char *name, igraph_integer_t from); -IGRAPH_FUNCATTR_PURE igraph_i_gml_tree_type_t igraph_gml_tree_type(const igraph_gml_tree_t *t, igraph_integer_t pos); -IGRAPH_FUNCATTR_PURE const char *igraph_gml_tree_name(const igraph_gml_tree_t *t, igraph_integer_t pos); -IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_gml_tree_line(const igraph_gml_tree_t *t, igraph_integer_t pos); -IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_gml_tree_get_integer(const igraph_gml_tree_t *t, - igraph_integer_t pos); +IGRAPH_FUNCATTR_PURE igraph_int_t igraph_gml_tree_length(const igraph_gml_tree_t *t); +IGRAPH_FUNCATTR_PURE igraph_int_t igraph_gml_tree_find(const igraph_gml_tree_t *t, + const char *name, igraph_int_t from); +IGRAPH_FUNCATTR_PURE igraph_int_t igraph_gml_tree_findback(const igraph_gml_tree_t *t, + const char *name, igraph_int_t from); +IGRAPH_FUNCATTR_PURE igraph_i_gml_tree_type_t igraph_gml_tree_type(const igraph_gml_tree_t *t, igraph_int_t pos); +IGRAPH_FUNCATTR_PURE const char *igraph_gml_tree_name(const igraph_gml_tree_t *t, igraph_int_t pos); +IGRAPH_FUNCATTR_PURE igraph_int_t igraph_gml_tree_line(const igraph_gml_tree_t *t, igraph_int_t pos); +IGRAPH_FUNCATTR_PURE igraph_int_t igraph_gml_tree_get_integer(const igraph_gml_tree_t *t, + igraph_int_t pos); IGRAPH_FUNCATTR_PURE igraph_real_t igraph_gml_tree_get_real(const igraph_gml_tree_t *t, - igraph_integer_t pos); + igraph_int_t pos); IGRAPH_FUNCATTR_PURE const char *igraph_gml_tree_get_string(const igraph_gml_tree_t *t, - igraph_integer_t pos); + igraph_int_t pos); IGRAPH_FUNCATTR_PURE igraph_gml_tree_t *igraph_gml_tree_get_tree(const igraph_gml_tree_t *t, - igraph_integer_t pos); + igraph_int_t pos); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/io/gml.c b/src/vendor/cigraph/src/io/gml.c index f5ddc1c1027..85df1fc5eff 100644 --- a/src/vendor/cigraph/src/io/gml.c +++ b/src/vendor/cigraph/src/io/gml.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -66,7 +65,7 @@ static igraph_bool_t needs_coding(const char *str) { * '*dest' must be deallocated by the caller. */ static igraph_error_t entity_encode(const char *src, char **dest, igraph_bool_t only_quot) { - igraph_integer_t destlen = 0; + igraph_int_t destlen = 0; const char *s; char *d; @@ -162,36 +161,7 @@ static igraph_error_t entity_decode(const char *src, char **dest, igraph_bool_t return IGRAPH_SUCCESS; } -static void igraph_i_gml_destroy_attrs(igraph_vector_ptr_t **ptr) { - - igraph_vector_ptr_t *vec; - for (igraph_integer_t i = 0; i < 3; i++) { - vec = ptr[i]; - for (igraph_integer_t j = 0; j < igraph_vector_ptr_size(vec); j++) { - igraph_attribute_record_t *atrec = VECTOR(*vec)[j]; - if (atrec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *value = (igraph_vector_t*)atrec->value; - if (value != 0) { - igraph_vector_destroy(value); - IGRAPH_FREE(value); - } - } else if (atrec->type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *value = (igraph_strvector_t*)atrec->value; - if (value != 0) { - igraph_strvector_destroy(value); - IGRAPH_FREE(value); - } - } else { - /* Some empty attribute records may have been created for composite attributes */ - } - IGRAPH_FREE(atrec->name); - IGRAPH_FREE(atrec); - } - igraph_vector_ptr_destroy(vec); - } -} - -static igraph_real_t igraph_i_gml_toreal(igraph_gml_tree_t *node, igraph_integer_t pos) { +static igraph_real_t igraph_i_gml_toreal(igraph_gml_tree_t *node, igraph_int_t pos) { igraph_i_gml_tree_type_t type = igraph_gml_tree_type(node, pos); switch (type) { @@ -208,11 +178,11 @@ static igraph_real_t igraph_i_gml_toreal(igraph_gml_tree_t *node, igraph_integer } } -static const char *igraph_i_gml_tostring(igraph_gml_tree_t *node, igraph_integer_t pos) { +static const char *igraph_i_gml_tostring(igraph_gml_tree_t *node, igraph_int_t pos) { igraph_i_gml_tree_type_t type = igraph_gml_tree_type(node, pos); static char tmp[100]; const char *p = tmp; - igraph_integer_t i; + igraph_int_t i; igraph_real_t d; switch (type) { @@ -263,22 +233,33 @@ void igraph_i_gml_parsedata_destroy(igraph_i_gml_parsedata_t *context) { /* Takes a vector of attribute records and removes those elements * whose type is unspecified, i.e. IGRAPH_ATTRIBUTE_UNSPECIFIED. */ -static void prune_unknown_attributes(igraph_vector_ptr_t *attrs) { - igraph_integer_t i, j; - for (i = 0, j = 0; i < igraph_vector_ptr_size(attrs); i++) { - igraph_attribute_record_t *atrec = VECTOR(*attrs)[i]; +static igraph_error_t prune_unknown_attributes(igraph_attribute_record_list_t *attrs) { + igraph_int_t i, n; + igraph_vector_int_t to_remove; + + IGRAPH_VECTOR_INT_INIT_FINALLY(&to_remove, 0); + + n = igraph_attribute_record_list_size(attrs); + for (i = 0; i < n; i++) { + igraph_attribute_record_t *atrec = igraph_attribute_record_list_get_ptr(attrs, i); if (atrec->type == IGRAPH_ATTRIBUTE_UNSPECIFIED) { - IGRAPH_FREE(atrec->name); - IGRAPH_FREE(atrec); - } else { - VECTOR(*attrs)[j++] = VECTOR(*attrs)[i]; + IGRAPH_CHECK(igraph_vector_int_push_back(&to_remove, i)); } } - igraph_vector_ptr_resize(attrs, j); /* shrinks */ + + n = igraph_vector_int_size(&to_remove); + for (i = n - 1; i >= 0; i--) { + igraph_attribute_record_list_discard(attrs, VECTOR(to_remove)[i]); + } + + igraph_vector_int_destroy(&to_remove); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; } /* Converts an integer id to an optionally prefixed string id. */ -static const char *strid(igraph_integer_t id, const char *prefix) { +static const char *strid(igraph_int_t id, const char *prefix) { static char name[100]; snprintf(name, sizeof(name) / sizeof(char) - 1, "%s%" IGRAPH_PRId, prefix, id); return name; @@ -290,38 +271,39 @@ static const char *strid(igraph_integer_t id, const char *prefix) { static igraph_error_t create_or_update_attribute(const char *name, igraph_i_gml_tree_type_t type, igraph_trie_t *attrnames, - igraph_vector_ptr_t *attrs) { + igraph_attribute_record_list_t *attrs) { + + igraph_int_t trieid, triesize = igraph_trie_size(attrnames); + igraph_attribute_type_t desired_type; - igraph_integer_t trieid, triesize = igraph_trie_size(attrnames); IGRAPH_CHECK(igraph_trie_get(attrnames, name, &trieid)); if (trieid == triesize) { /* new attribute */ - igraph_attribute_record_t *atrec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - IGRAPH_CHECK_OOM(atrec, "Cannot read GML file."); - IGRAPH_FINALLY(igraph_free, atrec); - - atrec->name = strdup(name); - IGRAPH_CHECK_OOM(atrec->name, "Cannot read GML file."); - IGRAPH_FINALLY(igraph_free, (char *) atrec->name); + igraph_attribute_record_t atrec; if (type == IGRAPH_I_GML_TREE_INTEGER || type == IGRAPH_I_GML_TREE_REAL) { - atrec->type = IGRAPH_ATTRIBUTE_NUMERIC; + desired_type = IGRAPH_ATTRIBUTE_NUMERIC; } else if (type == IGRAPH_I_GML_TREE_STRING) { - atrec->type = IGRAPH_ATTRIBUTE_STRING; + desired_type = IGRAPH_ATTRIBUTE_STRING; } else { - atrec->type = IGRAPH_ATTRIBUTE_UNSPECIFIED; + desired_type = IGRAPH_ATTRIBUTE_UNSPECIFIED; } - IGRAPH_CHECK(igraph_vector_ptr_push_back(attrs, atrec)); - IGRAPH_FINALLY_CLEAN(2); + + IGRAPH_CHECK(igraph_attribute_record_init(&atrec, name, desired_type)); + IGRAPH_FINALLY(igraph_attribute_record_destroy, &atrec); + IGRAPH_CHECK(igraph_attribute_record_list_push_back(attrs, &atrec)); + IGRAPH_FINALLY_CLEAN(1); /* ownership of 'atrec' taken by 'attrs' */ } else { /* already seen, should we update type? */ - igraph_attribute_record_t *atrec = VECTOR(*attrs)[trieid]; - igraph_attribute_type_t type1 = atrec->type; + igraph_attribute_record_t *atrec = igraph_attribute_record_list_get_ptr(attrs, trieid); + igraph_attribute_type_t existing_type = atrec->type; if (type == IGRAPH_I_GML_TREE_STRING) { - atrec->type = IGRAPH_ATTRIBUTE_STRING; - } else if (type1 == IGRAPH_ATTRIBUTE_UNSPECIFIED) { + if (existing_type != IGRAPH_ATTRIBUTE_STRING) { + IGRAPH_CHECK(igraph_attribute_record_set_type(atrec, IGRAPH_ATTRIBUTE_STRING)); + } + } else if (existing_type == IGRAPH_ATTRIBUTE_UNSPECIFIED) { if (type == IGRAPH_I_GML_TREE_INTEGER || type == IGRAPH_I_GML_TREE_REAL) { - atrec->type = IGRAPH_ATTRIBUTE_NUMERIC; + IGRAPH_CHECK(igraph_attribute_record_set_type(atrec, IGRAPH_ATTRIBUTE_NUMERIC)); } } } @@ -334,34 +316,23 @@ static igraph_error_t create_or_update_attribute(const char *name, * no_of_edges, or 1 for vertex, edge and graph attributes. * The 'kind' parameter can be "vertex", "edge" or "graph", and * is used solely for showing better warning messages. */ -static igraph_error_t allocate_attributes(igraph_vector_ptr_t *attrs, - igraph_integer_t no_of_items, - const char *kind) { - - igraph_integer_t i, n = igraph_vector_ptr_size(attrs); +static igraph_error_t allocate_attributes( + igraph_attribute_record_list_t *attrs, igraph_int_t no_of_items, + const char *kind +) { + igraph_int_t i, n = igraph_attribute_record_list_size(attrs); for (i = 0; i < n; i++) { - igraph_attribute_record_t *atrec = VECTOR(*attrs)[i]; - igraph_attribute_type_t type = atrec->type; - if (type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *p = IGRAPH_CALLOC(1, igraph_vector_t); - IGRAPH_CHECK_OOM(p, "Cannot read GML file."); - IGRAPH_FINALLY(igraph_free, p); - IGRAPH_CHECK(igraph_vector_init(p, no_of_items)); - igraph_vector_fill(p, IGRAPH_NAN); /* use NaN as default */ - atrec->value = p; - IGRAPH_FINALLY_CLEAN(1); - } else if (type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *p = IGRAPH_CALLOC(1, igraph_strvector_t); - IGRAPH_CHECK_OOM(p, "Cannot read GML file."); - IGRAPH_FINALLY(igraph_free, p); - IGRAPH_CHECK(igraph_strvector_init(p, no_of_items)); - atrec->value = p; - IGRAPH_FINALLY_CLEAN(1); - } else if (type == IGRAPH_ATTRIBUTE_UNSPECIFIED) { - IGRAPH_WARNINGF("Composite %s attribute '%s' ignored in GML file.", kind, atrec->name); + igraph_attribute_record_t *atrec = igraph_attribute_record_list_get_ptr(attrs, i); + + /* We have unspecified attribute types in the attribute record list at + * this point because we need to keep the same order in the attribute + * record list as it was in the trie that we use to look up an + * attribute record by name. However, we cannot resize unknown attributes + * so we need to take care of this */ + if (atrec->type != IGRAPH_ATTRIBUTE_UNSPECIFIED) { + IGRAPH_CHECK(igraph_attribute_record_resize(atrec, no_of_items)); } else { - /* Must never reach here. */ - IGRAPH_FATAL("Unexpected attribute type."); + IGRAPH_WARNINGF("Composite %s attribute '%s' ignored in GML file.", kind, atrec->name); } } return IGRAPH_SUCCESS; @@ -414,23 +385,21 @@ static igraph_error_t allocate_attributes(igraph_vector_ptr_t *attrs, */ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { - igraph_integer_t i; - igraph_integer_t no_of_nodes = 0, no_of_edges = 0; - igraph_integer_t node_no; + igraph_int_t i; + igraph_int_t no_of_nodes = 0, no_of_edges = 0; + igraph_int_t node_no; igraph_trie_t trie; igraph_vector_int_t edges; igraph_bool_t directed = IGRAPH_UNDIRECTED; igraph_bool_t has_directed = false; igraph_gml_tree_t *gtree; - igraph_integer_t gidx; + igraph_int_t gidx; igraph_trie_t vattrnames; igraph_trie_t eattrnames; igraph_trie_t gattrnames; - igraph_vector_ptr_t gattrs = IGRAPH_VECTOR_PTR_NULL, - vattrs = IGRAPH_VECTOR_PTR_NULL, - eattrs = IGRAPH_VECTOR_PTR_NULL; - igraph_vector_ptr_t *attrs[3]; - igraph_integer_t edgeptr = 0; + igraph_attribute_record_list_t gattrs, vattrs, eattrs; + igraph_attribute_record_list_t *attrs[3]; + igraph_int_t edgeptr = 0; igraph_i_gml_parsedata_t context; igraph_bool_t entity_warned = false; /* used to warn at most once about unsupported entities */ @@ -493,10 +462,12 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { } gtree = igraph_gml_tree_get_tree(context.tree, gidx); - IGRAPH_FINALLY(igraph_i_gml_destroy_attrs, attrs); - IGRAPH_CHECK(igraph_vector_ptr_init(&gattrs, 0)); - IGRAPH_CHECK(igraph_vector_ptr_init(&vattrs, 0)); - IGRAPH_CHECK(igraph_vector_ptr_init(&eattrs, 0)); + IGRAPH_CHECK(igraph_attribute_record_list_init(&gattrs, 0)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &gattrs); + IGRAPH_CHECK(igraph_attribute_record_list_init(&vattrs, 0)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &vattrs); + IGRAPH_CHECK(igraph_attribute_record_list_init(&eattrs, 0)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &eattrs); IGRAPH_TRIE_INIT_FINALLY(&trie, 0); IGRAPH_TRIE_INIT_FINALLY(&vattrnames, 0); @@ -533,14 +504,14 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { } node = igraph_gml_tree_get_tree(gtree, i); hasid = false; - for (igraph_integer_t j = 0; j < igraph_gml_tree_length(node); j++) { + for (igraph_int_t j = 0; j < igraph_gml_tree_length(node); j++) { const char *name = igraph_gml_tree_name(node, j); igraph_i_gml_tree_type_t type = igraph_gml_tree_type(node, j); IGRAPH_CHECK(create_or_update_attribute(name, type, &vattrnames, &vattrs)); /* check id */ if (!strcmp(name, "id")) { - igraph_integer_t id, trie_id; - igraph_integer_t trie_size = igraph_trie_size(&trie); + igraph_int_t id, trie_id; + igraph_int_t trie_size = igraph_trie_size(&trie); if (hasid) { /* A 'node' must not have more than one 'id' field. * This error cannot be relaxed into a warning because all ids we find are @@ -566,7 +537,7 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { if (!hasid) { /* Isolated nodes are allowed not to have an id. * We generate an "n"-prefixed string id to be used in the trie. */ - igraph_integer_t trie_id; + igraph_int_t trie_id; IGRAPH_CHECK(igraph_trie_get(&trie, strid(node_no, "n"), &trie_id)); } } else if (!strcmp(name, "edge")) { @@ -578,7 +549,7 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { igraph_gml_tree_line(gtree, i)); } edge = igraph_gml_tree_get_tree(gtree, i); - for (igraph_integer_t j = 0; j < igraph_gml_tree_length(edge); j++) { + for (igraph_int_t j = 0; j < igraph_gml_tree_length(edge); j++) { const char *name = igraph_gml_tree_name(edge, j); igraph_i_gml_tree_type_t type = igraph_gml_tree_type(edge, j); if (!strcmp(name, "source")) { @@ -631,7 +602,7 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { igraph_gml_tree_line(gtree, i)); } if (igraph_gml_tree_type(gtree, i) == IGRAPH_I_GML_TREE_INTEGER) { - igraph_integer_t dir = igraph_gml_tree_get_integer(gtree, i); + igraph_int_t dir = igraph_gml_tree_get_integer(gtree, i); if (dir != 0 && dir != 1) { IGRAPH_WARNINGF( "Invalid value %" IGRAPH_PRId " for 'directed' attribute on line %" IGRAPH_PRId ", should be 0 or 1.", @@ -670,8 +641,8 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { name = igraph_gml_tree_name(gtree, i); if (!strcmp(name, "node")) { igraph_gml_tree_t *node = igraph_gml_tree_get_tree(gtree, i); - igraph_integer_t iidx = igraph_gml_tree_find(node, "id", 0); - igraph_integer_t trie_id; + igraph_int_t iidx = igraph_gml_tree_find(node, "id", 0); + igraph_int_t trie_id; const char *sid; node_no++; if (iidx < 0) { @@ -681,19 +652,18 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { sid = strid(igraph_gml_tree_get_integer(node, iidx), ""); } IGRAPH_CHECK(igraph_trie_get(&trie, sid, &trie_id)); - for (igraph_integer_t j = 0; j < igraph_gml_tree_length(node); j++) { + for (igraph_int_t j = 0; j < igraph_gml_tree_length(node); j++) { const char *aname = igraph_gml_tree_name(node, j); igraph_attribute_record_t *atrec; igraph_attribute_type_t type; - igraph_integer_t ai; + igraph_int_t ai; IGRAPH_CHECK(igraph_trie_get(&vattrnames, aname, &ai)); - atrec = VECTOR(vattrs)[ai]; + atrec = igraph_attribute_record_list_get_ptr(&vattrs, ai); type = atrec->type; if (type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *v = (igraph_vector_t *) atrec->value; - VECTOR(*v)[trie_id] = igraph_i_gml_toreal(node, j); + VECTOR(*atrec->value.as_vector)[trie_id] = igraph_i_gml_toreal(node, j); } else if (type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *v = (igraph_strvector_t *) atrec->value; + igraph_strvector_t *v = atrec->value.as_strvector; const char *value = igraph_i_gml_tostring(node, j); if (needs_coding(value)) { char *value_decoded; @@ -711,27 +681,26 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { } } else if (!strcmp(name, "edge")) { igraph_gml_tree_t *edge; - igraph_integer_t from, to, fromidx = 0, toidx = 0; + igraph_int_t from, to, fromidx = 0, toidx = 0; edge = igraph_gml_tree_get_tree(gtree, i); - for (igraph_integer_t j = 0; j < igraph_gml_tree_length(edge); j++) { + for (igraph_int_t j = 0; j < igraph_gml_tree_length(edge); j++) { const char *aname = igraph_gml_tree_name(edge, j); if (!strcmp(aname, "source")) { fromidx = igraph_gml_tree_find(edge, "source", 0); } else if (!strcmp(aname, "target")) { toidx = igraph_gml_tree_find(edge, "target", 0); } else { - igraph_integer_t edgeid = edgeptr / 2; - igraph_integer_t ai; + igraph_int_t edgeid = edgeptr / 2; + igraph_int_t ai; igraph_attribute_record_t *atrec; igraph_attribute_type_t type; IGRAPH_CHECK(igraph_trie_get(&eattrnames, aname, &ai)); - atrec = VECTOR(eattrs)[ai]; + atrec = igraph_attribute_record_list_get_ptr(&eattrs, ai); type = atrec->type; if (type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *v = (igraph_vector_t *) atrec->value; - VECTOR(*v)[edgeid] = igraph_i_gml_toreal(edge, j); + VECTOR(*atrec->value.as_vector)[edgeid] = igraph_i_gml_toreal(edge, j); } else if (type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *v = (igraph_strvector_t *) atrec->value; + igraph_strvector_t *v = atrec->value.as_strvector; const char *value = igraph_i_gml_tostring(edge, j); if (needs_coding(value)) { char *value_decoded; @@ -766,17 +735,16 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { /* Nothing to do for 'directed' field, already handled earlier. */ } else { /* Set the rest as graph attributes */ - igraph_integer_t ai; + igraph_int_t ai; igraph_attribute_record_t *atrec; igraph_attribute_type_t type; IGRAPH_CHECK(igraph_trie_get(&gattrnames, name, &ai)); - atrec = VECTOR(gattrs)[ai]; + atrec = igraph_attribute_record_list_get_ptr(&gattrs, ai); type = atrec->type; if (type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *v = (igraph_vector_t *) atrec->value; - VECTOR(*v)[0] = igraph_i_gml_toreal(gtree, i); + VECTOR(*atrec->value.as_vector)[0] = igraph_i_gml_toreal(gtree, i); } else if (type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *v = (igraph_strvector_t *) atrec->value; + igraph_strvector_t *v = atrec->value.as_strvector; const char *value = igraph_i_gml_tostring(gtree, i); if (needs_coding(value)) { char *value_decoded; @@ -794,10 +762,10 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { } } - /* Remove composite attributes */ - prune_unknown_attributes(&vattrs); - prune_unknown_attributes(&eattrs); - prune_unknown_attributes(&gattrs); + /* Remove composite attributes that we cannot represent in igraph */ + IGRAPH_CHECK(prune_unknown_attributes(&vattrs)); + IGRAPH_CHECK(prune_unknown_attributes(&eattrs)); + IGRAPH_CHECK(prune_unknown_attributes(&gattrs)); igraph_trie_destroy(&trie); igraph_trie_destroy(&gattrnames); @@ -812,9 +780,11 @@ igraph_error_t igraph_read_graph_gml(igraph_t *graph, FILE *instream) { IGRAPH_FINALLY_CLEAN(1); /* do not destroy 'graph', just pop it from the stack */ igraph_vector_int_destroy(&edges); - igraph_i_gml_destroy_attrs(attrs); + igraph_attribute_record_list_destroy(&eattrs); + igraph_attribute_record_list_destroy(&vattrs); + igraph_attribute_record_list_destroy(&gattrs); igraph_i_gml_parsedata_destroy(&context); - IGRAPH_FINALLY_CLEAN(3); + IGRAPH_FINALLY_CLEAN(5); return IGRAPH_SUCCESS; } @@ -850,7 +820,7 @@ static igraph_error_t igraph_i_gml_convert_to_key(const char *orig, char **key) * will not be detected. */ static igraph_error_t igraph_i_vector_is_duplicate_free(const igraph_vector_t *v, igraph_bool_t *res) { igraph_vector_t u; - igraph_integer_t n = igraph_vector_size(v); + igraph_int_t n = igraph_vector_size(v); if (n < 2) { *res = true; @@ -862,7 +832,7 @@ static igraph_error_t igraph_i_vector_is_duplicate_free(const igraph_vector_t *v igraph_vector_sort(&u); *res = true; - for (igraph_integer_t i=1; i < n; i++) { + for (igraph_int_t i=1; i < n; i++) { if (VECTOR(u)[i-1] == VECTOR(u)[i]) { *res = false; break; @@ -962,13 +932,13 @@ igraph_error_t igraph_write_graph_gml(const igraph_t *graph, FILE *outstream, const igraph_vector_t *id, const char *creator) { igraph_strvector_t gnames, vnames, enames; /* attribute names */ igraph_vector_int_t gtypes, vtypes, etypes; /* attribute types */ - igraph_integer_t gattr_no, vattr_no, eattr_no; /* attribute counts */ + igraph_int_t gattr_no, vattr_no, eattr_no; /* attribute counts */ igraph_vector_t numv; igraph_strvector_t strv; igraph_vector_bool_t boolv; - igraph_integer_t i; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t i; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); /* Each element is a bit field used to prevent showing more * than one warning for each vertex or edge attribute. */ @@ -1141,7 +1111,7 @@ igraph_error_t igraph_write_graph_gml(const igraph_t *graph, FILE *outstream, #define SETBIT(k, i) ((k) |= (1 << i)) #define WARN_ONCE(attrno, bit, warn) \ do { \ - igraph_integer_t *p = &VECTOR(warning_shown)[attrno]; \ + igraph_int_t *p = &VECTOR(warning_shown)[attrno]; \ if (! GETBIT(*p, bit)) { \ warn; \ SETBIT(*p, bit); \ @@ -1152,10 +1122,10 @@ igraph_error_t igraph_write_graph_gml(const igraph_t *graph, FILE *outstream, /* Now come the vertices */ IGRAPH_VECTOR_INT_INIT_FINALLY(&warning_shown, vattr_no); for (i = 0; i < no_of_nodes; i++) { - igraph_integer_t j; + igraph_int_t j; CHECK(fprintf(outstream, " node\n [\n")); /* id */ - CHECK(fprintf(outstream, " id %" IGRAPH_PRId "\n", myid ? (igraph_integer_t)VECTOR(*myid)[i] : i)); + CHECK(fprintf(outstream, " id %" IGRAPH_PRId "\n", myid ? (igraph_int_t)VECTOR(*myid)[i] : i)); /* other attributes */ for (j = 0; j < vattr_no; j++) { igraph_attribute_type_t type = (igraph_attribute_type_t) VECTOR(vtypes)[j]; @@ -1223,15 +1193,15 @@ igraph_error_t igraph_write_graph_gml(const igraph_t *graph, FILE *outstream, IGRAPH_CHECK(igraph_vector_int_resize(&warning_shown, eattr_no)); igraph_vector_int_null(&warning_shown); for (i = 0; i < no_of_edges; i++) { - igraph_integer_t from = IGRAPH_FROM(graph, i); - igraph_integer_t to = IGRAPH_TO(graph, i); - igraph_integer_t j; + igraph_int_t from = IGRAPH_FROM(graph, i); + igraph_int_t to = IGRAPH_TO(graph, i); + igraph_int_t j; CHECK(fprintf(outstream, " edge\n [\n")); /* source and target */ CHECK(fprintf(outstream, " source %" IGRAPH_PRId "\n", - myid ? (igraph_integer_t)VECTOR(*myid)[from] : from)); + myid ? (igraph_int_t)VECTOR(*myid)[from] : from)); CHECK(fprintf(outstream, " target %" IGRAPH_PRId "\n", - myid ? (igraph_integer_t)VECTOR(*myid)[to] : to)); + myid ? (igraph_int_t)VECTOR(*myid)[to] : to)); /* other attributes */ for (j = 0; j < eattr_no; j++) { diff --git a/src/vendor/cigraph/src/io/graphdb.c b/src/vendor/cigraph/src/io/graphdb.c index b5dc0b262e0..63d52a52d61 100644 --- a/src/vendor/cigraph/src/io/graphdb.c +++ b/src/vendor/cigraph/src/io/graphdb.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -110,7 +109,7 @@ static igraph_error_t handle_input_error(FILE *instream) { igraph_error_t igraph_read_graph_graphdb(igraph_t *graph, FILE *instream, igraph_bool_t directed) { - const igraph_integer_t nodes = igraph_i_read_graph_graphdb_getword(instream); + const igraph_int_t nodes = igraph_i_read_graph_graphdb_getword(instream); if (nodes < 0) { IGRAPH_CHECK(handle_input_error(instream)); } @@ -119,13 +118,13 @@ igraph_error_t igraph_read_graph_graphdb(igraph_t *graph, FILE *instream, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 100); igraph_vector_int_clear(&edges); - for (igraph_integer_t i = 0; i < nodes; i++) { - igraph_integer_t len = igraph_i_read_graph_graphdb_getword(instream); + for (igraph_int_t i = 0; i < nodes; i++) { + igraph_int_t len = igraph_i_read_graph_graphdb_getword(instream); if (len < 0) { IGRAPH_CHECK(handle_input_error(instream)); } - for (igraph_integer_t j = 0; j < len; j++) { - igraph_integer_t to = igraph_i_read_graph_graphdb_getword(instream); + for (igraph_int_t j = 0; j < len; j++) { + igraph_int_t to = igraph_i_read_graph_graphdb_getword(instream); if (to < 0) { IGRAPH_CHECK(handle_input_error(instream)); } diff --git a/src/vendor/cigraph/src/io/graphml.c b/src/vendor/cigraph/src/io/graphml.c index 28b3c435252..05630b267cf 100644 --- a/src/vendor/cigraph/src/io/graphml.c +++ b/src/vendor/cigraph/src/io/graphml.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -88,17 +88,13 @@ static xmlEntity blankEntity = { } while (0) typedef struct igraph_i_graphml_attribute_record_t { - const char *id; /* GraphML id */ + char *id; /* GraphML id */ enum { I_GRAPHML_BOOLEAN, I_GRAPHML_INTEGER, I_GRAPHML_LONG, I_GRAPHML_FLOAT, I_GRAPHML_DOUBLE, I_GRAPHML_STRING, I_GRAPHML_UNKNOWN_TYPE } type; /* GraphML type */ - union { - igraph_real_t as_numeric; - igraph_bool_t as_boolean; - char *as_string; - } default_value; /* Default value of the attribute, if any */ igraph_attribute_record_t record; + igraph_bool_t record_disowned; /* true if ownership of the record was taken over */ } igraph_i_graphml_attribute_record_t; typedef enum { @@ -114,7 +110,7 @@ struct igraph_i_graphml_parser_state { igraph_vector_int_t edgelist; igraph_vector_int_t prev_state_stack; unsigned int unknown_depth; - igraph_integer_t index; + igraph_int_t index; igraph_bool_t successful; igraph_bool_t edges_directed; igraph_trie_t v_attr_ids; @@ -128,7 +124,7 @@ struct igraph_i_graphml_parser_state { igraph_attribute_elemtype_t data_type; char *error_message; igraph_vector_char_t data_char; - igraph_integer_t act_node; + igraph_int_t act_node; igraph_bool_t ignore_namespaces; }; @@ -162,7 +158,7 @@ static igraph_error_t igraph_i_graphml_parse_numeric( static igraph_error_t igraph_i_graphml_parse_boolean( const char* char_data, igraph_bool_t* result, igraph_bool_t default_value ) { - igraph_integer_t value; + igraph_int_t value; const char* trimmed; size_t trimmed_length; @@ -210,37 +206,19 @@ static igraph_error_t igraph_i_graphml_parse_boolean( } static void igraph_i_graphml_attribute_record_destroy(igraph_i_graphml_attribute_record_t* rec) { - if (rec->record.type == IGRAPH_ATTRIBUTE_NUMERIC) { - if (rec->record.value != 0) { - igraph_vector_destroy((igraph_vector_t*)rec->record.value); - IGRAPH_FREE(rec->record.value); - } - } else if (rec->record.type == IGRAPH_ATTRIBUTE_STRING) { - if (rec->record.value != 0) { - igraph_strvector_destroy((igraph_strvector_t*)rec->record.value); - IGRAPH_FREE(rec->record.value); - } - if (rec->default_value.as_string != 0) { - IGRAPH_FREE(rec->default_value.as_string); - } - } else if (rec->record.type == IGRAPH_ATTRIBUTE_BOOLEAN) { - if (rec->record.value != 0) { - igraph_vector_bool_destroy((igraph_vector_bool_t*)rec->record.value); - IGRAPH_FREE(rec->record.value); - } - } else if (rec->record.type == IGRAPH_ATTRIBUTE_UNSPECIFIED) { - /* no value was set */ + if (!rec->record_disowned) { + igraph_attribute_record_destroy(&rec->record); } + if (rec->id != NULL) { - xmlFree((void *) rec->id); + igraph_free(rec->id); rec->id = NULL; } - if (rec->record.name != 0) { - IGRAPH_FREE(rec->record.name); - } + + memset(rec, 0, sizeof(igraph_i_graphml_attribute_record_t)); } -static igraph_error_t igraph_i_graphml_parser_state_init(struct igraph_i_graphml_parser_state* state, igraph_t* graph, igraph_integer_t index) { +static igraph_error_t igraph_i_graphml_parser_state_init(struct igraph_i_graphml_parser_state* state, igraph_t* graph, igraph_int_t index) { memset(state, 0, sizeof(struct igraph_i_graphml_parser_state)); state->g = graph; @@ -409,34 +387,25 @@ static void igraph_i_graphml_sax_handler_start_document(void *state0) { } static igraph_error_t igraph_i_graphml_parser_state_finish_parsing(struct igraph_i_graphml_parser_state *state) { - igraph_integer_t i, l; - igraph_attribute_record_t idrec, eidrec; + igraph_int_t i; const char *idstr = "id"; igraph_bool_t already_has_vertex_id = false, already_has_edge_id = false; - igraph_vector_ptr_t vattr, eattr, gattr; - igraph_integer_t esize; + igraph_attribute_record_list_t vattr, eattr, gattr; + igraph_attribute_record_t *idrec; IGRAPH_ASSERT(state->successful); /* check that we have found and parsed the graph the user is interested in */ IGRAPH_ASSERT(state->index < 0); - IGRAPH_CHECK(igraph_vector_ptr_init(&vattr, igraph_vector_ptr_size(&state->v_attrs) + 1)); /* +1 for 'id' */ - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vattr); - igraph_vector_ptr_resize(&vattr, 0); /* will be filled with push_back() */ - - esize = igraph_vector_ptr_size(&state->e_attrs); - if (igraph_strvector_size(&state->edgeids) != 0) { - esize++; - } - IGRAPH_CHECK(igraph_vector_ptr_init(&eattr, esize)); - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &eattr); - igraph_vector_ptr_resize(&eattr, 0); /* will be filled with push_back() */ - - IGRAPH_CHECK(igraph_vector_ptr_init(&gattr, igraph_vector_ptr_size(&state->g_attrs))); - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &gattr); - igraph_vector_ptr_resize(&gattr, 0); /* will be filled with push_back() */ + IGRAPH_CHECK(igraph_attribute_record_list_init(&vattr, 0)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &vattr); + IGRAPH_CHECK(igraph_attribute_record_list_init(&eattr, 0)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &eattr); + IGRAPH_CHECK(igraph_attribute_record_list_init(&gattr, 0)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &gattr); + /* Add default attribute values for vertices where needed */ for (i = 0; i < igraph_vector_ptr_size(&state->v_attrs); i++) { igraph_i_graphml_attribute_record_t *graphmlrec = VECTOR(state->v_attrs)[i]; @@ -444,131 +413,68 @@ static igraph_error_t igraph_i_graphml_parser_state_finish_parsing(struct igraph /* Check that the name of the vertex attribute is not 'id'. * If it is then we cannot add the complementary 'id' attribute. */ - if (! strcmp(rec->name, idstr)) { + if (!strcmp(rec->name, idstr)) { already_has_vertex_id = 1; } - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *vec = (igraph_vector_t*)rec->value; - igraph_integer_t origsize = igraph_vector_size(vec); - igraph_integer_t nodes = igraph_trie_size(&state->node_trie); - IGRAPH_CHECK(igraph_vector_resize(vec, nodes)); - for (l = origsize; l < nodes; l++) { - VECTOR(*vec)[l] = graphmlrec->default_value.as_numeric; - } - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *strvec = (igraph_strvector_t*)rec->value; - igraph_integer_t origsize = igraph_strvector_size(strvec); - igraph_integer_t nodes = igraph_trie_size(&state->node_trie); - IGRAPH_CHECK(igraph_strvector_resize(strvec, nodes)); - for (l = origsize; l < nodes; l++) { - IGRAPH_CHECK(igraph_strvector_set(strvec, l, graphmlrec->default_value.as_string)); - } - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *boolvec = (igraph_vector_bool_t*)rec->value; - igraph_integer_t origsize = igraph_vector_bool_size(boolvec); - igraph_integer_t nodes = igraph_trie_size(&state->node_trie); - IGRAPH_CHECK(igraph_vector_bool_resize(boolvec, nodes)); - for (l = origsize; l < nodes; l++) { - VECTOR(*boolvec)[l] = graphmlrec->default_value.as_boolean; - } - } else if (rec->type == IGRAPH_ATTRIBUTE_UNSPECIFIED) { - continue; /* skipped attribute */ + if (rec->type != IGRAPH_ATTRIBUTE_UNSPECIFIED) { + IGRAPH_CHECK(igraph_attribute_record_resize(rec, igraph_trie_size(&state->node_trie))); + IGRAPH_CHECK(igraph_attribute_record_list_push_back(&vattr, rec)); + graphmlrec->record_disowned = true; } - igraph_vector_ptr_push_back(&vattr, rec); /* reserved */ } + + /* Add vertex ID attribute if needed */ if (!already_has_vertex_id) { - idrec.name = idstr; - idrec.type = IGRAPH_ATTRIBUTE_STRING; - idrec.value = igraph_i_trie_borrow_keys(&state->node_trie); - igraph_vector_ptr_push_back(&vattr, &idrec); /* reserved */ + IGRAPH_CHECK(igraph_attribute_record_list_push_back_new(&vattr, &idrec)); + IGRAPH_CHECK(igraph_attribute_record_set_name(idrec, idstr)); + IGRAPH_CHECK(igraph_attribute_record_set_type(idrec, IGRAPH_ATTRIBUTE_STRING)); + IGRAPH_CHECK(igraph_strvector_update(idrec->value.as_strvector, igraph_i_trie_borrow_keys(&state->node_trie))); } else { IGRAPH_WARNING("Could not add vertex ids, there is already an 'id' vertex attribute."); } + /* Add default attribute values for edges where needed */ for (i = 0; i < igraph_vector_ptr_size(&state->e_attrs); i++) { igraph_i_graphml_attribute_record_t *graphmlrec = VECTOR(state->e_attrs)[i]; igraph_attribute_record_t *rec = &graphmlrec->record; - if (! strcmp(rec->name, idstr)) { + if (!strcmp(rec->name, idstr)) { already_has_edge_id = 1; } - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *vec = (igraph_vector_t*)rec->value; - igraph_integer_t origsize = igraph_vector_size(vec); - igraph_integer_t edges = igraph_vector_int_size(&state->edgelist) / 2; - IGRAPH_CHECK(igraph_vector_resize(vec, edges)); - for (l = origsize; l < edges; l++) { - VECTOR(*vec)[l] = graphmlrec->default_value.as_numeric; - } - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *strvec = (igraph_strvector_t*)rec->value; - igraph_integer_t origsize = igraph_strvector_size(strvec); - igraph_integer_t edges = igraph_vector_int_size(&state->edgelist) / 2; - IGRAPH_CHECK(igraph_strvector_resize(strvec, edges)); - for (l = origsize; l < edges; l++) { - IGRAPH_CHECK(igraph_strvector_set(strvec, l, graphmlrec->default_value.as_string)); - } - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *boolvec = (igraph_vector_bool_t*)rec->value; - igraph_integer_t origsize = igraph_vector_bool_size(boolvec); - igraph_integer_t edges = igraph_vector_int_size(&state->edgelist) / 2; - IGRAPH_CHECK(igraph_vector_bool_resize(boolvec, edges)); - for (l = origsize; l < edges; l++) { - VECTOR(*boolvec)[l] = graphmlrec->default_value.as_boolean; - } - } else if (rec->type == IGRAPH_ATTRIBUTE_UNSPECIFIED) { - continue; /* skipped attribute */ + if (rec->type != IGRAPH_ATTRIBUTE_UNSPECIFIED) { + IGRAPH_CHECK(igraph_attribute_record_resize(rec, igraph_vector_int_size(&state->edgelist) / 2)); + IGRAPH_CHECK(igraph_attribute_record_list_push_back(&eattr, rec)); + graphmlrec->record_disowned = true; } - igraph_vector_ptr_push_back(&eattr, rec); /* reserved */ } + + /* Add edge ID attribute if needed */ if (igraph_strvector_size(&state->edgeids) != 0) { if (!already_has_edge_id) { - igraph_integer_t origsize = igraph_strvector_size(&state->edgeids); - eidrec.name = idstr; - eidrec.type = IGRAPH_ATTRIBUTE_STRING; - IGRAPH_CHECK(igraph_strvector_resize(&state->edgeids, igraph_vector_int_size(&state->edgelist) / 2)); - for (; origsize < igraph_strvector_size(&state->edgeids); origsize++) { - IGRAPH_CHECK(igraph_strvector_set(&state->edgeids, origsize, "")); - } - eidrec.value = &state->edgeids; - igraph_vector_ptr_push_back(&eattr, &eidrec); /* reserved */ + IGRAPH_CHECK(igraph_attribute_record_list_push_back_new(&eattr, &idrec)); + IGRAPH_CHECK(igraph_attribute_record_set_name(idrec, idstr)); + IGRAPH_CHECK(igraph_attribute_record_set_type(idrec, IGRAPH_ATTRIBUTE_STRING)); + IGRAPH_CHECK(igraph_strvector_update(idrec->value.as_strvector, igraph_i_trie_borrow_keys(&state->node_trie))); + IGRAPH_CHECK(igraph_attribute_record_resize(idrec, igraph_vector_int_size(&state->edgelist) / 2)); } else { IGRAPH_WARNING("Could not add edge ids, there is already an 'id' edge attribute."); } } + /* Add default graph attribute values where needed */ for (i = 0; i < igraph_vector_ptr_size(&state->g_attrs); i++) { igraph_i_graphml_attribute_record_t *graphmlrec = VECTOR(state->g_attrs)[i]; igraph_attribute_record_t *rec = &graphmlrec->record; - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *vec = (igraph_vector_t*)rec->value; - igraph_integer_t origsize = igraph_vector_size(vec); - IGRAPH_CHECK(igraph_vector_resize(vec, 1)); - for (l = origsize; l < 1; l++) { - VECTOR(*vec)[l] = graphmlrec->default_value.as_numeric; - } - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *strvec = (igraph_strvector_t*)rec->value; - igraph_integer_t origsize = igraph_strvector_size(strvec); - IGRAPH_CHECK(igraph_strvector_resize(strvec, 1)); - for (l = origsize; l < 1; l++) { - IGRAPH_CHECK(igraph_strvector_set(strvec, l, graphmlrec->default_value.as_string)); - } - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *boolvec = (igraph_vector_bool_t*)rec->value; - igraph_integer_t origsize = igraph_vector_bool_size(boolvec); - IGRAPH_CHECK(igraph_vector_bool_resize(boolvec, 1)); - for (l = origsize; l < 1; l++) { - VECTOR(*boolvec)[l] = graphmlrec->default_value.as_boolean; - } - } else if (rec->type == IGRAPH_ATTRIBUTE_UNSPECIFIED) { - continue; /* skipped attribute */ + + if (rec->type != IGRAPH_ATTRIBUTE_UNSPECIFIED) { + IGRAPH_CHECK(igraph_attribute_record_resize(rec, 1)); + IGRAPH_CHECK(igraph_attribute_record_list_push_back(&gattr, rec)); + graphmlrec->record_disowned = true; } - igraph_vector_ptr_push_back(&gattr, rec); /* reserved */ } IGRAPH_CHECK(igraph_empty_attrs(state->g, 0, state->edges_directed, &gattr)); @@ -577,9 +483,9 @@ static igraph_error_t igraph_i_graphml_parser_state_finish_parsing(struct igraph IGRAPH_CHECK(igraph_add_edges(state->g, &state->edgelist, &eattr)); IGRAPH_FINALLY_CLEAN(1); /* graph construction completed successfully */ - igraph_vector_ptr_destroy(&vattr); - igraph_vector_ptr_destroy(&eattr); - igraph_vector_ptr_destroy(&gattr); + igraph_attribute_record_list_destroy(&vattr); + igraph_attribute_record_list_destroy(&eattr); + igraph_attribute_record_list_destroy(&gattr); IGRAPH_FINALLY_CLEAN(3); return IGRAPH_SUCCESS; @@ -595,6 +501,34 @@ static igraph_error_t igraph_i_graphml_parser_state_finish_parsing(struct igraph #define XML_ATTR_VALUE(it) it[3], (int)(it[4] - it[3]) /* for use in strnxxx()-style functions that take a char * and a length */ #define XML_ATTR_VALUE_PF(it) (int)(it[4] - it[3]), it[3] /* for use in printf-style function with "%.*s" */ +static igraph_error_t safely_convert_xml_attribute_to_string(xmlChar** it, char** str) { + /* This is quite convoluted but we need to go safely from xmlChar*-world + * to char*-world */ + xmlChar *xml_str; + char *c_str; + + xml_str = xmlStrndup(XML_ATTR_VALUE(it)); + IGRAPH_CHECK_OOM(xml_str, "Insufficient memory to duplicate attribute value."); + IGRAPH_FINALLY(xmlFree, xml_str); + + c_str = strdup(fromXmlChar(xml_str)); + IGRAPH_CHECK_OOM(c_str, "Insufficient memory to duplicate attribute value."); + + *str = c_str; + + xmlFree(xml_str); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} + +static void safely_free_optional_string(char** str) { + if (*str != NULL) { + igraph_free(*str); + *str = NULL; + } +} + static igraph_bool_t xmlAttrValueEqual(xmlChar** attr, const char* expected) { size_t expected_length = strlen(expected); return ( @@ -623,27 +557,30 @@ static igraph_error_t igraph_i_graphml_add_attribute_key( xmlChar **it; xmlChar *localname; - xmlChar *xmlStr; igraph_trie_t *trie = NULL; igraph_vector_ptr_t *ptrvector = NULL; - igraph_integer_t i, n; - igraph_integer_t id; + igraph_int_t i, n; + igraph_int_t id; igraph_i_graphml_attribute_record_t *rec = NULL; + char *attr_name; + igraph_attribute_type_t igraph_attr_type; igraph_bool_t skip = false; + attr_name = NULL; + IGRAPH_FINALLY(safely_free_optional_string, &attr_name); + if (!state->successful) { /* Parser is already in an error state */ goto exit; } rec = IGRAPH_CALLOC(1, igraph_i_graphml_attribute_record_t); - if (rec == NULL) { - IGRAPH_ERROR("Cannot allocate attribute record.", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ - } + IGRAPH_CHECK_OOM(rec, "Insufficient memory to allocate attribute record."); IGRAPH_FINALLY(igraph_free, rec); IGRAPH_FINALLY(igraph_i_graphml_attribute_record_destroy, rec); + memset(rec, 0, sizeof(igraph_i_graphml_attribute_record_t)); - rec->type = I_GRAPHML_UNKNOWN_TYPE; + igraph_attr_type = IGRAPH_ATTRIBUTE_UNSPECIFIED; for (i = 0, it = (xmlChar**)attrs; i < nb_attrs; i++, it += 5) { if (XML_ATTR_URI(it) != 0 && @@ -654,52 +591,30 @@ static igraph_error_t igraph_i_graphml_add_attribute_key( localname = XML_ATTR_LOCALNAME(it); if (xmlStrEqual(localname, toXmlChar("id"))) { - xmlStr = xmlStrndup(XML_ATTR_VALUE(it)); - IGRAPH_CHECK_OOM(xmlStr, "Cannot duplicate value of 'id' attribute."); - if (rec->id) { - /* may happen if the 'id' attribute is provided multiple times */ - xmlFree((void *) rec->id); - rec->id = NULL; - } - rec->id = fromXmlChar(xmlStr); - xmlStr = NULL; + safely_free_optional_string(&rec->id); + IGRAPH_CHECK(safely_convert_xml_attribute_to_string(it, &rec->id)); } else if (xmlStrEqual(localname, toXmlChar("attr.name"))) { - xmlStr = xmlStrndup(XML_ATTR_VALUE(it)); - IGRAPH_CHECK_OOM(xmlStr, "Cannot duplicate value of 'attr.name' attribute."); - if (rec->record.name) { - /* may happen if the 'attr.name' attribute is provided multiple times */ - xmlFree((void *) rec->record.name); - rec->record.name = NULL; - } - rec->record.name = fromXmlChar(xmlStr); - xmlStr = NULL; + safely_free_optional_string(&attr_name); + IGRAPH_CHECK(safely_convert_xml_attribute_to_string(it, &attr_name)); } else if (xmlStrEqual(localname, toXmlChar("attr.type"))) { if (xmlAttrValueEqual(it, "boolean")) { + igraph_attr_type = IGRAPH_ATTRIBUTE_BOOLEAN; rec->type = I_GRAPHML_BOOLEAN; - rec->record.type = IGRAPH_ATTRIBUTE_BOOLEAN; - rec->default_value.as_boolean = 0; } else if (xmlAttrValueEqual(it, "string")) { - char *str = strdup(""); - IGRAPH_CHECK_OOM(str, "Cannot allocate new empty string."); + igraph_attr_type = IGRAPH_ATTRIBUTE_STRING; rec->type = I_GRAPHML_STRING; - rec->record.type = IGRAPH_ATTRIBUTE_STRING; - rec->default_value.as_string = str; } else if (xmlAttrValueEqual(it, "float")) { + igraph_attr_type = IGRAPH_ATTRIBUTE_NUMERIC; rec->type = I_GRAPHML_FLOAT; - rec->record.type = IGRAPH_ATTRIBUTE_NUMERIC; - rec->default_value.as_numeric = IGRAPH_NAN; } else if (xmlAttrValueEqual(it, "double")) { + igraph_attr_type = IGRAPH_ATTRIBUTE_NUMERIC; rec->type = I_GRAPHML_DOUBLE; - rec->record.type = IGRAPH_ATTRIBUTE_NUMERIC; - rec->default_value.as_numeric = IGRAPH_NAN; } else if (xmlAttrValueEqual(it, "int")) { + igraph_attr_type = IGRAPH_ATTRIBUTE_NUMERIC; rec->type = I_GRAPHML_INTEGER; - rec->record.type = IGRAPH_ATTRIBUTE_NUMERIC; - rec->default_value.as_numeric = IGRAPH_NAN; } else if (xmlAttrValueEqual(it, "long")) { + igraph_attr_type = IGRAPH_ATTRIBUTE_NUMERIC; rec->type = I_GRAPHML_LONG; - rec->record.type = IGRAPH_ATTRIBUTE_NUMERIC; - rec->default_value.as_numeric = IGRAPH_NAN; } else { IGRAPH_ERRORF("Unknown attribute type '%.*s'.", IGRAPH_PARSEERROR, XML_ATTR_VALUE_PF(it)); @@ -749,9 +664,11 @@ static igraph_error_t igraph_i_graphml_add_attribute_key( } /* in case of a missing attr.name attribute, use the id as the attribute name */ - if (rec->record.name == NULL) { - rec->record.name = strdup(rec->id); - IGRAPH_CHECK_OOM(rec->record.name, "Cannot duplicate attribute ID as name."); + if (attr_name == NULL) { + /* Allocation here is protected by safely_free_optional_string(&attr_name), + * which is already in the finally stack */ + attr_name = strdup(rec->id); + IGRAPH_CHECK_OOM(attr_name, "Cannot duplicate attribute ID as name."); } /* if the attribute type is missing, ignore the attribute with a warning */ @@ -760,9 +677,10 @@ static igraph_error_t igraph_i_graphml_add_attribute_key( skip = 1; } - /* if the value of the 'for' attribute was unknown, throw an error */ + /* if the value of the 'for' attribute was missing, ignore the attribute with a warning */ if (!skip && trie == 0) { - IGRAPH_ERROR("Missing 'for' attribute in a tag.", IGRAPH_PARSEERROR); + IGRAPH_WARNINGF("Ignoring because of a missing 'for' attribute.", rec->id); + skip = 1; } /* If attribute is skipped, proceed according to the type of the associated graph element. */ @@ -780,7 +698,7 @@ static igraph_error_t igraph_i_graphml_add_attribute_key( /* If the skipped attribute was for a supported graph element, we add it * as "UNSPECIFIED" so that we can avoid reporting "unknown attribute" warnings * later. */ - rec->record.type = IGRAPH_ATTRIBUTE_UNSPECIFIED; + igraph_attr_type = IGRAPH_ATTRIBUTE_UNSPECIFIED; } } @@ -794,12 +712,12 @@ static igraph_error_t igraph_i_graphml_add_attribute_key( n = igraph_vector_ptr_size(ptrvector); for (i = 0; i < n; i++) { if (!strcmp( - rec->record.name, + attr_name, ((igraph_i_graphml_attribute_record_t*) igraph_vector_ptr_get(ptrvector, i))->record.name )) { IGRAPH_ERRORF( "Duplicate attribute name found: '%s' (for ).", - IGRAPH_PARSEERROR, rec->record.name, rec->id + IGRAPH_PARSEERROR, attr_name, rec->id ); } } @@ -813,42 +731,12 @@ static igraph_error_t igraph_i_graphml_add_attribute_key( IGRAPH_FINALLY_CLEAN(2); /* create the attribute values */ - switch (rec->record.type) { - igraph_vector_t *vec; - igraph_vector_bool_t *boolvec; - igraph_strvector_t *strvec; - case IGRAPH_ATTRIBUTE_BOOLEAN: - boolvec = IGRAPH_CALLOC(1, igraph_vector_bool_t); - IGRAPH_CHECK_OOM(boolvec, "Cannot allocate value vector for Boolean attribute."); - IGRAPH_FINALLY(igraph_free, boolvec); - IGRAPH_CHECK(igraph_vector_bool_init(boolvec, 0)); - rec->record.value = boolvec; - IGRAPH_FINALLY_CLEAN(1); - break; - case IGRAPH_ATTRIBUTE_NUMERIC: - vec = IGRAPH_CALLOC(1, igraph_vector_t); - IGRAPH_CHECK_OOM(vec, "Cannot allocate value vector for numeric attribute."); - IGRAPH_FINALLY(igraph_free, vec); - IGRAPH_CHECK(igraph_vector_init(vec, 0)); - rec->record.value = vec; - IGRAPH_FINALLY_CLEAN(1); - break; - case IGRAPH_ATTRIBUTE_STRING: - strvec = IGRAPH_CALLOC(1, igraph_strvector_t); - IGRAPH_CHECK_OOM(strvec, "Cannot allocate value vector for string attribute."); - IGRAPH_FINALLY(igraph_free, strvec); - IGRAPH_CHECK(igraph_strvector_init(strvec, 0)); - rec->record.value = strvec; - IGRAPH_FINALLY_CLEAN(1); - break; - case IGRAPH_ATTRIBUTE_UNSPECIFIED: - rec->record.value = NULL; - break; - default: - IGRAPH_FATAL("Unexpected attribute type."); - } + IGRAPH_CHECK(igraph_attribute_record_init(&rec->record, attr_name, igraph_attr_type)); exit: + safely_free_optional_string(&attr_name); + IGRAPH_FINALLY_CLEAN(1); + *record = rec; return IGRAPH_SUCCESS; } @@ -876,9 +764,7 @@ static igraph_error_t igraph_i_graphml_attribute_data_setup( state->data_key = NULL; } state->data_key = xmlStrndup(XML_ATTR_VALUE(it)); - if (state->data_key == 0) { - return IGRAPH_ENOMEM; /* LCOV_EXCL_LINE */ - } + IGRAPH_CHECK_OOM(state->data_key, "Insufficient memory to read GraphML file."); igraph_vector_char_clear(&state->data_char); state->data_type = type; } else { @@ -892,16 +778,18 @@ static igraph_error_t igraph_i_graphml_attribute_data_setup( static igraph_error_t igraph_i_graphml_append_to_data_char( struct igraph_i_graphml_parser_state *state, const xmlChar *data, int len ) { + const igraph_vector_char_t data_vec = + igraph_vector_char_view((char *) data, len); + if (!state->successful) { return IGRAPH_SUCCESS; } - /* vector_push_back() minimizes reallocations by doubling the size of the buffer, - * while vector_append() would only allocate as much additional memory as needed. */ IGRAPH_STATIC_ASSERT(sizeof(char) == sizeof(xmlChar)); - for (int i=0; i < len; i++) { - IGRAPH_CHECK(igraph_vector_char_push_back(&state->data_char, data[i])); - } + IGRAPH_CHECK(igraph_vector_char_append( + &state->data_char, + &data_vec + )); return IGRAPH_SUCCESS; } @@ -913,7 +801,7 @@ static igraph_error_t igraph_i_graphml_attribute_data_finish(struct igraph_i_gra igraph_vector_ptr_t *ptrvector = NULL; igraph_i_graphml_attribute_record_t *graphmlrec; igraph_attribute_record_t *rec; - igraph_integer_t recid, id = 0; + igraph_int_t recid, id = 0; igraph_error_t result = IGRAPH_SUCCESS; switch (type) { @@ -955,66 +843,44 @@ static igraph_error_t igraph_i_graphml_attribute_data_finish(struct igraph_i_gra graphmlrec = VECTOR(*ptrvector)[recid]; rec = &graphmlrec->record; + if (id >= igraph_attribute_record_size(rec) && rec->type != IGRAPH_ATTRIBUTE_UNSPECIFIED) { + IGRAPH_CHECK(igraph_attribute_record_resize(rec, id + 1)); + } + switch (rec->type) { igraph_vector_bool_t *boolvec; igraph_vector_t *vec; igraph_strvector_t *strvec; - igraph_integer_t s, i; const char* strvalue; case IGRAPH_ATTRIBUTE_BOOLEAN: - boolvec = (igraph_vector_bool_t *)rec->value; - s = igraph_vector_bool_size(boolvec); - if (id >= s) { - IGRAPH_CHECK(igraph_vector_bool_resize(boolvec, id + 1)); - for (i = s; i < id; i++) { - VECTOR(*boolvec)[i] = graphmlrec->default_value.as_boolean; - } - } - /* Add null terminator */ IGRAPH_CHECK(igraph_vector_char_push_back(&state->data_char, '\x00')); + boolvec = rec->value.as_vector_bool; IGRAPH_CHECK(igraph_i_graphml_parse_boolean( - VECTOR(state->data_char), VECTOR(*boolvec) + id, graphmlrec->default_value.as_boolean + VECTOR(state->data_char), VECTOR(*boolvec) + id, rec->default_value.boolean )); break; case IGRAPH_ATTRIBUTE_NUMERIC: - vec = (igraph_vector_t *)rec->value; - s = igraph_vector_size(vec); - if (id >= s) { - IGRAPH_CHECK(igraph_vector_resize(vec, id + 1)); - for (i = s; i < id; i++) { - VECTOR(*vec)[i] = graphmlrec->default_value.as_numeric; - } - } - /* Add null terminator */ IGRAPH_CHECK(igraph_vector_char_push_back(&state->data_char, '\x00')); + vec = rec->value.as_vector; IGRAPH_CHECK(igraph_i_graphml_parse_numeric( - VECTOR(state->data_char), VECTOR(*vec) + id, - graphmlrec->default_value.as_numeric + VECTOR(state->data_char), VECTOR(*vec) + id, rec->default_value.numeric )); break; case IGRAPH_ATTRIBUTE_STRING: - strvec = (igraph_strvector_t *)rec->value; - s = igraph_strvector_size(strvec); - if (id >= s) { - IGRAPH_CHECK(igraph_strvector_resize(strvec, id + 1)); - strvalue = graphmlrec->default_value.as_string; - for (i = s; i < id; i++) { - IGRAPH_CHECK(igraph_strvector_set(strvec, i, strvalue)); - } - } + /* Ensure that the vector ends with a null terminator */ + strvec = rec->value.as_strvector; if (igraph_vector_char_size(&state->data_char) > 0) { - /* Ensure that the vector ends with a null terminator */ IGRAPH_CHECK(igraph_vector_char_push_back(&state->data_char, '\x00')); strvalue = VECTOR(state->data_char); } else { - strvalue = graphmlrec->default_value.as_string; + strvalue = rec->default_value.string; } - IGRAPH_CHECK(igraph_strvector_set(strvec, id, strvalue)); + IGRAPH_CHECK(igraph_strvector_set(strvec, id, strvalue ? strvalue : "")); break; case IGRAPH_ATTRIBUTE_UNSPECIFIED: @@ -1032,8 +898,10 @@ static igraph_error_t igraph_i_graphml_attribute_data_finish(struct igraph_i_gra static igraph_error_t igraph_i_graphml_attribute_default_value_finish(struct igraph_i_graphml_parser_state *state) { igraph_i_graphml_attribute_record_t *graphmlrec = state->current_attr_record; + igraph_attribute_record_t *rec; igraph_error_t result = IGRAPH_SUCCESS; - char* str = 0; + igraph_real_t default_num; + igraph_bool_t default_bool; IGRAPH_ASSERT(state->current_attr_record != NULL); @@ -1041,32 +909,25 @@ static igraph_error_t igraph_i_graphml_attribute_default_value_finish(struct igr return IGRAPH_SUCCESS; } - switch (graphmlrec->record.type) { + rec = &graphmlrec->record; + + switch (rec->type) { case IGRAPH_ATTRIBUTE_BOOLEAN: /* Add null terminator */ IGRAPH_CHECK(igraph_vector_char_push_back(&state->data_char, '\x00')); - IGRAPH_CHECK(igraph_i_graphml_parse_boolean( - VECTOR(state->data_char), &graphmlrec->default_value.as_boolean, 0 - )); + IGRAPH_CHECK(igraph_i_graphml_parse_boolean(VECTOR(state->data_char), &default_bool, false)); + IGRAPH_CHECK(igraph_attribute_record_set_default_boolean(rec, default_bool)); break; case IGRAPH_ATTRIBUTE_NUMERIC: /* Add null terminator */ IGRAPH_CHECK(igraph_vector_char_push_back(&state->data_char, '\x00')); - IGRAPH_CHECK(igraph_i_graphml_parse_numeric( - VECTOR(state->data_char), &graphmlrec->default_value.as_numeric, IGRAPH_NAN - )); + IGRAPH_CHECK(igraph_i_graphml_parse_numeric(VECTOR(state->data_char), &default_num, IGRAPH_NAN)); + IGRAPH_CHECK(igraph_attribute_record_set_default_numeric(rec, default_num)); break; case IGRAPH_ATTRIBUTE_STRING: /* Add null terminator */ IGRAPH_CHECK(igraph_vector_char_push_back(&state->data_char, '\x00')); - str = strdup(VECTOR(state->data_char)); - IGRAPH_CHECK_OOM(str, "Cannot allocate memory for string attribute."); - - if (graphmlrec->default_value.as_string != 0) { - IGRAPH_FREE(graphmlrec->default_value.as_string); - } - graphmlrec->default_value.as_string = str; - str = NULL; + IGRAPH_CHECK(igraph_attribute_record_set_default_string(rec, VECTOR(state->data_char))); break; case IGRAPH_ATTRIBUTE_UNSPECIFIED: break; @@ -1085,7 +946,7 @@ static igraph_error_t igraph_i_graphml_sax_handler_start_element_ns_inner( int nb_attributes, int nb_defaulted, const xmlChar** attributes) { xmlChar** it; xmlChar* attr_value = 0; - igraph_integer_t id1, id2; + igraph_int_t id1, id2; int i; igraph_bool_t tag_is_unknown = false; @@ -1219,8 +1080,8 @@ static igraph_error_t igraph_i_graphml_sax_handler_start_element_ns_inner( xmlFree(attr_value); attr_value = NULL; IGRAPH_FINALLY_CLEAN(1); } else if (xmlStrEqual(*it, toXmlChar("id"))) { - igraph_integer_t edges = igraph_vector_int_size(&state->edgelist) / 2 + 1; - igraph_integer_t origsize = igraph_strvector_size(&state->edgeids); + igraph_int_t edges = igraph_vector_int_size(&state->edgelist) / 2 + 1; + igraph_int_t origsize = igraph_strvector_size(&state->edgeids); attr_value = xmlStrndup(XML_ATTR_VALUE(it)); if (attr_value == 0) { @@ -1508,7 +1369,7 @@ static xmlSAXHandler igraph_i_graphml_sax_handler = { * \return Error code. */ static igraph_error_t igraph_i_xml_escape(const char *src, char **dest, const char *what) { - igraph_integer_t destlen = 0; + igraph_int_t destlen = 0; const char *s; char *d; unsigned char ch; @@ -1607,7 +1468,7 @@ static void igraph_i_libxml_structured_error_handler(void* ctx, const xmlError * * * \example examples/simple/graphml.c */ -igraph_error_t igraph_read_graph_graphml(igraph_t *graph, FILE *instream, igraph_integer_t index) { +igraph_error_t igraph_read_graph_graphml(igraph_t *graph, FILE *instream, igraph_int_t index) { #if HAVE_LIBXML == 1 xmlParserCtxtPtr ctxt; @@ -1787,11 +1648,11 @@ igraph_error_t igraph_read_graph_graphml(igraph_t *graph, FILE *instream, igraph igraph_error_t igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream, igraph_bool_t prefixattr) { int ret; - igraph_integer_t l, vc; + igraph_int_t l, vc; igraph_eit_t it; igraph_strvector_t gnames, vnames, enames; igraph_vector_int_t gtypes, vtypes, etypes; - igraph_integer_t i; + igraph_int_t i; igraph_vector_t numv; igraph_strvector_t strv; igraph_vector_bool_t boolv; @@ -2065,9 +1926,9 @@ igraph_error_t igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), &it)); IGRAPH_FINALLY(igraph_eit_destroy, &it); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t from, to; + igraph_int_t from, to; const char *name; char *name_escaped; - igraph_integer_t edge = IGRAPH_EIT_GET(it); + igraph_int_t edge = IGRAPH_EIT_GET(it); igraph_edge(graph, edge, &from, &to); ret = fprintf(outstream, " \n", from, to); diff --git a/src/vendor/cigraph/src/io/leda.c b/src/vendor/cigraph/src/io/leda.c index cf742cdde62..465cf65a7b0 100644 --- a/src/vendor/cigraph/src/io/leda.c +++ b/src/vendor/cigraph/src/io/leda.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -65,13 +64,13 @@ igraph_error_t igraph_write_graph_leda(const igraph_t *graph, FILE *outstream, const char *vertex_attr_name, const char *edge_attr_name) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_eit_t it; - igraph_integer_t i = 0; + igraph_int_t i = 0; igraph_attribute_type_t vertex_attr_type = IGRAPH_ATTRIBUTE_UNSPECIFIED; igraph_attribute_type_t edge_attr_type = IGRAPH_ATTRIBUTE_UNSPECIFIED; - igraph_integer_t from, to, rev; + igraph_int_t from, to, rev; IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &it)); IGRAPH_FINALLY(igraph_eit_destroy, &it); @@ -84,7 +83,7 @@ igraph_error_t igraph_write_graph_leda(const igraph_t *graph, FILE *outstream, vertex_attr_name = NULL; } if (vertex_attr_name) { - IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &vertex_attr_type, + IGRAPH_CHECK(igraph_i_attribute_get_type(graph, &vertex_attr_type, IGRAPH_ATTRIBUTE_VERTEX, vertex_attr_name)); if (vertex_attr_type != IGRAPH_ATTRIBUTE_NUMERIC && vertex_attr_type != IGRAPH_ATTRIBUTE_STRING && @@ -104,7 +103,7 @@ igraph_error_t igraph_write_graph_leda(const igraph_t *graph, FILE *outstream, edge_attr_name = NULL; } if (edge_attr_name) { - IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &edge_attr_type, + IGRAPH_CHECK(igraph_i_attribute_get_type(graph, &edge_attr_type, IGRAPH_ATTRIBUTE_EDGE, edge_attr_name)); if (edge_attr_type != IGRAPH_ATTRIBUTE_NUMERIC && edge_attr_type != IGRAPH_ATTRIBUTE_STRING && @@ -221,7 +220,7 @@ igraph_error_t igraph_write_graph_leda(const igraph_t *graph, FILE *outstream, IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr( graph, edge_attr_name, igraph_ess_all(IGRAPH_EDGEORDER_ID), &values)); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t eid = IGRAPH_EIT_GET(it); + igraph_int_t eid = IGRAPH_EIT_GET(it); igraph_edge(graph, eid, &from, &to); igraph_get_eid(graph, &rev, to, from, IGRAPH_DIRECTED, false); if (rev == IGRAPH_EIT_GET(it)) { @@ -244,7 +243,7 @@ igraph_error_t igraph_write_graph_leda(const igraph_t *graph, FILE *outstream, IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr( graph, edge_attr_name, igraph_ess_all(IGRAPH_EDGEORDER_ID), &values)); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t eid = IGRAPH_EIT_GET(it); + igraph_int_t eid = IGRAPH_EIT_GET(it); const char *str = igraph_strvector_get(&values, eid); igraph_edge(graph, eid, &from, &to); igraph_get_eid(graph, &rev, to, from, IGRAPH_DIRECTED, false); @@ -271,7 +270,7 @@ igraph_error_t igraph_write_graph_leda(const igraph_t *graph, FILE *outstream, graph, vertex_attr_name, igraph_ess_all(IGRAPH_EDGEORDER_ID), &values)); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t eid = IGRAPH_EIT_GET(it); + igraph_int_t eid = IGRAPH_EIT_GET(it); igraph_edge(graph, eid, &from, &to); igraph_get_eid(graph, &rev, to, from, IGRAPH_DIRECTED, false); if (rev == IGRAPH_EIT_GET(it)) { diff --git a/src/vendor/cigraph/src/io/lgl-header.h b/src/vendor/cigraph/src/io/lgl-header.h index f8579e4a7a0..b67e7725f60 100644 --- a/src/vendor/cigraph/src/io/lgl-header.h +++ b/src/vendor/cigraph/src/io/lgl-header.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2011-2012 Gabor Csardi 334 Harvard street, Cambridge MA, 02139 USA @@ -33,5 +33,5 @@ typedef struct { igraph_vector_int_t *vector; igraph_vector_t *weights; igraph_trie_t *trie; - igraph_integer_t actvertex; + igraph_int_t actvertex; } igraph_i_lgl_parsedata_t; diff --git a/src/vendor/cigraph/src/io/lgl-lexer.l b/src/vendor/cigraph/src/io/lgl-lexer.l index 64802df0e93..8b9fd06b8ac 100644 --- a/src/vendor/cigraph/src/io/lgl-lexer.l +++ b/src/vendor/cigraph/src/io/lgl-lexer.l @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -23,7 +23,7 @@ %{ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA diff --git a/src/vendor/cigraph/src/io/lgl-parser.y b/src/vendor/cigraph/src/io/lgl-parser.y index 792bbbfab28..2a6459ac802 100644 --- a/src/vendor/cigraph/src/io/lgl-parser.y +++ b/src/vendor/cigraph/src/io/lgl-parser.y @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -23,7 +23,7 @@ %{ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -74,7 +74,7 @@ int igraph_lgl_yyerror(YYLTYPE* locp, igraph_i_lgl_parsedata_t *context, %lex-param { void *scanner } %union { - igraph_integer_t edgenum; + igraph_int_t edgenum; igraph_real_t weightnum; } @@ -103,7 +103,7 @@ edges : /* empty */ | edges edge ; edge : edgeid NEWLINE { IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, context->actvertex)); IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, $1)); - IGRAPH_YY_CHECK(igraph_vector_push_back(context->weights, 0)); + IGRAPH_YY_CHECK(igraph_vector_push_back(context->weights, 1.0)); } | edgeid weight NEWLINE { IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, context->actvertex)); @@ -115,7 +115,7 @@ edge : edgeid NEWLINE { edgeid : ALNUM { - igraph_integer_t trie_id; + igraph_int_t trie_id; IGRAPH_YY_CHECK(igraph_trie_get_len(context->trie, igraph_lgl_yyget_text(scanner), igraph_lgl_yyget_leng(scanner), diff --git a/src/vendor/cigraph/src/io/lgl.c b/src/vendor/cigraph/src/io/lgl.c index 3cba8c034bd..e6ad1e263af 100644 --- a/src/vendor/cigraph/src/io/lgl.c +++ b/src/vendor/cigraph/src/io/lgl.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -77,10 +76,11 @@ vertex3name [optionalWeight] \endverbatim * graph as an edge attribute called \quote weight\endquote. * \c IGRAPH_ADD_WEIGHTS_YES adds the weights (even if they * are not present in the file, in this case they are assumed - * to be zero). \c IGRAPH_ADD_WEIGHTS_NO does not add any + * to be 1). \c IGRAPH_ADD_WEIGHTS_NO does not add any * edge attribute. \c IGRAPH_ADD_WEIGHTS_IF_PRESENT adds the * attribute if and only if there is at least one explicit - * edge weight in the input file. + * edge weight in the input file, and edges without an explicit + * weight are assumed to have a weight of 1. * \param directed Whether to create a directed graph. As this format * was originally used only for undirected graphs there is no * information in the file about the directedness of the graph. @@ -109,9 +109,9 @@ igraph_error_t igraph_read_graph_lgl(igraph_t *graph, FILE *instream, igraph_vector_int_t edges = IGRAPH_VECTOR_NULL; igraph_vector_t ws = IGRAPH_VECTOR_NULL; igraph_trie_t trie = IGRAPH_TRIE_NULL; - igraph_vector_ptr_t name, weight; - igraph_vector_ptr_t *pname = 0, *pweight = 0; - igraph_attribute_record_t namerec, weightrec; + igraph_attribute_record_list_t name, weight; + igraph_attribute_record_list_t *pname = NULL, *pweight = NULL; + igraph_attribute_record_t *namerec, *weightrec; const char *namestr = "name", *weightstr = "weight"; igraph_i_lgl_parsedata_t context; @@ -159,27 +159,32 @@ igraph_error_t igraph_read_graph_lgl(igraph_t *graph, FILE *instream, IGRAPH_FATALF("Parser returned unexpected error code (%d) when reading LGL file.", err); } - /* Prepare attributes, if needed */ - + /* Prepare attributes if needed */ if (names) { - IGRAPH_CHECK(igraph_vector_ptr_init(&name, 1)); - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &name); + IGRAPH_CHECK(igraph_attribute_record_list_init(&name, 1)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &name); + + namerec = igraph_attribute_record_list_get_ptr(&name, 0); + IGRAPH_CHECK(igraph_attribute_record_set_name(namerec, namestr)); + IGRAPH_CHECK(igraph_attribute_record_set_type(namerec, IGRAPH_ATTRIBUTE_STRING)); + IGRAPH_CHECK(igraph_strvector_update( + namerec->value.as_strvector, igraph_i_trie_borrow_keys(context.trie)) + ); + pname = &name; - namerec.name = namestr; - namerec.type = IGRAPH_ATTRIBUTE_STRING; - namerec.value = igraph_i_trie_borrow_keys(&trie); - VECTOR(name)[0] = &namerec; } if (weights == IGRAPH_ADD_WEIGHTS_YES || (weights == IGRAPH_ADD_WEIGHTS_IF_PRESENT && context.has_weights)) { - IGRAPH_CHECK(igraph_vector_ptr_init(&weight, 1)); - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &weight); + IGRAPH_CHECK(igraph_attribute_record_list_init(&weight, 1)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &weight); + + weightrec = igraph_attribute_record_list_get_ptr(&weight, 0); + IGRAPH_CHECK(igraph_attribute_record_set_name(weightrec, weightstr)); + IGRAPH_CHECK(igraph_attribute_record_set_type(weightrec, IGRAPH_ATTRIBUTE_NUMERIC)); + igraph_vector_swap(weightrec->value.as_vector, context.weights); + pweight = &weight; - weightrec.name = weightstr; - weightrec.type = IGRAPH_ATTRIBUTE_NUMERIC; - weightrec.value = &ws; - VECTOR(weight)[0] = &weightrec; } /* Create graph */ @@ -189,11 +194,11 @@ igraph_error_t igraph_read_graph_lgl(igraph_t *graph, FILE *instream, IGRAPH_CHECK(igraph_add_edges(graph, &edges, pweight)); if (pweight) { - igraph_vector_ptr_destroy(pweight); + igraph_attribute_record_list_destroy(pweight); IGRAPH_FINALLY_CLEAN(1); } if (pname) { - igraph_vector_ptr_destroy(pname); + igraph_attribute_record_list_destroy(pname); IGRAPH_FINALLY_CLEAN(1); } igraph_trie_destroy(&trie); @@ -265,9 +270,9 @@ igraph_error_t igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream, const char *names, const char *weights, igraph_bool_t isolates) { igraph_eit_t it; - igraph_integer_t actvertex = -1; + igraph_int_t actvertex = -1; igraph_attribute_type_t nametype, weighttype; - const igraph_integer_t vcount = igraph_vcount(graph), ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph), ecount = igraph_ecount(graph); IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &it)); @@ -280,7 +285,7 @@ igraph_error_t igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream, names = NULL; } if (names) { - IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &nametype, + IGRAPH_CHECK(igraph_i_attribute_get_type(graph, &nametype, IGRAPH_ATTRIBUTE_VERTEX, names)); if (nametype != IGRAPH_ATTRIBUTE_STRING) { IGRAPH_WARNINGF("Ignoring names attribute '%s', unknown attribute type.", names); @@ -294,7 +299,7 @@ igraph_error_t igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream, weights = NULL; } if (weights) { - IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &weighttype, + IGRAPH_CHECK(igraph_i_attribute_get_type(graph, &weighttype, IGRAPH_ATTRIBUTE_EDGE, weights)); if (weighttype != IGRAPH_ATTRIBUTE_NUMERIC) { IGRAPH_WARNINGF("Ignoring weights attribute '%s', unknown attribute type.", weights); @@ -305,7 +310,7 @@ igraph_error_t igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream, if (names == NULL && weights == NULL) { /* No names, no weights */ while (!IGRAPH_EIT_END(it)) { - igraph_integer_t from, to; + igraph_int_t from, to; int ret; igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to); if (from == actvertex) { @@ -327,8 +332,8 @@ igraph_error_t igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream, igraph_vss_all(), &nvec)); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t edge = IGRAPH_EIT_GET(it); - igraph_integer_t from, to; + igraph_int_t edge = IGRAPH_EIT_GET(it); + igraph_int_t from, to; int ret = 0; const char *str1, *str2; igraph_edge(graph, edge, &from, &to); @@ -358,8 +363,8 @@ igraph_error_t igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream, igraph_ess_all(IGRAPH_EDGEORDER_ID), &wvec)); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t edge = IGRAPH_EIT_GET(it); - igraph_integer_t from, to; + igraph_int_t edge = IGRAPH_EIT_GET(it); + igraph_int_t from, to; int ret1, ret2, ret3; igraph_edge(graph, edge, &from, &to); if (from == actvertex) { @@ -390,8 +395,8 @@ igraph_error_t igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream, igraph_vss_all(), &nvec)); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t edge = IGRAPH_EIT_GET(it); - igraph_integer_t from, to; + igraph_int_t edge = IGRAPH_EIT_GET(it); + igraph_int_t from, to; int ret = 0, ret2; const char *str1, *str2; igraph_edge(graph, edge, &from, &to); @@ -422,10 +427,10 @@ igraph_error_t igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream, } if (isolates) { - igraph_integer_t nov = vcount; - igraph_integer_t i; + igraph_int_t nov = vcount; + igraph_int_t i; int ret = 0; - igraph_integer_t deg; + igraph_int_t deg; igraph_strvector_t nvec; const char *str; diff --git a/src/vendor/cigraph/src/io/ncol-header.h b/src/vendor/cigraph/src/io/ncol-header.h index 655ef2e7277..230a995b5f8 100644 --- a/src/vendor/cigraph/src/io/ncol-header.h +++ b/src/vendor/cigraph/src/io/ncol-header.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2011-2012 Gabor Csardi 334 Harvard street, Cambridge MA, 02139 USA diff --git a/src/vendor/cigraph/src/io/ncol-lexer.l b/src/vendor/cigraph/src/io/ncol-lexer.l index b668b48cc60..9851a7c8737 100644 --- a/src/vendor/cigraph/src/io/ncol-lexer.l +++ b/src/vendor/cigraph/src/io/ncol-lexer.l @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -23,7 +23,7 @@ %{ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA diff --git a/src/vendor/cigraph/src/io/ncol-parser.y b/src/vendor/cigraph/src/io/ncol-parser.y index caec463cc29..0af69d284b0 100644 --- a/src/vendor/cigraph/src/io/ncol-parser.y +++ b/src/vendor/cigraph/src/io/ncol-parser.y @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -23,7 +23,7 @@ %{ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -75,7 +75,7 @@ int igraph_ncol_yyerror(YYLTYPE* locp, %lex-param { void *scanner } %union { - igraph_integer_t edgenum; + igraph_int_t edgenum; igraph_real_t weightnum; } @@ -95,7 +95,7 @@ input : /* empty */ ; edge : endpoints NEWLINE { - IGRAPH_YY_CHECK(igraph_vector_push_back(context->weights, 0.0)); + IGRAPH_YY_CHECK(igraph_vector_push_back(context->weights, 1.0)); } | endpoints weight NEWLINE { IGRAPH_YY_CHECK(igraph_vector_push_back(context->weights, $2)); @@ -109,7 +109,7 @@ endpoints : edgeid edgeid { }; edgeid : ALNUM { - igraph_integer_t trie_id; + igraph_int_t trie_id; IGRAPH_YY_CHECK(igraph_trie_get_len(context->trie, igraph_ncol_yyget_text(scanner), igraph_ncol_yyget_leng(scanner), diff --git a/src/vendor/cigraph/src/io/ncol.c b/src/vendor/cigraph/src/io/ncol.c index d5f739a77dc..0804f92ec48 100644 --- a/src/vendor/cigraph/src/io/ncol.c +++ b/src/vendor/cigraph/src/io/ncol.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -81,10 +80,11 @@ void igraph_ncol_yylex_destroy_wrapper (void *scanner ) { * graph as an edge attribute called \quote weight\endquote. * \c IGRAPH_ADD_WEIGHTS_YES adds the weights (even if they * are not present in the file, in this case they are assumed - * to be zero). \c IGRAPH_ADD_WEIGHTS_NO does not add any + * to be 1). \c IGRAPH_ADD_WEIGHTS_NO does not add any * edge attribute. \c IGRAPH_ADD_WEIGHTS_IF_PRESENT adds the * attribute if and only if there is at least one explicit - * edge weight in the input file. + * edge weight in the input file, and edges without an explicit + * weight are assumed to have a weight of 1. * \param directed Whether to create a directed graph. As this format * was originally used only for undirected graphs there is no * information in the file about the directedness of the graph. @@ -112,11 +112,11 @@ igraph_error_t igraph_read_graph_ncol(igraph_t *graph, FILE *instream, igraph_vector_int_t edges; igraph_vector_t ws; igraph_trie_t trie = IGRAPH_TRIE_NULL; - igraph_integer_t no_of_nodes; - igraph_integer_t no_predefined = 0; - igraph_vector_ptr_t name, weight; - igraph_vector_ptr_t *pname = NULL, *pweight = NULL; - igraph_attribute_record_t namerec, weightrec; + igraph_int_t no_of_nodes; + igraph_int_t no_predefined = 0; + igraph_attribute_record_list_t name, weight; + igraph_attribute_record_list_t *pname = NULL, *pweight = NULL; + igraph_attribute_record_t *namerec, *weightrec; const char *namestr = "name", *weightstr = "weight"; igraph_i_ncol_parsedata_t context; @@ -127,7 +127,7 @@ igraph_error_t igraph_read_graph_ncol(igraph_t *graph, FILE *instream, /* Add the predefined names, if any */ if (predefnames != 0) { - igraph_integer_t i, id, n; + igraph_int_t i, id, n; const char *key; n = no_predefined = igraph_strvector_size(predefnames); for (i = 0; i < n; i++) { @@ -185,28 +185,32 @@ igraph_error_t igraph_read_graph_ncol(igraph_t *graph, FILE *instream, IGRAPH_WARNING("Unknown vertex/vertices found in NCOL file, predefined names extended."); } - /* Prepare attributes, if needed */ - + /* Prepare attributes if needed */ if (names) { - IGRAPH_CHECK(igraph_vector_ptr_init(&name, 1)); - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &name); + IGRAPH_CHECK(igraph_attribute_record_list_init(&name, 1)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &name); + + namerec = igraph_attribute_record_list_get_ptr(&name, 0); + IGRAPH_CHECK(igraph_attribute_record_set_name(namerec, namestr)); + IGRAPH_CHECK(igraph_attribute_record_set_type(namerec, IGRAPH_ATTRIBUTE_STRING)); + IGRAPH_CHECK(igraph_strvector_update( + namerec->value.as_strvector, igraph_i_trie_borrow_keys(context.trie)) + ); + pname = &name; - namerec.name = namestr; - namerec.type = IGRAPH_ATTRIBUTE_STRING; - namerec.value = igraph_i_trie_borrow_keys(&trie); - VECTOR(name)[0] = &namerec; } if (weights == IGRAPH_ADD_WEIGHTS_YES || (weights == IGRAPH_ADD_WEIGHTS_IF_PRESENT && context.has_weights)) { + IGRAPH_CHECK(igraph_attribute_record_list_init(&weight, 1)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &weight); + + weightrec = igraph_attribute_record_list_get_ptr(&weight, 0); + IGRAPH_CHECK(igraph_attribute_record_set_name(weightrec, weightstr)); + IGRAPH_CHECK(igraph_attribute_record_set_type(weightrec, IGRAPH_ATTRIBUTE_NUMERIC)); + igraph_vector_swap(weightrec->value.as_vector, context.weights); - IGRAPH_CHECK(igraph_vector_ptr_init(&weight, 1)); - IGRAPH_FINALLY(igraph_vector_ptr_destroy, &weight); pweight = &weight; - weightrec.name = weightstr; - weightrec.type = IGRAPH_ATTRIBUTE_NUMERIC; - weightrec.value = &ws; - VECTOR(weight)[0] = &weightrec; } if (igraph_vector_int_empty(&edges)) { @@ -222,11 +226,11 @@ igraph_error_t igraph_read_graph_ncol(igraph_t *graph, FILE *instream, IGRAPH_CHECK(igraph_add_edges(graph, &edges, pweight)); if (pname) { - igraph_vector_ptr_destroy(pname); + igraph_attribute_record_list_destroy(pname); IGRAPH_FINALLY_CLEAN(1); } if (pweight) { - igraph_vector_ptr_destroy(pweight); + igraph_attribute_record_list_destroy(pweight); IGRAPH_FINALLY_CLEAN(1); } igraph_vector_destroy(&ws); @@ -309,7 +313,7 @@ igraph_error_t igraph_write_graph_ncol(const igraph_t *graph, FILE *outstream, names = NULL; } if (names) { - IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &nametype, + IGRAPH_CHECK(igraph_i_attribute_get_type(graph, &nametype, IGRAPH_ATTRIBUTE_VERTEX, names)); if (nametype != IGRAPH_ATTRIBUTE_STRING) { IGRAPH_WARNINGF("Ignoring names attribute '%s', " @@ -324,7 +328,7 @@ igraph_error_t igraph_write_graph_ncol(const igraph_t *graph, FILE *outstream, weights = NULL; } if (weights) { - IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &weighttype, + IGRAPH_CHECK(igraph_i_attribute_get_type(graph, &weighttype, IGRAPH_ATTRIBUTE_EDGE, weights)); if (weighttype != IGRAPH_ATTRIBUTE_NUMERIC) { IGRAPH_WARNINGF("Ignoring weights attribute '%s', " @@ -336,7 +340,7 @@ igraph_error_t igraph_write_graph_ncol(const igraph_t *graph, FILE *outstream, if (names == NULL && weights == NULL) { /* No names, no weights */ while (!IGRAPH_EIT_END(it)) { - igraph_integer_t from, to; + igraph_int_t from, to; int ret; igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to); ret = fprintf(outstream, "%" IGRAPH_PRId " %" IGRAPH_PRId "\n", from, to); @@ -354,8 +358,8 @@ igraph_error_t igraph_write_graph_ncol(const igraph_t *graph, FILE *outstream, igraph_vss_all(), &nvec)); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t edge = IGRAPH_EIT_GET(it); - igraph_integer_t from, to; + igraph_int_t edge = IGRAPH_EIT_GET(it); + igraph_int_t from, to; int ret = 0; const char *str1, *str2; igraph_edge(graph, edge, &from, &to); @@ -379,8 +383,8 @@ igraph_error_t igraph_write_graph_ncol(const igraph_t *graph, FILE *outstream, igraph_ess_all(IGRAPH_EDGEORDER_ID), &wvec)); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t edge = IGRAPH_EIT_GET(it); - igraph_integer_t from, to; + igraph_int_t edge = IGRAPH_EIT_GET(it); + igraph_int_t from, to; int ret1, ret2, ret3; igraph_edge(graph, edge, &from, &to); ret1 = fprintf(outstream, "%" IGRAPH_PRId " %" IGRAPH_PRId " ", from, to); @@ -407,8 +411,8 @@ igraph_error_t igraph_write_graph_ncol(const igraph_t *graph, FILE *outstream, igraph_vss_all(), &nvec)); while (!IGRAPH_EIT_END(it)) { - igraph_integer_t edge = IGRAPH_EIT_GET(it); - igraph_integer_t from, to; + igraph_int_t edge = IGRAPH_EIT_GET(it); + igraph_int_t from, to; int ret = 0, ret2 = 0; const char *str1, *str2; igraph_edge(graph, edge, &from, &to); diff --git a/src/vendor/cigraph/src/io/pajek-header.h b/src/vendor/cigraph/src/io/pajek-header.h index 63308777adf..d6d16dd0615 100644 --- a/src/vendor/cigraph/src/io/pajek-header.h +++ b/src/vendor/cigraph/src/io/pajek-header.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2011-2012 Gabor Csardi 334 Harvard street, Cambridge MA, 02139 USA @@ -20,10 +20,10 @@ */ +#include "igraph_attributes.h" #include "igraph_bitset.h" #include "igraph_error.h" #include "igraph_vector.h" -#include "igraph_vector_ptr.h" #include "core/trie.h" @@ -51,14 +51,14 @@ typedef struct { igraph_vector_int_t *vector; igraph_bitset_t *seen; igraph_bool_t directed; - igraph_integer_t vcount, vcount2; - igraph_integer_t actfrom; - igraph_integer_t actto; + igraph_int_t vcount, vcount2; + igraph_int_t actfrom; + igraph_int_t actto; igraph_trie_t *vertex_attribute_names; - igraph_vector_ptr_t *vertex_attributes; + igraph_attribute_record_list_t *vertex_attributes; igraph_trie_t *edge_attribute_names; - igraph_vector_ptr_t *edge_attributes; - igraph_integer_t vertexid; - igraph_integer_t actvertex; - igraph_integer_t actedge; + igraph_attribute_record_list_t *edge_attributes; + igraph_int_t vertexid; + igraph_int_t actvertex; + igraph_int_t actedge; } igraph_i_pajek_parsedata_t; diff --git a/src/vendor/cigraph/src/io/pajek-lexer.l b/src/vendor/cigraph/src/io/pajek-lexer.l index fdb4ac82a2a..8453bef4f01 100644 --- a/src/vendor/cigraph/src/io/pajek-lexer.l +++ b/src/vendor/cigraph/src/io/pajek-lexer.l @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -23,7 +23,7 @@ %{ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA diff --git a/src/vendor/cigraph/src/io/pajek-parser.y b/src/vendor/cigraph/src/io/pajek-parser.y index da13026d141..b253aee8e8a 100644 --- a/src/vendor/cigraph/src/io/pajek-parser.y +++ b/src/vendor/cigraph/src/io/pajek-parser.y @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -23,7 +23,7 @@ %{ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard st, Cambridge, MA, 02138 USA @@ -78,18 +78,20 @@ static igraph_error_t add_numeric_edge_attribute(const char *name, igraph_real_t value, igraph_i_pajek_parsedata_t *context); static igraph_error_t add_numeric_attribute(igraph_trie_t *names, - igraph_vector_ptr_t *attrs, - igraph_integer_t count, + igraph_attribute_record_list_t *attrs, + igraph_int_t count, const char *attrname, - igraph_integer_t vid, + igraph_real_t default_value, + igraph_int_t vid, igraph_real_t number); static igraph_error_t add_string_attribute(igraph_trie_t *names, - igraph_vector_ptr_t *attrs, - igraph_integer_t count, + igraph_attribute_record_list_t *attrs, + igraph_int_t count, const char *attrname, - igraph_integer_t vid, + const char *default_value, + igraph_int_t vid, const char *str, - igraph_integer_t str_len); + igraph_int_t str_len); static igraph_error_t add_bipartite_type(igraph_i_pajek_parsedata_t *context); static igraph_error_t check_bipartite(igraph_i_pajek_parsedata_t *context); @@ -98,6 +100,10 @@ static igraph_error_t make_dynstr(const char *src, size_t len, char **res); static igraph_bool_t is_standard_vattr(const char *attrname); static igraph_bool_t is_standard_eattr(const char *attrname); static igraph_error_t deconflict_attrname(char **attrname); +static igraph_real_t get_default_value_for_numeric_vattr(const char *attrname); +static igraph_real_t get_default_value_for_numeric_eattr(const char *attrname); +static const char* get_default_value_for_string_vattr(const char *attrname); +static const char* get_default_value_for_string_eattr(const char *attrname); #define scanner context->scanner @@ -114,7 +120,7 @@ static igraph_error_t deconflict_attrname(char **attrname); %lex-param { void *scanner } %union { - igraph_integer_t intnum; + igraph_int_t intnum; igraph_real_t realnum; struct { char *str; @@ -236,7 +242,7 @@ vertdefs: /* empty */ | vertdefs vertexline; vertexline: vertex NEWLINE | vertex { context->actvertex=$1; } vertexid vertexcoords shape vertparams NEWLINE { - igraph_integer_t v = $1-1; /* zero-based vertex ID */ + igraph_int_t v = $1-1; /* zero-based vertex ID */ if (IGRAPH_BIT_TEST(*context->seen, v)) { IGRAPH_WARNINGF("Vertex ID %" IGRAPH_PRId " appears twice in Pajek file. Duplicate attributes will be overwritten.", v+1); } else { @@ -246,7 +252,7 @@ vertexline: vertex NEWLINE | ; vertex: integer { - igraph_integer_t v = $1; + igraph_int_t v = $1; /* Per feedback from Pajek's authors, negative signs should be ignored for vertex IDs. * See https://nascol.discourse.group/t/pajek-arcslist-edgelist-format/44/2 * This applies to all of *Edges, *Arcs, *Edgeslist, *Arcslist and *Vertices section. @@ -265,7 +271,6 @@ vertex: integer { }; vertexid: word { - IGRAPH_YY_CHECK(add_string_vertex_attribute("id", $1.str, $1.len, context)); IGRAPH_YY_CHECK(add_string_vertex_attribute("name", $1.str, $1.len, context)); }; @@ -523,7 +528,7 @@ adjmatrixentry: number { /* -----------------------------------------------------*/ integer: NUM { - igraph_integer_t val; + igraph_int_t val; IGRAPH_YY_CHECK(igraph_i_parse_integer(igraph_pajek_yyget_text(scanner), igraph_pajek_yyget_leng(scanner), &val)); @@ -565,49 +570,38 @@ int igraph_pajek_yyerror(YYLTYPE* locp, /* TODO: NA's */ static igraph_error_t add_numeric_attribute(igraph_trie_t *names, - igraph_vector_ptr_t *attrs, - igraph_integer_t count, + igraph_attribute_record_list_t *attrs, + igraph_int_t count, const char *attrname, - igraph_integer_t elem_id, + igraph_real_t default_value, + igraph_int_t elem_id, igraph_real_t number) { - igraph_integer_t attrsize = igraph_trie_size(names); - igraph_integer_t id; + igraph_int_t attrsize = igraph_trie_size(names); + igraph_int_t id; igraph_vector_t *na; - igraph_attribute_record_t *rec; + igraph_attribute_record_t *prec; IGRAPH_CHECK(igraph_trie_get(names, attrname, &id)); if (id == attrsize) { - /* add a new attribute */ - rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - CHECK_OOM_RP(rec); - IGRAPH_FINALLY(igraph_free, rec); - - na = IGRAPH_CALLOC(1, igraph_vector_t); - CHECK_OOM_RP(na); - IGRAPH_FINALLY(igraph_free, na); - IGRAPH_VECTOR_INIT_FINALLY(na, count); + igraph_attribute_record_t rec; - rec->name = strdup(attrname); - CHECK_OOM_RP(rec->name); - IGRAPH_FINALLY(igraph_free, (void *) rec->name); + /* add a new attribute */ + IGRAPH_CHECK(igraph_attribute_record_init(&rec, attrname, IGRAPH_ATTRIBUTE_NUMERIC)); + IGRAPH_FINALLY(igraph_attribute_record_destroy, &rec); - rec->type = IGRAPH_ATTRIBUTE_NUMERIC; - rec->value = na; + IGRAPH_CHECK(igraph_attribute_record_set_default_numeric(&rec, default_value)); - IGRAPH_CHECK(igraph_vector_ptr_push_back(attrs, rec)); - IGRAPH_FINALLY_CLEAN(4); /* ownership of rec transferred to attrs */ + IGRAPH_CHECK(igraph_attribute_record_resize(&rec, count)); + IGRAPH_CHECK(igraph_attribute_record_list_push_back(attrs, &rec)); + IGRAPH_FINALLY_CLEAN(1); /* ownership of rec transferred to attrs */ } - rec = VECTOR(*attrs)[id]; - na = (igraph_vector_t *) rec->value; + prec = igraph_attribute_record_list_get_ptr(attrs, id); + na = prec->value.as_vector; if (igraph_vector_size(na) == elem_id) { IGRAPH_CHECK(igraph_vector_push_back(na, number)); } else if (igraph_vector_size(na) < elem_id) { - igraph_integer_t origsize=igraph_vector_size(na); - IGRAPH_CHECK(igraph_vector_resize(na, elem_id+1)); - for (;origsizename = strdup(attrname); - CHECK_OOM_RP(rec->name); - IGRAPH_FINALLY(igraph_free, (char *) rec->name); + IGRAPH_CHECK(igraph_attribute_record_init(&rec, attrname, IGRAPH_ATTRIBUTE_STRING)); + IGRAPH_FINALLY(igraph_attribute_record_destroy, &rec); - rec->type = IGRAPH_ATTRIBUTE_STRING; - rec->value = na; + IGRAPH_CHECK(igraph_attribute_record_set_default_string(&rec, default_value)); - IGRAPH_CHECK(igraph_vector_ptr_push_back(attrs, rec)); - IGRAPH_FINALLY_CLEAN(4); /* ownership of rec transferred to attrs */ + IGRAPH_CHECK(igraph_attribute_record_resize(&rec, count)); + IGRAPH_CHECK(igraph_attribute_record_list_push_back(attrs, &rec)); + IGRAPH_FINALLY_CLEAN(1); /* ownership of rec transferred to attrs */ } - rec = VECTOR(*attrs)[id]; - na = (igraph_strvector_t *) rec->value; + prec = igraph_attribute_record_list_get_ptr(attrs, id); + na = prec->value.as_strvector; if (igraph_strvector_size(na) <= elem_id) { IGRAPH_CHECK(igraph_strvector_resize(na, elem_id+1)); } @@ -692,7 +675,9 @@ static igraph_error_t add_string_vertex_attribute(const char *name, return add_string_attribute(context->vertex_attribute_names, context->vertex_attributes, context->vcount, - name, context->actvertex-1, + name, + get_default_value_for_string_vattr(name), + context->actvertex-1, value, len); } @@ -704,7 +689,9 @@ static igraph_error_t add_string_edge_attribute(const char *name, return add_string_attribute(context->edge_attribute_names, context->edge_attributes, context->actedge, - name, context->actedge-1, + name, + get_default_value_for_string_eattr(name), + context->actedge-1, value, len); } @@ -715,7 +702,9 @@ static igraph_error_t add_numeric_vertex_attribute(const char *name, return add_numeric_attribute(context->vertex_attribute_names, context->vertex_attributes, context->vcount, - name, context->actvertex-1, + name, + get_default_value_for_numeric_vattr(name), + context->actvertex-1, value); } @@ -726,7 +715,9 @@ static igraph_error_t add_numeric_edge_attribute(const char *name, return add_numeric_attribute(context->edge_attribute_names, context->edge_attributes, context->actedge, - name, context->actedge-1, + name, + get_default_value_for_numeric_eattr(name), + context->actedge-1, value); } @@ -734,10 +725,10 @@ static igraph_error_t add_bipartite_type(igraph_i_pajek_parsedata_t *context) { const char *attrname="type"; igraph_trie_t *names=context->vertex_attribute_names; - igraph_vector_ptr_t *attrs=context->vertex_attributes; - igraph_integer_t n=context->vcount, n1=context->vcount2; - igraph_integer_t attrid, attrsize = igraph_trie_size(names); - igraph_attribute_record_t *rec; + igraph_attribute_record_list_t *attrs=context->vertex_attributes; + igraph_int_t n=context->vcount, n1=context->vcount2; + igraph_int_t attrid, attrsize = igraph_trie_size(names); + igraph_attribute_record_t* rec; igraph_vector_bool_t *na; if (n1 > n) { @@ -752,29 +743,13 @@ static igraph_error_t add_bipartite_type(igraph_i_pajek_parsedata_t *context) { IGRAPH_ASSERT(attrid == attrsize); /* add a new attribute */ - rec = IGRAPH_CALLOC(1, igraph_attribute_record_t); - CHECK_OOM_RP(rec); - IGRAPH_FINALLY(igraph_free, rec); - - na = IGRAPH_CALLOC(1, igraph_vector_bool_t); - CHECK_OOM_RP(na); - IGRAPH_FINALLY(igraph_free, na); - IGRAPH_VECTOR_BOOL_INIT_FINALLY(na, n); - - rec->name = strdup(attrname); - CHECK_OOM_RP(rec->name); - IGRAPH_FINALLY(igraph_free, (char *) rec->name); + IGRAPH_CHECK(igraph_attribute_record_list_push_back_new(attrs, &rec)); + IGRAPH_CHECK(igraph_attribute_record_set_name(rec, attrname)); + IGRAPH_CHECK(igraph_attribute_record_set_type(rec, IGRAPH_ATTRIBUTE_BOOLEAN)); + IGRAPH_CHECK(igraph_attribute_record_resize(rec, n)); - rec->type = IGRAPH_ATTRIBUTE_BOOLEAN; - rec->value = na; - - IGRAPH_CHECK(igraph_vector_ptr_push_back(attrs, rec)); - IGRAPH_FINALLY_CLEAN(4); /* ownership of 'rec' transferred to 'attrs' */ - - for (igraph_integer_t i=0; ivalue.as_vector_bool; + for (igraph_int_t i = n1; i < n; i++) { VECTOR(*na)[i] = true; } @@ -783,12 +758,12 @@ static igraph_error_t add_bipartite_type(igraph_i_pajek_parsedata_t *context) { static igraph_error_t check_bipartite(igraph_i_pajek_parsedata_t *context) { const igraph_vector_int_t *edges=context->vector; - igraph_integer_t n1=context->vcount2; - igraph_integer_t ne=igraph_vector_int_size(edges); + igraph_int_t n1=context->vcount2; + igraph_int_t ne=igraph_vector_int_size(edges); - for (igraph_integer_t i=0; i n1 && v2 > n1) ) { IGRAPH_WARNING("Invalid edge in bipartite graph."); } @@ -814,7 +789,7 @@ static igraph_bool_t is_standard_vattr(const char *attrname) { "font", "url", "color", "framecolor", "labelcolor" }; - for (size_t i=0; i < sizeof(names) / sizeof(names[0]); i++) { + for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); i++) { if (strcmp(attrname, names[i]) == 0) { return true; } @@ -856,3 +831,108 @@ static igraph_error_t deconflict_attrname(char **attrname) { *attrname = tmp; return IGRAPH_SUCCESS; } + +typedef struct { + const char* name; + igraph_real_t default_value; +} attribute_numeric_defaults_t; + +typedef struct { + const char* name; + const char* default_value; +} attribute_string_defaults_t; + +/* The defaults listed below are Pajek's built-in defaults unless the user + * overrides them. + * + * See: https://nascol.discourse.group/t/pajek-file-format-default-values-for-attributes/38/2 + */ + +const attribute_numeric_defaults_t vattr_numeric_defaults[] = { + { "xfact", 1 }, + { "yfact", 1 }, + { "labeldist", 20 }, + { "labeldegree2", 285 }, + { "framewidth", 1 }, + { "fontsize", 15 }, + { "rotation", 0 }, + { "radius", 0 }, + { "diamondratio", 0.01 }, + { "labeldegree", 0 }, + { 0 } +}; + +const attribute_string_defaults_t vattr_string_defaults[] = { + { "color", "LightOrange" }, + { "framecolor", "Brown" }, + { "labelcolor", "Maroon" }, + { 0 } +}; + +const attribute_numeric_defaults_t eattr_numeric_defaults[] = { + { "arrowsize", 1 }, + { "edgewidth", 2 }, + { "hook1", 0 }, + { "hook2", 0 }, + { "angle1", 0 }, + { "angle2", 0 }, + { "velocity1", 1 }, + { "velocity2", 1 }, + { "arrowpos", 0 }, + { "labelpos", 0.5 }, + { "labelangle", 10 }, + { "labelangle2", 90 }, + { "labeldegree", 0 }, + { "fontsize", 15 }, + { 0 } +}; + +const attribute_string_defaults_t eattr_string_defaults[] = { + { "color", "MidnightBlue" }, + { "labelcolor", "Black" }, + { 0 } +}; + +static igraph_real_t get_default_value_for_numeric_attr( + const char *attrname, const attribute_numeric_defaults_t* table +) { + const attribute_numeric_defaults_t* ptr; + + for (ptr = table; ptr->name != 0; ptr++) { + if (!strcmp(attrname, ptr->name)) { + return ptr->default_value; + } + } + + return IGRAPH_NAN; +} + +static const char* get_default_value_for_string_attr( + const char *attrname, const attribute_string_defaults_t* table +) { + const attribute_string_defaults_t* ptr; + + for (ptr = table; ptr->name != 0; ptr++) { + if (!strcmp(attrname, ptr->name)) { + return ptr->default_value; + } + } + + return ""; +} + +static igraph_real_t get_default_value_for_numeric_vattr(const char *attrname) { + return get_default_value_for_numeric_attr(attrname, vattr_numeric_defaults); +} + +static igraph_real_t get_default_value_for_numeric_eattr(const char *attrname) { + return get_default_value_for_numeric_attr(attrname, eattr_numeric_defaults); +} + +static const char* get_default_value_for_string_vattr(const char *attrname) { + return get_default_value_for_string_attr(attrname, vattr_string_defaults); +} + +static const char* get_default_value_for_string_eattr(const char *attrname) { + return get_default_value_for_string_attr(attrname, eattr_string_defaults); +} diff --git a/src/vendor/cigraph/src/io/pajek.c b/src/vendor/cigraph/src/io/pajek.c index d229a370020..0b59398d79f 100644 --- a/src/vendor/cigraph/src/io/pajek.c +++ b/src/vendor/cigraph/src/io/pajek.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -48,32 +47,6 @@ void igraph_pajek_yylex_destroy_wrapper (void *scanner ) { (void) igraph_pajek_yylex_destroy(scanner); } -static void pajek_destroy_attr_vector(igraph_vector_ptr_t *attrs) { - const igraph_integer_t attr_count = igraph_vector_ptr_size(attrs); - for (igraph_integer_t i = 0; i < attr_count; i++) { - igraph_attribute_record_t *rec = VECTOR(*attrs)[i]; - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *vec = (igraph_vector_t*) rec->value; - igraph_vector_destroy(vec); - IGRAPH_FREE(vec); - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - igraph_vector_bool_t *vec = (igraph_vector_bool_t*) rec->value; - igraph_vector_bool_destroy(vec); - IGRAPH_FREE(vec); - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *strvec = (igraph_strvector_t *)rec->value; - igraph_strvector_destroy(strvec); - IGRAPH_FREE(strvec); - } else { - /* Must never reach here */ - IGRAPH_FATAL("Unknown attribute type encountered."); - } - IGRAPH_FREE(rec->name); - IGRAPH_FREE(rec); - } - igraph_vector_ptr_destroy(attrs); -} - /** * \function igraph_read_graph_pajek * \brief Reads a file in Pajek format. @@ -135,11 +108,10 @@ static void pajek_destroy_attr_vector(igraph_vector_ptr_t *attrs) { * character is appended to it to avoid conflict. * * - * In addition the following vertex attributes might be added: \c id - * and \c name are added (with the same value) if there are vertex IDs in the - * file. \c id is deprecated in favour of \c name and will no longer be used - * by future versions of igraph. \c x and \c y, and potentially \c z are also - * added if there are vertex coordinates in the file. + * In addition the following vertex attributes might be added: \c name is added + * (with the same value) if there are vertex IDs in the file. + * \c x and \c y, and potentially \c z are also added if there are vertex + * coordinates in the file. * * * The \c weight edge attribute will be added if there are edge weights present. @@ -172,22 +144,22 @@ igraph_error_t igraph_read_graph_pajek(igraph_t *graph, FILE *instream) { igraph_vector_int_t edges; igraph_trie_t vattrnames; - igraph_vector_ptr_t vattrs; + igraph_attribute_record_list_t vattrs; igraph_trie_t eattrnames; - igraph_vector_ptr_t eattrs; - igraph_integer_t i, j; + igraph_attribute_record_list_t eattrs; + igraph_int_t i; igraph_i_pajek_parsedata_t context; igraph_bitset_t seen; /* used to mark already seen vertex IDs */ IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_TRIE_INIT_FINALLY(&vattrnames, 1); - IGRAPH_CHECK(igraph_vector_ptr_init(&vattrs, 0)); - IGRAPH_FINALLY(pajek_destroy_attr_vector, &vattrs); + IGRAPH_CHECK(igraph_attribute_record_list_init(&vattrs, 0)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &vattrs); IGRAPH_TRIE_INIT_FINALLY(&eattrnames, 1); - IGRAPH_CHECK(igraph_vector_ptr_init(&eattrs, 0)); - IGRAPH_FINALLY(pajek_destroy_attr_vector, &eattrs); + IGRAPH_CHECK(igraph_attribute_record_list_init(&eattrs, 0)); + IGRAPH_FINALLY(igraph_attribute_record_list_destroy, &eattrs); IGRAPH_BITSET_INIT_FINALLY(&seen, 0); @@ -243,33 +215,10 @@ igraph_error_t igraph_read_graph_pajek(igraph_t *graph, FILE *instream) { IGRAPH_FINALLY_CLEAN(2); /* Prepare attributes */ - const igraph_integer_t eattr_count = igraph_vector_ptr_size(&eattrs); + const igraph_int_t eattr_count = igraph_attribute_record_list_size(&eattrs); for (i = 0; i < eattr_count; i++) { - igraph_attribute_record_t *rec = VECTOR(eattrs)[i]; - if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) { - igraph_vector_t *vec = (igraph_vector_t*)rec->value; - igraph_integer_t origsize = igraph_vector_size(vec); - IGRAPH_CHECK(igraph_vector_resize(vec, context.actedge)); - for (j = origsize; j < context.actedge; j++) { - VECTOR(*vec)[j] = IGRAPH_NAN; - } - } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) { - /* Boolean attributes are not currently added by the parser. - * This section is here for future-proofing. */ - igraph_vector_bool_t *vec = (igraph_vector_bool_t*)rec->value; - igraph_integer_t origsize = igraph_vector_bool_size(vec); - IGRAPH_CHECK(igraph_vector_bool_resize(vec, context.actedge)); - for (j = origsize; j < context.actedge; j++) { - VECTOR(*vec)[j] = 0; - } - } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) { - igraph_strvector_t *strvec = (igraph_strvector_t*)rec->value; - /* strvector_resize() adds empty strings */ - IGRAPH_CHECK(igraph_strvector_resize(strvec, context.actedge)); - } else { - /* Must never reach here */ - IGRAPH_FATAL("Unknown attribute type encountered."); - } + igraph_attribute_record_t *rec = igraph_attribute_record_list_get_ptr(&eattrs, i); + IGRAPH_CHECK(igraph_attribute_record_resize(rec, context.actedge)); } /* Create graph */ @@ -279,9 +228,9 @@ igraph_error_t igraph_read_graph_pajek(igraph_t *graph, FILE *instream) { IGRAPH_CHECK(igraph_add_edges(graph, &edges, &eattrs)); igraph_vector_int_destroy(&edges); - pajek_destroy_attr_vector(&eattrs); + igraph_attribute_record_list_destroy(&eattrs); igraph_trie_destroy(&eattrnames); - pajek_destroy_attr_vector(&vattrs); + igraph_attribute_record_list_destroy(&vattrs); igraph_trie_destroy(&vattrnames); IGRAPH_FINALLY_CLEAN(6); /* +1 for 'graph' */ @@ -319,7 +268,7 @@ igraph_error_t igraph_read_graph_pajek(igraph_t *graph, FILE *instream) { /* Pajek encodes newlines as \n, and any unicode character can be encoded * in the form &#hhhh;. Therefore we encode quotation marks as " */ static igraph_error_t pajek_escape(const char* src, char** dest) { - igraph_integer_t destlen = 0; + igraph_int_t destlen = 0; igraph_bool_t need_escape = false; /* Determine whether the string contains characters to be escaped */ @@ -446,13 +395,13 @@ static igraph_error_t pajek_escape(const char* src, char** dest) { */ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_attribute_type_t vtypes[V_LAST], etypes[E_LAST]; igraph_bool_t write_vertex_attrs = false; /* Same order as the #define's */ - const char *vnames[] = { "id", "x", "y", "z", "shape", "xfact", "yfact", + const char *vnames[] = { "name", "x", "y", "z", "shape", "xfact", "yfact", "labeldist", "labeldegree2", "framewidth", "fontsize", "rotation", "radius", "diamondratio", "labeldegree", @@ -521,7 +470,7 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) igraph_bool_t bipartite = false; igraph_vector_int_t bip_index, bip_index2; igraph_vector_bool_t bvec; - igraph_integer_t notop = 0, nobottom = 0; + igraph_int_t notop = 0, nobottom = 0; IGRAPH_VECTOR_INIT_FINALLY(&numv, 1); IGRAPH_STRVECTOR_INIT_FINALLY(&strv, 1); @@ -534,7 +483,7 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) /* Check if graph is bipartite, i.e. whether it has a Boolean 'type' vertex attribute. */ if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX, "type")) { igraph_attribute_type_t type_type; - IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &type_type, IGRAPH_ATTRIBUTE_VERTEX, "type")); + IGRAPH_CHECK(igraph_i_attribute_get_type(graph, &type_type, IGRAPH_ATTRIBUTE_VERTEX, "type")); if (type_type == IGRAPH_ATTRIBUTE_BOOLEAN) { bipartite = true; write_vertex_attrs = true; /* Count top and bottom vertices, we go over them twice, @@ -542,7 +491,7 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) IGRAPH_VECTOR_INT_INIT_FINALLY(&bip_index, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&bip_index2, no_of_nodes); IGRAPH_VECTOR_BOOL_INIT_FINALLY(&bvec, 1); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { IGRAPH_CHECK(igraph_i_attribute_get_bool_vertex_attr(graph, "type", igraph_vss_1(i), &bvec)); if (VECTOR(bvec)[0]) { @@ -551,7 +500,7 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) nobottom++; } } - for (igraph_integer_t i = 0, bptr = 0, tptr = nobottom; i < no_of_nodes; i++) { + for (igraph_int_t i = 0, bptr = 0, tptr = nobottom; i < no_of_nodes; i++) { IGRAPH_CHECK(igraph_i_attribute_get_bool_vertex_attr(graph, "type", igraph_vss_1(i), &bvec)); if (VECTOR(bvec)[0]) { @@ -583,29 +532,29 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) /* Check the vertex attributes, and determine if we need to write them. */ memset(vtypes, 0, sizeof(vtypes[0])*V_LAST); - for (igraph_integer_t i = 0; i < V_LAST; i++) { + for (igraph_int_t i = 0; i < V_LAST; i++) { if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX, vnames[i])) { - IGRAPH_CHECK(igraph_i_attribute_gettype( + IGRAPH_CHECK(igraph_i_attribute_get_type( graph, &vtypes[i], IGRAPH_ATTRIBUTE_VERTEX, vnames[i])); write_vertex_attrs = true; } else { vtypes[i] = (igraph_attribute_type_t) -1; } } - for (igraph_integer_t i = 0; i < (igraph_integer_t) (sizeof(vnumnames) / sizeof(vnumnames[0])); i++) { + for (igraph_int_t i = 0; i < (igraph_int_t) (sizeof(vnumnames) / sizeof(vnumnames[0])); i++) { igraph_attribute_type_t type; if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX, vnumnames[i])) { - IGRAPH_CHECK(igraph_i_attribute_gettype( + IGRAPH_CHECK(igraph_i_attribute_get_type( graph, &type, IGRAPH_ATTRIBUTE_VERTEX, vnumnames[i])); if (type == IGRAPH_ATTRIBUTE_NUMERIC) { IGRAPH_CHECK(igraph_vector_int_push_back(&vx_numa, i)); } } } - for (igraph_integer_t i = 0; i < (igraph_integer_t) (sizeof(vstrnames) / sizeof(vstrnames[0])); i++) { + for (igraph_int_t i = 0; i < (igraph_int_t) (sizeof(vstrnames) / sizeof(vstrnames[0])); i++) { igraph_attribute_type_t type; if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX, vstrnames[i])) { - IGRAPH_CHECK(igraph_i_attribute_gettype( + IGRAPH_CHECK(igraph_i_attribute_get_type( graph, &type, IGRAPH_ATTRIBUTE_VERTEX, vstrnames[i])); if (type == IGRAPH_ATTRIBUTE_STRING) { IGRAPH_CHECK(igraph_vector_int_push_back(&vx_stra, i)); @@ -615,8 +564,8 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) /* Write vertices */ if (write_vertex_attrs) { - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t id = bipartite ? VECTOR(bip_index)[i] : i; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t id = bipartite ? VECTOR(bip_index)[i] : i; /* vertex ID */ fprintf(outstream, "%" IGRAPH_PRId, i + 1); @@ -667,8 +616,8 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) } /* numeric parameters */ - for (igraph_integer_t j = 0; j < igraph_vector_int_size(&vx_numa); j++) { - igraph_integer_t idx = VECTOR(vx_numa)[j]; + for (igraph_int_t j = 0; j < igraph_vector_int_size(&vx_numa); j++) { + igraph_int_t idx = VECTOR(vx_numa)[j]; IGRAPH_CHECK(igraph_i_attribute_get_numeric_vertex_attr( graph, vnumnames[idx], igraph_vss_1(id), &numv)); fprintf(outstream, " %s ", vnumnames2[idx]); @@ -676,8 +625,8 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) } /* string parameters */ - for (igraph_integer_t j = 0; j < igraph_vector_int_size(&vx_stra); j++) { - igraph_integer_t idx = VECTOR(vx_stra)[j]; + for (igraph_int_t j = 0; j < igraph_vector_int_size(&vx_stra); j++) { + igraph_int_t idx = VECTOR(vx_stra)[j]; IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr( graph, vstrnames[idx], igraph_vss_1(id), &strv)); s = igraph_strvector_get(&strv, 0); @@ -705,28 +654,28 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) /* Check edge attributes */ /* TODO: refactor and simplify since only "weight" is relevant */ - for (igraph_integer_t i = 0; i < E_LAST; i++) { + for (igraph_int_t i = 0; i < E_LAST; i++) { if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE, enames[i])) { - IGRAPH_CHECK(igraph_i_attribute_gettype( + IGRAPH_CHECK(igraph_i_attribute_get_type( graph, &etypes[i], IGRAPH_ATTRIBUTE_EDGE, enames[i])); } else { etypes[i] = (igraph_attribute_type_t) -1; } } - for (igraph_integer_t i = 0; i < (igraph_integer_t) (sizeof(enumnames) / sizeof(enumnames[0])); i++) { + for (igraph_int_t i = 0; i < (igraph_int_t) (sizeof(enumnames) / sizeof(enumnames[0])); i++) { igraph_attribute_type_t type; if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE, enumnames[i])) { - IGRAPH_CHECK(igraph_i_attribute_gettype( + IGRAPH_CHECK(igraph_i_attribute_get_type( graph, &type, IGRAPH_ATTRIBUTE_EDGE, enumnames[i])); if (type == IGRAPH_ATTRIBUTE_NUMERIC) { IGRAPH_CHECK(igraph_vector_int_push_back(&ex_numa, i)); } } } - for (igraph_integer_t i = 0; i < (igraph_integer_t) (sizeof(estrnames) / sizeof(estrnames[0])); i++) { + for (igraph_int_t i = 0; i < (igraph_int_t) (sizeof(estrnames) / sizeof(estrnames[0])); i++) { igraph_attribute_type_t type; if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE, estrnames[i])) { - IGRAPH_CHECK(igraph_i_attribute_gettype( + IGRAPH_CHECK(igraph_i_attribute_get_type( graph, &type, IGRAPH_ATTRIBUTE_EDGE, estrnames[i])); if (type == IGRAPH_ATTRIBUTE_STRING) { IGRAPH_CHECK(igraph_vector_int_push_back(&ex_stra, i)); @@ -734,9 +683,9 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) } } - for (igraph_integer_t i = 0; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit), i++) { - igraph_integer_t edge = IGRAPH_EIT_GET(eit); - igraph_integer_t from, to; + for (igraph_int_t i = 0; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit), i++) { + igraph_int_t edge = IGRAPH_EIT_GET(eit); + igraph_int_t from, to; igraph_edge(graph, edge, &from, &to); if (bipartite) { from = VECTOR(bip_index2)[from]; @@ -753,8 +702,8 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) } /* numeric parameters */ - for (igraph_integer_t j = 0; j < igraph_vector_int_size(&ex_numa); j++) { - igraph_integer_t idx = VECTOR(ex_numa)[j]; + for (igraph_int_t j = 0; j < igraph_vector_int_size(&ex_numa); j++) { + igraph_int_t idx = VECTOR(ex_numa)[j]; IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr( graph, enumnames[idx], igraph_ess_1(edge), &numv)); fprintf(outstream, " %s ", enumnames2[idx]); @@ -762,8 +711,8 @@ igraph_error_t igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) } /* string parameters */ - for (igraph_integer_t j = 0; j < igraph_vector_int_size(&ex_stra); j++) { - igraph_integer_t idx = VECTOR(ex_stra)[j]; + for (igraph_int_t j = 0; j < igraph_vector_int_size(&ex_stra); j++) { + igraph_int_t idx = VECTOR(ex_stra)[j]; IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr( graph, estrnames[idx], igraph_ess_1(edge), &strv)); s = igraph_strvector_get(&strv, 0); diff --git a/src/vendor/cigraph/src/io/parse_utils.c b/src/vendor/cigraph/src/io/parse_utils.c index 2b0e0d73da6..6be36aaab9a 100644 --- a/src/vendor/cigraph/src/io/parse_utils.c +++ b/src/vendor/cigraph/src/io/parse_utils.c @@ -49,7 +49,7 @@ void igraph_i_trim_whitespace(const char *str, size_t str_len, const char **res, * * An error is returned if the input is an empty string. */ -igraph_error_t igraph_i_parse_integer(const char *str, size_t length, igraph_integer_t *value) { +igraph_error_t igraph_i_parse_integer(const char *str, size_t length, igraph_int_t *value) { char buffer[128]; char *tmp, *end; char last_char; @@ -73,12 +73,12 @@ igraph_error_t igraph_i_parse_integer(const char *str, size_t length, igraph_int tmp[length]='\0'; /* To avoid having to choose the appropriate strto?() function based on - * the definition of igraph_integer_t, we first use a long long variable - * which should be at least as large as igraph_integer_t on any platform. */ + * the definition of igraph_int_t, we first use a long long variable + * which should be at least as large as igraph_int_t on any platform. */ errno = 0; val = strtoll(tmp, &end, 10); out_of_range = errno == ERANGE; - *value = (igraph_integer_t) val; + *value = (igraph_int_t) val; last_char = *end; if (*value != val) { out_of_range = true; @@ -178,7 +178,7 @@ igraph_error_t igraph_i_fskip_whitespace(FILE *file) { * This function assumes that the number is followed by whitespace or the end of the file. * If this is not the case, an error will be raised. */ -igraph_error_t igraph_i_fget_integer(FILE *file, igraph_integer_t *value) { +igraph_error_t igraph_i_fget_integer(FILE *file, igraph_int_t *value) { /* The value requiring the most characters on 64-bit is -2^63, i.e. "-9223372036854775808". * This is 20 characters long, plus one for the null terminator, requiring a buffer of * at least 21 characters. We use a slightly larger buffer to allow for leading zeros and @@ -296,8 +296,6 @@ struct igraph_safelocale_s { * \function igraph_enter_safelocale * \brief Temporarily set the C locale. * - * \experimental - * * igraph's foreign format readers and writers require a locale that uses a * decimal point instead of a decimal comma. This is a convenience function * that temporarily sets the C locale so that readers and writers would work @@ -354,8 +352,6 @@ igraph_error_t igraph_enter_safelocale(igraph_safelocale_t *loc) { * \function igraph_exit_safelocale * \brief Temporarily set the C locale. * - * \experimental - * * Restores a locale saved by \ref igraph_enter_safelocale() and deallocates * all associated data. This function \em must be paired with a call to * \ref igraph_enter_safelocale(). diff --git a/src/vendor/cigraph/src/io/parse_utils.h b/src/vendor/cigraph/src/io/parse_utils.h index 49a23d03a2a..b94a3b13d63 100644 --- a/src/vendor/cigraph/src/io/parse_utils.h +++ b/src/vendor/cigraph/src/io/parse_utils.h @@ -32,10 +32,10 @@ void igraph_i_trim_whitespace(const char *str, size_t str_len, const char **res, igraph_error_t igraph_i_fskip_whitespace(FILE *file); -igraph_error_t igraph_i_parse_integer(const char *str, size_t length, igraph_integer_t *value); +igraph_error_t igraph_i_parse_integer(const char *str, size_t length, igraph_int_t *value); igraph_error_t igraph_i_parse_real(const char *str, size_t length, igraph_real_t *value); -igraph_error_t igraph_i_fget_integer(FILE *file, igraph_integer_t *value); +igraph_error_t igraph_i_fget_integer(FILE *file, igraph_int_t *value); igraph_error_t igraph_i_fget_real(FILE *file, igraph_real_t *value); #endif /* IGRAPH_PARSE_UTILS_H */ diff --git a/src/vendor/cigraph/src/isomorphism/bliss.cc b/src/vendor/cigraph/src/isomorphism/bliss.cc index fedc3c3c421..d4c66f56dcf 100644 --- a/src/vendor/cigraph/src/isomorphism/bliss.cc +++ b/src/vendor/cigraph/src/isomorphism/bliss.cc @@ -19,7 +19,7 @@ #include "bliss/graph.hh" -#include "igraph_topology.h" +#include "igraph_isomorphism.h" #include "igraph_conversion.h" #include "igraph_interface.h" #include "igraph_interrupt.h" @@ -29,6 +29,7 @@ #include "core/exceptions.h" #include +#include #include using namespace bliss; @@ -76,8 +77,8 @@ using namespace std; namespace { // unnamed namespace inline AbstractGraph *bliss_from_igraph(const igraph_t *graph) { - igraph_integer_t nof_vertices = igraph_vcount(graph); - igraph_integer_t nof_edges = igraph_ecount(graph); + igraph_int_t nof_vertices = igraph_vcount(graph); + igraph_int_t nof_edges = igraph_ecount(graph); if (nof_vertices > UINT_MAX || nof_edges > UINT_MAX) { throw std::runtime_error("Graph too large for BLISS"); @@ -148,7 +149,7 @@ inline igraph_error_t bliss_set_colors(AbstractGraph *g, const igraph_vector_int IGRAPH_ERROR("Invalid vertex color vector length.", IGRAPH_EINVAL); } for (int i = 0; i < n; ++i) { - igraph_integer_t color = VECTOR(*colors)[i]; + igraph_int_t color = VECTOR(*colors)[i]; if (color < INT_MIN || color > INT_MAX) { IGRAPH_ERRORF("Invalid vertex color index %" IGRAPH_PRId " for vertex %d.", IGRAPH_EOVERFLOW, color, i); } @@ -191,7 +192,7 @@ struct AbortChecker { AbortChecker() : aborted(false) { } bool operator()() { - if (igraph_allow_interruption(NULL) != IGRAPH_SUCCESS) { + if (igraph_allow_interruption() != IGRAPH_SUCCESS) { aborted = true; return true; } @@ -217,7 +218,7 @@ class AutCollector { throw bad_alloc(); } - copy(aut, aut + n, VECTOR(newvector)); // takes care of unsigned int -> igraph_integer_t conversion + copy(aut, aut + n, VECTOR(newvector)); // takes care of unsigned int -> igraph_int_t conversion err = igraph_vector_int_list_push_back(generators, &newvector); if (err != IGRAPH_SUCCESS) { @@ -231,6 +232,49 @@ class AutCollector { /** * \function igraph_canonical_permutation + * \brief Canonical permutation of a graph. + * + * This function computes the vertex permutation which transforms + * the graph into a canonical form. Two graphs have the same canonical form if + * and only if they are isomorphic. Use \ref igraph_is_same_graph() to compare + * two canonical forms. + * + * + * The current implementation uses the BLISS isomorphism algorithms with + * sensible defaults. Use \ref igraph_canonical_permutation_bliss() to fine-tune + * the parameters. + * + * \param graph The input graph. Multiple edges between the same nodes + * are not supported and will cause an incorrect result to be returned. + * \param colors An optional vertex color vector for the graph. Supply a + * null pointer is the graph is not colored. + * \param labeling Pointer to a vector, the result is stored here. The + * permutation takes vertex 0 to the first element of the vector, + * vertex 1 to the second, etc. The vector will be resized as + * needed. + * \return Error code. + * + * \sa \ref igraph_is_same_graph() + * + * Time complexity: exponential, in practice it is fast for many graphs. + */ +igraph_error_t igraph_canonical_permutation( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_vector_int_t *labeling +) { + return igraph_canonical_permutation_bliss( + graph, colors, labeling, IGRAPH_BLISS_FL, NULL + ); +} + +static igraph_error_t igraph_i_canonical_permutation_bliss( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_vector_int_t *labeling, igraph_bliss_sh_t sh, + igraph_bliss_info_t *info +); + +/** + * \function igraph_canonical_permutation_bliss * \brief Canonical permutation using Bliss. * * This function computes the vertex permutation which transforms @@ -258,8 +302,27 @@ class AutCollector { * * Time complexity: exponential, in practice it is fast for many graphs. */ -igraph_error_t igraph_canonical_permutation(const igraph_t *graph, const igraph_vector_int_t *colors, - igraph_vector_int_t *labeling, igraph_bliss_sh_t sh, igraph_bliss_info_t *info) { +igraph_error_t igraph_canonical_permutation_bliss( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_vector_int_t *labeling, igraph_bliss_sh_t sh, + igraph_bliss_info_t *info +) { + igraph_vector_int_t inv_permutation; + + IGRAPH_VECTOR_INT_INIT_FINALLY(&inv_permutation, igraph_vcount(graph)); + IGRAPH_CHECK(igraph_i_canonical_permutation_bliss(graph, colors, &inv_permutation, sh, info)); + IGRAPH_CHECK(igraph_invert_permutation(&inv_permutation, labeling)); + igraph_vector_int_destroy(&inv_permutation); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} + +static igraph_error_t igraph_i_canonical_permutation_bliss( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_vector_int_t *labeling, igraph_bliss_sh_t sh, + igraph_bliss_info_t *info +) { IGRAPH_HANDLE_EXCEPTIONS( AbstractGraph *g = bliss_from_igraph(graph); IGRAPH_FINALLY(bliss_free_graph, g); @@ -290,18 +353,53 @@ igraph_error_t igraph_canonical_permutation(const igraph_t *graph, const igraph_ } /** - * \function igraph_automorphisms - * \brief Number of automorphisms using Bliss (deprecated alias). + * \function igraph_count_automorphisms + * \brief Number of automorphisms of a graph. * - * \deprecated-by igraph_count_automorphisms 0.10.5 + * This function computes the number of automorphisms of a graph. Since the + * number of automorphisms may be very large, the result is returned as an + * \c igraph_real_t instead of an integer. If the number of automorphisms + * is larger than what can be represented in an \c igraph_real_t and you need + * the exact number, use \ref igraph_count_automorphisms_bliss(), which can + * return the number as a string. + * + * \param graph The input graph. Multiple edges between the same nodes + * are not supported and will cause an incorrect result to be returned. + * \param colors An optional vertex color vector for the graph. Supply a + * null pointer is the graph is not colored. + * \param result Pointer to an \c igraph_real_t, the number of automorphisms + * will be returned here. + * \return Error code. \c IGRAPH_EOVERFLOW if the number of automorphisms is + * too large to be represented in an \c igraph_real_t . + * + * Time complexity: exponential, in practice it is fast for many graphs. */ -igraph_error_t igraph_automorphisms(const igraph_t *graph, const igraph_vector_int_t *colors, - igraph_bliss_sh_t sh, igraph_bliss_info_t *info) { - return igraph_count_automorphisms(graph, colors, sh, info); +igraph_error_t igraph_count_automorphisms( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_real_t *result +) { + igraph_bliss_info_t info; + double x; + + IGRAPH_CHECK(igraph_count_automorphisms_bliss(graph, colors, IGRAPH_BLISS_FL, &info)); + + x = strtod(info.group_size, NULL); + igraph_free(info.group_size); + + if (x == 0) { + return IGRAPH_FAILURE; + } else if (x == HUGE_VAL) { + return IGRAPH_EOVERFLOW; + } else { + if (result) { + *result = x; + } + return IGRAPH_SUCCESS; + } } /** - * \function igraph_count_automorphisms + * \function igraph_count_automorphisms_bliss * \brief Number of automorphisms using Bliss. * * The number of automorphisms of a graph is computed using Bliss. The @@ -322,8 +420,10 @@ igraph_error_t igraph_automorphisms(const igraph_t *graph, const igraph_vector_i * * Time complexity: exponential, in practice it is fast for many graphs. */ -igraph_error_t igraph_count_automorphisms(const igraph_t *graph, const igraph_vector_int_t *colors, - igraph_bliss_sh_t sh, igraph_bliss_info_t *info) { +igraph_error_t igraph_count_automorphisms_bliss( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_bliss_sh_t sh, igraph_bliss_info_t *info +) { IGRAPH_HANDLE_EXCEPTIONS( AbstractGraph *g = bliss_from_igraph(graph); IGRAPH_FINALLY(bliss_free_graph, g); @@ -349,6 +449,39 @@ igraph_error_t igraph_count_automorphisms(const igraph_t *graph, const igraph_ve /** * \function igraph_automorphism_group + * \brief Automorphism group generators of a graph. + * + * This function computes the generators of the automorphism group of a graph. + * The generator set may not be minimal and may depend on the specific parameters + * of the algorithm under the hood. The generators are permutations represented + * using zero-based indexing. + * + * + * The current implementation uses BLISS behind the scenes and the result may + * be dependent on the splitting heuristics. Use \ref igraph_automorphism_group_bliss() + * if you want to fine-tune the splitting heuristics. + * + * \param graph The input graph. Multiple edges between the same nodes + * are not supported and will cause an incorrect result to be returned. + * \param colors An optional vertex color vector for the graph. Supply a + * null pointer is the graph is not colored. + * \param generators Must be an initialized interger vector list. + * The generators of the automorphism group will be stored here. + * \return Error code. + * + * Time complexity: exponential, in practice it is fast for many graphs. + */ +igraph_error_t igraph_automorphism_group( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_vector_int_list_t *generators +) { + return igraph_automorphism_group_bliss( + graph, colors, generators, IGRAPH_BLISS_FL, NULL + ); +} + +/** + * \function igraph_automorphism_group_bliss * \brief Automorphism group generators using Bliss. * * The generators of the automorphism group of a graph are computed @@ -371,9 +504,11 @@ igraph_error_t igraph_count_automorphisms(const igraph_t *graph, const igraph_ve * * Time complexity: exponential, in practice it is fast for many graphs. */ -igraph_error_t igraph_automorphism_group( - const igraph_t *graph, const igraph_vector_int_t *colors, igraph_vector_int_list_t *generators, - igraph_bliss_sh_t sh, igraph_bliss_info_t *info) { +igraph_error_t igraph_automorphism_group_bliss( + const igraph_t *graph, const igraph_vector_int_t *colors, + igraph_vector_int_list_t *generators, igraph_bliss_sh_t sh, + igraph_bliss_info_t *info +) { IGRAPH_HANDLE_EXCEPTIONS( AbstractGraph *g = bliss_from_igraph(graph); IGRAPH_FINALLY(bliss_free_graph, g); @@ -402,7 +537,7 @@ igraph_error_t igraph_automorphism_group( /* The following license notice applies to the rest of this file */ /* - IGraph library. + igraph library. Copyright (C) 2006-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -431,7 +566,7 @@ igraph_error_t igraph_automorphism_group( * * * Isomorphism testing is implemented by producing the canonical form - * of both graphs using \ref igraph_canonical_permutation() and + * of both graphs using \ref igraph_canonical_permutation_bliss() and * comparing them. * * \param graph1 The first input graph. Multiple edges between the same nodes @@ -468,14 +603,14 @@ igraph_error_t igraph_isomorphic_bliss(const igraph_t *graph1, const igraph_t *g igraph_vector_int_t *map21, igraph_bliss_sh_t sh, igraph_bliss_info_t *info1, igraph_bliss_info_t *info2) { - igraph_integer_t no_of_nodes = igraph_vcount(graph1); - igraph_integer_t no_of_edges = igraph_ecount(graph1); + igraph_int_t no_of_nodes = igraph_vcount(graph1); + igraph_int_t no_of_edges = igraph_ecount(graph1); igraph_vector_int_t perm1, perm2; igraph_vector_int_t vmap12, *mymap12 = &vmap12; igraph_vector_int_t from, to, index; igraph_vector_int_t from2, to2, index2; igraph_bool_t directed; - igraph_integer_t i, j; + igraph_int_t i, j; *iso = 0; if (info1) { @@ -519,8 +654,8 @@ igraph_error_t igraph_isomorphic_bliss(const igraph_t *graph1, const igraph_t *g IGRAPH_VECTOR_INT_INIT_FINALLY(&perm1, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&perm2, no_of_nodes); - IGRAPH_CHECK(igraph_canonical_permutation(graph1, colors1, &perm1, sh, info1)); - IGRAPH_CHECK(igraph_canonical_permutation(graph2, colors2, &perm2, sh, info2)); + IGRAPH_CHECK(igraph_i_canonical_permutation_bliss(graph1, colors1, &perm1, sh, info1)); + IGRAPH_CHECK(igraph_i_canonical_permutation_bliss(graph2, colors2, &perm2, sh, info2)); IGRAPH_CHECK(igraph_vector_int_resize(mymap12, no_of_nodes)); @@ -553,7 +688,7 @@ igraph_error_t igraph_isomorphic_bliss(const igraph_t *graph1, const igraph_t *g VECTOR(from)[i] = VECTOR(*mymap12)[ IGRAPH_FROM(graph1, i) ]; VECTOR(to)[i] = VECTOR(*mymap12)[ IGRAPH_TO (graph1, i) ]; if (! directed && VECTOR(from)[i] < VECTOR(to)[i]) { - igraph_integer_t tmp = VECTOR(from)[i]; + igraph_int_t tmp = VECTOR(from)[i]; VECTOR(from)[i] = VECTOR(to)[i]; VECTOR(to)[i] = tmp; } @@ -564,7 +699,7 @@ igraph_error_t igraph_isomorphic_bliss(const igraph_t *graph1, const igraph_t *g for (i = 0, j = no_of_edges; i < no_of_edges; i++, j++) { VECTOR(to2)[i] = VECTOR(from2)[j]; if (! directed && VECTOR(from2)[i] < VECTOR(to2)[i]) { - igraph_integer_t tmp = VECTOR(from2)[i]; + igraph_int_t tmp = VECTOR(from2)[i]; VECTOR(from2)[i] = VECTOR(to2)[i]; VECTOR(to2)[i] = tmp; } @@ -574,8 +709,8 @@ igraph_error_t igraph_isomorphic_bliss(const igraph_t *graph1, const igraph_t *g *iso = 1; for (i = 0; i < no_of_edges; i++) { - igraph_integer_t i1 = VECTOR(index)[i]; - igraph_integer_t i2 = VECTOR(index2)[i]; + igraph_int_t i1 = VECTOR(index)[i]; + igraph_int_t i2 = VECTOR(index2)[i]; if (VECTOR(from)[i1] != VECTOR(from2)[i2] || VECTOR(to)[i1] != VECTOR(to2)[i2]) { *iso = 0; diff --git a/src/vendor/cigraph/src/isomorphism/isoclasses.c b/src/vendor/cigraph/src/isomorphism/isoclasses.c index a15db7b20c3..a3259539b5f 100644 --- a/src/vendor/cigraph/src/isomorphism/isoclasses.c +++ b/src/vendor/cigraph/src/isomorphism/isoclasses.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -19,7 +18,7 @@ 02110-1301 USA */ -#include "igraph_topology.h" +#include "igraph_isomorphism.h" #include "igraph_constructors.h" #include "igraph_interface.h" @@ -2548,10 +2547,10 @@ const unsigned int igraph_i_classedges_6u[] = { 4, 5, 3, 5, 2, 5, 1, 5, 0, 5, 3, * * Time complexity: O(|E|), the number of edges in the graph. */ -igraph_error_t igraph_isoclass(const igraph_t *graph, igraph_integer_t *isoclass) { - igraph_integer_t e; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); +igraph_error_t igraph_isoclass(const igraph_t *graph, igraph_int_t *isoclass) { + igraph_int_t e; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); unsigned int idx, mul; const unsigned int *arr_idx, *arr_code; unsigned int code; @@ -2606,7 +2605,7 @@ igraph_error_t igraph_isoclass(const igraph_t *graph, igraph_integer_t *isoclass code |= arr_idx[idx]; } - *isoclass = (igraph_integer_t) arr_code[code]; + *isoclass = (igraph_int_t) arr_code[code]; return IGRAPH_SUCCESS; } @@ -2626,8 +2625,7 @@ igraph_error_t igraph_isoclass(const igraph_t *graph, igraph_integer_t *isoclass * Multi-edges and self-loops are ignored by this function. * * \param graph The graph object. - * \param vids A vector containing the vertex IDs to be considered as - * a subgraph. Each vertex ID should be included at most once. + * \param vids The vertices of the subgraph. Each vertex must be included at most once. * \param isoclass Pointer to an integer, this will be set to the * isomorphism class. * \return Error code. @@ -2637,16 +2635,18 @@ igraph_error_t igraph_isoclass(const igraph_t *graph, igraph_integer_t *isoclass * Time complexity: O((d+n)*n), d is the average degree in the network, * and n is the number of vertices in \c vids. */ -igraph_error_t igraph_isoclass_subgraph(const igraph_t *graph, const igraph_vector_int_t *vids, - igraph_integer_t *isoclass) { - igraph_integer_t subgraph_size = igraph_vector_int_size(vids); - igraph_vector_int_t neis; +igraph_error_t igraph_isoclass_subgraph(const igraph_t *graph, igraph_vs_t vids, + igraph_int_t *isoclass) { + igraph_int_t subgraph_size; + igraph_vector_int_t vertices, neis; unsigned int mul, idx; const unsigned int *arr_idx, *arr_code; unsigned int code = 0; - igraph_integer_t i, j, s; + IGRAPH_VECTOR_INT_INIT_FINALLY(&vertices, 0); + IGRAPH_CHECK(igraph_vs_as_vector(graph, vids, &vertices)); + subgraph_size = igraph_vector_int_size(&vertices); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); @@ -2694,13 +2694,15 @@ igraph_error_t igraph_isoclass_subgraph(const igraph_t *graph, const igraph_vect } } - for (i = 0; i < subgraph_size; i++) { - igraph_integer_t from = VECTOR(*vids)[i]; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, from, IGRAPH_OUT)); - s = igraph_vector_int_size(&neis); - for (j = 0; j < s; j++) { - igraph_integer_t nei = VECTOR(neis)[j], to; - if (igraph_vector_int_search(vids, 0, nei, &to)) { + for (igraph_int_t i = 0; i < subgraph_size; i++) { + igraph_int_t from = VECTOR(vertices)[i]; + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, from, IGRAPH_OUT, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); + const igraph_int_t s = igraph_vector_int_size(&neis); + for (igraph_int_t j = 0; j < s; j++) { + igraph_int_t nei = VECTOR(neis)[j], to; + if (igraph_vector_int_search(&vertices, 0, nei, &to)) { idx = (mul * i + to); code |= arr_idx[idx]; } @@ -2709,7 +2711,8 @@ igraph_error_t igraph_isoclass_subgraph(const igraph_t *graph, const igraph_vect *isoclass = arr_code[code]; igraph_vector_int_destroy(&neis); - IGRAPH_FINALLY_CLEAN(1); + igraph_vector_int_destroy(&vertices); + IGRAPH_FINALLY_CLEAN(2); return IGRAPH_SUCCESS; } @@ -2746,12 +2749,12 @@ igraph_error_t igraph_isoclass_subgraph(const igraph_t *graph, const igraph_vect * Time complexity: O(|V|+|E|), the number of vertices plus the number * of edges in the graph to create. */ -igraph_error_t igraph_isoclass_create(igraph_t *graph, igraph_integer_t size, - igraph_integer_t number, igraph_bool_t directed) { +igraph_error_t igraph_isoclass_create(igraph_t *graph, igraph_int_t size, + igraph_int_t number, igraph_bool_t directed) { igraph_vector_int_t edges; const unsigned int *classedges; - igraph_integer_t graphcount; - igraph_integer_t pos; + igraph_int_t graphcount; + igraph_int_t pos; unsigned int power; unsigned int code; @@ -2877,7 +2880,7 @@ igraph_error_t igraph_isoclass_create(igraph_t *graph, igraph_integer_t size, } /* https://oeis.org/A000088 */ -static igraph_integer_t undirected_graph_counts[] = { +static igraph_int_t undirected_graph_counts[] = { 1, 1, 2, 4, 11, 34, 156, 1044, 12346, 274668, 12005168, 1018997864, #if IGRAPH_INTEGER_SIZE == 64 165091172592, 50502031367952, 29054155657235488 @@ -2885,7 +2888,7 @@ static igraph_integer_t undirected_graph_counts[] = { }; /* https://oeis.org/A000273 */ -static igraph_integer_t directed_graph_counts[] = { +static igraph_int_t directed_graph_counts[] = { 1, 1, 3, 16, 218, 9608, 1540944, 882033440, #if IGRAPH_INTEGER_SIZE == 64 1793359192848, 13027956824399552 @@ -2902,7 +2905,7 @@ static igraph_integer_t directed_graph_counts[] = { * * This function is meant to be used in conjunction with isoclass and motif finder * functions. It will only work for small \p n values for which the result is - * represetable in an \type igraph_integer_t. For larger \p n values, an overflow + * represetable in an \type igraph_int_t. For larger \p n values, an overflow * error is raised. * * \param n The number of vertices. @@ -2914,17 +2917,17 @@ static igraph_integer_t directed_graph_counts[] = { * * Time complexity: O(1). */ -igraph_error_t igraph_graph_count(igraph_integer_t n, igraph_bool_t directed, igraph_integer_t *count) { +igraph_error_t igraph_graph_count(igraph_int_t n, igraph_bool_t directed, igraph_int_t *count) { if (n < 0) { IGRAPH_ERROR("Graph size must not be negative.", IGRAPH_EINVAL); } if (directed) { - if (n >= (igraph_integer_t) (sizeof directed_graph_counts / sizeof directed_graph_counts[0])) { + if (n >= (igraph_int_t) (sizeof directed_graph_counts / sizeof directed_graph_counts[0])) { IGRAPH_ERRORF("Graph size of % " IGRAPH_PRId " too large.", IGRAPH_EOVERFLOW, n); } *count = directed_graph_counts[n]; } else { - if (n >= (igraph_integer_t) (sizeof undirected_graph_counts / sizeof undirected_graph_counts[0])) { + if (n >= (igraph_int_t) (sizeof undirected_graph_counts / sizeof undirected_graph_counts[0])) { IGRAPH_ERRORF("Graph size of % " IGRAPH_PRId " too large.", IGRAPH_EOVERFLOW, n); } *count = undirected_graph_counts[n]; diff --git a/src/vendor/cigraph/src/isomorphism/isoclasses.h b/src/vendor/cigraph/src/isomorphism/isoclasses.h index 67fa9a2b06c..9d543b6d1a7 100644 --- a/src/vendor/cigraph/src/isomorphism/isoclasses.h +++ b/src/vendor/cigraph/src/isomorphism/isoclasses.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2008-2020 The igraph development team 334 Harvard street, Cambridge, MA 02139 USA @@ -26,7 +25,7 @@ #include "igraph_decls.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS extern const unsigned int igraph_i_isoclass2_3[]; extern const unsigned int igraph_i_isoclass2_4[]; @@ -41,6 +40,6 @@ extern const unsigned int igraph_i_isoclass_4u_idx[]; extern const unsigned int igraph_i_isoclass_5u_idx[]; extern const unsigned int igraph_i_isoclass_6u_idx[]; -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/isomorphism/isomorphism_misc.c b/src/vendor/cigraph/src/isomorphism/isomorphism_misc.c index 2b8ff8e693c..7133e81a9c0 100644 --- a/src/vendor/cigraph/src/isomorphism/isomorphism_misc.c +++ b/src/vendor/cigraph/src/isomorphism/isomorphism_misc.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -21,7 +20,7 @@ */ -#include "igraph_topology.h" +#include "igraph_isomorphism.h" #include "igraph_constructors.h" #include "igraph_interface.h" @@ -58,10 +57,10 @@ igraph_error_t igraph_simplify_and_colorize( igraph_es_t es; igraph_eit_t eit; igraph_vector_int_t edges; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t pto = -1, pfrom = -1; - igraph_integer_t i; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t pto = -1, pfrom = -1; + igraph_int_t i; IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_FROM)); IGRAPH_FINALLY(igraph_es_destroy, &es); @@ -79,9 +78,9 @@ igraph_error_t igraph_simplify_and_colorize( i = -1; for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t edge = IGRAPH_EIT_GET(eit); - igraph_integer_t from = IGRAPH_FROM(graph, edge); - igraph_integer_t to = IGRAPH_TO(graph, edge); + igraph_int_t edge = IGRAPH_EIT_GET(eit); + igraph_int_t from = IGRAPH_FROM(graph, edge); + igraph_int_t to = IGRAPH_TO(graph, edge); if (to == from) { VECTOR(*vertex_color)[to]++; diff --git a/src/vendor/cigraph/src/isomorphism/lad.c b/src/vendor/cigraph/src/isomorphism/lad.c index 689c3260c9f..3c2cc4009a2 100644 --- a/src/vendor/cigraph/src/isomorphism/lad.c +++ b/src/vendor/cigraph/src/isomorphism/lad.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -46,7 +45,7 @@ -- Tamas Nepusz, 11 July 2013 */ -#include "igraph_topology.h" +#include "igraph_isomorphism.h" #include "igraph_adjlist.h" #include "igraph_bitset.h" @@ -90,15 +89,15 @@ #define SETEDGE(G, i, j) IGRAPH_BIT_SET(G->isEdge, i * G->nbVertices + j) typedef struct { - igraph_integer_t nbVertices; /* Number of vertices */ + igraph_int_t nbVertices; /* Number of vertices */ igraph_vector_int_t nbSucc; igraph_adjlist_t succ; igraph_bitset_t isEdge; } Tgraph; static igraph_error_t igraph_i_lad_createGraph(const igraph_t *igraph, Tgraph* graph) { - igraph_integer_t i, j, n; - igraph_integer_t no_of_nodes = igraph_vcount(igraph); + igraph_int_t i, j, n; + igraph_int_t no_of_nodes = igraph_vcount(igraph); igraph_vector_int_t *neis; graph->nbVertices = no_of_nodes; @@ -117,7 +116,7 @@ static igraph_error_t igraph_i_lad_createGraph(const igraph_t *igraph, Tgraph* g neis = igraph_adjlist_get(&graph->succ, i); n = igraph_vector_int_size(neis); for (j = 0; j < n; j++) { - igraph_integer_t v = VECTOR(*neis)[j]; + igraph_int_t v = VECTOR(*neis)[j]; if (ISEDGE(graph, i, v)) { IGRAPH_ERROR("LAD functions do not support graphs with multi-edges.", IGRAPH_EINVAL); } @@ -151,17 +150,17 @@ typedef struct { /* If v in D[u] then firstVal[u] <= posInVal[u][v] < firstVal[u]+nbVal[u] and val[posInVal[u][v]] = v otherwise posInVal[u][v] >= firstVal[u]+nbVal[u] */ - igraph_integer_t valSize; /* size of val */ + igraph_int_t valSize; /* size of val */ igraph_matrix_int_t firstMatch; /* firstMatch[u][v] = pos in match of the first vertex of the covering matching of G_(u, v) */ igraph_vector_int_t matching; /* matching[firstMatch[u][v]..firstMatch[u][v]+nbSucc[u]-1] = covering matching of G_(u, v) */ - igraph_integer_t nextOutToFilter; /* position in toFilter of the next pattern node whose + igraph_int_t nextOutToFilter; /* position in toFilter of the next pattern node whose domain should be filtered (-1 if no domain to filter) */ - igraph_integer_t lastInToFilter; /* position in toFilter of the last pattern node whose + igraph_int_t lastInToFilter; /* position in toFilter of the last pattern node whose domain should be filtered */ igraph_vector_int_t toFilter; /* contain all pattern nodes whose domain should be filtered */ @@ -186,11 +185,11 @@ static void igraph_i_lad_resetToFilter(Tdomain *D) { } -static igraph_integer_t igraph_i_lad_nextToFilter(Tdomain* D, igraph_integer_t size) { +static igraph_int_t igraph_i_lad_nextToFilter(Tdomain* D, igraph_int_t size) { /* precondition: emptyToFilter = false remove a node from toFilter (FIFO) unmark this node and return it */ - igraph_integer_t u = VECTOR(D->toFilter)[D->nextOutToFilter]; + igraph_int_t u = VECTOR(D->toFilter)[D->nextOutToFilter]; IGRAPH_BIT_CLEAR(D->markedToFilter, u); if (D->nextOutToFilter == D->lastInToFilter) { /* u was the last node in tofilter */ @@ -203,7 +202,7 @@ static igraph_integer_t igraph_i_lad_nextToFilter(Tdomain* D, igraph_integer_t s return u; } -static void igraph_i_lad_addToFilter(igraph_integer_t u, Tdomain* D, igraph_integer_t size) { +static void igraph_i_lad_addToFilter(igraph_int_t u, Tdomain* D, igraph_int_t size) { /* if u is not marked, then add it to toFilter and mark it */ if (IGRAPH_BIT_TEST(D->markedToFilter, u)) { return; @@ -220,29 +219,29 @@ static void igraph_i_lad_addToFilter(igraph_integer_t u, Tdomain* D, igraph_inte VECTOR(D->toFilter)[D->lastInToFilter] = u; } -static bool igraph_i_lad_isInD(igraph_integer_t u, igraph_integer_t v, Tdomain* D) { +static bool igraph_i_lad_isInD(igraph_int_t u, igraph_int_t v, Tdomain* D) { /* returns true if v belongs to D(u); false otherwise */ return (MATRIX(D->posInVal, u, v) < VECTOR(D->firstVal)[u] + VECTOR(D->nbVal)[u]); } -static igraph_error_t igraph_i_lad_augmentingPath(igraph_integer_t u, Tdomain* D, igraph_integer_t nbV, bool* result) { +static igraph_error_t igraph_i_lad_augmentingPath(igraph_int_t u, Tdomain* D, igraph_int_t nbV, bool* result) { /* return true if there exists an augmenting path starting from u and ending on a free vertex v in the bipartite directed graph G=(U, V, E) such that U=pattern nodes, V=target nodes, and E={(u, v), v in D(u)} U {(v, u), D->globalMatchingP[u]=v} update D-globalMatchingP and D->globalMatchingT consequently */ - igraph_integer_t *fifo, *pred; + igraph_int_t *fifo, *pred; igraph_bitset_t marked; - igraph_integer_t nextIn = 0; - igraph_integer_t nextOut = 0; - igraph_integer_t i, v, v2, u2; + igraph_int_t nextIn = 0; + igraph_int_t nextOut = 0; + igraph_int_t i, v, v2, u2; *result = false; /* Allocate memory */ - ALLOC_ARRAY(fifo, nbV, igraph_integer_t); - ALLOC_ARRAY(pred, nbV, igraph_integer_t); + ALLOC_ARRAY(fifo, nbV, igraph_int_t); + ALLOC_ARRAY(pred, nbV, igraph_int_t); IGRAPH_BITSET_INIT_FINALLY(&marked, nbV); for (i = 0; i < VECTOR(D->nbVal)[u]; i++) { @@ -294,14 +293,14 @@ static igraph_error_t igraph_i_lad_augmentingPath(igraph_integer_t u, Tdomain* D return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_lad_removeAllValuesButOne(igraph_integer_t u, igraph_integer_t v, Tdomain* D, Tgraph* Gp, +static igraph_error_t igraph_i_lad_removeAllValuesButOne(igraph_int_t u, igraph_int_t v, Tdomain* D, Tgraph* Gp, Tgraph* Gt, bool* result) { /* remove all values but v from D(u) and add all successors of u in toFilter return false if an inconsistency is detected wrt to global all diff */ - igraph_integer_t j, oldPos, newPos; + igraph_int_t j, oldPos, newPos; igraph_vector_int_t *uneis = igraph_adjlist_get(&Gp->succ, u); - igraph_integer_t n = igraph_vector_int_size(uneis); + igraph_int_t n = igraph_vector_int_size(uneis); /* add all successors of u in toFilter */ for (j = 0; j < n; j++) { igraph_i_lad_addToFilter(VECTOR(*uneis)[j], D, @@ -328,14 +327,14 @@ static igraph_error_t igraph_i_lad_removeAllValuesButOne(igraph_integer_t u, igr } -static igraph_error_t igraph_i_lad_removeValue(igraph_integer_t u, igraph_integer_t v, Tdomain* D, Tgraph* Gp, +static igraph_error_t igraph_i_lad_removeValue(igraph_int_t u, igraph_int_t v, Tdomain* D, Tgraph* Gp, Tgraph* Gt, bool* result) { /* remove v from D(u) and add all successors of u in toFilter return false if an inconsistency is detected wrt global all diff */ - igraph_integer_t j; + igraph_int_t j; igraph_vector_int_t *uneis = igraph_adjlist_get(&Gp->succ, u); - igraph_integer_t n = igraph_vector_int_size(uneis); - igraph_integer_t oldPos, newPos; + igraph_int_t n = igraph_vector_int_size(uneis); + igraph_int_t oldPos, newPos; /* add all successors of u in toFilter */ for (j = 0; j < n; j++) { @@ -363,7 +362,7 @@ static igraph_error_t igraph_i_lad_removeValue(igraph_integer_t u, igraph_intege } -static igraph_error_t igraph_i_lad_matchVertices(igraph_integer_t nb, igraph_vector_int_t* toBeMatched, +static igraph_error_t igraph_i_lad_matchVertices(igraph_int_t nb, igraph_vector_int_t* toBeMatched, bool induced, Tdomain* D, Tgraph* Gp, Tgraph* Gt, igraph_bool_t *invalid) { /* for each u in toBeMatched[0..nb-1], match u to @@ -373,7 +372,7 @@ static igraph_error_t igraph_i_lad_matchVertices(igraph_integer_t nb, igraph_vec FC(diff), but this speeds up the solution process). return false if an inconsistency is detected by FC(Edges) or FC(diff); true otherwise; */ - igraph_integer_t j, u, v, u2, oldNbVal; + igraph_int_t j, u, v, u2, oldNbVal; igraph_vector_int_t *vneis; bool result = false; @@ -448,7 +447,7 @@ static igraph_error_t igraph_i_lad_matchVertices(igraph_integer_t nb, igraph_vec } -static bool igraph_i_lad_matchVertex(igraph_integer_t u, bool induced, Tdomain* D, Tgraph* Gp, +static bool igraph_i_lad_matchVertex(igraph_int_t u, bool induced, Tdomain* D, Tgraph* Gp, Tgraph *Gt) { igraph_bool_t invalid; /* match u to D->val[D->firstVal[u]] and filter domains of other non @@ -471,7 +470,7 @@ static bool igraph_i_lad_matchVertex(igraph_integer_t u, bool induced, Tdomain* static int igraph_i_lad_qcompare (void const *a, void const *b) { /* function used by the qsort function */ - igraph_integer_t pa = ((*((igraph_integer_t*)a) - *((igraph_integer_t*)b))); + igraph_int_t pa = ((*((igraph_int_t*)a) - *((igraph_int_t*)b))); if (pa < 0) { return -1; } else if (pa > 0) { @@ -480,11 +479,11 @@ static int igraph_i_lad_qcompare (void const *a, void const *b) { return 0; } -static bool igraph_i_lad_compare(igraph_integer_t size_mu, igraph_integer_t* mu, igraph_integer_t size_mv, igraph_integer_t* mv) { +static bool igraph_i_lad_compare(igraph_int_t size_mu, igraph_int_t* mu, igraph_int_t size_mv, igraph_int_t* mv) { /* return true if for every element u of mu there exists a different element v of mv such that u <= v; return false otherwise */ - igraph_integer_t i, j; + igraph_int_t i, j; igraph_qsort(mu, (size_t) size_mu, sizeof(mu[0]), igraph_i_lad_qcompare); igraph_qsort(mv, (size_t) size_mv, sizeof(mv[0]), igraph_i_lad_qcompare); i = size_mv - 1; @@ -506,13 +505,13 @@ static igraph_error_t igraph_i_lad_initDomains(bool initialDomains, if initialDomains, then filter initial domains wrt compatibilities given in file return false if a domain is empty and true otherwise */ - igraph_integer_t *val; + igraph_int_t *val; igraph_bitset_t dom; - igraph_integer_t *mu, *mv; - igraph_integer_t matchingSize, u, v, i, j; + igraph_int_t *mu, *mv; + igraph_int_t matchingSize, u, v, i, j; igraph_vector_int_t *vec; - ALLOC_ARRAY(val, Gp->nbVertices * Gt->nbVertices, igraph_integer_t); + ALLOC_ARRAY(val, Gp->nbVertices * Gt->nbVertices, igraph_int_t); IGRAPH_BITSET_INIT_FINALLY(&dom, Gt->nbVertices); IGRAPH_VECTOR_INT_INIT_FINALLY(&D->globalMatchingP, Gp->nbVertices); @@ -558,11 +557,11 @@ static igraph_error_t igraph_i_lad_initDomains(bool initialDomains, MATRIX(D->firstMatch, u, v) = matchingSize; matchingSize += VECTOR(Gp->nbSucc)[u]; if (VECTOR(Gp->nbSucc)[u] <= VECTOR(Gt->nbSucc)[v]) { - mu = IGRAPH_CALLOC(VECTOR(Gp->nbSucc)[u], igraph_integer_t); + mu = IGRAPH_CALLOC(VECTOR(Gp->nbSucc)[u], igraph_int_t); IGRAPH_CHECK_OOM(mu, "Insufficient memory for subisomorphism search with LAD."); IGRAPH_FINALLY(igraph_free, mu); - mv = IGRAPH_CALLOC(VECTOR(Gt->nbSucc)[v], igraph_integer_t); + mv = IGRAPH_CALLOC(VECTOR(Gt->nbSucc)[v], igraph_int_t); IGRAPH_CHECK_OOM(mu, "Insufficient memory for subisomorphism search with LAD."); IGRAPH_FINALLY(igraph_free, mv); @@ -650,14 +649,14 @@ static void igraph_i_lad_destroyDomains(Tdomain *D) { #define toBeDeleted 3 #define deleted 4 -static void igraph_i_lad_addToDelete(igraph_integer_t u, igraph_integer_t* list, igraph_integer_t* nb, igraph_integer_t* marked) { +static void igraph_i_lad_addToDelete(igraph_int_t u, igraph_int_t* list, igraph_int_t* nb, igraph_int_t* marked) { if (marked[u] < toBeDeleted) { list[(*nb)++] = u; marked[u] = toBeDeleted; } } -static igraph_error_t igraph_i_lad_updateMatching(igraph_integer_t sizeOfU, igraph_integer_t sizeOfV, +static igraph_error_t igraph_i_lad_updateMatching(igraph_int_t sizeOfU, igraph_int_t sizeOfV, igraph_vector_int_t *degree, igraph_vector_int_t *firstAdj, igraph_vector_int_t *adj, @@ -677,27 +676,27 @@ static igraph_error_t igraph_i_lad_updateMatching(igraph_integer_t sizeOfU, igra for every u in 0..nbU-1, there exists a different v in 0..nb-1 such that v is adjacent to u; returns false otherwise */ - igraph_integer_t *matchedWithV; /* matchedWithV[matchedWithU[u]]=u */ - igraph_integer_t *nbPred; /* nbPred[i] = nb of predecessors of the ith + igraph_int_t *matchedWithV; /* matchedWithV[matchedWithU[u]]=u */ + igraph_int_t *nbPred; /* nbPred[i] = nb of predecessors of the ith vertex of V in the DAG */ - igraph_integer_t *pred; /* pred[i][j] = jth predecessor the ith + igraph_int_t *pred; /* pred[i][j] = jth predecessor the ith vertex of V in the DAG */ - igraph_integer_t *nbSucc; /* nbSucc[i] = nb of successors of the ith + igraph_int_t *nbSucc; /* nbSucc[i] = nb of successors of the ith vertex of U in the DAG */ - igraph_integer_t *succ; /* succ[i][j] = jth successor of the ith + igraph_int_t *succ; /* succ[i][j] = jth successor of the ith vertex of U in the DAG */ - igraph_integer_t *listV, *listU, *listDV, *listDU; - igraph_integer_t nbV, nbU, nbDV, nbDU; - igraph_integer_t i, j, k, stop, u, v; - igraph_integer_t *markedV, *markedU; + igraph_int_t *listV, *listU, *listDV, *listDU; + igraph_int_t nbV, nbU, nbDV, nbDU; + igraph_int_t i, j, k, stop, u, v; + igraph_int_t *markedV, *markedU; /* markedX[i]=white if X[i] is not in the DAG markedX[i]=grey if X[i] has been added to the DAG, but not its successors markedX[i]=black if X[i] and its successors have been added to the DAG markedX[i]=toBeDeleted if X[i] must be deleted from the DAG markedX[i]=deleted if X[i] has been deleted from the DAG */ - igraph_integer_t nbUnmatched = 0; /* number of vertices of U that are not matched */ - igraph_integer_t *unmatched; /* vertices of U that are not matched */ - igraph_integer_t *posInUnmatched; /* unmatched[posInUnmatched[u]]=u */ + igraph_int_t nbUnmatched = 0; /* number of vertices of U that are not matched */ + igraph_int_t *unmatched; /* vertices of U that are not matched */ + igraph_int_t *posInUnmatched; /* unmatched[posInUnmatched[u]]=u */ igraph_vector_int_t path; if (sizeOfU > sizeOfV) { @@ -705,19 +704,19 @@ static igraph_error_t igraph_i_lad_updateMatching(igraph_integer_t sizeOfU, igra return IGRAPH_SUCCESS; } - ALLOC_ARRAY(matchedWithV, sizeOfV, igraph_integer_t); - ALLOC_ARRAY(nbPred, sizeOfV, igraph_integer_t); - ALLOC_ARRAY(pred, sizeOfV * sizeOfU, igraph_integer_t); - ALLOC_ARRAY(nbSucc, sizeOfU, igraph_integer_t); - ALLOC_ARRAY(succ, sizeOfU * sizeOfV, igraph_integer_t); - ALLOC_ARRAY(listV, sizeOfV, igraph_integer_t); - ALLOC_ARRAY(listU, sizeOfU, igraph_integer_t); - ALLOC_ARRAY(listDV, sizeOfV, igraph_integer_t); - ALLOC_ARRAY(listDU, sizeOfU, igraph_integer_t); - ALLOC_ARRAY(markedV, sizeOfV, igraph_integer_t); - ALLOC_ARRAY(markedU, sizeOfU, igraph_integer_t); - ALLOC_ARRAY(unmatched, sizeOfU, igraph_integer_t); - ALLOC_ARRAY(posInUnmatched, sizeOfU, igraph_integer_t); + ALLOC_ARRAY(matchedWithV, sizeOfV, igraph_int_t); + ALLOC_ARRAY(nbPred, sizeOfV, igraph_int_t); + ALLOC_ARRAY(pred, sizeOfV * sizeOfU, igraph_int_t); + ALLOC_ARRAY(nbSucc, sizeOfU, igraph_int_t); + ALLOC_ARRAY(succ, sizeOfU * sizeOfV, igraph_int_t); + ALLOC_ARRAY(listV, sizeOfV, igraph_int_t); + ALLOC_ARRAY(listU, sizeOfU, igraph_int_t); + ALLOC_ARRAY(listDV, sizeOfV, igraph_int_t); + ALLOC_ARRAY(listDU, sizeOfU, igraph_int_t); + ALLOC_ARRAY(markedV, sizeOfV, igraph_int_t); + ALLOC_ARRAY(markedU, sizeOfU, igraph_int_t); + ALLOC_ARRAY(unmatched, sizeOfU, igraph_int_t); + ALLOC_ARRAY(posInUnmatched, sizeOfU, igraph_int_t); IGRAPH_VECTOR_INT_INIT_FINALLY(&path, 0); @@ -907,9 +906,9 @@ static igraph_error_t igraph_i_lad_updateMatching(igraph_integer_t sizeOfU, igra return IGRAPH_SUCCESS; } -static void igraph_i_lad_DFS(igraph_integer_t nbU, igraph_integer_t nbV, igraph_integer_t u, igraph_bitset_t *marked, igraph_integer_t* nbSucc, - igraph_integer_t* succ, igraph_vector_int_t * matchedWithU, - igraph_integer_t* order, igraph_integer_t* nb) { +static void igraph_i_lad_DFS(igraph_int_t nbU, igraph_int_t nbV, igraph_int_t u, igraph_bitset_t *marked, igraph_int_t* nbSucc, + igraph_int_t* succ, igraph_vector_int_t * matchedWithU, + igraph_int_t* order, igraph_int_t* nb) { /* perform a depth first search, starting from u, in the bipartite graph Go=(U, V, E) such that U = vertices of Gp @@ -920,8 +919,8 @@ static void igraph_i_lad_DFS(igraph_integer_t nbU, igraph_integer_t nbV, igraph_ Given a vertex v of Gt, nbSucc[v]=number of successors of v and succ[v]=list of successors of v. order[nb^out+1..nb^in] contains the vertices discovered by the DFS */ - igraph_integer_t i; - igraph_integer_t v = VECTOR(*matchedWithU)[u]; /* the only one predecessor of v is u */ + igraph_int_t i; + igraph_int_t v = VECTOR(*matchedWithU)[u]; /* the only one predecessor of v is u */ IGRAPH_BIT_SET(*marked, u); if (v >= 0) { for (i = 0; i < nbSucc[v]; i++) { @@ -935,9 +934,9 @@ static void igraph_i_lad_DFS(igraph_integer_t nbU, igraph_integer_t nbV, igraph_ order[*nb] = u; (*nb)--; } -static igraph_error_t igraph_i_lad_SCC(igraph_integer_t nbU, igraph_integer_t nbV, igraph_integer_t* numV, igraph_integer_t* numU, - igraph_integer_t* nbSucc, igraph_integer_t* succ, - igraph_integer_t* nbPred, igraph_integer_t* pred, +static igraph_error_t igraph_i_lad_SCC(igraph_int_t nbU, igraph_int_t nbV, igraph_int_t* numV, igraph_int_t* numU, + igraph_int_t* nbSucc, igraph_int_t* succ, + igraph_int_t* nbPred, igraph_int_t* pred, igraph_vector_int_t * matchedWithU, igraph_vector_int_t * matchedWithV) { /* postrelation: numV[v]==numU[u] iff they belong to the same @@ -950,15 +949,15 @@ static igraph_error_t igraph_i_lad_SCC(igraph_integer_t nbU, igraph_integer_t nb Given a vertex v of Gt, nbSucc[v]=number of sucessors of v and succ[v]=list of successors of v */ - igraph_integer_t *order; + igraph_int_t *order; igraph_bitset_t marked; - igraph_integer_t *fifo; - igraph_integer_t u, v, i, j, k, nbSCC, nb; + igraph_int_t *fifo; + igraph_int_t u, v, i, j, k, nbSCC, nb; /* Allocate memory */ - ALLOC_ARRAY(order, nbU, igraph_integer_t); + ALLOC_ARRAY(order, nbU, igraph_int_t); IGRAPH_BITSET_INIT_FINALLY(&marked, nbU); - ALLOC_ARRAY(fifo, nbV, igraph_integer_t); + ALLOC_ARRAY(fifo, nbV, igraph_int_t); /* Order vertices of Gp wrt DFS */ nb = nbU - 1; @@ -1022,29 +1021,29 @@ static igraph_error_t igraph_i_lad_ensureGACallDiff(bool induced, Tgraph* Gp, Tg v=D->globalMatchingP[u])} U { (v, u) / v is a vertex of Gt which is in D(u) but is not matched to u} */ - igraph_integer_t *nbPred; /* nbPred[u] = nb of predecessors of u in Go */ - igraph_integer_t *pred; /* pred[u][i] = ith + igraph_int_t *nbPred; /* nbPred[u] = nb of predecessors of u in Go */ + igraph_int_t *pred; /* pred[u][i] = ith predecessor of u in Go */ - igraph_integer_t *nbSucc; /* nbSucc[v] = nb of successors of v in Go */ - igraph_integer_t *succ; /* succ[v][i] = ith + igraph_int_t *nbSucc; /* nbSucc[v] = nb of successors of v in Go */ + igraph_int_t *succ; /* succ[v][i] = ith successor of v in Go */ - igraph_integer_t u, v, i, w, oldNbVal, nbToMatch; - igraph_integer_t *numV, *numU; + igraph_int_t u, v, i, w, oldNbVal, nbToMatch; + igraph_int_t *numV, *numU; igraph_vector_int_t toMatch; igraph_bitset_t used; - igraph_integer_t *list; - igraph_integer_t nb = 0; + igraph_int_t *list; + igraph_int_t nb = 0; bool result; /* Allocate memory */ - ALLOC_ARRAY(nbPred, Gp->nbVertices, igraph_integer_t); - ALLOC_ARRAY(pred, Gp->nbVertices * Gt->nbVertices, igraph_integer_t); - ALLOC_ARRAY(nbSucc, Gt->nbVertices, igraph_integer_t); - ALLOC_ARRAY(succ, Gt->nbVertices * Gp->nbVertices, igraph_integer_t); - ALLOC_ARRAY(numV, Gt->nbVertices, igraph_integer_t); - ALLOC_ARRAY(numU, Gp->nbVertices, igraph_integer_t); + ALLOC_ARRAY(nbPred, Gp->nbVertices, igraph_int_t); + ALLOC_ARRAY(pred, Gp->nbVertices * Gt->nbVertices, igraph_int_t); + ALLOC_ARRAY(nbSucc, Gt->nbVertices, igraph_int_t); + ALLOC_ARRAY(succ, Gt->nbVertices * Gp->nbVertices, igraph_int_t); + ALLOC_ARRAY(numV, Gt->nbVertices, igraph_int_t); + ALLOC_ARRAY(numU, Gp->nbVertices, igraph_int_t); IGRAPH_BITSET_INIT_FINALLY(&used, Gp->nbVertices * Gt->nbVertices); - ALLOC_ARRAY(list, Gt->nbVertices, igraph_integer_t); + ALLOC_ARRAY(list, Gt->nbVertices, igraph_int_t); IGRAPH_VECTOR_INT_INIT_FINALLY(&toMatch, Gp->nbVertices); for (u = 0; u < Gp->nbVertices; u++) { @@ -1136,20 +1135,20 @@ static igraph_error_t igraph_i_lad_ensureGACallDiff(bool induced, Tgraph* Gp, Tg /* Coming from lad.c */ /* ---------------------------------------------------------*/ -static igraph_error_t igraph_i_lad_checkLAD(igraph_integer_t u, igraph_integer_t v, Tdomain* D, Tgraph* Gp, Tgraph* Gt, +static igraph_error_t igraph_i_lad_checkLAD(igraph_int_t u, igraph_int_t v, Tdomain* D, Tgraph* Gp, Tgraph* Gt, bool *result) { /* return true if G_(u, v) has a adj(u)-covering matching; false otherwise */ - igraph_integer_t u2, v2, i, j; - igraph_integer_t nbMatched = 0; + igraph_int_t u2, v2, i, j; + igraph_int_t nbMatched = 0; igraph_vector_int_t *Gp_uneis = igraph_adjlist_get(&Gp->succ, u); - igraph_integer_t *num, *numInv; + igraph_int_t *num, *numInv; igraph_vector_int_t nbComp; igraph_vector_int_t firstComp; igraph_vector_int_t comp; - igraph_integer_t nbNum = 0; - igraph_integer_t posInComp = 0; + igraph_int_t nbNum = 0; + igraph_int_t posInComp = 0; igraph_vector_int_t matchedWithU; igraph_bool_t invalid; @@ -1192,8 +1191,8 @@ static igraph_error_t igraph_i_lad_checkLAD(igraph_integer_t u, igraph_integer_t } /* The matching still covers adj(u) */ /* Allocate memory */ - ALLOC_ARRAY(num, Gt->nbVertices, igraph_integer_t); - ALLOC_ARRAY(numInv, Gt->nbVertices, igraph_integer_t); + ALLOC_ARRAY(num, Gt->nbVertices, igraph_int_t); + ALLOC_ARRAY(numInv, Gt->nbVertices, igraph_int_t); /* Build the bipartite graph let U be the set of nodes adjacent to u @@ -1287,7 +1286,7 @@ static igraph_error_t igraph_i_lad_filter(bool induced, Tdomain* D, Tgraph* Gp, /* filter domains of all vertices in D->toFilter wrt LAD and ensure GAC(allDiff) return false if some domain becomes empty; true otherwise */ - igraph_integer_t u, v, i, oldNbVal; + igraph_int_t u, v, i, oldNbVal; igraph_bool_t invalid; bool result2; while (!igraph_i_lad_toFilterEmpty(D)) { @@ -1332,11 +1331,11 @@ static igraph_error_t igraph_i_lad_filter(bool induced, Tdomain* D, Tgraph* Gp, -static igraph_error_t igraph_i_lad_solve(igraph_integer_t timeLimit, bool firstSol, bool induced, +static igraph_error_t igraph_i_lad_solve(bool firstSol, bool induced, Tdomain* D, Tgraph* Gp, Tgraph* Gt, igraph_bool_t *invalid, igraph_bool_t *iso, igraph_vector_int_t *vec, igraph_vector_int_t *map, igraph_vector_int_list_t *maps, - igraph_integer_t *nbNodes, igraph_integer_t *nbFail, igraph_integer_t *nbSol, + igraph_int_t *nbNodes, igraph_int_t *nbFail, igraph_int_t *nbSol, clock_t *begin, igraph_vector_ptr_t *alloc_history) { /* if firstSol then search for the first solution; otherwise search for all solutions if induced then search for induced subgraphs; @@ -1344,23 +1343,17 @@ static igraph_error_t igraph_i_lad_solve(igraph_integer_t timeLimit, bool firstS return false if CPU time limit exceeded before the search is completed, return true otherwise */ - igraph_integer_t u, v, minDom, i; - igraph_integer_t* nbVal; - igraph_integer_t* globalMatching; - clock_t end = clock(); - igraph_integer_t* val; + igraph_int_t u, v, minDom, i; + igraph_int_t* nbVal; + igraph_int_t* globalMatching; + igraph_int_t* val; bool result; (*nbNodes)++; - if ( (double)(end - *begin) / CLOCKS_PER_SEC >= timeLimit) { - /* CPU time limit exceeded */ - IGRAPH_ERROR("LAD CPU time exceeded", IGRAPH_CPUTIME); - } - /* Allocate memory */ - ALLOC_ARRAY_IN_HISTORY(nbVal, Gp->nbVertices, igraph_integer_t, alloc_history); - ALLOC_ARRAY_IN_HISTORY(globalMatching, Gp->nbVertices, igraph_integer_t, alloc_history); + ALLOC_ARRAY_IN_HISTORY(nbVal, Gp->nbVertices, igraph_int_t, alloc_history); + ALLOC_ARRAY_IN_HISTORY(globalMatching, Gp->nbVertices, igraph_int_t, alloc_history); IGRAPH_CHECK(igraph_i_lad_filter(induced, D, Gp, Gt, &result)); if (!result) { @@ -1408,7 +1401,7 @@ static igraph_error_t igraph_i_lad_solve(igraph_integer_t timeLimit, bool firstS } /* save the domain of minDom to iterate on its values */ - ALLOC_ARRAY_IN_HISTORY(val, VECTOR(D->nbVal)[minDom], igraph_integer_t, alloc_history); + ALLOC_ARRAY_IN_HISTORY(val, VECTOR(D->nbVal)[minDom], igraph_int_t, alloc_history); for (i = 0; i < VECTOR(D->nbVal)[minDom]; i++) { val[i] = VECTOR(D->val)[ VECTOR(D->firstVal)[minDom] + i ]; } @@ -1423,7 +1416,7 @@ static igraph_error_t igraph_i_lad_solve(igraph_integer_t timeLimit, bool firstS (*nbNodes)++; igraph_i_lad_resetToFilter(D); } else { - IGRAPH_CHECK(igraph_i_lad_solve(timeLimit, firstSol, induced, + IGRAPH_CHECK(igraph_i_lad_solve(firstSol, induced, D, Gp, Gt, invalid, iso, vec, map, maps, nbNodes, nbFail, nbSol, begin, alloc_history)); @@ -1522,23 +1515,23 @@ igraph_error_t igraph_subisomorphic_lad(const igraph_t *pattern, const igraph_t const igraph_vector_int_list_t *domains, igraph_bool_t *iso, igraph_vector_int_t *map, igraph_vector_int_list_t *maps, - igraph_bool_t induced, igraph_integer_t time_limit) { + igraph_bool_t induced) { bool firstSol = maps == NULL; bool initialDomains = domains != NULL; Tgraph Gp, Gt; Tdomain D; igraph_bool_t invalidDomain; - igraph_integer_t u, nbToMatch = 0; + igraph_int_t u, nbToMatch = 0; igraph_vector_int_t toMatch; /* Helper vector in which we build the current subisomorphism mapping */ igraph_vector_int_t vec; /* Number of nodes in the search tree */ - igraph_integer_t nbNodes = 0; + igraph_int_t nbNodes = 0; /* number of failed nodes in the search tree */ - igraph_integer_t nbFail = 0; + igraph_int_t nbFail = 0; /* number of solutions found */ - igraph_integer_t nbSol = 0; + igraph_int_t nbSol = 0; /* reusable structure to get CPU time usage */ clock_t begin = clock(); /* Stack to store memory blocks that are allocated during igraph_i_lad_solve */ @@ -1553,9 +1546,6 @@ igraph_error_t igraph_subisomorphic_lad(const igraph_t *pattern, const igraph_t IGRAPH_ERROR("Cannot search for a directed pattern in an undirected target " "or vice versa", IGRAPH_EINVAL); } - if (time_limit <= 0) { - time_limit = IGRAPH_INTEGER_MAX; - } if (iso) { *iso = (igraph_vcount(pattern) == 0); @@ -1631,7 +1621,7 @@ igraph_error_t igraph_subisomorphic_lad(const igraph_t *pattern, const igraph_t IGRAPH_CHECK(igraph_vector_ptr_init(&alloc_history, 0)); IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &alloc_history); - IGRAPH_CHECK(igraph_i_lad_solve(time_limit, firstSol, (bool) induced, &D, + IGRAPH_CHECK(igraph_i_lad_solve(firstSol, (bool) induced, &D, &Gp, &Gt, &invalidDomain, iso, &vec, map, maps, &nbNodes, &nbFail, &nbSol, &begin, &alloc_history)); diff --git a/src/vendor/cigraph/src/isomorphism/queries.c b/src/vendor/cigraph/src/isomorphism/queries.c index 5768bc57022..c6329600d48 100644 --- a/src/vendor/cigraph/src/isomorphism/queries.c +++ b/src/vendor/cigraph/src/isomorphism/queries.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -20,7 +19,7 @@ */ -#include "igraph_topology.h" +#include "igraph_isomorphism.h" #include "igraph_interface.h" #include "igraph_structural.h" @@ -101,8 +100,8 @@ static igraph_error_t igraph_i_isomorphic_small( igraph_error_t igraph_isomorphic(const igraph_t *graph1, const igraph_t *graph2, igraph_bool_t *iso) { - igraph_integer_t nodes1 = igraph_vcount(graph1), nodes2 = igraph_vcount(graph2); - igraph_integer_t edges1 = igraph_ecount(graph1), edges2 = igraph_ecount(graph2); + igraph_int_t nodes1 = igraph_vcount(graph1), nodes2 = igraph_vcount(graph2); + igraph_int_t edges1 = igraph_ecount(graph1), edges2 = igraph_ecount(graph2); igraph_bool_t dir1 = igraph_is_directed(graph1), dir2 = igraph_is_directed(graph2); igraph_bool_t loop1, loop2, multi1, multi2; @@ -161,33 +160,6 @@ igraph_error_t igraph_isomorphic(const igraph_t *graph1, const igraph_t *graph2, return IGRAPH_SUCCESS; } -/** - * \function igraph_isomorphic_34 - * \brief Graph isomorphism for 3-4 vertices (deprecated). - * - * \deprecated-by igraph_isomorphic 0.10.0 - * - * If you really care about performance and you \em know for sure that your - * input graphs are simple and have either 3 or 4 vertices for directed graphs, - * or 3-6 vertices for undirected graphs, you can compare their isomorphism - * classes obtained from \ref igraph_isoclass() directly instead of calling - * \ref igraph_isomorphic(); this saves the cost of checking whether the graphs - * do not contain multiple edges or self-loops. - * - * \param graph1 The first input graph. - * \param graph2 The second input graph. Must have the same - * directedness as \p graph1. - * \param iso Pointer to a boolean, the result is stored here. - * \return Error code. - * - * Time complexity: O(1). - */ -igraph_error_t igraph_isomorphic_34( - const igraph_t *graph1, const igraph_t *graph2, igraph_bool_t *iso -) { - return igraph_i_isomorphic_small(graph1, graph2, iso); -} - /** * \function igraph_i_isomorphic_small * \brief Graph isomorphism for small graphs. @@ -208,7 +180,7 @@ igraph_error_t igraph_isomorphic_34( igraph_error_t igraph_i_isomorphic_small( const igraph_t *graph1, const igraph_t *graph2, igraph_bool_t *iso ) { - igraph_integer_t class1, class2; + igraph_int_t class1, class2; IGRAPH_CHECK(igraph_isoclass(graph1, &class1)); IGRAPH_CHECK(igraph_isoclass(graph2, &class2)); *iso = (class1 == class2); diff --git a/src/vendor/cigraph/src/isomorphism/vf2.c b/src/vendor/cigraph/src/isomorphism/vf2.c index 646a49bb228..7f3075fca64 100644 --- a/src/vendor/cigraph/src/isomorphism/vf2.c +++ b/src/vendor/cigraph/src/isomorphism/vf2.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -21,7 +20,7 @@ */ -#include "igraph_topology.h" +#include "igraph_isomorphism.h" #include "igraph_adjlist.h" #include "igraph_interface.h" @@ -144,20 +143,20 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( igraph_isocompat_t *edge_compat_fn, void *arg ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph1); - igraph_integer_t no_of_edges = igraph_ecount(graph1); + igraph_int_t no_of_nodes = igraph_vcount(graph1); + igraph_int_t no_of_edges = igraph_ecount(graph1); igraph_vector_int_t mycore_1, mycore_2, *core_1 = &mycore_1, *core_2 = &mycore_2; igraph_vector_int_t in_1, in_2, out_1, out_2; - igraph_integer_t in_1_size = 0, in_2_size = 0, out_1_size = 0, out_2_size = 0; + igraph_int_t in_1_size = 0, in_2_size = 0, out_1_size = 0, out_2_size = 0; igraph_vector_int_t *inneis_1, *inneis_2, *outneis_1, *outneis_2; - igraph_integer_t matched_nodes = 0; - igraph_integer_t depth; - igraph_integer_t cand1, cand2; - igraph_integer_t last1, last2; + igraph_int_t matched_nodes = 0; + igraph_int_t depth; + igraph_int_t cand1, cand2; + igraph_int_t last1, last2; igraph_stack_int_t path; igraph_lazy_adjlist_t inadj1, inadj2, outadj1, outadj2; igraph_vector_int_t indeg1, indeg2, outdeg1, outdeg2; - igraph_integer_t vsize; + igraph_int_t vsize; IGRAPH_CHECK(igraph_i_perform_vf2_pre_checks(graph1, graph2)); @@ -275,7 +274,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( depth = 0; last1 = -1; last2 = -1; while (depth >= 0) { - igraph_integer_t i; + igraph_int_t i; IGRAPH_ALLOW_INTERRUPTION(); @@ -381,7 +380,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( vsize = igraph_vector_int_size(inneis_1); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_1)[i]; + igraph_int_t node = VECTOR(*inneis_1)[i]; if (VECTOR(in_1)[node] == depth) { VECTOR(in_1)[node] = 0; in_1_size -= 1; @@ -393,7 +392,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( vsize = igraph_vector_int_size(outneis_1); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_1)[i]; + igraph_int_t node = VECTOR(*outneis_1)[i]; if (VECTOR(out_1)[node] == depth) { VECTOR(out_1)[node] = 0; out_1_size -= 1; @@ -405,7 +404,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( vsize = igraph_vector_int_size(inneis_2); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_2)[i]; + igraph_int_t node = VECTOR(*inneis_2)[i]; if (VECTOR(in_2)[node] == depth) { VECTOR(in_2)[node] = 0; in_2_size -= 1; @@ -417,7 +416,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( vsize = igraph_vector_int_size(outneis_2); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_2)[i]; + igraph_int_t node = VECTOR(*outneis_2)[i]; if (VECTOR(out_2)[node] == depth) { VECTOR(out_2)[node] = 0; out_2_size -= 1; @@ -431,7 +430,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( } else { /**************************************************************/ /* step forward if worth, check if worth first */ - igraph_integer_t xin1 = 0, xin2 = 0, xout1 = 0, xout2 = 0; + igraph_int_t xin1 = 0, xin2 = 0, xout1 = 0, xout2 = 0; igraph_bool_t end = false; inneis_1 = igraph_lazy_adjlist_get(&inadj1, cand1); @@ -456,14 +455,14 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( vsize = igraph_vector_int_size(inneis_1); for (i = 0; !end && i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_1)[i]; + igraph_int_t node = VECTOR(*inneis_1)[i]; if (VECTOR(*core_1)[node] >= 0) { - igraph_integer_t node2 = VECTOR(*core_1)[node]; + igraph_int_t node2 = VECTOR(*core_1)[node]; /* check if there is a node2->cand2 edge */ if (!igraph_vector_int_contains_sorted(inneis_2, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { - igraph_integer_t eid1, eid2; + igraph_int_t eid1, eid2; igraph_get_eid(graph1, &eid1, node, cand1, IGRAPH_DIRECTED, /*error=*/ true); igraph_get_eid(graph2, &eid2, node2, cand2, IGRAPH_DIRECTED, @@ -488,14 +487,14 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( } vsize = igraph_vector_int_size(outneis_1); for (i = 0; !end && i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_1)[i]; + igraph_int_t node = VECTOR(*outneis_1)[i]; if (VECTOR(*core_1)[node] >= 0) { - igraph_integer_t node2 = VECTOR(*core_1)[node]; + igraph_int_t node2 = VECTOR(*core_1)[node]; /* check if there is a cand2->node2 edge */ if (!igraph_vector_int_contains_sorted(outneis_2, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { - igraph_integer_t eid1, eid2; + igraph_int_t eid1, eid2; igraph_get_eid(graph1, &eid1, cand1, node, IGRAPH_DIRECTED, /*error=*/ true); igraph_get_eid(graph2, &eid2, cand2, node2, IGRAPH_DIRECTED, @@ -520,14 +519,14 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( } vsize = igraph_vector_int_size(inneis_2); for (i = 0; !end && i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_2)[i]; + igraph_int_t node = VECTOR(*inneis_2)[i]; if (VECTOR(*core_2)[node] >= 0) { - igraph_integer_t node2 = VECTOR(*core_2)[node]; + igraph_int_t node2 = VECTOR(*core_2)[node]; /* check if there is a node2->cand1 edge */ if (!igraph_vector_int_contains_sorted(inneis_1, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { - igraph_integer_t eid1, eid2; + igraph_int_t eid1, eid2; igraph_get_eid(graph1, &eid1, node2, cand1, IGRAPH_DIRECTED, /*error=*/ true); igraph_get_eid(graph2, &eid2, node, cand2, IGRAPH_DIRECTED, @@ -552,14 +551,14 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( } vsize = igraph_vector_int_size(outneis_2); for (i = 0; !end && i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_2)[i]; + igraph_int_t node = VECTOR(*outneis_2)[i]; if (VECTOR(*core_2)[node] >= 0) { - igraph_integer_t node2 = VECTOR(*core_2)[node]; + igraph_int_t node2 = VECTOR(*core_2)[node]; /* check if there is a cand1->node2 edge */ if (!igraph_vector_int_contains_sorted(outneis_1, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { - igraph_integer_t eid1, eid2; + igraph_int_t eid1, eid2; igraph_get_eid(graph1, &eid1, cand1, node2, IGRAPH_DIRECTED, /*error=*/ true); igraph_get_eid(graph2, &eid2, cand2, node, IGRAPH_DIRECTED, @@ -611,7 +610,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( vsize = igraph_vector_int_size(inneis_1); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_1)[i]; + igraph_int_t node = VECTOR(*inneis_1)[i]; if (VECTOR(in_1)[node] == 0 && VECTOR(*core_1)[node] < 0) { VECTOR(in_1)[node] = depth; in_1_size += 1; @@ -623,7 +622,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( vsize = igraph_vector_int_size(outneis_1); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_1)[i]; + igraph_int_t node = VECTOR(*outneis_1)[i]; if (VECTOR(out_1)[node] == 0 && VECTOR(*core_1)[node] < 0) { VECTOR(out_1)[node] = depth; out_1_size += 1; @@ -635,7 +634,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( vsize = igraph_vector_int_size(inneis_2); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_2)[i]; + igraph_int_t node = VECTOR(*inneis_2)[i]; if (VECTOR(in_2)[node] == 0 && VECTOR(*core_2)[node] < 0) { VECTOR(in_2)[node] = depth; in_2_size += 1; @@ -647,7 +646,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( vsize = igraph_vector_int_size(outneis_2); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_2)[i]; + igraph_int_t node = VECTOR(*outneis_2)[i]; if (VECTOR(out_2)[node] == 0 && VECTOR(*core_2)[node] < 0) { VECTOR(out_2)[node] = depth; out_2_size += 1; @@ -697,26 +696,6 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( return IGRAPH_SUCCESS; } -/** - * \function igraph_isomorphic_function_vf2 - * \brief The generic VF2 interface (deprecated alias). - * - * \deprecated-by igraph_get_isomorphisms_vf2_callback 0.10.0 - */ -igraph_error_t igraph_isomorphic_function_vf2( - const igraph_t *graph1, const igraph_t *graph2, - const igraph_vector_int_t *vertex_color1, const igraph_vector_int_t *vertex_color2, - const igraph_vector_int_t *edge_color1, const igraph_vector_int_t *edge_color2, - igraph_vector_int_t *map12, igraph_vector_int_t *map21, - igraph_isohandler_t *isohandler_fn, igraph_isocompat_t *node_compat_fn, - igraph_isocompat_t *edge_compat_fn, void *arg -) { - return igraph_get_isomorphisms_vf2_callback( - graph1, graph2, vertex_color1, vertex_color2, edge_color1, edge_color2, - map12, map21, isohandler_fn, node_compat_fn, edge_compat_fn, arg - ); -} - typedef struct { igraph_isocompat_t *node_compat_fn, *edge_compat_fn; void *arg, *carg; @@ -725,8 +704,8 @@ typedef struct { static igraph_bool_t igraph_i_isocompat_node_cb( const igraph_t *graph1, const igraph_t *graph2, - const igraph_integer_t g1_num, - const igraph_integer_t g2_num, + const igraph_int_t g1_num, + const igraph_int_t g2_num, void *arg) { igraph_i_iso_cb_data_t *data = arg; return data->node_compat_fn(graph1, graph2, g1_num, g2_num, data->carg); @@ -735,8 +714,8 @@ static igraph_bool_t igraph_i_isocompat_node_cb( static igraph_bool_t igraph_i_isocompat_edge_cb( const igraph_t *graph1, const igraph_t *graph2, - const igraph_integer_t g1_num, - const igraph_integer_t g2_num, + const igraph_int_t g1_num, + const igraph_int_t g2_num, void *arg) { igraph_i_iso_cb_data_t *data = arg; return data->edge_compat_fn(graph1, graph2, g1_num, g2_num, data->carg); @@ -845,7 +824,7 @@ static igraph_error_t igraph_i_count_isomorphisms_vf2_cb( void *arg ) { igraph_i_iso_cb_data_t *data = arg; - igraph_integer_t *count = data->arg; + igraph_int_t *count = data->arg; IGRAPH_UNUSED(map12); IGRAPH_UNUSED(map21); *count += 1; return IGRAPH_SUCCESS; @@ -885,7 +864,7 @@ static igraph_error_t igraph_i_count_isomorphisms_vf2_cb( * \p edge_compat_fn. * \return Error code. * - * \sa igraph_count_automorphisms() + * \sa igraph_count_automorphisms_bliss() * * Time complexity: exponential. */ @@ -895,7 +874,7 @@ igraph_error_t igraph_count_isomorphisms_vf2(const igraph_t *graph1, const igrap const igraph_vector_int_t *vertex_color2, const igraph_vector_int_t *edge_color1, const igraph_vector_int_t *edge_color2, - igraph_integer_t *count, + igraph_int_t *count, igraph_isocompat_t *node_compat_fn, igraph_isocompat_t *edge_compat_fn, void *arg) { @@ -1050,22 +1029,22 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( igraph_isocompat_t *edge_compat_fn, void *arg ) { - igraph_integer_t no_of_nodes1 = igraph_vcount(graph1), + igraph_int_t no_of_nodes1 = igraph_vcount(graph1), no_of_nodes2 = igraph_vcount(graph2); - igraph_integer_t no_of_edges1 = igraph_ecount(graph1), + igraph_int_t no_of_edges1 = igraph_ecount(graph1), no_of_edges2 = igraph_ecount(graph2); igraph_vector_int_t mycore_1, mycore_2, *core_1 = &mycore_1, *core_2 = &mycore_2; igraph_vector_int_t in_1, in_2, out_1, out_2; - igraph_integer_t in_1_size = 0, in_2_size = 0, out_1_size = 0, out_2_size = 0; + igraph_int_t in_1_size = 0, in_2_size = 0, out_1_size = 0, out_2_size = 0; igraph_vector_int_t *inneis_1, *inneis_2, *outneis_1, *outneis_2; - igraph_integer_t matched_nodes = 0; - igraph_integer_t depth; - igraph_integer_t cand1, cand2; - igraph_integer_t last1, last2; + igraph_int_t matched_nodes = 0; + igraph_int_t depth; + igraph_int_t cand1, cand2; + igraph_int_t last1, last2; igraph_stack_int_t path; igraph_lazy_adjlist_t inadj1, inadj2, outadj1, outadj2; igraph_vector_int_t indeg1, indeg2, outdeg1, outdeg2; - igraph_integer_t vsize; + igraph_int_t vsize; IGRAPH_CHECK(igraph_i_perform_vf2_pre_checks(graph1, graph2)); @@ -1152,7 +1131,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( depth = 0; last1 = -1; last2 = -1; while (depth >= 0) { - igraph_integer_t i; + igraph_int_t i; IGRAPH_ALLOW_INTERRUPTION(); @@ -1258,7 +1237,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( vsize = igraph_vector_int_size(inneis_1); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_1)[i]; + igraph_int_t node = VECTOR(*inneis_1)[i]; if (VECTOR(in_1)[node] == depth) { VECTOR(in_1)[node] = 0; in_1_size -= 1; @@ -1270,7 +1249,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( vsize = igraph_vector_int_size(outneis_1); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_1)[i]; + igraph_int_t node = VECTOR(*outneis_1)[i]; if (VECTOR(out_1)[node] == depth) { VECTOR(out_1)[node] = 0; out_1_size -= 1; @@ -1282,7 +1261,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( vsize = igraph_vector_int_size(inneis_2); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_2)[i]; + igraph_int_t node = VECTOR(*inneis_2)[i]; if (VECTOR(in_2)[node] == depth) { VECTOR(in_2)[node] = 0; in_2_size -= 1; @@ -1294,7 +1273,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( vsize = igraph_vector_int_size(outneis_2); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_2)[i]; + igraph_int_t node = VECTOR(*outneis_2)[i]; if (VECTOR(out_2)[node] == depth) { VECTOR(out_2)[node] = 0; out_2_size -= 1; @@ -1308,7 +1287,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( } else { /**************************************************************/ /* step forward if worth, check if worth first */ - igraph_integer_t xin1 = 0, xin2 = 0, xout1 = 0, xout2 = 0; + igraph_int_t xin1 = 0, xin2 = 0, xout1 = 0, xout2 = 0; igraph_bool_t end = false; inneis_1 = igraph_lazy_adjlist_get(&inadj1, cand1); @@ -1333,7 +1312,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( vsize = igraph_vector_int_size(inneis_1); for (i = 0; !end && i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_1)[i]; + igraph_int_t node = VECTOR(*inneis_1)[i]; if (VECTOR(*core_1)[node] < 0) { if (VECTOR(in_1)[node] != 0) { xin1++; @@ -1345,7 +1324,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( } vsize = igraph_vector_int_size(outneis_1); for (i = 0; !end && i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_1)[i]; + igraph_int_t node = VECTOR(*outneis_1)[i]; if (VECTOR(*core_1)[node] < 0) { if (VECTOR(in_1)[node] != 0) { xin1++; @@ -1357,14 +1336,14 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( } vsize = igraph_vector_int_size(inneis_2); for (i = 0; !end && i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_2)[i]; + igraph_int_t node = VECTOR(*inneis_2)[i]; if (VECTOR(*core_2)[node] >= 0) { - igraph_integer_t node2 = VECTOR(*core_2)[node]; + igraph_int_t node2 = VECTOR(*core_2)[node]; /* check if there is a node2->cand1 edge */ if (!igraph_vector_int_contains_sorted(inneis_1, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { - igraph_integer_t eid1, eid2; + igraph_int_t eid1, eid2; igraph_get_eid(graph1, &eid1, node2, cand1, IGRAPH_DIRECTED, /*error=*/ true); igraph_get_eid(graph2, &eid2, node, cand2, IGRAPH_DIRECTED, @@ -1389,14 +1368,14 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( } vsize = igraph_vector_int_size(outneis_2); for (i = 0; !end && i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_2)[i]; + igraph_int_t node = VECTOR(*outneis_2)[i]; if (VECTOR(*core_2)[node] >= 0) { - igraph_integer_t node2 = VECTOR(*core_2)[node]; + igraph_int_t node2 = VECTOR(*core_2)[node]; /* check if there is a cand1->node2 edge */ if (!igraph_vector_int_contains_sorted(outneis_1, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { - igraph_integer_t eid1, eid2; + igraph_int_t eid1, eid2; igraph_get_eid(graph1, &eid1, cand1, node2, IGRAPH_DIRECTED, /*error=*/ true); igraph_get_eid(graph2, &eid2, cand2, node, IGRAPH_DIRECTED, @@ -1448,7 +1427,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( vsize = igraph_vector_int_size(inneis_1); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_1)[i]; + igraph_int_t node = VECTOR(*inneis_1)[i]; if (VECTOR(in_1)[node] == 0 && VECTOR(*core_1)[node] < 0) { VECTOR(in_1)[node] = depth; in_1_size += 1; @@ -1460,7 +1439,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( vsize = igraph_vector_int_size(outneis_1); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_1)[i]; + igraph_int_t node = VECTOR(*outneis_1)[i]; if (VECTOR(out_1)[node] == 0 && VECTOR(*core_1)[node] < 0) { VECTOR(out_1)[node] = depth; out_1_size += 1; @@ -1472,7 +1451,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( vsize = igraph_vector_int_size(inneis_2); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*inneis_2)[i]; + igraph_int_t node = VECTOR(*inneis_2)[i]; if (VECTOR(in_2)[node] == 0 && VECTOR(*core_2)[node] < 0) { VECTOR(in_2)[node] = depth; in_2_size += 1; @@ -1484,7 +1463,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( vsize = igraph_vector_int_size(outneis_2); for (i = 0; i < vsize; i++) { - igraph_integer_t node = VECTOR(*outneis_2)[i]; + igraph_int_t node = VECTOR(*outneis_2)[i]; if (VECTOR(out_2)[node] == 0 && VECTOR(*core_2)[node] < 0) { VECTOR(out_2)[node] = depth; out_2_size += 1; @@ -1545,26 +1524,6 @@ static igraph_error_t igraph_i_subisomorphic_vf2_cb( return IGRAPH_STOP; } -/** - * \function igraph_subisomorphic_function_vf2 - * \brief Generic VF2 function for subgraph isomorphism problems (deprecated alias). - * - * \deprecated-by igraph_get_subisomorphisms_vf2_callback 0.10.0 - */ -igraph_error_t igraph_subisomorphic_function_vf2( - const igraph_t *graph1, const igraph_t *graph2, - const igraph_vector_int_t *vertex_color1, const igraph_vector_int_t *vertex_color2, - const igraph_vector_int_t *edge_color1, const igraph_vector_int_t *edge_color2, - igraph_vector_int_t *map12, igraph_vector_int_t *map21, - igraph_isohandler_t *isohandler_fn, igraph_isocompat_t *node_compat_fn, - igraph_isocompat_t *edge_compat_fn, void *arg -) { - return igraph_get_subisomorphisms_vf2_callback( - graph1, graph2, vertex_color1, vertex_color2, edge_color1, edge_color2, - map12, map21, isohandler_fn, node_compat_fn, edge_compat_fn, arg - ); -} - /** * \function igraph_subisomorphic_vf2 * Decide subgraph isomorphism using VF2 @@ -1646,7 +1605,7 @@ static igraph_error_t igraph_i_count_subisomorphisms_vf2_cb( void *arg ) { igraph_i_iso_cb_data_t *data = arg; - igraph_integer_t *count = data->arg; + igraph_int_t *count = data->arg; IGRAPH_UNUSED(map12); IGRAPH_UNUSED(map21); *count += 1; return IGRAPH_SUCCESS; @@ -1695,7 +1654,7 @@ igraph_error_t igraph_count_subisomorphisms_vf2(const igraph_t *graph1, const ig const igraph_vector_int_t *vertex_color2, const igraph_vector_int_t *edge_color1, const igraph_vector_int_t *edge_color2, - igraph_integer_t *count, + igraph_int_t *count, igraph_isocompat_t *node_compat_fn, igraph_isocompat_t *edge_compat_fn, void *arg) { diff --git a/src/vendor/cigraph/src/layout/align.c b/src/vendor/cigraph/src/layout/align.c index 0888a9b63f5..7496b68a545 100644 --- a/src/vendor/cigraph/src/layout/align.c +++ b/src/vendor/cigraph/src/layout/align.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2025 The igraph development team This program is free software; you can redistribute it and/or modify @@ -30,8 +30,6 @@ * \function igraph_layout_align * \brief Aligns a graph layout with the coordinate axes. * - * \experimental - * * This function centers a vertex layout on the coordinate system origin and * rotates the layout to achieve a visually pleasing alignment with the coordinate * axes. Doing this is particularly useful with force-directed layouts such as @@ -47,9 +45,9 @@ */ igraph_error_t igraph_layout_align(const igraph_t *graph, igraph_matrix_t *layout) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); - const igraph_integer_t dim = igraph_matrix_ncol(layout); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); + const igraph_int_t dim = igraph_matrix_ncol(layout); igraph_matrix_t M, Q; /* nematic tensor */ igraph_real_t norm2_sum; /* sum of squared norms of alignment vectors */ igraph_matrix_t R; /* rotation matrix consisting of Q's eigenvectors */ @@ -114,8 +112,8 @@ igraph_error_t igraph_layout_align(const igraph_t *graph, igraph_matrix_t *layou IGRAPH_CHECK(igraph_matrix_colsum(layout, ¢er)); igraph_vector_scale(¢er, 1.0 / vcount); - for (igraph_integer_t j=0; j < dim; j++) { - for (igraph_integer_t i=0; i < vcount; i++) { + for (igraph_int_t j=0; j < dim; j++) { + for (igraph_int_t i=0; i < vcount; i++) { MATRIX(*layout, i, j) -= VECTOR(center)[j]; } } @@ -138,18 +136,18 @@ igraph_error_t igraph_layout_align(const igraph_t *graph, igraph_matrix_t *layou IGRAPH_VECTOR_INIT_FINALLY(&edge_vec, dim); norm2_sum = 0; - for (igraph_integer_t eid=0; eid < ecount; eid++) { - const igraph_integer_t from = IGRAPH_FROM(graph, eid); - const igraph_integer_t to = IGRAPH_TO(graph, eid); + for (igraph_int_t eid=0; eid < ecount; eid++) { + const igraph_int_t from = IGRAPH_FROM(graph, eid); + const igraph_int_t to = IGRAPH_TO(graph, eid); if (from == to) continue; /* skip self-loops */ - for (igraph_integer_t i=0; i < dim; i++) { + for (igraph_int_t i=0; i < dim; i++) { VECTOR(edge_vec)[i] = MATRIX(*layout, from, i) - MATRIX(*layout, to, i); } - for (igraph_integer_t i=0; i < dim; i++) { - for (igraph_integer_t j=0; j < dim; j++) { + for (igraph_int_t i=0; i < dim; i++) { + for (igraph_int_t j=0; j < dim; j++) { igraph_real_t m = VECTOR(edge_vec)[i] * VECTOR(edge_vec)[j]; MATRIX(M, i, j) += m; if (i == j) { @@ -178,9 +176,9 @@ igraph_error_t igraph_layout_align(const igraph_t *graph, igraph_matrix_t *layou * to compute M_ij. Note that the layout has already been centered. */ if (norm2_sum == 0) { /* If norm2_sum == 0 then M is also all-zero, no need to null it explicitly. */ - for (igraph_integer_t vid=0; vid < vcount; vid++) { - for (igraph_integer_t i=0; i < dim; i++) { - for (igraph_integer_t j=0; j < dim; j++) { + for (igraph_int_t vid=0; vid < vcount; vid++) { + for (igraph_int_t i=0; i < dim; i++) { + for (igraph_int_t j=0; j < dim; j++) { igraph_real_t m = MATRIX(*layout, vid, i) * MATRIX(*layout, vid, j); MATRIX(M, i, j) += m; if (i == j) { @@ -218,7 +216,7 @@ igraph_error_t igraph_layout_align(const igraph_t *graph, igraph_matrix_t *layou * Q_ij = M_ij / norm2 - delta_ij / d. */ IGRAPH_CHECK(igraph_matrix_update(&Q, &M)); igraph_matrix_scale(&Q, 1.0 / norm2_sum); - for (igraph_integer_t i=0; i < dim; i++) { + for (igraph_int_t i=0; i < dim; i++) { MATRIX(Q, i, i) -= 1.0 / dim; } @@ -239,7 +237,7 @@ igraph_error_t igraph_layout_align(const igraph_t *graph, igraph_matrix_t *layou /* Compute the matrix norm, i.e. the largest eigenvalue magnitude, * to determine if the nematic tensor Q is close to zero. */ igraph_real_t matrix_norm = 0; - for (igraph_integer_t i=0; i < dim; i++) { + for (igraph_int_t i=0; i < dim; i++) { igraph_real_t magnitude = fabs(VECTOR(lambda)[i]); if (magnitude > matrix_norm) { matrix_norm = magnitude; @@ -285,9 +283,9 @@ igraph_error_t igraph_layout_align(const igraph_t *graph, igraph_matrix_t *layou IGRAPH_VECTOR_INIT_FINALLY(&extent, dim); IGRAPH_VECTOR_INT_INIT_FINALLY(&permutation, dim); - for (igraph_integer_t j=0; j < dim; j++) { + for (igraph_int_t j=0; j < dim; j++) { igraph_real_t min = IGRAPH_INFINITY, max = -IGRAPH_INFINITY; - for (igraph_integer_t i=0; i < vcount; i++) { + for (igraph_int_t i=0; i < vcount; i++) { igraph_real_t c = MATRIX(temp_layout, i, j); if (c < min) min = c; if (c > max) max = c; @@ -296,8 +294,8 @@ igraph_error_t igraph_layout_align(const igraph_t *graph, igraph_matrix_t *layou } IGRAPH_CHECK(igraph_vector_sort_ind(&extent, &permutation, IGRAPH_DESCENDING)); - for (igraph_integer_t j=0; j < dim; j++) { - for (igraph_integer_t i=0; i < vcount; i++) { + for (igraph_int_t j=0; j < dim; j++) { + for (igraph_int_t i=0; i < vcount; i++) { MATRIX(*layout, i, j) = MATRIX(temp_layout, i, VECTOR(permutation)[j]); } } diff --git a/src/vendor/cigraph/src/layout/circular.c b/src/vendor/cigraph/src/layout/circular.c index ed1bad318ca..5a474de8579 100644 --- a/src/vendor/cigraph/src/layout/circular.c +++ b/src/vendor/cigraph/src/layout/circular.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -47,8 +45,8 @@ igraph_error_t igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res, igraph_vs_t order) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t vs_size; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t vs_size; igraph_vit_t vit; IGRAPH_CHECK(igraph_vs_size(graph, &order, &vs_size)); @@ -57,9 +55,9 @@ igraph_error_t igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res, igraph_matrix_null(res); IGRAPH_CHECK(igraph_vit_create(graph, order, &vit)); - for (igraph_integer_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { + for (igraph_int_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { igraph_real_t phi = 2 * M_PI / vs_size * i; - igraph_integer_t idx = IGRAPH_VIT_GET(vit); + igraph_int_t idx = IGRAPH_VIT_GET(vit); MATRIX(*res, idx, 0) = cos(phi); MATRIX(*res, idx, 1) = sin(phi); } @@ -89,9 +87,9 @@ igraph_error_t igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res, * \sa \ref igraph_layout_circle() and other layout generators. */ igraph_error_t igraph_layout_star(const igraph_t *graph, igraph_matrix_t *res, - igraph_integer_t center, const igraph_vector_int_t *order) { + igraph_int_t center, const igraph_vector_int_t *order) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); if (no_of_nodes > 0 && (center < 0 || center >= no_of_nodes)) { IGRAPH_ERROR("The given center is not a vertex of the graph.", IGRAPH_EINVAL); @@ -106,8 +104,8 @@ igraph_error_t igraph_layout_star(const igraph_t *graph, igraph_matrix_t *res, MATRIX(*res, 0, 0) = MATRIX(*res, 0, 1) = 0.0; } else if (no_of_nodes > 1) { igraph_real_t phi = 0.0; - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t node = order ? VECTOR(*order)[i] : i; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t node = order ? VECTOR(*order)[i] : i; if (order && (node < 0 || node >= no_of_nodes)) { IGRAPH_ERROR("Elements in the order vector are not all vertices of the graph.", IGRAPH_EINVAL); } @@ -152,13 +150,13 @@ igraph_error_t igraph_layout_star(const igraph_t *graph, igraph_matrix_t *res, */ igraph_error_t igraph_layout_sphere(const igraph_t *graph, igraph_matrix_t *res) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); const igraph_real_t sqrt_no_of_nodes = sqrt(no_of_nodes); IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 3)); igraph_real_t phi = 0; - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { igraph_real_t r, z; /* The first and last point are handled separately to avoid diff --git a/src/vendor/cigraph/src/layout/davidson_harel.c b/src/vendor/cigraph/src/layout/davidson_harel.c index 551d29202df..2b24b06cac3 100644 --- a/src/vendor/cigraph/src/layout/davidson_harel.c +++ b/src/vendor/cigraph/src/layout/davidson_harel.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -27,7 +25,7 @@ #include "igraph_random.h" #include "core/interruption.h" -#include "core/math.h" +#include "core/math.h" /* M_PI */ #include "layout/layout_internal.h" #include @@ -141,15 +139,15 @@ igraph_real_t igraph_i_layout_point_segment_dist2(igraph_real_t v_x, igraph_real */ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix_t *res, - igraph_bool_t use_seed, igraph_integer_t maxiter, - igraph_integer_t fineiter, igraph_real_t cool_fact, + igraph_bool_t use_seed, igraph_int_t maxiter, + igraph_int_t fineiter, igraph_real_t cool_fact, igraph_real_t weight_node_dist, igraph_real_t weight_border, igraph_real_t weight_edge_lengths, igraph_real_t weight_edge_crossings, igraph_real_t weight_node_edge_dist) { - igraph_integer_t no_nodes = igraph_vcount(graph); - igraph_integer_t no_edges = igraph_ecount(graph); + igraph_int_t no_nodes = igraph_vcount(graph); + igraph_int_t no_edges = igraph_ecount(graph); igraph_real_t width = sqrt(no_nodes) * 10, height = width; igraph_vector_int_t perm; igraph_bool_t fine_tuning = false; @@ -160,7 +158,7 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix igraph_vector_int_t neis; igraph_real_t min_x = width / 2, max_x = -width / 2, min_y = height / 2, max_y = -height / 2; - igraph_integer_t no_tries = 30; + igraph_int_t no_tries = 30; igraph_real_t w_node_dist = weight_node_dist ; /* 1.0 */ igraph_real_t w_borderlines = weight_border; /* 0.0 */ igraph_real_t w_edge_lengths = weight_edge_lengths; /* 0.0001; */ @@ -197,10 +195,8 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix IGRAPH_FINALLY(igraph_vector_int_destroy, &try_idx); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 100); - RNG_BEGIN(); - if (!use_seed) { - for (igraph_integer_t i = 0; i < no_nodes; i++) { + for (igraph_int_t i = 0; i < no_nodes; i++) { igraph_real_t x, y; x = MATRIX(*res, i, 0) = RNG_UNIF(-width / 2, width / 2); y = MATRIX(*res, i, 1) = RNG_UNIF(-height / 2, height / 2); @@ -218,7 +214,7 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix } else { min_x = IGRAPH_INFINITY; max_x = -IGRAPH_INFINITY; min_y = IGRAPH_INFINITY; max_y = -IGRAPH_INFINITY; - for (igraph_integer_t i = 0; i < no_nodes; i++) { + for (igraph_int_t i = 0; i < no_nodes; i++) { igraph_real_t x = MATRIX(*res, i, 0); igraph_real_t y = MATRIX(*res, i, 1); if (x < min_x) { @@ -234,13 +230,13 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix } } - for (igraph_integer_t i = 0; i < no_tries; i++) { + for (igraph_int_t i = 0; i < no_tries; i++) { double phi = 2 * M_PI / no_tries * i; VECTOR(try_x)[i] = cos(phi); VECTOR(try_y)[i] = sin(phi); } - for (igraph_integer_t round = 0; round < maxiter + fineiter; round++) { + for (igraph_int_t round = 0; round < maxiter + fineiter; round++) { IGRAPH_ALLOW_INTERRUPTION(); igraph_vector_int_shuffle(&perm); @@ -252,13 +248,13 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix move_radius = fx < fy ? fx : fy; } - for (igraph_integer_t p = 0; p < no_nodes; p++) { - igraph_integer_t v = VECTOR(perm)[p]; + for (igraph_int_t p = 0; p < no_nodes; p++) { + igraph_int_t v = VECTOR(perm)[p]; igraph_vector_int_shuffle(&try_idx); - for (igraph_integer_t t = 0; t < no_tries; t++) { + for (igraph_int_t t = 0; t < no_tries; t++) { igraph_real_t diff_energy = 0.0; - igraph_integer_t ti = VECTOR(try_idx)[t]; + igraph_int_t ti = VECTOR(try_idx)[t]; /* Try moving it */ igraph_real_t old_x = MATRIX(*res, v, 0); @@ -280,7 +276,7 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix } if (w_node_dist != 0) { - for (igraph_integer_t u = 0; u < no_nodes; u++) { + for (igraph_int_t u = 0; u < no_nodes; u++) { igraph_real_t odx, ody, odist2, dx, dy, dist2; if (u == v) { continue; @@ -329,10 +325,12 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix } if (w_edge_lengths != 0) { - IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, IGRAPH_ALL)); - igraph_integer_t len = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < len; j++) { - igraph_integer_t u = VECTOR(neis)[j]; + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, v, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); + igraph_int_t len = igraph_vector_int_size(&neis); + for (igraph_int_t j = 0; j < len; j++) { + igraph_int_t u = VECTOR(neis)[j]; igraph_real_t odx = old_x - MATRIX(*res, u, 0); igraph_real_t ody = old_y - MATRIX(*res, u, 1); igraph_real_t odist2 = odx * odx + ody * ody; @@ -344,18 +342,20 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix } if (w_edge_crossings != 0) { - igraph_integer_t no = 0; - - IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, IGRAPH_ALL)); - igraph_integer_t len = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < len; j++) { - igraph_integer_t u = VECTOR(neis)[j]; + igraph_int_t no = 0; + + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, v, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); + igraph_int_t len = igraph_vector_int_size(&neis); + for (igraph_int_t j = 0; j < len; j++) { + igraph_int_t u = VECTOR(neis)[j]; igraph_real_t u_x = MATRIX(*res, u, 0); igraph_real_t u_y = MATRIX(*res, u, 1); - igraph_integer_t e; + igraph_int_t e; for (e = 0; e < no_edges; e++) { - igraph_integer_t u1 = IGRAPH_FROM(graph, e); - igraph_integer_t u2 = IGRAPH_TO(graph, e); + igraph_int_t u1 = IGRAPH_FROM(graph, e); + igraph_int_t u2 = IGRAPH_TO(graph, e); igraph_real_t u1_x, u1_y, u2_x, u2_y; if (u1 == v || u2 == v || u1 == u || u2 == u) { continue; @@ -375,9 +375,9 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix if (w_node_edge_dist != 0 && fine_tuning) { /* All non-incident edges from the moved 'v' */ - for (igraph_integer_t e = 0; e < no_edges; e++) { - igraph_integer_t u1 = IGRAPH_FROM(graph, e); - igraph_integer_t u2 = IGRAPH_TO(graph, e); + for (igraph_int_t e = 0; e < no_edges; e++) { + igraph_int_t u1 = IGRAPH_FROM(graph, e); + igraph_int_t u2 = IGRAPH_TO(graph, e); igraph_real_t u1_x, u1_y, u2_x, u2_y, d_ev; if (u1 == v || u2 == v) { continue; @@ -395,14 +395,14 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix } /* All other nodes from all of v's incident edges */ - IGRAPH_CHECK(igraph_incident(graph, &neis, v, IGRAPH_ALL)); - igraph_integer_t no = igraph_vector_int_size(&neis); - for (igraph_integer_t e = 0; e < no; e++) { - igraph_integer_t mye = VECTOR(neis)[e]; - igraph_integer_t u = IGRAPH_OTHER(graph, mye, v); + IGRAPH_CHECK(igraph_incident(graph, &neis, v, IGRAPH_ALL, IGRAPH_NO_LOOPS)); + igraph_int_t no = igraph_vector_int_size(&neis); + for (igraph_int_t e = 0; e < no; e++) { + igraph_int_t mye = VECTOR(neis)[e]; + igraph_int_t u = IGRAPH_OTHER(graph, mye, v); igraph_real_t u_x = MATRIX(*res, u, 0); igraph_real_t u_y = MATRIX(*res, u, 1); - for (igraph_integer_t w = 0; w < no_nodes; w++) { + for (igraph_int_t w = 0; w < no_nodes; w++) { igraph_real_t w_x, w_y, d_ev; if (w == v || w == u) { continue; @@ -443,8 +443,6 @@ igraph_error_t igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix } /* round < maxiter */ - RNG_END(); - igraph_vector_int_destroy(&neis); igraph_vector_int_destroy(&try_idx); igraph_vector_destroy(&try_x); diff --git a/src/vendor/cigraph/src/layout/drl/drl_Node.h b/src/vendor/cigraph/src/layout/drl/drl_Node.h index 387bbb293c8..f7a6cceb01c 100644 --- a/src/vendor/cigraph/src/layout/drl/drl_Node.h +++ b/src/vendor/cigraph/src/layout/drl/drl_Node.h @@ -48,7 +48,7 @@ class Node { public: bool fixed; // if true do not change the - igraph_integer_t id; + igraph_int_t id; // position of this node float x, y; @@ -57,7 +57,7 @@ class Node { public: - Node( igraph_integer_t node_id ) { + Node( igraph_int_t node_id ) { x = y = 0.0; fixed = false; id = node_id; } diff --git a/src/vendor/cigraph/src/layout/drl/drl_Node_3d.h b/src/vendor/cigraph/src/layout/drl/drl_Node_3d.h index 250e934a366..4be0eab9b46 100644 --- a/src/vendor/cigraph/src/layout/drl/drl_Node_3d.h +++ b/src/vendor/cigraph/src/layout/drl/drl_Node_3d.h @@ -48,7 +48,7 @@ class Node { public: bool fixed; // if true do not change the - igraph_integer_t id; + igraph_int_t id; // position of this node float x, y, z; @@ -57,7 +57,7 @@ class Node { public: - Node( igraph_integer_t node_id ) { + Node( igraph_int_t node_id ) { x = y = z = 0.0; fixed = false; id = node_id; } diff --git a/src/vendor/cigraph/src/layout/drl/drl_graph.cpp b/src/vendor/cigraph/src/layout/drl/drl_graph.cpp index 1707163cdde..64028a6fc63 100644 --- a/src/vendor/cigraph/src/layout/drl/drl_graph.cpp +++ b/src/vendor/cigraph/src/layout/drl/drl_graph.cpp @@ -172,11 +172,11 @@ graph::graph(const igraph_t *igraph, // scan .int file for node info highest_sim = 1.0; num_nodes = igraph_vcount(igraph); - igraph_integer_t no_of_edges = igraph_ecount(igraph); - for (igraph_integer_t i = 0; i < num_nodes; i++) { + igraph_int_t no_of_edges = igraph_ecount(igraph); + for (igraph_int_t i = 0; i < num_nodes; i++) { id_catalog[i] = 1; } - map::iterator cat_iter; + map::iterator cat_iter; for ( cat_iter = id_catalog.begin(); cat_iter != id_catalog.end(); cat_iter++) { cat_iter->second = cat_iter->first; @@ -191,9 +191,9 @@ graph::graph(const igraph_t *igraph, } // read .int file for graph info - igraph_integer_t node_1, node_2; + igraph_int_t node_1, node_2; igraph_real_t weight; - for (igraph_integer_t i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { node_1 = IGRAPH_FROM(igraph, i); node_2 = IGRAPH_TO(igraph, i); weight = weights ? VECTOR(*weights)[i] : 1.0 ; @@ -392,17 +392,17 @@ void graph::init_parms ( int rand_seed, float edge_cut, float real_parm ) { cut_rate = ( cut_length_start - cut_length_end ) / 400.0; // finally set the number of iterations to leave .real coords fixed - igraph_integer_t full_comp_iters; + igraph_int_t full_comp_iters; full_comp_iters = liquid.iterations + expansion.iterations + cooldown.iterations + crunch.iterations + 3; // adjust real parm to iterations (do not enter simmer halfway) if ( real_parm < 0 ) { - real_iterations = (igraph_integer_t)real_parm; + real_iterations = (igraph_int_t)real_parm; } else if ( real_parm == 1) { real_iterations = full_comp_iters + simmer.iterations + 100; } else { - real_iterations = (igraph_integer_t)(real_parm * full_comp_iters); + real_iterations = (igraph_int_t)(real_parm * full_comp_iters); } tot_iterations = 0; @@ -486,8 +486,8 @@ void graph::init_parms(const igraph_layout_drl_options_t *options) { // } int graph::read_real(const igraph_matrix_t *real_mat) { - igraph_integer_t n = igraph_matrix_nrow(real_mat); - for (igraph_integer_t i = 0; i < n; i++) { + igraph_int_t n = igraph_matrix_nrow(real_mat); + for (igraph_int_t i = 0; i < n; i++) { positions[id_catalog[i]].x = MATRIX(*real_mat, i, 0); positions[id_catalog[i]].y = MATRIX(*real_mat, i, 1); positions[id_catalog[i]].fixed = false; @@ -815,7 +815,7 @@ int graph::ReCompute( ) { void graph::update_nodes ( ) { - vector node_indices; // node list of nodes currently being updated + vector node_indices; // node list of nodes currently being updated float old_positions[2 * MAX_PROCS]; // positions before update float new_positions[2 * MAX_PROCS]; // positions after update @@ -828,9 +828,9 @@ void graph::update_nodes ( ) { // next we calculate the number of nodes there would be if the // num_nodes by num_procs schedule grid were perfectly square - igraph_integer_t square_num_nodes = (igraph_integer_t)(num_procs + num_procs * floor ((float)(num_nodes - 1) / (float)num_procs )); + igraph_int_t square_num_nodes = (igraph_int_t)(num_procs + num_procs * floor ((float)(num_nodes - 1) / (float)num_procs )); - for ( igraph_integer_t i = myid; i < square_num_nodes; i += num_procs ) { + for ( igraph_int_t i = myid; i < square_num_nodes; i += num_procs ) { // get old positions get_positions ( node_indices, old_positions ); @@ -890,7 +890,7 @@ void graph::update_nodes ( ) { // The get_positions function takes the node_indices list // and returns the corresponding positions in an array. -void graph::get_positions ( vector &node_indices, +void graph::get_positions ( vector &node_indices, float return_positions[2 * MAX_PROCS] ) { // fill positions @@ -906,7 +906,7 @@ void graph::get_positions ( vector &node_indices, // of active processes at this level for use by the random number // generators. -void graph::update_node_pos ( igraph_integer_t node_ind, +void graph::update_node_pos ( igraph_int_t node_ind, float old_positions[2 * MAX_PROCS], float new_positions[2 * MAX_PROCS] ) { @@ -978,7 +978,7 @@ void graph::update_node_pos ( igraph_integer_t node_ind, // updates the positions by subtracting the old positions and adding the // new positions to the density grid. -void graph::update_density ( vector &node_indices, +void graph::update_density ( vector &node_indices, float old_positions[2 * MAX_PROCS], float new_positions[2 * MAX_PROCS] ) { @@ -1004,13 +1004,13 @@ void graph::update_density ( vector &node_indices, * original code by B. Wylie. * *********************************************/ -float graph::Compute_Node_Energy( igraph_integer_t node_ind ) { +float graph::Compute_Node_Energy( igraph_int_t node_ind ) { /* Want to expand 4th power range of attraction */ float attraction_factor = attraction * attraction * attraction * attraction * 2e-2; - map ::iterator EI; + map ::iterator EI; float x_dis, y_dis; float energy_distance, weight; float node_energy = 0; @@ -1061,9 +1061,9 @@ float graph::Compute_Node_Energy( igraph_integer_t node_ind ) { * originally written by B. Wylie * *********************************************/ -void graph::Solve_Analytic( igraph_integer_t node_ind, float &pos_x, float &pos_y ) { +void graph::Solve_Analytic( igraph_int_t node_ind, float &pos_x, float &pos_y ) { - map ::iterator EI; + map ::iterator EI; float total_weight = 0; float x_dis, y_dis, x_cen = 0, y_cen = 0; float x = 0, y = 0, dis; @@ -1104,7 +1104,7 @@ void graph::Solve_Analytic( igraph_integer_t node_ind, float &pos_x, float &pos_ float num_connections = sqrt((double)neighbors[node_ind].size()); float maxLength = 0; - map::iterator maxIndex; + map::iterator maxIndex; // Go through nodes edges... cutting if necessary for (EI = maxIndex = neighbors[node_ind].begin(); @@ -1258,9 +1258,9 @@ igraph_error_t graph::draw_graph(igraph_matrix_t *res) { while (ReCompute()) { IGRAPH_ALLOW_INTERRUPTION(); } - igraph_integer_t n = positions.size(); + igraph_int_t n = positions.size(); IGRAPH_CHECK(igraph_matrix_resize(res, n, 2)); - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { MATRIX(*res, i, 0) = positions[i].x; MATRIX(*res, i, 1) = positions[i].y; } diff --git a/src/vendor/cigraph/src/layout/drl/drl_graph.h b/src/vendor/cigraph/src/layout/drl/drl_graph.h index 3fc68337950..0ff95b5485c 100644 --- a/src/vendor/cigraph/src/layout/drl/drl_graph.h +++ b/src/vendor/cigraph/src/layout/drl/drl_graph.h @@ -45,7 +45,7 @@ namespace drl { // layout schedule information struct layout_schedule { - igraph_integer_t iterations; + igraph_int_t iterations; float temperature; float attraction; float damping_mult; @@ -82,13 +82,13 @@ class graph { // Methods int ReCompute ( ); void update_nodes ( ); - float Compute_Node_Energy ( igraph_integer_t node_ind ); - void Solve_Analytic ( igraph_integer_t node_ind, float &pos_x, float &pos_y ); - void get_positions ( std::vector &node_indices, float return_positions[2 * MAX_PROCS] ); - void update_density ( std::vector &node_indices, + float Compute_Node_Energy ( igraph_int_t node_ind ); + void Solve_Analytic ( igraph_int_t node_ind, float &pos_x, float &pos_y ); + void get_positions ( std::vector &node_indices, float return_positions[2 * MAX_PROCS] ); + void update_density ( std::vector &node_indices, float old_positions[2 * MAX_PROCS], float new_positions[2 * MAX_PROCS] ); - void update_node_pos ( igraph_integer_t node_ind, + void update_node_pos ( igraph_int_t node_ind, float old_positions[2 * MAX_PROCS], float new_positions[2 * MAX_PROCS] ); @@ -96,10 +96,10 @@ class graph { int myid, num_procs; // graph decomposition information - igraph_integer_t num_nodes; // number of nodes in graph + igraph_int_t num_nodes; // number of nodes in graph float highest_sim; // highest sim for normalization - std::map id_catalog; // id_catalog[file id] = internal id - std::map > neighbors; // neighbors of nodes on this proc. + std::map id_catalog; // id_catalog[file id] = internal id + std::map > neighbors; // neighbors of nodes on this proc. // graph layout information std::vector positions; @@ -107,7 +107,7 @@ class graph { // original VxOrd information int STAGE; - igraph_integer_t iterations; + igraph_int_t iterations; float temperature, attraction, damping_mult; float min_edges, CUT_END, cut_length_end, cut_off_length, cut_rate; bool first_add, fine_first_add, fineDensity; @@ -123,9 +123,9 @@ class graph { time_t start_time, stop_time; // online clustering information - igraph_integer_t real_iterations; // number of iterations to hold .real input fixed - igraph_integer_t tot_iterations; - igraph_integer_t tot_expected_iterations; // for progress bar + igraph_int_t real_iterations; // number of iterations to hold .real input fixed + igraph_int_t tot_iterations; + igraph_int_t tot_expected_iterations; // for progress bar bool real_fixed; }; diff --git a/src/vendor/cigraph/src/layout/drl/drl_graph_3d.cpp b/src/vendor/cigraph/src/layout/drl/drl_graph_3d.cpp index b64fd957c5b..0600fc532e6 100644 --- a/src/vendor/cigraph/src/layout/drl/drl_graph_3d.cpp +++ b/src/vendor/cigraph/src/layout/drl/drl_graph_3d.cpp @@ -95,11 +95,11 @@ graph::graph(const igraph_t *igraph, // scan .int file for node info highest_sim = 1.0; num_nodes = igraph_vcount(igraph); - igraph_integer_t no_of_edges = igraph_ecount(igraph); - for (igraph_integer_t i = 0; i < num_nodes; i++) { + igraph_int_t no_of_edges = igraph_ecount(igraph); + for (igraph_int_t i = 0; i < num_nodes; i++) { id_catalog[i] = 1; } - map< igraph_integer_t, igraph_integer_t>::iterator cat_iter; + map< igraph_int_t, igraph_int_t>::iterator cat_iter; for ( cat_iter = id_catalog.begin(); cat_iter != id_catalog.end(); cat_iter++) { cat_iter->second = cat_iter->first; @@ -114,9 +114,9 @@ graph::graph(const igraph_t *igraph, } // read .int file for graph info - igraph_integer_t node_1, node_2; + igraph_int_t node_1, node_2; igraph_real_t weight; - for (igraph_integer_t i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { node_1 = IGRAPH_FROM(igraph, i); node_2 = IGRAPH_TO(igraph, i); weight = weights ? VECTOR(*weights)[i] : 1.0 ; @@ -153,7 +153,7 @@ void graph::init_parms ( int rand_seed, float edge_cut, float real_parm ) { cut_rate = ( cut_length_start - cut_length_end ) / 400.0; // finally set the number of iterations to leave .real coords fixed - igraph_integer_t full_comp_iters; + igraph_int_t full_comp_iters; full_comp_iters = liquid.iterations + expansion.iterations + cooldown.iterations + crunch.iterations + 3; @@ -198,8 +198,8 @@ void graph::init_parms(const igraph_layout_drl_options_t *options) { } int graph::read_real(const igraph_matrix_t *real_mat) { - igraph_integer_t n = igraph_matrix_nrow(real_mat); - for (igraph_integer_t i = 0; i < n; i++) { + igraph_int_t n = igraph_matrix_nrow(real_mat); + for (igraph_int_t i = 0; i < n; i++) { positions[id_catalog[i]].x = MATRIX(*real_mat, i, 0); positions[id_catalog[i]].y = MATRIX(*real_mat, i, 1); positions[id_catalog[i]].z = MATRIX(*real_mat, i, 2); @@ -466,7 +466,7 @@ int graph::ReCompute( ) { void graph::update_nodes ( ) { - vector node_indices; // node list of nodes currently being updated + vector node_indices; // node list of nodes currently being updated float old_positions[2 * MAX_PROCS]; // positions before update float new_positions[2 * MAX_PROCS]; // positions after update @@ -479,9 +479,9 @@ void graph::update_nodes ( ) { // next we calculate the number of nodes there would be if the // num_nodes by num_procs schedule grid were perfectly square - igraph_integer_t square_num_nodes = (igraph_integer_t)(num_procs + num_procs * floor ((float)(num_nodes - 1) / (float)num_procs )); + igraph_int_t square_num_nodes = (igraph_int_t)(num_procs + num_procs * floor ((float)(num_nodes - 1) / (float)num_procs )); - for ( igraph_integer_t i = myid; i < square_num_nodes; i += num_procs ) { + for ( igraph_int_t i = myid; i < square_num_nodes; i += num_procs ) { // get old positions get_positions ( node_indices, old_positions ); @@ -541,7 +541,7 @@ void graph::update_nodes ( ) { // The get_positions function takes the node_indices list // and returns the corresponding positions in an array. -void graph::get_positions ( vector &node_indices, +void graph::get_positions ( vector &node_indices, float return_positions[3 * MAX_PROCS] ) { // fill positions @@ -558,7 +558,7 @@ void graph::get_positions ( vector &node_indices, // of active processes at this level for use by the random number // generators. -void graph::update_node_pos ( igraph_integer_t node_ind, +void graph::update_node_pos ( igraph_int_t node_ind, float old_positions[3 * MAX_PROCS], float new_positions[3 * MAX_PROCS] ) { @@ -636,7 +636,7 @@ void graph::update_node_pos ( igraph_integer_t node_ind, // updates the positions by subtracting the old positions and adding the // new positions to the density grid. -void graph::update_density ( vector &node_indices, +void graph::update_density ( vector &node_indices, float old_positions[3 * MAX_PROCS], float new_positions[3 * MAX_PROCS] ) { @@ -664,13 +664,13 @@ void graph::update_density ( vector &node_indices, * original code by B. Wylie. * *********************************************/ -float graph::Compute_Node_Energy( igraph_integer_t node_ind ) { +float graph::Compute_Node_Energy( igraph_int_t node_ind ) { /* Want to expand 4th power range of attraction */ float attraction_factor = attraction * attraction * attraction * attraction * 2e-2; - map ::iterator EI; + map ::iterator EI; float x_dis, y_dis, z_dis; float energy_distance, weight; float node_energy = 0; @@ -722,10 +722,10 @@ float graph::Compute_Node_Energy( igraph_integer_t node_ind ) { * originally written by B. Wylie * *********************************************/ -void graph::Solve_Analytic( igraph_integer_t node_ind, float &pos_x, float &pos_y, +void graph::Solve_Analytic( igraph_int_t node_ind, float &pos_x, float &pos_y, float &pos_z) { - map ::iterator EI; + map ::iterator EI; float total_weight = 0; float x_dis, y_dis, z_dis, x_cen = 0, y_cen = 0, z_cen = 0; float x = 0, y = 0, z = 0, dis; @@ -766,7 +766,7 @@ void graph::Solve_Analytic( igraph_integer_t node_ind, float &pos_x, float &pos_ float num_connections = (float)sqrt((float)neighbors[node_ind].size()); float maxLength = 0; - map::iterator maxIndex; + map::iterator maxIndex; // Go through nodes edges... cutting if necessary for (EI = maxIndex = neighbors[node_ind].begin(); diff --git a/src/vendor/cigraph/src/layout/drl/drl_graph_3d.h b/src/vendor/cigraph/src/layout/drl/drl_graph_3d.h index ffaad8e4835..18e7e39124b 100644 --- a/src/vendor/cigraph/src/layout/drl/drl_graph_3d.h +++ b/src/vendor/cigraph/src/layout/drl/drl_graph_3d.h @@ -45,7 +45,7 @@ namespace drl3d { // layout schedule information struct layout_schedule { - igraph_integer_t iterations; + igraph_int_t iterations; float temperature; float attraction; float damping_mult; @@ -74,13 +74,13 @@ class graph { // Methods int ReCompute ( ); void update_nodes ( ); - float Compute_Node_Energy ( igraph_integer_t node_ind ); - void Solve_Analytic ( igraph_integer_t node_ind, float &pos_x, float &pos_y, float &pos_z ); - void get_positions ( std::vector &node_indices, float return_positions[3 * MAX_PROCS] ); - void update_density ( std::vector &node_indices, + float Compute_Node_Energy ( igraph_int_t node_ind ); + void Solve_Analytic ( igraph_int_t node_ind, float &pos_x, float &pos_y, float &pos_z ); + void get_positions ( std::vector &node_indices, float return_positions[3 * MAX_PROCS] ); + void update_density ( std::vector &node_indices, float old_positions[3 * MAX_PROCS], float new_positions[3 * MAX_PROCS] ); - void update_node_pos ( igraph_integer_t node_ind, + void update_node_pos ( igraph_int_t node_ind, float old_positions[3 * MAX_PROCS], float new_positions[3 * MAX_PROCS] ); @@ -88,10 +88,10 @@ class graph { int myid, num_procs; // graph decomposition information - igraph_integer_t num_nodes; // number of nodes in graph + igraph_int_t num_nodes; // number of nodes in graph float highest_sim; // highest sim for normalization - std::map id_catalog; // id_catalog[file id] = internal id - std::map > neighbors; // neighbors of nodes on this proc. + std::map id_catalog; // id_catalog[file id] = internal id + std::map > neighbors; // neighbors of nodes on this proc. // graph layout information std::vector positions; @@ -99,7 +99,7 @@ class graph { // original VxOrd information int STAGE; - igraph_integer_t iterations; + igraph_int_t iterations; float temperature, attraction, damping_mult; float min_edges, CUT_END, cut_length_end, cut_off_length, cut_rate; bool first_add, fine_first_add, fineDensity; @@ -115,9 +115,9 @@ class graph { time_t start_time, stop_time; // online clustering information - igraph_integer_t real_iterations; // number of iterations to hold .real input fixed - igraph_integer_t tot_iterations; - igraph_integer_t tot_expected_iterations; // for progress bar + igraph_int_t real_iterations; // number of iterations to hold .real input fixed + igraph_int_t tot_iterations; + igraph_int_t tot_expected_iterations; // for progress bar bool real_fixed; }; diff --git a/src/vendor/cigraph/src/layout/drl/drl_layout.cpp b/src/vendor/cigraph/src/layout/drl/drl_layout.cpp index 9e15e9d72bd..f998fc6aba9 100644 --- a/src/vendor/cigraph/src/layout/drl/drl_layout.cpp +++ b/src/vendor/cigraph/src/layout/drl/drl_layout.cpp @@ -458,7 +458,7 @@ igraph_error_t igraph_layout_drl(const igraph_t *graph, igraph_matrix_t *res, } if (weights) { - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); if (igraph_vector_size(weights) != no_of_edges) { IGRAPH_ERROR("Length of weight vector does not match number of edges.", IGRAPH_EINVAL); } @@ -468,8 +468,6 @@ igraph_error_t igraph_layout_drl(const igraph_t *graph, igraph_matrix_t *res, } IGRAPH_HANDLE_EXCEPTIONS( - RNG_BEGIN(); - drl::graph neighbors(graph, options, weights); neighbors.init_parms(options); if (use_seed) { @@ -477,8 +475,6 @@ igraph_error_t igraph_layout_drl(const igraph_t *graph, igraph_matrix_t *res, neighbors.read_real(res); } IGRAPH_CHECK(neighbors.draw_graph(res)); - - RNG_END(); ); return IGRAPH_SUCCESS; diff --git a/src/vendor/cigraph/src/layout/drl/drl_layout_3d.cpp b/src/vendor/cigraph/src/layout/drl/drl_layout_3d.cpp index de2b809845e..3f8008d0b5f 100644 --- a/src/vendor/cigraph/src/layout/drl/drl_layout_3d.cpp +++ b/src/vendor/cigraph/src/layout/drl/drl_layout_3d.cpp @@ -109,7 +109,7 @@ igraph_error_t igraph_layout_drl_3d(const igraph_t *graph, igraph_matrix_t *res, } if (weights) { - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); if (igraph_vector_size(weights) != no_of_edges) { IGRAPH_ERROR("Length of weight vector does not match number of edges.", IGRAPH_EINVAL); } @@ -119,8 +119,6 @@ igraph_error_t igraph_layout_drl_3d(const igraph_t *graph, igraph_matrix_t *res, } IGRAPH_HANDLE_EXCEPTIONS( - RNG_BEGIN(); - drl3d::graph neighbors(graph, options, weights); neighbors.init_parms(options); if (use_seed) { @@ -128,8 +126,6 @@ igraph_error_t igraph_layout_drl_3d(const igraph_t *graph, igraph_matrix_t *res, neighbors.read_real(res); } IGRAPH_CHECK(neighbors.draw_graph(res)); - - RNG_END(); ); return IGRAPH_SUCCESS; diff --git a/src/vendor/cigraph/src/layout/fruchterman_reingold.c b/src/vendor/cigraph/src/layout/fruchterman_reingold.c index 60b38c1b7ce..0b2abfa6a76 100644 --- a/src/vendor/cigraph/src/layout/fruchterman_reingold.c +++ b/src/vendor/cigraph/src/layout/fruchterman_reingold.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2003-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -29,7 +29,7 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, - igraph_integer_t niter, + igraph_int_t niter, igraph_real_t start_temp, const igraph_vector_t *weight, const igraph_vector_t *minx, @@ -37,8 +37,8 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, const igraph_vector_t *miny, const igraph_vector_t *maxy) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_vector_t dispx, dispy; igraph_real_t temp = start_temp; igraph_real_t difftemp = start_temp / niter; @@ -57,8 +57,7 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, IGRAPH_VECTOR_INIT_FINALLY(&dispx, vcount); IGRAPH_VECTOR_INIT_FINALLY(&dispy, vcount); - RNG_BEGIN(); - for (igraph_integer_t i = 0; i < niter; i++) { + for (igraph_int_t i = 0; i < niter; i++) { IGRAPH_ALLOW_INTERRUPTION(); /* calculate repulsive forces, we have a special version @@ -66,8 +65,8 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, igraph_vector_null(&dispx); igraph_vector_null(&dispy); if (conn) { - for (igraph_integer_t v = 0; v < vcount; v++) { - for (igraph_integer_t u = v + 1; u < vcount; u++) { + for (igraph_int_t v = 0; v < vcount; v++) { + for (igraph_int_t u = v + 1; u < vcount; u++) { igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t dlen = dx * dx + dy * dy; @@ -85,8 +84,8 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, } } } else { - for (igraph_integer_t v = 0; v < vcount; v++) { - for (igraph_integer_t u = v + 1; u < vcount; u++) { + for (igraph_int_t v = 0; v < vcount; v++) { + for (igraph_int_t u = v + 1; u < vcount; u++) { igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t dlen, rdlen; @@ -109,10 +108,10 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, } /* calculate attractive forces */ - for (igraph_integer_t e = 0; e < ecount; e++) { + for (igraph_int_t e = 0; e < ecount; e++) { /* each edge is an ordered pair of vertices v and u */ - igraph_integer_t v = IGRAPH_FROM(graph, e); - igraph_integer_t u = IGRAPH_TO(graph, e); + igraph_int_t v = IGRAPH_FROM(graph, e); + igraph_int_t u = IGRAPH_TO(graph, e); igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t w = weight ? VECTOR(*weight)[e] : 1.0; @@ -125,7 +124,7 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, /* limit max displacement to temperature t and prevent from displacement outside frame */ - for (igraph_integer_t v = 0; v < vcount; v++) { + for (igraph_int_t v = 0; v < vcount; v++) { igraph_real_t dx = VECTOR(dispx)[v] + RNG_UNIF(-1e-9, 1e-9); igraph_real_t dy = VECTOR(dispy)[v] + RNG_UNIF(-1e-9, 1e-9); igraph_real_t displen = sqrt(dx * dx + dy * dy); @@ -155,7 +154,6 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, temp -= difftemp; } - RNG_END(); igraph_vector_destroy(&dispx); igraph_vector_destroy(&dispy); @@ -167,13 +165,13 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, static igraph_error_t igraph_layout_i_grid_fr( const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, - igraph_integer_t niter, igraph_real_t start_temp, + igraph_int_t niter, igraph_real_t start_temp, const igraph_vector_t *weight, const igraph_vector_t *minx, const igraph_vector_t *maxx, const igraph_vector_t *miny, const igraph_vector_t *maxy) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); const igraph_real_t width = sqrt(vcount), height = width; igraph_2dgrid_t grid; igraph_vector_t dispx, dispy; @@ -192,16 +190,15 @@ static igraph_error_t igraph_layout_i_grid_fr( IGRAPH_FINALLY(igraph_2dgrid_destroy, &grid); /* place vertices on grid */ - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { igraph_2dgrid_add2(&grid, i); } IGRAPH_VECTOR_INIT_FINALLY(&dispx, vcount); IGRAPH_VECTOR_INIT_FINALLY(&dispy, vcount); - RNG_BEGIN(); - for (igraph_integer_t i = 0; i < niter; i++) { - igraph_integer_t v, u; + for (igraph_int_t i = 0; i < niter; i++) { + igraph_int_t v, u; IGRAPH_ALLOW_INTERRUPTION(); @@ -230,9 +227,9 @@ static igraph_error_t igraph_layout_i_grid_fr( } /* attraction */ - for (igraph_integer_t e = 0; e < ecount; e++) { - igraph_integer_t v = IGRAPH_FROM(graph, e); - igraph_integer_t u = IGRAPH_TO(graph, e); + for (igraph_int_t e = 0; e < ecount; e++) { + igraph_int_t v = IGRAPH_FROM(graph, e); + igraph_int_t u = IGRAPH_TO(graph, e); igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t w = weight ? VECTOR(*weight)[e] : 1.0; @@ -274,7 +271,6 @@ static igraph_error_t igraph_layout_i_grid_fr( temp -= difftemp; } - RNG_END(); igraph_vector_destroy(&dispx); igraph_vector_destroy(&dispy); @@ -357,7 +353,7 @@ static igraph_error_t igraph_layout_i_grid_fr( igraph_error_t igraph_layout_fruchterman_reingold(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, - igraph_integer_t niter, + igraph_int_t niter, igraph_real_t start_temp, igraph_layout_grid_t grid, const igraph_vector_t *weights, @@ -366,8 +362,8 @@ igraph_error_t igraph_layout_fruchterman_reingold(const igraph_t *graph, const igraph_vector_t *miny, const igraph_vector_t *maxy) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); if (niter < 0) { IGRAPH_ERROR("Number of iterations must be non-negative in " @@ -475,7 +471,7 @@ igraph_error_t igraph_layout_fruchterman_reingold(const igraph_t *graph, igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, - igraph_integer_t niter, + igraph_int_t niter, igraph_real_t start_temp, const igraph_vector_t *weights, const igraph_vector_t *minx, @@ -485,8 +481,8 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, const igraph_vector_t *minz, const igraph_vector_t *maxz) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_vector_t dispx, dispy, dispz; igraph_real_t temp = start_temp; igraph_real_t difftemp = start_temp / niter; @@ -552,8 +548,7 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, IGRAPH_VECTOR_INIT_FINALLY(&dispy, vcount); IGRAPH_VECTOR_INIT_FINALLY(&dispz, vcount); - RNG_BEGIN(); - for (igraph_integer_t i = 0; i < niter; i++) { + for (igraph_int_t i = 0; i < niter; i++) { IGRAPH_ALLOW_INTERRUPTION(); /* calculate repulsive forces, we have a special version @@ -562,8 +557,8 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, igraph_vector_null(&dispy); igraph_vector_null(&dispz); if (conn) { - for (igraph_integer_t v = 0; v < vcount; v++) { - for (igraph_integer_t u = v + 1; u < vcount; u++) { + for (igraph_int_t v = 0; v < vcount; v++) { + for (igraph_int_t u = v + 1; u < vcount; u++) { igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t dz = MATRIX(*res, v, 2) - MATRIX(*res, u, 2); @@ -585,8 +580,8 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, } } } else { - for (igraph_integer_t v = 0; v < vcount; v++) { - for (igraph_integer_t u = v + 1; u < vcount; u++) { + for (igraph_int_t v = 0; v < vcount; v++) { + for (igraph_int_t u = v + 1; u < vcount; u++) { igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t dz = MATRIX(*res, v, 2) - MATRIX(*res, u, 2); @@ -613,10 +608,10 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, } /* calculate attractive forces */ - for (igraph_integer_t e = 0; e < ecount; e++) { + for (igraph_int_t e = 0; e < ecount; e++) { /* each edges is an ordered pair of vertices v and u */ - igraph_integer_t v = IGRAPH_FROM(graph, e); - igraph_integer_t u = IGRAPH_TO(graph, e); + igraph_int_t v = IGRAPH_FROM(graph, e); + igraph_int_t u = IGRAPH_TO(graph, e); igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t dz = MATRIX(*res, v, 2) - MATRIX(*res, u, 2); @@ -632,7 +627,7 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, /* limit max displacement to temperature t and prevent from displacement outside frame */ - for (igraph_integer_t v = 0; v < vcount; v++) { + for (igraph_int_t v = 0; v < vcount; v++) { igraph_real_t dx = VECTOR(dispx)[v] + RNG_UNIF(-1e-9, 1e-9); igraph_real_t dy = VECTOR(dispy)[v] + RNG_UNIF(-1e-9, 1e-9); igraph_real_t dz = VECTOR(dispz)[v] + RNG_UNIF(-1e-9, 1e-9); @@ -671,7 +666,6 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, temp -= difftemp; } - RNG_END(); igraph_vector_destroy(&dispx); igraph_vector_destroy(&dispy); diff --git a/src/vendor/cigraph/src/layout/gem.c b/src/vendor/cigraph/src/layout/gem.c index 4526b7ebcb3..866e5c6235a 100644 --- a/src/vendor/cigraph/src/layout/gem.c +++ b/src/vendor/cigraph/src/layout/gem.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -28,7 +26,7 @@ #include "igraph_structural.h" #include "core/interruption.h" -#include "core/math.h" +#include "core/math.h" /* M_PI */ /** * \ingroup layout @@ -67,16 +65,16 @@ */ igraph_error_t igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res, - igraph_bool_t use_seed, igraph_integer_t maxiter, + igraph_bool_t use_seed, igraph_int_t maxiter, igraph_real_t temp_max, igraph_real_t temp_min, igraph_real_t temp_init) { - igraph_integer_t no_nodes = igraph_vcount(graph); + igraph_int_t no_nodes = igraph_vcount(graph); igraph_vector_int_t perm; igraph_vector_t impulse_x, impulse_y, temp, skew_gauge; - igraph_integer_t i; + igraph_int_t i; igraph_real_t temp_global; - igraph_integer_t perm_pointer = 0; + igraph_int_t perm_pointer = 0; igraph_real_t barycenter_x = 0, barycenter_y = 0; igraph_vector_t phi; igraph_vector_int_t neis; @@ -131,8 +129,6 @@ igraph_error_t igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res, IGRAPH_VECTOR_INIT_FINALLY(&phi, no_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 10); - RNG_BEGIN(); - /* Initialization */ IGRAPH_CHECK(igraph_strength(graph, &phi, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS, /* weights = */ 0)); @@ -157,7 +153,7 @@ igraph_error_t igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res, temp_global = temp_init * no_nodes; while (temp_global > temp_min * no_nodes && maxiter > 0) { - igraph_integer_t u, v, nlen, j; + igraph_int_t u, v, nlen, j; igraph_real_t px, py, pvx, pvy; IGRAPH_ALLOW_INTERRUPTION(); @@ -189,10 +185,12 @@ igraph_error_t igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res, } } - IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, v, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); nlen = igraph_vector_int_size(&neis); for (j = 0; j < nlen; j++) { - igraph_integer_t u = VECTOR(neis)[j]; + igraph_int_t u = VECTOR(neis)[j]; igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t dist2 = dx * dx + dy * dy; @@ -238,9 +236,6 @@ igraph_error_t igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res, } /* while temp && iter */ - - RNG_END(); - igraph_vector_int_destroy(&neis); igraph_vector_destroy(&phi); igraph_vector_int_destroy(&perm); diff --git a/src/vendor/cigraph/src/layout/graphopt.c b/src/vendor/cigraph/src/layout/graphopt.c index c985122de55..16e11b192a6 100644 --- a/src/vendor/cigraph/src/layout/graphopt.c +++ b/src/vendor/cigraph/src/layout/graphopt.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -33,7 +31,7 @@ static igraph_real_t igraph_i_distance_between( const igraph_matrix_t *c, - igraph_integer_t a, igraph_integer_t b); + igraph_int_t a, igraph_int_t b); static void igraph_i_determine_electric_axal_forces( const igraph_matrix_t *pos, @@ -41,14 +39,14 @@ static void igraph_i_determine_electric_axal_forces( igraph_real_t *y, igraph_real_t directed_force, igraph_real_t distance, - igraph_integer_t other_node, - igraph_integer_t this_node); + igraph_int_t other_node, + igraph_int_t this_node); static void igraph_i_apply_electrical_force( const igraph_matrix_t *pos, igraph_vector_t *pending_forces_x, igraph_vector_t *pending_forces_y, - igraph_integer_t other_node, igraph_integer_t this_node, + igraph_int_t other_node, igraph_int_t this_node, igraph_real_t node_charge, igraph_real_t distance); @@ -58,15 +56,15 @@ static void igraph_i_determine_spring_axal_forces( igraph_real_t directed_force, igraph_real_t distance, igraph_real_t spring_length, - igraph_integer_t other_node, - igraph_integer_t this_node); + igraph_int_t other_node, + igraph_int_t this_node); static void igraph_i_apply_spring_force( const igraph_matrix_t *pos, igraph_vector_t *pending_forces_x, igraph_vector_t *pending_forces_y, - igraph_integer_t other_node, - igraph_integer_t this_node, igraph_real_t spring_length, + igraph_int_t other_node, + igraph_int_t this_node, igraph_real_t spring_length, igraph_real_t spring_constant); static void igraph_i_move_nodes( @@ -78,7 +76,7 @@ static void igraph_i_move_nodes( static igraph_real_t igraph_i_distance_between( const igraph_matrix_t *c, - igraph_integer_t a, igraph_integer_t b) { + igraph_int_t a, igraph_int_t b) { igraph_real_t diffx = MATRIX(*c, a, 0) - MATRIX(*c, b, 0); igraph_real_t diffy = MATRIX(*c, a, 1) - MATRIX(*c, b, 1); return sqrt(diffx*diffx + diffy*diffy); @@ -89,8 +87,8 @@ static void igraph_i_determine_electric_axal_forces(const igraph_matrix_t *pos, igraph_real_t *y, igraph_real_t directed_force, igraph_real_t distance, - igraph_integer_t other_node, - igraph_integer_t this_node) { + igraph_int_t other_node, + igraph_int_t this_node) { // We know what the directed force is. We now need to translate it // into the appropriate x and y components. @@ -139,7 +137,7 @@ static void igraph_i_apply_electrical_force( const igraph_matrix_t *pos, igraph_vector_t *pending_forces_x, igraph_vector_t *pending_forces_y, - igraph_integer_t other_node, igraph_integer_t this_node, + igraph_int_t other_node, igraph_int_t this_node, igraph_real_t node_charge, igraph_real_t distance) { @@ -163,7 +161,7 @@ static void igraph_i_determine_spring_axal_forces( igraph_real_t directed_force, igraph_real_t distance, igraph_real_t spring_length, - igraph_integer_t other_node, igraph_integer_t this_node) { + igraph_int_t other_node, igraph_int_t this_node) { // if the spring is just the right size, the forces will be 0, so we can // skip the computation. @@ -198,8 +196,8 @@ static void igraph_i_apply_spring_force( const igraph_matrix_t *pos, igraph_vector_t *pending_forces_x, igraph_vector_t *pending_forces_y, - igraph_integer_t other_node, - igraph_integer_t this_node, igraph_real_t spring_length, + igraph_int_t other_node, + igraph_int_t this_node, igraph_real_t spring_length, igraph_real_t spring_constant) { // determined using Hooke's Law: @@ -260,7 +258,7 @@ static void igraph_i_move_nodes( // velocity = force / mass // displacement = force / mass - igraph_integer_t this_node, no_of_nodes = igraph_vector_size(pending_forces_x); + igraph_int_t this_node, no_of_nodes = igraph_vector_size(pending_forces_x); for (this_node = 0; this_node < no_of_nodes; this_node++) { @@ -341,23 +339,23 @@ static void igraph_i_move_nodes( * of edges. If \p node_charge is zero then it is only O(n|E|). */ igraph_error_t igraph_layout_graphopt(const igraph_t *graph, igraph_matrix_t *res, - igraph_integer_t niter, + igraph_int_t niter, igraph_real_t node_charge, igraph_real_t node_mass, igraph_real_t spring_length, igraph_real_t spring_constant, igraph_real_t max_sa_movement, igraph_bool_t use_seed) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_t pending_forces_x, pending_forces_y; /* Set a flag to calculate (or not) the electrical forces that the nodes */ /* apply on each other based on if both node types' charges are zero. */ igraph_bool_t apply_electric_charges = (node_charge != 0); - igraph_integer_t this_node, other_node, edge; + igraph_int_t this_node, other_node, edge; igraph_real_t distance; - igraph_integer_t i; + igraph_int_t i; IGRAPH_VECTOR_INIT_FINALLY(&pending_forces_x, no_of_nodes); IGRAPH_VECTOR_INIT_FINALLY(&pending_forces_y, no_of_nodes); @@ -416,8 +414,8 @@ igraph_error_t igraph_layout_graphopt(const igraph_t *graph, igraph_matrix_t *re // Apply force from springs for (edge = 0; edge < no_of_edges; edge++) { - igraph_integer_t tthis_node = IGRAPH_FROM(graph, edge); - igraph_integer_t oother_node = IGRAPH_TO(graph, edge); + igraph_int_t tthis_node = IGRAPH_FROM(graph, edge); + igraph_int_t oother_node = IGRAPH_TO(graph, edge); // Apply spring force on both nodes igraph_i_apply_spring_force(res, &pending_forces_x, &pending_forces_y, oother_node, tthis_node, spring_length, diff --git a/src/vendor/cigraph/src/layout/kamada_kawai.c b/src/vendor/cigraph/src/layout/kamada_kawai.c index 7b1012166b6..d7b7085f3d2 100644 --- a/src/vendor/cigraph/src/layout/kamada_kawai.c +++ b/src/vendor/cigraph/src/layout/kamada_kawai.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2003-2025 The igraph development team This program is free software; you can redistribute it and/or modify @@ -103,19 +103,19 @@ */ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t *res, - igraph_bool_t use_seed, igraph_integer_t maxiter, + igraph_bool_t use_seed, igraph_int_t maxiter, igraph_real_t epsilon, igraph_real_t kkconst, const igraph_vector_t *weights, const igraph_vector_t *minx, const igraph_vector_t *maxx, const igraph_vector_t *miny, const igraph_vector_t *maxy) { - igraph_integer_t vcount = igraph_vcount(graph); - igraph_integer_t ecount = igraph_ecount(graph); + igraph_int_t vcount = igraph_vcount(graph); + igraph_int_t ecount = igraph_ecount(graph); igraph_real_t L, L0 = sqrt(vcount); igraph_matrix_t dij, lij, kij; igraph_real_t max_dij; igraph_vector_t D1, D2; - igraph_integer_t m; + igraph_int_t m; if (maxiter < 0) { IGRAPH_ERROR("Number of iterations must be non-negative in " @@ -183,8 +183,8 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t /* Find largest finite distance */ max_dij = 0.0; - for (igraph_integer_t j = 0; j < vcount; j++) { - for (igraph_integer_t i = j + 1; i < vcount; i++) { + for (igraph_int_t j = 0; j < vcount; j++) { + for (igraph_int_t i = j + 1; i < vcount; i++) { if (!isfinite(MATRIX(dij, i, j))) { continue; } @@ -196,8 +196,8 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t /* Replace infinite distances by the largest finite distance, * effectively making the graph connected. */ - for (igraph_integer_t j = 0; j < vcount; j++) { - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t j = 0; j < vcount; j++) { + for (igraph_int_t i = 0; i < vcount; i++) { if (MATRIX(dij, i, j) > max_dij) { MATRIX(dij, i, j) = max_dij; } @@ -205,8 +205,8 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t } L = L0 / max_dij; - for (igraph_integer_t j = 0; j < vcount; j++) { - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t j = 0; j < vcount; j++) { + for (igraph_int_t i = 0; i < vcount; i++) { if (i == j) { continue; } @@ -219,7 +219,7 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t /* Initialize delta */ IGRAPH_VECTOR_INIT_FINALLY(&D1, vcount); IGRAPH_VECTOR_INIT_FINALLY(&D2, vcount); - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { for (m = 0; m < vcount; m++) { igraph_real_t dx, dy, mi_dist; if (i == m) { @@ -233,7 +233,7 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t } } - for (igraph_integer_t j = 0; j < maxiter; j++) { + for (igraph_int_t j = 0; j < maxiter; j++) { igraph_real_t myD1, myD2, A, B, C; igraph_real_t max_delta, delta_x, delta_y; igraph_real_t old_x, old_y, new_x, new_y; @@ -244,7 +244,7 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t /* Select maximal delta */ m = 0; max_delta = -1; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { igraph_real_t delta = (VECTOR(D1)[i] * VECTOR(D1)[i] + VECTOR(D2)[i] * VECTOR(D2)[i]); if (delta > max_delta) { @@ -258,7 +258,7 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t old_y = MATRIX(*res, m, 1); /* Calculate D1 and D2, A, B, C */ - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { igraph_real_t dx, dy, dist, den; if (i == m) { continue; @@ -313,7 +313,7 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t /* Update delta, only with/for the affected node */ VECTOR(D1)[m] = VECTOR(D2)[m] = 0.0; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { igraph_real_t old_dx, old_dy, new_dx, new_dy, new_mi_dist, old_mi_dist; if (i == m) { continue; @@ -412,20 +412,20 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t */ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matrix_t *res, - igraph_bool_t use_seed, igraph_integer_t maxiter, + igraph_bool_t use_seed, igraph_int_t maxiter, igraph_real_t epsilon, igraph_real_t kkconst, const igraph_vector_t *weights, const igraph_vector_t *minx, const igraph_vector_t *maxx, const igraph_vector_t *miny, const igraph_vector_t *maxy, const igraph_vector_t *minz, const igraph_vector_t *maxz) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_real_t L, L0 = sqrt(vcount); igraph_matrix_t dij, lij, kij; igraph_real_t max_dij; igraph_vector_t D1, D2, D3; - igraph_integer_t m; + igraph_int_t m; if (maxiter < 0) { IGRAPH_ERROR("Number of iterations must be non-negative in " @@ -499,8 +499,8 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri igraph_vss_all(), weights, IGRAPH_ALL)); max_dij = 0.0; - for (igraph_integer_t i = 0; i < vcount; i++) { - for (igraph_integer_t j = i + 1; j < vcount; j++) { + for (igraph_int_t i = 0; i < vcount; i++) { + for (igraph_int_t j = i + 1; j < vcount; j++) { if (!isfinite(MATRIX(dij, i, j))) { continue; } @@ -509,8 +509,8 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri } } } - for (igraph_integer_t i = 0; i < vcount; i++) { - for (igraph_integer_t j = 0; j < vcount; j++) { + for (igraph_int_t i = 0; i < vcount; i++) { + for (igraph_int_t j = 0; j < vcount; j++) { if (MATRIX(dij, i, j) > max_dij) { MATRIX(dij, i, j) = max_dij; } @@ -518,8 +518,8 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri } L = L0 / max_dij; - for (igraph_integer_t i = 0; i < vcount; i++) { - for (igraph_integer_t j = 0; j < vcount; j++) { + for (igraph_int_t i = 0; i < vcount; i++) { + for (igraph_int_t j = 0; j < vcount; j++) { igraph_real_t tmp = MATRIX(dij, i, j) * MATRIX(dij, i, j); if (i == j) { continue; @@ -536,7 +536,7 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri for (m = 0; m < vcount; m++) { igraph_real_t dx, dy, dz, mi_dist; igraph_real_t myD1 = 0.0, myD2 = 0.0, myD3 = 0.0; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { if (i == m) { continue; } @@ -553,7 +553,7 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri VECTOR(D3)[m] = myD3; } - for (igraph_integer_t j = 0; j < maxiter; j++) { + for (igraph_int_t j = 0; j < maxiter; j++) { igraph_real_t Ax = 0.0, Ay = 0.0, Az = 0.0; igraph_real_t Axx = 0.0, Axy = 0.0, Axz = 0.0, Ayy = 0.0, Ayz = 0.0, Azz = 0.0; @@ -564,7 +564,7 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri /* Select maximal delta */ m = 0; max_delta = -1; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { igraph_real_t delta = (VECTOR(D1)[i] * VECTOR(D1)[i] + VECTOR(D2)[i] * VECTOR(D2)[i] + VECTOR(D3)[i] * VECTOR(D3)[i]); @@ -580,7 +580,7 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri old_z = MATRIX(*res, m, 2); /* Calculate D1, D2 and D3, and other coefficients */ - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { igraph_real_t dx, dy, dz, dist, den, k_mi, l_mi; if (i == m) { continue; @@ -646,7 +646,7 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri /* Update delta, only with/for the affected node */ VECTOR(D1)[m] = VECTOR(D2)[m] = VECTOR(D3)[m] = 0.0; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { igraph_real_t old_dx, old_dy, old_dz, old_mi_dist, new_dx, new_dy, new_dz, new_mi_dist; if (i == m) { continue; diff --git a/src/vendor/cigraph/src/layout/large_graph.c b/src/vendor/cigraph/src/layout/large_graph.c index 96df10947aa..27ae2ee9291 100644 --- a/src/vendor/cigraph/src/layout/large_graph.c +++ b/src/vendor/cigraph/src/layout/large_graph.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -30,7 +28,7 @@ #include "core/grid.h" #include "core/interruption.h" -#include "core/math.h" +#include "core/math.h" /* M_PI */ static void igraph_i_norm2d(igraph_real_t *x, igraph_real_t *y) { igraph_real_t len = sqrt(*x * *x + *y * *y); @@ -88,16 +86,16 @@ static void igraph_i_norm2d(igraph_real_t *x, igraph_real_t *y) { */ igraph_error_t igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res, - igraph_integer_t maxit, igraph_real_t maxdelta, + igraph_int_t maxit, igraph_real_t maxdelta, igraph_real_t area, igraph_real_t coolexp, igraph_real_t repulserad, igraph_real_t cellsize, - igraph_integer_t proot) { + igraph_int_t proot) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t root; - igraph_integer_t no_of_layers, actlayer = 0; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t root; + igraph_int_t no_of_layers, actlayer = 0; igraph_vector_int_t vids; igraph_vector_int_t layers; igraph_vector_int_t parents; @@ -155,8 +153,6 @@ igraph_error_t igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res, * TODO: If this function is updated to handle weights, it should * construct the MST and traverse that instead. */ - RNG_BEGIN(); - /* Determine the root vertex, random pick right now */ if (proot < 0) { root = RNG_INTEGER(0, no_of_nodes - 1); @@ -205,15 +201,15 @@ igraph_error_t igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res, for (actlayer = 1; actlayer < no_of_layers; actlayer++) { igraph_real_t c = 1; - igraph_integer_t i, j; + igraph_int_t i, j; igraph_real_t massx, massy; igraph_real_t px, py; igraph_real_t sx, sy; - igraph_integer_t it = 0; + igraph_int_t it = 0; igraph_real_t epsilon = 10e-6; igraph_real_t maxchange = epsilon + 1; - /* igraph_integer_t pairs; */ + /* igraph_int_t pairs; */ igraph_real_t sconst = sqrt(area / M_PI) / H_n; igraph_2dgrid_iterator_t vidit; @@ -227,8 +223,8 @@ igraph_error_t igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res, for (i = VECTOR(layers)[actlayer - 1]; i < VECTOR(layers)[actlayer]; i++) { - igraph_integer_t vid = VECTOR(vids)[i]; - igraph_integer_t par = VECTOR(parents)[vid]; + igraph_int_t vid = VECTOR(vids)[i]; + igraph_int_t par = VECTOR(parents)[vid]; if (par < 0) { if (par == -1) { @@ -275,16 +271,16 @@ igraph_error_t igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res, for (j = VECTOR(layers)[actlayer]; j < VECTOR(layers)[actlayer + 1]; j++) { - igraph_integer_t vid = VECTOR(vids)[j]; - igraph_integer_t k; + igraph_int_t vid = VECTOR(vids)[j]; + igraph_int_t k; IGRAPH_ALLOW_INTERRUPTION(); - IGRAPH_CHECK(igraph_incident(graph, &eids, vid, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(graph, &eids, vid, IGRAPH_ALL, IGRAPH_LOOPS)); for (k = 0; k < igraph_vector_int_size(&eids); k++) { - igraph_integer_t eid = VECTOR(eids)[k]; - igraph_integer_t from = IGRAPH_FROM(graph, eid), to = IGRAPH_TO(graph, eid); + igraph_int_t eid = VECTOR(eids)[k]; + igraph_int_t from = IGRAPH_FROM(graph, eid), to = IGRAPH_TO(graph, eid); if ((from != vid && igraph_2dgrid_in(&grid, from)) || (to != vid && igraph_2dgrid_in(&grid, to))) { - igraph_vector_int_push_back(&edges, eid); + igraph_vector_int_push_back(&edges, eid); /* reserved */ } } } @@ -295,9 +291,9 @@ igraph_error_t igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res, maxchange = epsilon + 1; while (it < maxit && maxchange > epsilon) { - igraph_integer_t jj; + igraph_int_t jj; igraph_real_t t = maxdelta * pow((maxit - it) / (igraph_real_t) maxit, coolexp); - igraph_integer_t vid, nei; + igraph_int_t vid, nei; IGRAPH_PROGRESS("Large graph layout", 100.0 * ((actlayer - 1.0) / (no_of_layers - 1.0) + (it) / (maxit * (no_of_layers - 1.0))), @@ -310,8 +306,8 @@ igraph_error_t igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res, /* attractive "forces" along the edges */ for (jj = 0; jj < igraph_vector_int_size(&edges); jj++) { - igraph_integer_t from = IGRAPH_FROM(graph, VECTOR(edges)[jj]); - igraph_integer_t to = IGRAPH_TO(graph, VECTOR(edges)[jj]); + igraph_int_t from = IGRAPH_FROM(graph, VECTOR(edges)[jj]); + igraph_int_t to = IGRAPH_TO(graph, VECTOR(edges)[jj]); igraph_real_t xd, yd, dist, force; IGRAPH_ALLOW_INTERRUPTION(); xd = MATRIX(*res, from, 0) - MATRIX(*res, to, 0); @@ -357,7 +353,7 @@ igraph_error_t igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res, /* apply the changes */ for (jj = 0; jj < VECTOR(layers)[actlayer + 1]; jj++) { - igraph_integer_t vvid = VECTOR(vids)[jj]; + igraph_int_t vvid = VECTOR(vids)[jj]; igraph_real_t fx = VECTOR(forcex)[vvid]; igraph_real_t fy = VECTOR(forcey)[vvid]; igraph_real_t ded = sqrt(fx*fx + fy*fy); @@ -378,8 +374,6 @@ igraph_error_t igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res, } } - RNG_END(); - IGRAPH_PROGRESS("Large graph layout", 100.0, 0); igraph_vector_int_destroy(&vids); igraph_vector_int_destroy(&layers); diff --git a/src/vendor/cigraph/src/layout/layout_bipartite.c b/src/vendor/cigraph/src/layout/layout_bipartite.c index 92d018b4cda..6e92102e0f6 100644 --- a/src/vendor/cigraph/src/layout/layout_bipartite.c +++ b/src/vendor/cigraph/src/layout/layout_bipartite.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -52,9 +50,9 @@ igraph_error_t igraph_layout_bipartite(const igraph_t *graph, const igraph_vector_bool_t *types, igraph_matrix_t *res, igraph_real_t hgap, - igraph_real_t vgap, igraph_integer_t maxiter) { + igraph_real_t vgap, igraph_int_t maxiter) { - igraph_integer_t i, no_of_nodes = igraph_vcount(graph); + igraph_int_t i, no_of_nodes = igraph_vcount(graph); igraph_vector_int_t layers; if (igraph_vector_bool_size(types) != no_of_nodes) { @@ -70,9 +68,8 @@ igraph_error_t igraph_layout_bipartite(const igraph_t *graph, VECTOR(layers)[i] = VECTOR(*types)[i] ? 0 : 1; } - IGRAPH_CHECK(igraph_layout_sugiyama(graph, res, /*extd_graph=*/ 0, - /*extd_to_orig_eids=*/ 0, &layers, hgap, - vgap, maxiter, /*weights=*/ 0)); + IGRAPH_CHECK(igraph_layout_sugiyama(graph, res, /* routing= */ 0, + &layers, hgap, vgap, maxiter, /* weights= */ 0)); igraph_vector_int_destroy(&layers); IGRAPH_FINALLY_CLEAN(1); diff --git a/src/vendor/cigraph/src/layout/layout_grid.c b/src/vendor/cigraph/src/layout/layout_grid.c index 16ec85b88fe..ab35e0c2a07 100644 --- a/src/vendor/cigraph/src/layout/layout_grid.c +++ b/src/vendor/cigraph/src/layout/layout_grid.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -41,8 +39,8 @@ * * Time complexity: O(|V|), the number of vertices. */ -igraph_error_t igraph_layout_grid(const igraph_t *graph, igraph_matrix_t *res, igraph_integer_t width) { - igraph_integer_t i, no_of_nodes = igraph_vcount(graph); +igraph_error_t igraph_layout_grid(const igraph_t *graph, igraph_matrix_t *res, igraph_int_t width) { + igraph_int_t i, no_of_nodes = igraph_vcount(graph); igraph_real_t x, y; IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2)); @@ -82,8 +80,8 @@ igraph_error_t igraph_layout_grid(const igraph_t *graph, igraph_matrix_t *res, i * Time complexity: O(|V|), the number of vertices. */ igraph_error_t igraph_layout_grid_3d(const igraph_t *graph, igraph_matrix_t *res, - igraph_integer_t width, igraph_integer_t height) { - igraph_integer_t i, no_of_nodes = igraph_vcount(graph); + igraph_int_t width, igraph_int_t height) { + igraph_int_t i, no_of_nodes = igraph_vcount(graph); igraph_real_t x, y, z; IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 3)); diff --git a/src/vendor/cigraph/src/layout/layout_internal.h b/src/vendor/cigraph/src/layout/layout_internal.h index a9b193a16ac..72aeaae5be3 100644 --- a/src/vendor/cigraph/src/layout/layout_internal.h +++ b/src/vendor/cigraph/src/layout/layout_internal.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -31,10 +30,10 @@ #include "layout/merge_grid.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_layout_merge_dla(igraph_i_layout_mergegrid_t *grid, - igraph_integer_t actg, igraph_real_t *x, igraph_real_t *y, igraph_real_t r, + igraph_int_t actg, igraph_real_t *x, igraph_real_t *y, igraph_real_t r, igraph_real_t cx, igraph_real_t cy, igraph_real_t startr, igraph_real_t killr); @@ -71,6 +70,6 @@ igraph_error_t igraph_i_layout_random_bounded_3d( const igraph_vector_t *miny, const igraph_vector_t *maxy, const igraph_vector_t *minz, const igraph_vector_t *maxz); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/layout/layout_random.c b/src/vendor/cigraph/src/layout/layout_random.c index 92db18e75a4..499b103826e 100644 --- a/src/vendor/cigraph/src/layout/layout_random.c +++ b/src/vendor/cigraph/src/layout/layout_random.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -45,20 +43,16 @@ */ igraph_error_t igraph_layout_random(const igraph_t *graph, igraph_matrix_t *res) { - const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_int_t vcount = igraph_vcount(graph); IGRAPH_CHECK(igraph_matrix_resize(res, vcount, 2)); - RNG_BEGIN(); - - for (igraph_integer_t j = 0; j < 2; j++) { - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t j = 0; j < 2; j++) { + for (igraph_int_t i = 0; i < vcount; i++) { MATRIX(*res, i, j) = RNG_UNIF(-1, 1); } } - RNG_END(); - return IGRAPH_SUCCESS; } @@ -80,20 +74,16 @@ igraph_error_t igraph_layout_random(const igraph_t *graph, igraph_matrix_t *res) */ igraph_error_t igraph_layout_random_3d(const igraph_t *graph, igraph_matrix_t *res) { - const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_int_t vcount = igraph_vcount(graph); IGRAPH_CHECK(igraph_matrix_resize(res, vcount, 3)); - RNG_BEGIN(); - - for (igraph_integer_t j = 0; j < 3; j++) { - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t j = 0; j < 3; j++) { + for (igraph_int_t i = 0; i < vcount; i++) { MATRIX(*res, i, j) = RNG_UNIF(-1, 1); } } - RNG_END(); - return IGRAPH_SUCCESS; } @@ -107,7 +97,7 @@ igraph_error_t igraph_i_layout_random_bounded( const igraph_vector_t *minx, const igraph_vector_t *maxx, const igraph_vector_t *miny, const igraph_vector_t *maxy) { - const igraph_integer_t no_nodes = igraph_vcount(graph); + const igraph_int_t no_nodes = igraph_vcount(graph); const igraph_real_t width = sqrt(no_nodes), height = width; igraph_real_t dminx = -width/2, dmaxx = width/2, @@ -152,9 +142,8 @@ igraph_error_t igraph_i_layout_random_bounded( } } - RNG_BEGIN(); IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2)); - for (igraph_integer_t i = 0; i < no_nodes; i++) { + for (igraph_int_t i = 0; i < no_nodes; i++) { igraph_real_t x1 = minx ? VECTOR(*minx)[i] : dminx; igraph_real_t x2 = maxx ? VECTOR(*maxx)[i] : dmaxx; igraph_real_t y1 = miny ? VECTOR(*miny)[i] : dminy; @@ -174,7 +163,6 @@ igraph_error_t igraph_i_layout_random_bounded( MATRIX(*res, i, 0) = RNG_UNIF(x1, x2); MATRIX(*res, i, 1) = RNG_UNIF(y1, y2); } - RNG_END(); return IGRAPH_SUCCESS; } @@ -185,7 +173,7 @@ igraph_error_t igraph_i_layout_random_bounded_3d( const igraph_vector_t *miny, const igraph_vector_t *maxy, const igraph_vector_t *minz, const igraph_vector_t *maxz) { - const igraph_integer_t no_nodes = igraph_vcount(graph); + const igraph_int_t no_nodes = igraph_vcount(graph); const igraph_real_t width = sqrt(no_nodes), height = width, depth = width; igraph_real_t dminx = -width/2, dmaxx = width/2, @@ -249,9 +237,8 @@ igraph_error_t igraph_i_layout_random_bounded_3d( } } - RNG_BEGIN(); IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 3)); - for (igraph_integer_t i = 0; i < no_nodes; i++) { + for (igraph_int_t i = 0; i < no_nodes; i++) { igraph_real_t x1 = minx ? VECTOR(*minx)[i] : dminx; igraph_real_t x2 = maxx ? VECTOR(*maxx)[i] : dmaxx; igraph_real_t y1 = miny ? VECTOR(*miny)[i] : dminy; @@ -280,7 +267,6 @@ igraph_error_t igraph_i_layout_random_bounded_3d( MATRIX(*res, i, 1) = RNG_UNIF(y1, y2); MATRIX(*res, i, 2) = RNG_UNIF(z1, z2); } - RNG_END(); return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/layout/mds.c b/src/vendor/cigraph/src/layout/mds.c index 6a34b6f9f26..5cdc87cfb62 100644 --- a/src/vendor/cigraph/src/layout/mds.c +++ b/src/vendor/cigraph/src/layout/mds.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -28,7 +26,6 @@ #include "igraph_components.h" #include "igraph_eigen.h" #include "igraph_interface.h" -#include "igraph_memory.h" #include "igraph_operators.h" #include "igraph_paths.h" #include "igraph_random.h" @@ -40,7 +37,7 @@ static igraph_error_t igraph_i_layout_mds_step(igraph_real_t *to, const igraph_r int n, void *extra); static igraph_error_t igraph_i_layout_mds_single(const igraph_t* graph, igraph_matrix_t *res, - igraph_matrix_t *dist, igraph_integer_t dim); + igraph_matrix_t *dist, igraph_int_t dim); static igraph_error_t igraph_i_layout_mds_step(igraph_real_t *to, const igraph_real_t *from, int n, void *extra) { @@ -53,14 +50,14 @@ static igraph_error_t igraph_i_layout_mds_step(igraph_real_t *to, const igraph_r /* MDS layout for a connected graph, with no error checking on the * input parameters. The distance matrix will be modified in-place. */ igraph_error_t igraph_i_layout_mds_single(const igraph_t* graph, igraph_matrix_t *res, - igraph_matrix_t *dist, igraph_integer_t dim) { + igraph_matrix_t *dist, igraph_int_t dim) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t nev = dim; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t nev = dim; igraph_matrix_t vectors; igraph_vector_t values, row_means; igraph_real_t grand_mean; - igraph_integer_t i, j, k; + igraph_int_t i, j, k; igraph_eigen_which_t which; if (no_of_nodes > INT_MAX) { @@ -189,14 +186,12 @@ igraph_error_t igraph_i_layout_mds_single(const igraph_t* graph, igraph_matrix_t */ igraph_error_t igraph_layout_mds(const igraph_t *graph, igraph_matrix_t *res, - const igraph_matrix_t *dist, igraph_integer_t dim) { + const igraph_matrix_t *dist, igraph_int_t dim) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_matrix_t m; igraph_bool_t conn; - RNG_BEGIN(); - /* Check the distance matrix */ if (dist && (igraph_matrix_nrow(dist) != no_of_nodes || igraph_matrix_ncol(dist) != no_of_nodes)) { @@ -215,12 +210,12 @@ igraph_error_t igraph_layout_mds(const igraph_t *graph, igraph_matrix_t *res, /* Copy or obtain the distance matrix */ if (dist == 0) { IGRAPH_MATRIX_INIT_FINALLY(&m, no_of_nodes, no_of_nodes); - IGRAPH_CHECK(igraph_distances(graph, &m, igraph_vss_all(), igraph_vss_all(), IGRAPH_ALL)); + IGRAPH_CHECK(igraph_distances(graph, NULL, &m, igraph_vss_all(), igraph_vss_all(), IGRAPH_ALL)); } else { IGRAPH_CHECK(igraph_matrix_init_copy(&m, dist)); IGRAPH_FINALLY(igraph_matrix_destroy, &m); /* Make sure that the diagonal contains zeroes only */ - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { MATRIX(m, i, i) = 0.0; } } @@ -239,7 +234,7 @@ igraph_error_t igraph_layout_mds(const igraph_t *graph, igraph_matrix_t *res, igraph_matrix_t layout; igraph_matrix_t dist_submatrix; igraph_bitset_t seen_vertices; - igraph_integer_t n, processed_vertex_count = 0; + igraph_int_t n, processed_vertex_count = 0; IGRAPH_VECTOR_INT_INIT_FINALLY(&comp, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&vertex_order, no_of_nodes); @@ -252,7 +247,7 @@ igraph_error_t igraph_layout_mds(const igraph_t *graph, igraph_matrix_t *res, IGRAPH_BITSET_INIT_FINALLY(&seen_vertices, no_of_nodes); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (IGRAPH_BIT_TEST(seen_vertices, i)) { continue; } @@ -274,7 +269,7 @@ igraph_error_t igraph_layout_mds(const igraph_t *graph, igraph_matrix_t *res, IGRAPH_FINALLY_CLEAN(1); /* Mark all the vertices in the component as visited */ n = igraph_vector_int_size(&comp); - for (igraph_integer_t j = 0; j < n; j++) { + for (igraph_int_t j = 0; j < n; j++) { IGRAPH_BIT_SET(seen_vertices, VECTOR(comp)[j]); VECTOR(vertex_order)[VECTOR(comp)[j]] = processed_vertex_count++; } @@ -293,8 +288,6 @@ igraph_error_t igraph_layout_mds(const igraph_t *graph, igraph_matrix_t *res, IGRAPH_FINALLY_CLEAN(6); } - RNG_END(); - igraph_matrix_destroy(&m); IGRAPH_FINALLY_CLEAN(1); diff --git a/src/vendor/cigraph/src/layout/merge_dla.c b/src/vendor/cigraph/src/layout/merge_dla.c index 7082540aacf..93a0287f8bd 100644 --- a/src/vendor/cigraph/src/layout/merge_dla.c +++ b/src/vendor/cigraph/src/layout/merge_dla.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -27,16 +25,31 @@ #include "igraph_random.h" #include "core/interruption.h" -#include "core/math.h" +#include "core/math.h" /* M_PI */ #include "layout/merge_grid.h" #include "layout/layout_internal.h" +static igraph_error_t vector_order(igraph_vector_t *v) { + const igraph_int_t n = igraph_vector_size(v); + igraph_vector_int_t ind; + + IGRAPH_VECTOR_INT_INIT_FINALLY(&ind, n); + IGRAPH_CHECK(igraph_vector_sort_ind(v, &ind, IGRAPH_DESCENDING)); + + for (igraph_int_t i=0; i < n; i++) { + VECTOR(*v)[i] = VECTOR(ind)[i]; + } + + igraph_vector_int_destroy(&ind); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} + /** * \function igraph_layout_merge_dla * \brief Merges multiple layouts by using a DLA algorithm. * - * \experimental - * * First each layout is covered by a circle. Then the layout of the * largest graph is placed at the origin. Then the other layouts are * placed by the DLA algorithm, larger ones first and smaller ones @@ -59,19 +72,19 @@ igraph_error_t igraph_layout_merge_dla( const igraph_vector_ptr_t *thegraphs, const igraph_matrix_list_t *coords, igraph_matrix_t *res ) { - igraph_integer_t coords_len = igraph_matrix_list_size(coords); + igraph_int_t coords_len = igraph_matrix_list_size(coords); igraph_vector_t sizes; igraph_vector_t x, y, r; igraph_vector_t nx, ny, nr; - igraph_integer_t allnodes = 0; - igraph_integer_t i, j; - igraph_integer_t actg; + igraph_int_t allnodes = 0; + igraph_int_t i, j; + igraph_int_t actg; igraph_i_layout_mergegrid_t grid; - igraph_integer_t jpos = 0; + igraph_int_t jpos = 0; igraph_real_t minx, maxx, miny, maxy; igraph_real_t area = 0; igraph_real_t maxr = 0; - igraph_integer_t respos; + igraph_int_t respos; /* Graphs are currently not used, only the coordinates */ IGRAPH_UNUSED(thegraphs); @@ -84,11 +97,9 @@ igraph_error_t igraph_layout_merge_dla( IGRAPH_VECTOR_INIT_FINALLY(&ny, coords_len); IGRAPH_VECTOR_INIT_FINALLY(&nr, coords_len); - RNG_BEGIN(); - for (i = 0; i < coords_len; i++) { igraph_matrix_t *mat = igraph_matrix_list_get_ptr(coords, i); - igraph_integer_t size = igraph_matrix_nrow(mat); + igraph_int_t size = igraph_matrix_nrow(mat); if (igraph_matrix_ncol(mat) != 2) { IGRAPH_ERROR("igraph_layout_merge_dla works for 2D layouts only", @@ -109,7 +120,7 @@ igraph_error_t igraph_layout_merge_dla( igraph_vector_get_ptr(&ny, i), igraph_vector_get_ptr(&nr, i)); } - igraph_vector_order2(&sizes); /* largest first */ + vector_order(&sizes); /* largest first */ /* 0. create grid */ minx = miny = -sqrt(5 * area); @@ -149,7 +160,7 @@ igraph_error_t igraph_layout_merge_dla( respos = 0; for (i = 0; i < coords_len; i++) { igraph_matrix_t *mat = igraph_matrix_list_get_ptr(coords, i); - igraph_integer_t size = igraph_matrix_nrow(mat); + igraph_int_t size = igraph_matrix_nrow(mat); igraph_real_t xx = VECTOR(x)[i]; igraph_real_t yy = VECTOR(y)[i]; igraph_real_t rr = VECTOR(r)[i] / VECTOR(nr)[i]; @@ -166,8 +177,6 @@ igraph_error_t igraph_layout_merge_dla( } } - RNG_END(); - igraph_i_layout_mergegrid_destroy(&grid); igraph_vector_destroy(&sizes); igraph_vector_destroy(&x); @@ -183,8 +192,8 @@ igraph_error_t igraph_layout_merge_dla( igraph_error_t igraph_i_layout_sphere_2d(igraph_matrix_t *coords, igraph_real_t *x, igraph_real_t *y, igraph_real_t *r) { - igraph_integer_t nodes = igraph_matrix_nrow(coords); - igraph_integer_t i; + igraph_int_t nodes = igraph_matrix_nrow(coords); + igraph_int_t i; igraph_real_t xmin, xmax, ymin, ymax; xmin = xmax = MATRIX(*coords, 0, 0); @@ -215,8 +224,8 @@ igraph_error_t igraph_i_layout_sphere_2d(igraph_matrix_t *coords, igraph_error_t igraph_i_layout_sphere_3d(igraph_matrix_t *coords, igraph_real_t *x, igraph_real_t *y, igraph_real_t *z, igraph_real_t *r) { - igraph_integer_t nodes = igraph_matrix_nrow(coords); - igraph_integer_t i; + igraph_int_t nodes = igraph_matrix_nrow(coords); + igraph_int_t i; igraph_real_t xmin, xmax, ymin, ymax, zmin, zmax; xmin = xmax = MATRIX(*coords, 0, 0); @@ -256,10 +265,10 @@ igraph_error_t igraph_i_layout_sphere_3d(igraph_matrix_t *coords, #define DIST(x,y) (sqrt(pow((x)-cx,2)+pow((y)-cy,2))) igraph_error_t igraph_i_layout_merge_dla(igraph_i_layout_mergegrid_t *grid, - igraph_integer_t actg, igraph_real_t *x, igraph_real_t *y, igraph_real_t r, + igraph_int_t actg, igraph_real_t *x, igraph_real_t *y, igraph_real_t r, igraph_real_t cx, igraph_real_t cy, igraph_real_t startr, igraph_real_t killr) { - igraph_integer_t sp = -1; + igraph_int_t sp = -1; igraph_real_t angle, len; /* The graph is not used, only its coordinates */ diff --git a/src/vendor/cigraph/src/layout/merge_grid.c b/src/vendor/cigraph/src/layout/merge_grid.c index a037a111a80..b56f38a4ac9 100644 --- a/src/vendor/cigraph/src/layout/merge_grid.c +++ b/src/vendor/cigraph/src/layout/merge_grid.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -23,7 +23,7 @@ static igraph_error_t igraph_i_layout_mergegrid_which(igraph_i_layout_mergegrid_t *grid, igraph_real_t xc, igraph_real_t yc, - igraph_integer_t *x, igraph_integer_t *y) { + igraph_int_t *x, igraph_int_t *y) { if (xc <= grid->minx) { *x = 0; } else if (xc >= grid->maxx) { @@ -44,8 +44,8 @@ static igraph_error_t igraph_i_layout_mergegrid_which(igraph_i_layout_mergegrid_ } igraph_error_t igraph_i_layout_mergegrid_init(igraph_i_layout_mergegrid_t *grid, - igraph_real_t minx, igraph_real_t maxx, igraph_integer_t stepsx, - igraph_real_t miny, igraph_real_t maxy, igraph_integer_t stepsy) { + igraph_real_t minx, igraph_real_t maxx, igraph_int_t stepsx, + igraph_real_t miny, igraph_real_t maxy, igraph_int_t stepsy) { grid->minx = minx; grid->maxx = maxx; grid->stepsx = stepsx; @@ -55,7 +55,7 @@ igraph_error_t igraph_i_layout_mergegrid_init(igraph_i_layout_mergegrid_t *grid, grid->stepsy = stepsy; grid->deltay = (maxy - miny) / stepsy; - grid->data = IGRAPH_CALLOC(stepsx * stepsy, igraph_integer_t); + grid->data = IGRAPH_CALLOC(stepsx * stepsy, igraph_int_t); if (grid->data == 0) { IGRAPH_ERROR("Cannot create grid", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } @@ -71,9 +71,9 @@ void igraph_i_layout_mergegrid_destroy(igraph_i_layout_mergegrid_t *grid) { igraph_error_t igraph_i_layout_merge_place_sphere(igraph_i_layout_mergegrid_t *grid, igraph_real_t x, igraph_real_t y, igraph_real_t r, - igraph_integer_t id) { - igraph_integer_t cx, cy; - igraph_integer_t i, j; + igraph_int_t id) { + igraph_int_t cx, cy; + igraph_int_t i, j; igraph_i_layout_mergegrid_which(grid, x, y, &cx, &cy); @@ -124,10 +124,10 @@ igraph_error_t igraph_i_layout_merge_place_sphere(igraph_i_layout_mergegrid_t *g return IGRAPH_SUCCESS; } -igraph_integer_t igraph_i_layout_mergegrid_get(igraph_i_layout_mergegrid_t *grid, +igraph_int_t igraph_i_layout_mergegrid_get(igraph_i_layout_mergegrid_t *grid, igraph_real_t x, igraph_real_t y) { - igraph_integer_t cx, cy; - igraph_integer_t res; + igraph_int_t cx, cy; + igraph_int_t res; if (x <= grid->minx || x >= grid->maxx || y <= grid->miny || y >= grid->maxy) { @@ -142,11 +142,11 @@ igraph_integer_t igraph_i_layout_mergegrid_get(igraph_i_layout_mergegrid_t *grid #define DIST2(x2,y2) (sqrt(pow(x-(x2),2)+pow(y-(y2), 2))) -igraph_integer_t igraph_i_layout_mergegrid_get_sphere(igraph_i_layout_mergegrid_t *grid, +igraph_int_t igraph_i_layout_mergegrid_get_sphere(igraph_i_layout_mergegrid_t *grid, igraph_real_t x, igraph_real_t y, igraph_real_t r) { - igraph_integer_t cx, cy; - igraph_integer_t i, j; - igraph_integer_t ret; + igraph_int_t cx, cy; + igraph_int_t i, j; + igraph_int_t ret; if (x - r <= grid->minx || x + r >= grid->maxx || y - r <= grid->miny || y + r >= grid->maxy) { diff --git a/src/vendor/cigraph/src/layout/merge_grid.h b/src/vendor/cigraph/src/layout/merge_grid.h index c4dd0f2c76d..333b4738b19 100644 --- a/src/vendor/cigraph/src/layout/merge_grid.h +++ b/src/vendor/cigraph/src/layout/merge_grid.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2009-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -23,33 +23,33 @@ #include "igraph_error.h" #include "igraph_types.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* A type of grid used for merging layouts; each cell is owned by exactly one graph */ typedef struct igraph_i_layout_mergegrid_t { - igraph_integer_t *data; - igraph_integer_t stepsx, stepsy; + igraph_int_t *data; + igraph_int_t stepsx, stepsy; igraph_real_t minx, maxx, deltax; igraph_real_t miny, maxy, deltay; } igraph_i_layout_mergegrid_t; IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_layout_mergegrid_init(igraph_i_layout_mergegrid_t *grid, - igraph_real_t minx, igraph_real_t maxx, igraph_integer_t stepsx, - igraph_real_t miny, igraph_real_t maxy, igraph_integer_t stepsy); + igraph_real_t minx, igraph_real_t maxx, igraph_int_t stepsx, + igraph_real_t miny, igraph_real_t maxy, igraph_int_t stepsy); IGRAPH_PRIVATE_EXPORT void igraph_i_layout_mergegrid_destroy(igraph_i_layout_mergegrid_t *grid); IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_layout_merge_place_sphere(igraph_i_layout_mergegrid_t *grid, igraph_real_t x, igraph_real_t y, igraph_real_t r, - igraph_integer_t id); + igraph_int_t id); -igraph_integer_t igraph_i_layout_mergegrid_get(igraph_i_layout_mergegrid_t *grid, +igraph_int_t igraph_i_layout_mergegrid_get(igraph_i_layout_mergegrid_t *grid, igraph_real_t x, igraph_real_t y); -igraph_integer_t igraph_i_layout_mergegrid_get_sphere(igraph_i_layout_mergegrid_t *g, +igraph_int_t igraph_i_layout_mergegrid_get_sphere(igraph_i_layout_mergegrid_t *g, igraph_real_t x, igraph_real_t y, igraph_real_t r); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/layout/reingold_tilford.c b/src/vendor/cigraph/src/layout/reingold_tilford.c index d16949866c6..e1e28ad2ca9 100644 --- a/src/vendor/cigraph/src/layout/reingold_tilford.c +++ b/src/vendor/cigraph/src/layout/reingold_tilford.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -32,18 +30,18 @@ #include "igraph_progress.h" #include "igraph_structural.h" -#include "core/math.h" +#include "core/math.h" /* M_PI */ static igraph_error_t layout_reingold_tilford_unreachable( const igraph_t *graph, igraph_neimode_t mode, - igraph_integer_t real_root, - igraph_integer_t no_of_nodes, + igraph_int_t real_root, + igraph_int_t no_of_nodes, igraph_vector_int_t *pnewedges) { - igraph_integer_t no_of_newedges; + igraph_int_t no_of_newedges; igraph_vector_bool_t visited; - igraph_integer_t i, j, n; + igraph_int_t i, j, n; igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; igraph_adjlist_t allneis; igraph_vector_int_t *neis; @@ -61,12 +59,12 @@ static igraph_error_t layout_reingold_tilford_unreachable( /* start from real_root and go BFS */ IGRAPH_CHECK(igraph_dqueue_int_push(&q, real_root)); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); neis = igraph_adjlist_get(&allneis, actnode); n = igraph_vector_int_size(neis); VECTOR(visited)[actnode] = true; for (j = 0; j < n; j++) { - igraph_integer_t neighbor = VECTOR(*neis)[j]; + igraph_int_t neighbor = VECTOR(*neis)[j]; if (!VECTOR(visited)[neighbor]) { IGRAPH_CHECK(igraph_dqueue_int_push(&q, neighbor)); } @@ -107,26 +105,26 @@ static igraph_error_t layout_reingold_tilford_unreachable( /* Internal structure for Reingold-Tilford layout */ struct reingold_tilford_vertex { - igraph_integer_t parent; /* Parent node index */ - igraph_integer_t level; /* Level of the node */ + igraph_int_t parent; /* Parent node index */ + igraph_int_t level; /* Level of the node */ igraph_real_t offset; /* X offset from parent node */ - igraph_integer_t left_contour; /* Next left node of the contour + igraph_int_t left_contour; /* Next left node of the contour of the subtree rooted at this node */ - igraph_integer_t right_contour; /* Next right node of the contour + igraph_int_t right_contour; /* Next right node of the contour of the subtree rooted at this node */ igraph_real_t offset_to_left_contour; /* X offset when following the left contour */ igraph_real_t offset_to_right_contour; /* X offset when following the right contour */ - igraph_integer_t left_extreme; /* Leftmost node on the deepest layer of the subtree rooted at this node */ - igraph_integer_t right_extreme; /* Rightmost node on the deepest layer of the subtree rooted at this node */ + igraph_int_t left_extreme; /* Leftmost node on the deepest layer of the subtree rooted at this node */ + igraph_int_t right_extreme; /* Rightmost node on the deepest layer of the subtree rooted at this node */ igraph_real_t offset_to_left_extreme; /* X offset when jumping to the left extreme node */ igraph_real_t offset_to_right_extreme; /* X offset when jumping to the right extreme node */ }; static void layout_reingold_tilford_postorder(struct reingold_tilford_vertex *vdata, - igraph_integer_t node, igraph_integer_t vcount); + igraph_int_t node, igraph_int_t vcount); static void layout_reingold_tilford_calc_coords(struct reingold_tilford_vertex *vdata, - igraph_matrix_t *res, igraph_integer_t node, - igraph_integer_t vcount, igraph_real_t xpos); + igraph_matrix_t *res, igraph_int_t node, + igraph_int_t vcount, igraph_real_t xpos); /* uncomment the next line for debugging the Reingold-Tilford layout */ /* #define LAYOUT_RT_DEBUG 1 */ @@ -134,9 +132,9 @@ static void layout_reingold_tilford_calc_coords(struct reingold_tilford_vertex * static igraph_error_t layout_reingold_tilford(const igraph_t *graph, igraph_matrix_t *res, igraph_neimode_t mode, - igraph_integer_t root) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t i, n, j; + igraph_int_t root) { + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i, n, j; igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; igraph_adjlist_t allneis; igraph_vector_int_t *neis; @@ -175,13 +173,13 @@ static igraph_error_t layout_reingold_tilford(const igraph_t *graph, IGRAPH_CHECK(igraph_dqueue_int_push(&q, root)); IGRAPH_CHECK(igraph_dqueue_int_push(&q, 0)); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); neis = igraph_adjlist_get(&allneis, actnode); n = igraph_vector_int_size(neis); for (j = 0; j < n; j++) { - igraph_integer_t neighbor = VECTOR(*neis)[j]; + igraph_int_t neighbor = VECTOR(*neis)[j]; if (vdata[neighbor].parent >= 0) { continue; } @@ -230,11 +228,11 @@ static igraph_error_t layout_reingold_tilford(const igraph_t *graph, static void layout_reingold_tilford_calc_coords( struct reingold_tilford_vertex *vdata, - igraph_matrix_t *res, igraph_integer_t node, - igraph_integer_t vcount, igraph_real_t xpos) { + igraph_matrix_t *res, igraph_int_t node, + igraph_int_t vcount, igraph_real_t xpos) { MATRIX(*res, node, 0) = xpos; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { if (i == node) { continue; } @@ -247,9 +245,9 @@ static void layout_reingold_tilford_calc_coords( static void layout_reingold_tilford_postorder( struct reingold_tilford_vertex *vdata, - igraph_integer_t node, igraph_integer_t vcount) { + igraph_int_t node, igraph_int_t vcount) { - igraph_integer_t childcount, leftroot, leftrootidx; + igraph_int_t childcount, leftroot, leftrootidx; const igraph_real_t minsep = 1; igraph_real_t avg; @@ -259,7 +257,7 @@ static void layout_reingold_tilford_postorder( /* Check whether this node is a leaf node */ childcount = 0; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { if (i == node) { continue; } @@ -287,7 +285,7 @@ static void layout_reingold_tilford_postorder( #ifdef LAYOUT_RT_DEBUG printf("Visited node %" IGRAPH_PRId " and arranged its subtrees\n", node); #endif - for (igraph_integer_t i = 0, j = 0; i < vcount; i++) { + for (igraph_int_t i = 0, j = 0; i < vcount; i++) { if (i == node) { continue; } @@ -295,7 +293,7 @@ static void layout_reingold_tilford_postorder( if (leftroot >= 0) { /* Now we will follow the right contour of leftroot and the * left contour of the subtree rooted at i */ - igraph_integer_t lnode, rnode, auxnode; + igraph_int_t lnode, rnode, auxnode; igraph_real_t loffset, roffset, rootsep, newoffset; #ifdef LAYOUT_RT_DEBUG @@ -434,7 +432,7 @@ static void layout_reingold_tilford_postorder( vdata[node].offset_to_right_contour -= avg; vdata[node].offset_to_left_extreme -= avg; vdata[node].offset_to_right_extreme -= avg; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { if (i == node) { continue; } @@ -450,7 +448,7 @@ static void layout_reingold_tilford_postorder( static igraph_error_t layout_reingold_tilford_cluster_degrees_directed( const igraph_t *graph, const igraph_vector_int_t *membership, - igraph_integer_t no_comps, + igraph_int_t no_comps, igraph_neimode_t mode, igraph_vector_int_t *degrees) { @@ -467,15 +465,15 @@ static igraph_error_t layout_reingold_tilford_cluster_degrees_directed( IGRAPH_FINALLY(igraph_eit_destroy, &eit); for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t eid = IGRAPH_EIT_GET(eit); + igraph_int_t eid = IGRAPH_EIT_GET(eit); - igraph_integer_t from = IGRAPH_FROM(graph, eid); - igraph_integer_t to = IGRAPH_TO(graph, eid); + igraph_int_t from = IGRAPH_FROM(graph, eid); + igraph_int_t to = IGRAPH_TO(graph, eid); - igraph_integer_t from_cl = VECTOR(*membership)[from]; - igraph_integer_t to_cl = VECTOR(*membership)[to]; + igraph_int_t from_cl = VECTOR(*membership)[from]; + igraph_int_t to_cl = VECTOR(*membership)[to]; - igraph_integer_t cl = mode == IGRAPH_OUT ? from_cl : to_cl; + igraph_int_t cl = mode == IGRAPH_OUT ? from_cl : to_cl; if (from_cl != to_cl) { VECTOR(*degrees)[cl] += 1; @@ -541,10 +539,10 @@ igraph_error_t igraph_roots_for_tree_layout( igraph_vector_int_t *roots, igraph_root_choice_t heuristic) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t order, membership; - igraph_integer_t no_comps; - igraph_integer_t i, j; + igraph_int_t no_comps; + igraph_int_t i, j; igraph_bool_t use_eccentricity; switch (heuristic) { @@ -572,7 +570,7 @@ igraph_error_t igraph_roots_for_tree_layout( igraph_vector_t ecc; IGRAPH_VECTOR_INIT_FINALLY(&ecc, no_of_nodes); - IGRAPH_CHECK(igraph_eccentricity(graph, &ecc, igraph_vss_all(), mode)); + IGRAPH_CHECK(igraph_eccentricity(graph, NULL, &ecc, igraph_vss_all(), mode)); IGRAPH_CHECK(igraph_vector_sort_ind(&ecc, &order, IGRAPH_ASCENDING)); igraph_vector_destroy(&ecc); @@ -613,8 +611,8 @@ igraph_error_t igraph_roots_for_tree_layout( * and record largest degree node in each strongly-connected component * which has no incoming (outgoing) edges. */ for (i = 0; i < no_of_nodes; ++i) { - igraph_integer_t v = VECTOR(order)[i]; - igraph_integer_t cl = VECTOR(membership)[v]; + igraph_int_t v = VECTOR(order)[i]; + igraph_int_t cl = VECTOR(membership)[v]; if (VECTOR(cluster_degrees)[cl] == 0 && VECTOR(*roots)[cl] == -1) { VECTOR(*roots)[cl] = v; } @@ -639,11 +637,11 @@ igraph_error_t igraph_roots_for_tree_layout( * Select the highest degree node from each component. */ - igraph_integer_t no_seen = 0; + igraph_int_t no_seen = 0; for (i=0; i < no_of_nodes; ++i) { - igraph_integer_t v = VECTOR(order)[i]; - igraph_integer_t cl = VECTOR(membership)[v]; + igraph_int_t v = VECTOR(order)[i]; + igraph_int_t cl = VECTOR(membership)[v]; if (VECTOR(*roots)[cl] == -1) { no_seen += 1; VECTOR(*roots)[cl] = v; @@ -718,9 +716,9 @@ igraph_error_t igraph_layout_reingold_tilford(const igraph_t *graph, const igraph_vector_int_t *roots, const igraph_vector_int_t *rootlevel) { - const igraph_integer_t no_of_nodes_orig = igraph_vcount(graph); - igraph_integer_t no_of_nodes = no_of_nodes_orig; - igraph_integer_t real_root; + const igraph_int_t no_of_nodes_orig = igraph_vcount(graph); + igraph_int_t no_of_nodes = no_of_nodes_orig; + igraph_int_t real_root; igraph_t extended; const igraph_t *pextended = graph; igraph_vector_int_t myroots; @@ -762,7 +760,7 @@ igraph_error_t igraph_layout_reingold_tilford(const igraph_t *graph, /* ----------------------------------------------------------------------- */ /* Many roots were given to us, check 'rootlevel' */ - igraph_integer_t plus_levels = 0; + igraph_int_t plus_levels = 0; if (igraph_vector_int_size(roots) != igraph_vector_int_size(rootlevel)) { IGRAPH_ERROR("Reingold-Tilford: 'roots' and 'rootlevel' lengths differ", @@ -770,13 +768,13 @@ igraph_error_t igraph_layout_reingold_tilford(const igraph_t *graph, } /* count the rootlevels that are not zero */ - for (igraph_integer_t i = 0; i < igraph_vector_int_size(roots); i++) { + for (igraph_int_t i = 0; i < igraph_vector_int_size(roots); i++) { plus_levels += VECTOR(*rootlevel)[i]; } /* make copy of graph, add vertices/edges */ if (plus_levels != 0) { - igraph_integer_t edgeptr = 0; + igraph_int_t edgeptr = 0; pextended = &extended; IGRAPH_CHECK(igraph_copy(&extended, graph)); @@ -785,10 +783,10 @@ igraph_error_t igraph_layout_reingold_tilford(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_resize(&newedges, plus_levels * 2)); - for (igraph_integer_t i = 0; i < igraph_vector_int_size(roots); i++) { - igraph_integer_t rl = VECTOR(*rootlevel)[i]; - igraph_integer_t rn = VECTOR(*roots)[i]; - igraph_integer_t j; + for (igraph_int_t i = 0; i < igraph_vector_int_size(roots); i++) { + igraph_int_t rl = VECTOR(*rootlevel)[i]; + igraph_int_t rn = VECTOR(*roots)[i]; + igraph_int_t j; /* zero-level roots don't get anything special */ if (rl == 0) { @@ -860,7 +858,7 @@ igraph_error_t igraph_layout_reingold_tilford(const igraph_t *graph, /* else, we need to make real_root */ } else { - igraph_integer_t no_of_newedges; + igraph_int_t no_of_newedges; /* Make copy of the graph unless it exists already */ if (pextended == graph) { @@ -877,7 +875,7 @@ igraph_error_t igraph_layout_reingold_tilford(const igraph_t *graph, /* add edges from the roots to real_root */ no_of_newedges = igraph_vector_int_size(proots); IGRAPH_CHECK(igraph_vector_int_resize(&newedges, no_of_newedges * 2)); - for (igraph_integer_t i = 0; i < no_of_newedges; i++) { + for (igraph_int_t i = 0; i < no_of_newedges; i++) { VECTOR(newedges)[2 * i] = no_of_nodes - 1; VECTOR(newedges)[2 * i + 1] = VECTOR(*proots)[i]; } @@ -911,7 +909,7 @@ igraph_error_t igraph_layout_reingold_tilford(const igraph_t *graph, IGRAPH_CHECK(igraph_matrix_remove_row(res, no_of_nodes_orig)); } else { igraph_matrix_t tmp; - igraph_integer_t i; + igraph_int_t i; IGRAPH_MATRIX_INIT_FINALLY(&tmp, no_of_nodes_orig, 2); for (i = 0; i < no_of_nodes_orig; i++) { MATRIX(tmp, i, 0) = MATRIX(*res, i, 0); @@ -977,7 +975,7 @@ igraph_error_t igraph_layout_reingold_tilford_circular(const igraph_t *graph, const igraph_vector_int_t *roots, const igraph_vector_int_t *rootlevel) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_real_t ratio; igraph_real_t minx, maxx; @@ -990,7 +988,7 @@ igraph_error_t igraph_layout_reingold_tilford_circular(const igraph_t *graph, ratio = 2 * M_PI * (no_of_nodes - 1.0) / no_of_nodes; minx = maxx = MATRIX(*res, 0, 0); - for (igraph_integer_t i = 1; i < no_of_nodes; i++) { + for (igraph_int_t i = 1; i < no_of_nodes; i++) { if (MATRIX(*res, i, 0) > maxx) { maxx = MATRIX(*res, i, 0); } @@ -1001,7 +999,7 @@ igraph_error_t igraph_layout_reingold_tilford_circular(const igraph_t *graph, if (maxx > minx) { ratio /= (maxx - minx); } - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { igraph_real_t phi = (MATRIX(*res, i, 0) - minx) * ratio; igraph_real_t r = MATRIX(*res, i, 1); MATRIX(*res, i, 0) = r * cos(phi); diff --git a/src/vendor/cigraph/src/layout/sugiyama.c b/src/vendor/cigraph/src/layout/sugiyama.c index 097a96ce097..d30c8d969ab 100644 --- a/src/vendor/cigraph/src/layout/sugiyama.c +++ b/src/vendor/cigraph/src/layout/sugiyama.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -35,30 +33,18 @@ #include "igraph_types.h" #include "internal/glpk_support.h" -#include "misc/feedback_arc_set.h" +#include "cycles/feedback_sets.h" #include /* #define SUGIYAMA_DEBUG */ -#ifdef _MSC_VER -/* MSVC does not support variadic macros */ -#include -static void debug(const char* fmt, ...) { - va_list args; - va_start(args, fmt); -#ifdef SUGIYAMA_DEBUG - vfprintf(stderr, fmt, args); -#endif - va_end(args); -} -#else + #ifdef SUGIYAMA_DEBUG #define debug(...) fprintf(stderr, __VA_ARGS__) #else #define debug(...) #endif -#endif /* MSVC uses __forceinline instead of inline */ #ifdef _MSC_VER @@ -161,7 +147,7 @@ typedef struct { */ static igraph_error_t igraph_i_layering_init(igraph_i_layering_t* layering, const igraph_vector_int_t* membership) { - igraph_integer_t i, n, num_layers; + igraph_int_t i, n, num_layers; if (igraph_vector_int_size(membership) == 0) { num_layers = 0; @@ -173,7 +159,7 @@ static igraph_error_t igraph_i_layering_init(igraph_i_layering_t* layering, n = igraph_vector_int_size(membership); for (i = 0; i < n; i++) { - igraph_integer_t l = VECTOR(*membership)[i]; + igraph_int_t l = VECTOR(*membership)[i]; igraph_vector_int_t* vec = igraph_vector_int_list_get_ptr(&layering->layers, l); IGRAPH_CHECK(igraph_vector_int_push_back(vec, i)); } @@ -193,7 +179,7 @@ static void igraph_i_layering_destroy(igraph_i_layering_t* layering) { /** * Returns the number of layers in a layering. */ -static igraph_integer_t igraph_i_layering_num_layers(const igraph_i_layering_t* layering) { +static igraph_int_t igraph_i_layering_num_layers(const igraph_i_layering_t* layering) { return igraph_vector_int_list_size(&layering->layers); } @@ -201,7 +187,7 @@ static igraph_integer_t igraph_i_layering_num_layers(const igraph_i_layering_t* * Returns the list of vertices in a given layer */ static igraph_vector_int_t* igraph_i_layering_get(const igraph_i_layering_t* layering, - igraph_integer_t index) { + igraph_int_t index) { return igraph_vector_int_list_get_ptr(&layering->layers, index); } @@ -214,10 +200,10 @@ static igraph_error_t igraph_i_layout_sugiyama_place_nodes_vertically(const igra const igraph_vector_t* weights, igraph_vector_int_t* membership); static igraph_error_t igraph_i_layout_sugiyama_order_nodes_horizontally(const igraph_t* graph, igraph_matrix_t* layout, const igraph_i_layering_t* layering, - igraph_integer_t maxiter); + igraph_int_t maxiter); static igraph_error_t igraph_i_layout_sugiyama_place_nodes_horizontally(const igraph_t* graph, igraph_matrix_t* layout, const igraph_i_layering_t* layering, - igraph_real_t hgap, igraph_integer_t no_of_real_nodes); + igraph_real_t hgap, igraph_int_t no_of_real_nodes); /** * Calculated the median of four numbers (not necessarily sorted). @@ -225,8 +211,7 @@ static igraph_error_t igraph_i_layout_sugiyama_place_nodes_horizontally(const ig static INLINE igraph_real_t igraph_i_median_4(igraph_real_t x1, igraph_real_t x2, igraph_real_t x3, igraph_real_t x4) { igraph_real_t arr[4] = { x1, x2, x3, x4 }; - igraph_vector_t vec; - igraph_vector_view(&vec, arr, 4); + igraph_vector_t vec = igraph_vector_view(arr, 4); igraph_vector_sort(&vec); return (arr[1] + arr[2]) / 2.0; } @@ -252,15 +237,13 @@ static INLINE igraph_real_t igraph_i_median_4(igraph_real_t x1, * * * The Sugiyama layout may introduce "bends" on the edges in order to obtain a - * visually more pleasing layout. This is achieved by adding dummy nodes to - * edges spanning more than one layer. The resulting layout assigns coordinates - * not only to the nodes of the original graph but also to the dummy nodes. - * The layout algorithm will also return the extended graph with the dummy nodes. - * An edge in the original graph may either be mapped to a single edge in the - * extended graph or a \em path that starts and ends in the original - * source and target vertex and passes through multiple dummy vertices. In - * such cases, the user may also request the mapping of the edges of the extended - * graph back to the edges of the original graph. + * visually more pleasing layout. The additional control points of the edges are + * returned in a separate list of matrices, one matrix per edge in the original + * graph. If an edge requires no additional control points, the corresponding + * matrix will be empty, otherwise the matrix will contain the coordinates of + * the control points, one point per row. When drawing the graph, edges should + * be drawn in a way that the curve representing the edge passes through the + * control points. * * * For more details, see K. Sugiyama, S. Tagawa and M. Toda, "Methods for Visual @@ -269,21 +252,16 @@ static INLINE igraph_real_t igraph_i_median_4(igraph_real_t x1, * * \param graph Pointer to an initialized graph object. * \param res Pointer to an initialized matrix object. This will contain - * the result and will be resized as needed. The first |V| rows - * of the layout will contain the coordinates of the original graph, - * the remaining rows contain the positions of the dummy nodes. - * Therefore, you can use the result both with \p graph or with - * \p extended_graph. - * \param extd_graph Pointer to an uninitialized graph object or \c NULL. - * The extended graph with the added dummy nodes will be - * returned here. In this graph, each edge points downwards - * to lower layers, spans exactly one layer and the first - * |V| vertices coincide with the vertices of the - * original graph. - * \param extd_to_orig_eids Pointer to a vector or \c NULL. If not \c NULL, the - * mapping from the edge IDs of the extended graph back - * to the edge IDs of the original graph will be stored - * here. + * the result and will be resized as needed. The coordinates of the + * vertices in the layout will be stored in the rows of the matrix, + * one row per vertex. + * \param routing Pointer to an uninitialized list of matrices or \c NULL. + * When not \c NULL, the list will be resized as needed such + * that there will be one matrix for each edge of the graph, + * and the matrix will hold the additional control points that + * the edge must pass through, starting from the source vertex + * of the edge and ending at the target vertex. The matrix will + * have zero rows if an edge does not require control points. * \param layers The layer index for each vertex or \c NULL if the layers should * be determined automatically by igraph. * \param hgap The preferred minimum horizontal gap between vertices in the same @@ -297,37 +275,39 @@ static INLINE igraph_real_t igraph_i_median_4(igraph_real_t x1, * weights when breaking the cycles. * \return Error code. */ -igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *res, - igraph_t *extd_graph, igraph_vector_int_t *extd_to_orig_eids, - const igraph_vector_int_t* layers, igraph_real_t hgap, igraph_real_t vgap, - igraph_integer_t maxiter, const igraph_vector_t *weights) { - igraph_integer_t i, j, k, l, m, nei; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t comp_idx; - igraph_integer_t next_extd_vertex_id = no_of_nodes; +igraph_error_t igraph_layout_sugiyama( + const igraph_t *graph, igraph_matrix_t *res, igraph_matrix_list_t *routing, + const igraph_vector_int_t* layers, igraph_real_t hgap, igraph_real_t vgap, + igraph_int_t maxiter, const igraph_vector_t *weights +) { + igraph_int_t i, j, k, l, nei; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t comp_idx; igraph_bool_t directed = igraph_is_directed(graph); - igraph_integer_t no_of_components; /* number of components of the original graph */ + igraph_int_t no_of_components; /* number of components of the original graph */ igraph_vector_int_t membership; /* components of the original graph */ - igraph_vector_int_t extd_edgelist; /* edge list of the extended graph */ igraph_vector_int_t layers_own; /* layer indices after having eliminated empty layers */ - igraph_real_t dx = 0, dx2 = 0; /* displacement of the current component on the X axis */ + igraph_real_t dx = 0; /* displacement of the current component on the X axis */ igraph_vector_t layer_to_y; /* mapping from layer indices to final Y coordinates */ + igraph_matrix_t *control_points; if (layers && igraph_vector_int_size(layers) != no_of_nodes) { IGRAPH_ERROR("layer vector too short or too long", IGRAPH_EINVAL); } - if (extd_graph != 0) { - IGRAPH_VECTOR_INT_INIT_FINALLY(&extd_edgelist, 0); - if (extd_to_orig_eids != 0) { - igraph_vector_int_clear(extd_to_orig_eids); - } - } - IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2)); IGRAPH_VECTOR_INT_INIT_FINALLY(&membership, 0); IGRAPH_VECTOR_INIT_FINALLY(&layer_to_y, 0); + if (routing != 0) { + IGRAPH_CHECK(igraph_matrix_list_resize(routing, no_of_edges)); + for (i = 0; i < no_of_edges; i++) { + control_points = igraph_matrix_list_get_ptr(routing, i); + IGRAPH_CHECK(igraph_matrix_resize(control_points, 0, 2)); + } + } + /* 1. Find a feedback arc set if we don't have a layering yet. If we do have * a layering, we can leave all the edges as is as they will be re-oriented * to point downwards only anyway. */ @@ -367,9 +347,10 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re for (comp_idx = 0; comp_idx < no_of_components; comp_idx++) { /* Extract the edges of the comp_idx'th component and add dummy nodes for edges * spanning more than one layer. */ - igraph_integer_t component_size, next_new_vertex_id; + igraph_int_t component_size, next_new_vertex_id; igraph_vector_int_t old2new_vertex_ids; igraph_vector_int_t new2old_vertex_ids; + igraph_vector_int_t new_vertex_id_to_edge_id; igraph_vector_int_t new_layers; igraph_vector_int_t edgelist; igraph_vector_int_t neis; @@ -378,9 +359,11 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&new2old_vertex_ids, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&old2new_vertex_ids, no_of_nodes); + IGRAPH_VECTOR_INT_INIT_FINALLY(&new_vertex_id_to_edge_id, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&new_layers, 0); igraph_vector_int_fill(&old2new_vertex_ids, -1); + igraph_vector_int_fill(&new_vertex_id_to_edge_id, -1); /* Construct a mapping from the old vertex IDs to the new ones */ for (i = 0, next_new_vertex_id = 0; i < no_of_nodes; i++) { @@ -402,10 +385,10 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re /* Okay, this vertex is in the component we are considering. * Add the neighbors of this vertex, excluding loops */ - IGRAPH_CHECK(igraph_incident(graph, &neis, i, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(graph, &neis, i, IGRAPH_OUT, IGRAPH_LOOPS)); j = igraph_vector_int_size(&neis); for (k = 0; k < j; k++) { - igraph_integer_t eid = VECTOR(neis)[k]; + igraph_int_t eid = VECTOR(neis)[k]; if (directed) { nei = IGRAPH_TO(graph, eid); } else { @@ -416,16 +399,11 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re } if (VECTOR(layers_own)[i] == VECTOR(layers_own)[nei]) { /* Edge goes within the same layer, we don't need this in the - * layered graph, but we need it in the extended graph */ - if (extd_graph != 0) { - IGRAPH_CHECK(igraph_vector_int_push_back(&extd_edgelist, i)); - IGRAPH_CHECK(igraph_vector_int_push_back(&extd_edgelist, nei)); - if (extd_to_orig_eids != 0) { - IGRAPH_CHECK(igraph_vector_int_push_back(extd_to_orig_eids, eid)); - } - } + * layered graph */ } else if (VECTOR(layers_own)[i] > VECTOR(layers_own)[nei]) { - /* Edge goes upwards, we have to flip it */ + /* Edge goes upwards, we have to flip it and then later on we need to traverse + * its control points in reverse order. We remember that we need to flip it + * by storing -eid-1 in `new_vertex_id_to_edge_id` instead of eid */ IGRAPH_CHECK(igraph_vector_int_push_back(&edgelist, VECTOR(old2new_vertex_ids)[nei])); for (l = VECTOR(layers_own)[nei] + 1; @@ -433,27 +411,10 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re IGRAPH_CHECK(igraph_vector_int_push_back(&new_layers, l)); IGRAPH_CHECK(igraph_vector_int_push_back(&edgelist, next_new_vertex_id)); IGRAPH_CHECK(igraph_vector_int_push_back(&edgelist, next_new_vertex_id++)); + IGRAPH_CHECK(igraph_vector_int_push_back(&new_vertex_id_to_edge_id, -eid-1)); } IGRAPH_CHECK(igraph_vector_int_push_back(&edgelist, VECTOR(old2new_vertex_ids)[i])); - /* Also add the edge to the extended graph if needed, but this time - * with the proper orientation */ - if (extd_graph != 0) { - IGRAPH_CHECK(igraph_vector_int_push_back(&extd_edgelist, i)); - next_extd_vertex_id += VECTOR(layers_own)[i] - VECTOR(layers_own)[nei] - 1; - for (l = VECTOR(layers_own)[i] - 1, m = 1; - l > VECTOR(layers_own)[nei]; l--, m++) { - IGRAPH_CHECK(igraph_vector_int_push_back(&extd_edgelist, next_extd_vertex_id - m)); - IGRAPH_CHECK(igraph_vector_int_push_back(&extd_edgelist, next_extd_vertex_id - m)); - if (extd_to_orig_eids != 0) { - IGRAPH_CHECK(igraph_vector_int_push_back(extd_to_orig_eids, eid)); - } - } - IGRAPH_CHECK(igraph_vector_int_push_back(&extd_edgelist, nei)); - if (extd_to_orig_eids != 0) { - IGRAPH_CHECK(igraph_vector_int_push_back(extd_to_orig_eids, eid)); - } - } } else { /* Edge goes downwards */ IGRAPH_CHECK(igraph_vector_int_push_back(&edgelist, @@ -463,25 +424,10 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re IGRAPH_CHECK(igraph_vector_int_push_back(&new_layers, l)); IGRAPH_CHECK(igraph_vector_int_push_back(&edgelist, next_new_vertex_id)); IGRAPH_CHECK(igraph_vector_int_push_back(&edgelist, next_new_vertex_id++)); + IGRAPH_CHECK(igraph_vector_int_push_back(&new_vertex_id_to_edge_id, eid)); } IGRAPH_CHECK(igraph_vector_int_push_back(&edgelist, VECTOR(old2new_vertex_ids)[nei])); - /* Also add the edge to the extended graph */ - if (extd_graph != 0) { - IGRAPH_CHECK(igraph_vector_int_push_back(&extd_edgelist, i)); - for (l = VECTOR(layers_own)[i] + 1; - l < VECTOR(layers_own)[nei]; l++) { - IGRAPH_CHECK(igraph_vector_int_push_back(&extd_edgelist, next_extd_vertex_id)); - IGRAPH_CHECK(igraph_vector_int_push_back(&extd_edgelist, next_extd_vertex_id++)); - if (extd_to_orig_eids != 0) { - IGRAPH_CHECK(igraph_vector_int_push_back(extd_to_orig_eids, eid)); - } - } - IGRAPH_CHECK(igraph_vector_int_push_back(&extd_edgelist, nei)); - if (extd_to_orig_eids != 0) { - IGRAPH_CHECK(igraph_vector_int_push_back(extd_to_orig_eids, eid)); - } - } } } } @@ -492,6 +438,10 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re igraph_matrix_t layout; igraph_i_layering_t layering; igraph_t subgraph; + igraph_int_t eid; + igraph_real_t max_x; + igraph_bool_t flipped; + igraph_matrix_t *control_points; IGRAPH_CHECK(igraph_matrix_init(&layout, next_new_vertex_id, 2)); IGRAPH_FINALLY(igraph_matrix_destroy, &layout); @@ -521,29 +471,60 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re IGRAPH_CHECK(igraph_i_layout_sugiyama_place_nodes_horizontally(&subgraph, &layout, &layering, hgap, component_size)); - /* Re-assign rows into the result matrix, and at the same time, */ + /* Arrange rows of the layout into the result matrix, and at the same time, */ /* adjust dx so that the next component does not overlap this one */ - j = next_new_vertex_id - component_size; - k = igraph_matrix_nrow(res); - IGRAPH_CHECK(igraph_matrix_add_rows(res, j)); - dx2 = dx; + + /* First we arrange the "real" vertices */ for (i = 0; i < component_size; i++) { - l = VECTOR(new2old_vertex_ids)[i]; - MATRIX(*res, l, 0) = MATRIX(layout, i, 0) + dx; - MATRIX(*res, l, 1) = VECTOR(layer_to_y)[(igraph_integer_t) MATRIX(layout, i, 1)]; - if (dx2 < MATRIX(*res, l, 0)) { - dx2 = MATRIX(*res, l, 0); + k = VECTOR(new2old_vertex_ids)[i]; + MATRIX(*res, k, 0) = MATRIX(layout, i, 0) + dx; + MATRIX(*res, k, 1) = VECTOR(layer_to_y)[(igraph_int_t) MATRIX(layout, i, 1)]; + } + + /* Next we arrange the "dummy" vertices that become control points in the + * routing matrix list. Note that the dummy vertices were added in a way that + * the vertices that will become control points on an edge with a particular ID + * are always consecutive in `new_vertex_id_to_edge_id` so we can count the number + * of waypoints in an edg easily */ + if (routing) { + IGRAPH_CHECK(igraph_vector_int_push_back(&new_vertex_id_to_edge_id, -1)); /* sentinel */ + while (i < next_new_vertex_id) { + eid = VECTOR(new_vertex_id_to_edge_id)[i]; + + /* Find out how many control points we have for this edge */ + for (j = i; VECTOR(new_vertex_id_to_edge_id)[j] == eid; j++); + + /* Is this edge flipped in the layered graph? If so, recover the original eid */ + flipped = eid < 0; + if (flipped) { + eid = -eid-1; + } + + control_points = igraph_matrix_list_get_ptr(routing, eid); + IGRAPH_CHECK(igraph_matrix_resize(control_points, j - i, 2)); + + if (flipped) { + for (k = j - i - 1; i < j; k--, i++) { + MATRIX(*control_points, k, 0) = MATRIX(layout, i, 0) + dx; + MATRIX(*control_points, k, 1) = VECTOR(layer_to_y)[(igraph_int_t) MATRIX(layout, i, 1)]; + } + } else { + for (k = 0; i < j; k++, i++) { + MATRIX(*control_points, k, 0) = MATRIX(layout, i, 0) + dx; + MATRIX(*control_points, k, 1) = VECTOR(layer_to_y)[(igraph_int_t) MATRIX(layout, i, 1)]; + } + } } } - for (i = component_size; i < next_new_vertex_id; i++) { - MATRIX(*res, k, 0) = MATRIX(layout, i, 0) + dx; - MATRIX(*res, k, 1) = VECTOR(layer_to_y)[(igraph_integer_t) MATRIX(layout, i, 1)]; - if (dx2 < MATRIX(*res, k, 0)) { - dx2 = MATRIX(*res, k, 0); + + /* Update the left margin for the next component */ + max_x = 0; + for (i = 0; i < next_new_vertex_id; i++) { + if (MATRIX(layout, i, 0) > max_x) { + max_x = MATRIX(layout, i, 0); } - k++; } - dx = dx2 + hgap; + dx += max_x + hgap; igraph_destroy(&subgraph); igraph_i_layering_destroy(&layering); @@ -552,11 +533,12 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re } igraph_vector_int_destroy(&new_layers); + igraph_vector_int_destroy(&new_vertex_id_to_edge_id); igraph_vector_int_destroy(&old2new_vertex_ids); igraph_vector_int_destroy(&new2old_vertex_ids); igraph_vector_int_destroy(&edgelist); igraph_vector_int_destroy(&neis); - IGRAPH_FINALLY_CLEAN(5); + IGRAPH_FINALLY_CLEAN(6); } igraph_vector_int_destroy(&layers_own); @@ -564,19 +546,13 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re igraph_vector_int_destroy(&membership); IGRAPH_FINALLY_CLEAN(3); - if (extd_graph != 0) { - IGRAPH_CHECK(igraph_create(extd_graph, &extd_edgelist, next_extd_vertex_id, igraph_is_directed(graph))); - igraph_vector_int_destroy(&extd_edgelist); - IGRAPH_FINALLY_CLEAN(1); - } - return IGRAPH_SUCCESS; } static igraph_error_t igraph_i_layout_sugiyama_place_nodes_vertically(const igraph_t* graph, const igraph_vector_t* weights, igraph_vector_int_t* membership) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); IGRAPH_CHECK(igraph_vector_int_resize(membership, no_of_nodes)); if (no_of_edges == 0) { @@ -588,7 +564,7 @@ static igraph_error_t igraph_i_layout_sugiyama_place_nodes_vertically(const igra if (igraph_is_directed(graph) && no_of_nodes <= 1000) { /* Network simplex algorithm of Gansner et al, using the original linear * programming formulation */ - igraph_integer_t i, j; + igraph_int_t i, j; igraph_vector_t outdegs, indegs; igraph_vector_int_t feedback_edges; glp_prob *ip; @@ -611,14 +587,14 @@ static igraph_error_t igraph_i_layout_sugiyama_place_nodes_vertically(const igra /* Calculate in- and out-strengths for the remaining edges */ IGRAPH_CHECK(igraph_strength(graph, &indegs, igraph_vss_all(), - IGRAPH_IN, 1, weights)); + IGRAPH_IN, IGRAPH_LOOPS, weights)); IGRAPH_CHECK(igraph_strength(graph, &outdegs, igraph_vss_all(), - IGRAPH_IN, 1, weights)); + IGRAPH_IN, IGRAPH_LOOPS, weights)); j = igraph_vector_int_size(&feedback_edges); for (i = 0; i < j; i++) { - igraph_integer_t eid = VECTOR(feedback_edges)[i]; - igraph_integer_t from = IGRAPH_FROM(graph, eid); - igraph_integer_t to = IGRAPH_TO(graph, eid); + igraph_int_t eid = VECTOR(feedback_edges)[i]; + igraph_int_t from = IGRAPH_FROM(graph, eid); + igraph_int_t to = IGRAPH_TO(graph, eid); VECTOR(outdegs)[from] -= weights ? VECTOR(*weights)[eid] : 1; VECTOR(indegs)[to] -= weights ? VECTOR(*weights)[eid] : 1; } @@ -699,10 +675,10 @@ static igraph_error_t igraph_i_layout_sugiyama_place_nodes_vertically(const igra } static igraph_error_t igraph_i_layout_sugiyama_calculate_barycenters(const igraph_t* graph, - const igraph_i_layering_t* layering, igraph_integer_t layer_index, + const igraph_i_layering_t* layering, igraph_int_t layer_index, igraph_neimode_t direction, const igraph_matrix_t* layout, igraph_vector_t* barycenters) { - igraph_integer_t i, j, m, n; + igraph_int_t i, j, m, n; igraph_vector_int_t* layer_members = igraph_i_layering_get(layering, layer_index); igraph_vector_int_t neis; @@ -713,7 +689,10 @@ static igraph_error_t igraph_i_layout_sugiyama_calculate_barycenters(const igrap igraph_vector_null(barycenters); for (i = 0; i < n; i++) { - IGRAPH_CHECK(igraph_neighbors(graph, &neis, VECTOR(*layer_members)[i], direction)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, VECTOR(*layer_members)[i], direction, + IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); m = igraph_vector_int_size(&neis); if (m == 0) { /* No neighbors in this direction. Just use the current X coordinate */ @@ -739,11 +718,11 @@ static igraph_error_t igraph_i_layout_sugiyama_calculate_barycenters(const igrap */ static igraph_error_t igraph_i_layout_sugiyama_order_nodes_horizontally(const igraph_t* graph, igraph_matrix_t* layout, const igraph_i_layering_t* layering, - igraph_integer_t maxiter) { - igraph_integer_t i, n, nei; - igraph_integer_t no_of_vertices = igraph_vcount(graph); - igraph_integer_t no_of_layers = igraph_i_layering_num_layers(layering); - igraph_integer_t iter, layer_index; + igraph_int_t maxiter) { + igraph_int_t i, n, nei; + igraph_int_t no_of_vertices = igraph_vcount(graph); + igraph_int_t no_of_layers = igraph_i_layering_num_layers(layering); + igraph_int_t iter, layer_index; igraph_vector_int_t* layer_members; igraph_vector_int_t new_layer_members; igraph_vector_int_t neis; @@ -754,10 +733,10 @@ static igraph_error_t igraph_i_layout_sugiyama_order_nodes_horizontally(const ig /* The first column of the matrix will serve as the ordering */ /* Start with a first-seen ordering within each layer */ { - igraph_integer_t *xs = IGRAPH_CALLOC(no_of_layers, igraph_integer_t); + igraph_int_t *xs = IGRAPH_CALLOC(no_of_layers, igraph_int_t); IGRAPH_CHECK_OOM(xs, "Cannot order nodes horizontally during Sugiyama layout."); for (i = 0; i < no_of_vertices; i++) { - MATRIX(*layout, i, 0) = xs[(igraph_integer_t)MATRIX(*layout, i, 1)]++; + MATRIX(*layout, i, 0) = xs[(igraph_int_t)MATRIX(*layout, i, 1)]++; } free(xs); } @@ -870,7 +849,7 @@ static igraph_error_t igraph_i_layout_sugiyama_horizontal_compaction(const igrap const igraph_vector_int_t* vertex_to_the_left, const igraph_vector_int_t* roots, const igraph_vector_int_t* align, igraph_real_t hgap, igraph_vector_t* xs); -static void igraph_i_layout_sugiyama_horizontal_compaction_place_block(igraph_integer_t v, +static void igraph_i_layout_sugiyama_horizontal_compaction_place_block(igraph_int_t v, const igraph_vector_int_t* vertex_to_the_left, const igraph_vector_int_t* roots, const igraph_vector_int_t* align, igraph_vector_int_t* sinks, igraph_vector_t* shifts, @@ -878,12 +857,12 @@ static void igraph_i_layout_sugiyama_horizontal_compaction_place_block(igraph_in static igraph_error_t igraph_i_layout_sugiyama_place_nodes_horizontally(const igraph_t* graph, igraph_matrix_t* layout, const igraph_i_layering_t* layering, - igraph_real_t hgap, igraph_integer_t no_of_real_nodes) { + igraph_real_t hgap, igraph_int_t no_of_real_nodes) { - igraph_integer_t i, j, k, l, n; - igraph_integer_t no_of_layers = igraph_i_layering_num_layers(layering); - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t i, j, k, l, n; + igraph_int_t no_of_layers = igraph_i_layering_num_layers(layering); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_int_t neis1, neis2; igraph_vector_t xs[4]; igraph_vector_int_t roots, align; @@ -923,7 +902,10 @@ static igraph_error_t igraph_i_layout_sugiyama_place_nodes_horizontally(const ig /* Find all the edges from this layer to the next */ igraph_vector_int_clear(&neis1); for (j = 0; j < n; j++) { - IGRAPH_CHECK(igraph_neighbors(graph, &neis2, VECTOR(*vertices)[j], IGRAPH_OUT)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis2, VECTOR(*vertices)[j], IGRAPH_OUT, + IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); IGRAPH_CHECK(igraph_vector_int_append(&neis1, &neis2)); } @@ -931,14 +913,14 @@ static igraph_error_t igraph_i_layout_sugiyama_place_nodes_horizontally(const ig * conflict */ n = igraph_vector_int_size(&neis1); for (j = 0; j < n; j++) { - igraph_integer_t u = IGRAPH_FROM(graph, j); - igraph_integer_t v = IGRAPH_TO(graph, j); + igraph_int_t u = IGRAPH_FROM(graph, j); + igraph_int_t v = IGRAPH_TO(graph, j); igraph_bool_t j_inner = IS_INNER_SEGMENT(u, v); igraph_bool_t crossing; for (k = j + 1; k < n; k++) { - igraph_integer_t w = IGRAPH_FROM(graph, k); - igraph_integer_t x = IGRAPH_TO(graph, k); + igraph_int_t w = IGRAPH_FROM(graph, k); + igraph_int_t x = IGRAPH_TO(graph, k); if (IS_INNER_SEGMENT(w, x) == j_inner) { continue; } @@ -1069,9 +1051,9 @@ static igraph_error_t igraph_i_layout_sugiyama_vertical_alignment(const igraph_t const igraph_vector_bool_t* ignored_edges, igraph_bool_t reverse, igraph_bool_t align_right, igraph_vector_int_t* roots, igraph_vector_int_t* align) { - igraph_integer_t i, j, k, n, di, dj, i_limit, j_limit, r; - igraph_integer_t no_of_layers = igraph_i_layering_num_layers(layering); - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i, j, k, n, di, dj, i_limit, j_limit, r; + igraph_int_t no_of_layers = igraph_i_layering_num_layers(layering); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_neimode_t neimode = (reverse ? IGRAPH_OUT : IGRAPH_IN); igraph_vector_int_t neis; igraph_vector_t xs; @@ -1107,9 +1089,9 @@ static igraph_error_t igraph_i_layout_sugiyama_vertical_alignment(const igraph_t dj = align_right ? -1 : 1; j_limit = align_right ? -1 : igraph_vector_int_size(layer); for (; j != j_limit; j += dj) { - igraph_integer_t medians[2]; - igraph_integer_t vertex = VECTOR(*layer)[j]; - igraph_integer_t pos; + igraph_int_t medians[2]; + igraph_int_t vertex = VECTOR(*layer)[j]; + igraph_int_t pos; if (VECTOR(*align)[vertex] != vertex) /* This vertex is already aligned with some other vertex, @@ -1119,7 +1101,9 @@ static igraph_error_t igraph_i_layout_sugiyama_vertical_alignment(const igraph_t } /* Find the neighbors of vertex j in layer i */ - IGRAPH_CHECK(igraph_neighbors(graph, &neis, vertex, neimode)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, vertex, neimode, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE + )); n = igraph_vector_int_size(&neis); if (n == 0) @@ -1159,7 +1143,7 @@ static igraph_error_t igraph_i_layout_sugiyama_vertical_alignment(const igraph_t /* Try aligning with the medians */ for (k = 0; k < 2; k++) { - igraph_integer_t eid; + igraph_int_t eid; if (medians[k] < 0) { continue; } @@ -1207,8 +1191,8 @@ static igraph_error_t igraph_i_layout_sugiyama_horizontal_compaction(const igrap const igraph_vector_int_t* vertex_to_the_left, const igraph_vector_int_t* roots, const igraph_vector_int_t* align, igraph_real_t hgap, igraph_vector_t* xs) { - igraph_integer_t i; - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i; + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_t shifts, old_xs; igraph_vector_int_t sinks; igraph_real_t shift; @@ -1246,7 +1230,7 @@ static igraph_error_t igraph_i_layout_sugiyama_horizontal_compaction(const igrap /* Calculate the absolute coordinates */ IGRAPH_CHECK(igraph_vector_update(&old_xs, xs)); for (i = 0; i < no_of_nodes; i++) { - igraph_integer_t root = VECTOR(*roots)[i]; + igraph_int_t root = VECTOR(*roots)[i]; VECTOR(*xs)[i] = VECTOR(old_xs)[root]; shift = VECTOR(shifts)[VECTOR(sinks)[root]]; if (shift < IGRAPH_INFINITY) { @@ -1262,13 +1246,13 @@ static igraph_error_t igraph_i_layout_sugiyama_horizontal_compaction(const igrap return IGRAPH_SUCCESS; } -static void igraph_i_layout_sugiyama_horizontal_compaction_place_block(igraph_integer_t v, +static void igraph_i_layout_sugiyama_horizontal_compaction_place_block(igraph_int_t v, const igraph_vector_int_t* vertex_to_the_left, const igraph_vector_int_t* roots, const igraph_vector_int_t* align, igraph_vector_int_t* sinks, igraph_vector_t* shifts, igraph_real_t hgap, igraph_vector_t* xs) { - igraph_integer_t u, w; - igraph_integer_t u_sink, v_sink; + igraph_int_t u, w; + igraph_int_t u_sink, v_sink; if (VECTOR(*xs)[v] >= 0) { return; diff --git a/src/vendor/cigraph/src/layout/umap.c b/src/vendor/cigraph/src/layout/umap.c index e3bd10ec60d..de5627e306c 100644 --- a/src/vendor/cigraph/src/layout/umap.c +++ b/src/vendor/cigraph/src/layout/umap.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -101,16 +101,16 @@ static igraph_error_t igraph_i_umap_find_sigma(const igraph_vector_t *distances, igraph_real_t sigma = 1; igraph_real_t sum; igraph_real_t tol = 0.01; - igraph_integer_t maxiter = 100; - igraph_integer_t no_of_neis = igraph_vector_int_size(eids); - igraph_integer_t eid; + igraph_int_t maxiter = 100; + igraph_int_t no_of_neis = igraph_vector_int_size(eids); + igraph_int_t eid; igraph_real_t step = sigma; - igraph_integer_t seen_max = 0; + igraph_int_t seen_max = 0; /* Binary search */ - for (igraph_integer_t iter = 0; iter < maxiter; iter++) { + for (igraph_int_t iter = 0; iter < maxiter; iter++) { sum = 0; - for (igraph_integer_t j = 0; j < no_of_neis; j++) { + for (igraph_int_t j = 0; j < no_of_neis; j++) { eid = VECTOR(*eids)[j]; sum += exp(-(VECTOR(*distances)[eid] - rho) / sigma); } @@ -219,9 +219,9 @@ igraph_error_t igraph_layout_umap_compute_weights( const igraph_vector_t *distances, igraph_vector_t *weights) { - igraph_integer_t no_of_vertices = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_neis; + igraph_int_t no_of_vertices = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_neis; igraph_vector_int_t eids; igraph_vector_int_list_t neighbors_seen; igraph_vector_list_t weights_seen; @@ -253,9 +253,9 @@ igraph_error_t igraph_layout_umap_compute_weights( IGRAPH_VECTOR_LIST_INIT_FINALLY(&weights_seen, no_of_vertices); /* Iterate over vertices x, like in the paper */ - for (igraph_integer_t i = 0; i < no_of_vertices; i++) { + for (igraph_int_t i = 0; i < no_of_vertices; i++) { /* Edges out of this vertex, e.g. to its k-nearest neighbors */ - IGRAPH_CHECK(igraph_incident(graph, &eids, i, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(graph, &eids, i, IGRAPH_OUT, IGRAPH_LOOPS)); no_of_neis = igraph_vector_int_size(&eids); /* Vertex has no neighbors */ @@ -267,8 +267,8 @@ igraph_error_t igraph_layout_umap_compute_weights( if (distances != NULL) { rho = VECTOR(*distances)[VECTOR(eids)[0]]; dist_max = rho; - for (igraph_integer_t j = 1; j < no_of_neis; j++) { - const igraph_integer_t eid = VECTOR(eids)[j]; + for (igraph_int_t j = 1; j < no_of_neis; j++) { + const igraph_int_t eid = VECTOR(eids)[j]; dist = VECTOR(*distances)[eid]; rho = fmin(rho, dist); dist_max = fmax(dist_max, dist); @@ -292,8 +292,8 @@ igraph_error_t igraph_layout_umap_compute_weights( } /* Convert to weights */ - for (igraph_integer_t j = 0; j < no_of_neis; j++) { - const igraph_integer_t eid = VECTOR(eids)[j]; + for (igraph_int_t j = 0; j < no_of_neis; j++) { + const igraph_int_t eid = VECTOR(eids)[j]; /* Basically, nodes closer than rho have probability 1, the rest is * exponentially penalized keeping rough cardinality */ @@ -306,7 +306,7 @@ igraph_error_t igraph_layout_umap_compute_weights( #endif /* Store in vector lists for later symmetrization */ - const igraph_integer_t k = IGRAPH_OTHER(graph, eid, i); + const igraph_int_t k = IGRAPH_OTHER(graph, eid, i); if (k == i) { IGRAPH_ERROR("Input graph must contain no self-loops.", IGRAPH_EINVAL); } @@ -323,9 +323,9 @@ igraph_error_t igraph_layout_umap_compute_weights( /* Symmetrize the weights. UMAP weights are probabilities of that edge being a * "real" connection. Unlike the distances, which can represent a directed graph, * weights are usually symmetric. We symmetrize via fuzzy union. */ - for (igraph_integer_t eid=0; eid < no_of_edges; eid++) { - const igraph_integer_t i = IGRAPH_FROM(graph, eid); - const igraph_integer_t k = IGRAPH_TO(graph, eid); + for (igraph_int_t eid=0; eid < no_of_edges; eid++) { + const igraph_int_t i = IGRAPH_FROM(graph, eid); + const igraph_int_t k = IGRAPH_TO(graph, eid); /* Direct weight, if found */ /* NOTE: this and the subsequent loop could be faster if we sorted the vectors @@ -334,7 +334,7 @@ igraph_error_t igraph_layout_umap_compute_weights( neighbors_seen_elt = igraph_vector_int_list_get_ptr(&neighbors_seen, i); weights_seen_elt = igraph_vector_list_get_ptr(&weights_seen, i); no_of_neis = igraph_vector_int_size(neighbors_seen_elt); - for (igraph_integer_t l=0; l < no_of_neis; l++) { + for (igraph_int_t l=0; l < no_of_neis; l++) { if (VECTOR(*neighbors_seen_elt)[l] == k) { weight = VECTOR(*weights_seen_elt)[l]; /* Tag this weight so we can ignore it later on if the opposite @@ -355,7 +355,7 @@ igraph_error_t igraph_layout_umap_compute_weights( neighbors_seen_elt = igraph_vector_int_list_get_ptr(&neighbors_seen, k); weights_seen_elt = igraph_vector_list_get_ptr(&weights_seen, k); no_of_neis = igraph_vector_int_size(neighbors_seen_elt); - for (igraph_integer_t l=0; l < no_of_neis; l++) { + for (igraph_int_t l=0; l < no_of_neis; l++) { if (VECTOR(*neighbors_seen_elt)[l] == i) { weight_inv = VECTOR(*weights_seen_elt)[l]; /* Tag this weight so we can ignore it later on if the opposite @@ -386,13 +386,13 @@ igraph_error_t igraph_layout_umap_compute_weights( /* Helper function to compute a and b parameters (smoothing probability metric in embedding space) */ static igraph_error_t igraph_i_umap_get_ab_residuals(igraph_vector_t *residuals, - igraph_real_t *squared_sum_res, igraph_integer_t nr_points, igraph_real_t a, + igraph_real_t *squared_sum_res, igraph_int_t nr_points, igraph_real_t a, igraph_real_t b, igraph_vector_t *powb, const igraph_vector_t *x, igraph_real_t min_dist) { igraph_real_t tmp; *squared_sum_res = 0; - for (igraph_integer_t i = 0; i < nr_points; i++) { + for (igraph_int_t i = 0; i < nr_points; i++) { /* The ideal probability is: * * P(d) = d < min_dist ? 1 : e^{-(d - min_dist)} @@ -470,7 +470,7 @@ igraph_error_t igraph_i_umap_fit_ab(igraph_real_t min_dist, igraph_real_t *a_p, /* Make a lattice from 0 to 3 * sigma with 300 points. This is what * umap.umap_.fit_ab_params does, but sigma is fixed to 1.0 here since * that's the default value used in scanpy and by virtually everyone */ - igraph_integer_t nr_points = 300; + igraph_int_t nr_points = 300; igraph_real_t end_point = 3.0; /* Initial values takes as reasonable assumptions from typical min_dist values */ igraph_real_t b = 0.8; @@ -502,7 +502,7 @@ igraph_error_t igraph_i_umap_fit_ab(igraph_real_t min_dist, igraph_real_t *a_p, IGRAPH_VECTOR_INIT_FINALLY(&powb, nr_points); /* Distance |x-y| (this is a lattice, there are no actual x and y) */ - for (igraph_integer_t i = 0; i < nr_points; i++) { + for (igraph_int_t i = 0; i < nr_points; i++) { VECTOR(x)[i] = (end_point / nr_points) * i + 0.001; /* added a 0.001 to prevent NaNs */ } @@ -513,7 +513,7 @@ igraph_error_t igraph_i_umap_fit_ab(igraph_real_t min_dist, igraph_real_t *a_p, #ifdef UMAP_DEBUG printf("start fit_ab\n"); #endif - for (igraph_integer_t iter = 0; iter < maxiter; iter++) { + for (igraph_int_t iter = 0; iter < maxiter; iter++) { IGRAPH_CHECK(igraph_i_umap_get_ab_residuals(&residuals, &squared_sum_res, nr_points, a, b, &powb, &x, min_dist)); @@ -533,7 +533,7 @@ igraph_error_t igraph_i_umap_fit_ab(igraph_real_t min_dist, igraph_real_t *a_p, } /* Jacobian (first derivatives) of squared residuals at (a, b) */ - for (igraph_integer_t i = 0; i < nr_points; i++) { + for (igraph_int_t i = 0; i < nr_points; i++) { tmp = 1 + a * VECTOR(powb)[i]; MATRIX(jacobian, i, 0) = - 2 * VECTOR(powb)[i] / tmp / tmp; MATRIX(jacobian, i, 1) = MATRIX(jacobian, i, 0) * a * log(VECTOR(x)[i]) * 2; @@ -562,9 +562,9 @@ igraph_error_t igraph_i_umap_fit_ab(igraph_real_t min_dist, igraph_real_t *a_p, /* Compute A and B, i.e. J^T @ J and J^T @ r */ MATRIX(jTj, 0, 0) = MATRIX(jTj, 0, 1) = MATRIX(jTj, 1, 0) = MATRIX(jTj, 1, 1) = 0; MATRIX(jTr, 0, 0) = MATRIX(jTr, 1, 0) = 0; - for (igraph_integer_t i = 0; i < nr_points; i++) { - for (igraph_integer_t j1 = 0; j1 < 2; j1++) { - for (igraph_integer_t j2 = 0; j2 < 2; j2++) { + for (igraph_int_t i = 0; i < nr_points; i++) { + for (igraph_int_t j1 = 0; j1 < 2; j1++) { + for (igraph_int_t j2 = 0; j2 < 2; j2++) { MATRIX(jTj, j1, j2) += MATRIX(jacobian, i, j1) * MATRIX(jacobian, i, j2); } MATRIX(jTr, j1, 0) += MATRIX(jacobian, i, j1) * VECTOR(residuals)[i]; @@ -592,7 +592,7 @@ igraph_error_t igraph_i_umap_fit_ab(igraph_real_t min_dist, igraph_real_t *a_p, printf("start line search, SSR before delta: %g, current SSR:, %g\n", squared_sum_res_old, squared_sum_res); #endif - for (igraph_integer_t k = 0; k < 30; k++) { + for (igraph_int_t k = 0; k < 30; k++) { /* Try new parameters */ da /= 2.0; db /= 2.0; @@ -648,9 +648,9 @@ static igraph_error_t igraph_i_umap_compute_cross_entropy(const igraph_t *graph, igraph_real_t *cross_entropy) { igraph_real_t mu, nu, xd, yd, sqd; - igraph_integer_t from, to; - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_vertices = igraph_vcount(graph); + igraph_int_t from, to; + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_vertices = igraph_vcount(graph); igraph_matrix_t edge_seen; IGRAPH_MATRIX_INIT_FINALLY(&edge_seen, no_of_vertices, no_of_vertices); @@ -663,7 +663,7 @@ static igraph_error_t igraph_i_umap_compute_cross_entropy(const igraph_t *graph, * repelling unconnected edges. * */ *cross_entropy = 0; - for (igraph_integer_t eid = 0; eid < no_of_edges; eid++) { + for (igraph_int_t eid = 0; eid < no_of_edges; eid++) { mu = VECTOR(*umap_weights)[eid]; /* Find vertices */ @@ -686,8 +686,8 @@ static igraph_error_t igraph_i_umap_compute_cross_entropy(const igraph_t *graph, MATRIX(edge_seen, from, to) = MATRIX(edge_seen, to, from) = 1; } /* Add the entropy from the missing edges */ - for (igraph_integer_t from = 0; from < no_of_vertices; from++) { - for (igraph_integer_t to = 0; to < from; to++) { + for (igraph_int_t from = 0; from < no_of_vertices; from++) { + for (igraph_int_t to = 0; to < from; to++) { if (MATRIX(edge_seen, from, to) > 0) { continue; } @@ -746,20 +746,20 @@ static igraph_error_t igraph_i_umap_apply_forces( igraph_real_t b, igraph_real_t learning_rate, igraph_bool_t avoid_neighbor_repulsion, - igraph_integer_t negative_sampling_rate, - igraph_integer_t epoch, + igraph_int_t negative_sampling_rate, + igraph_int_t epoch, igraph_vector_t *next_epoch_sample_per_edge) { - const igraph_integer_t no_of_vertices = igraph_matrix_nrow(layout); - const igraph_integer_t no_of_edges = igraph_ecount(graph); - const igraph_integer_t ndim = igraph_matrix_ncol(layout); + const igraph_int_t no_of_vertices = igraph_matrix_nrow(layout); + const igraph_int_t no_of_edges = igraph_ecount(graph); + const igraph_int_t ndim = igraph_matrix_ncol(layout); igraph_vector_t from_emb, to_emb, delta; /* The following is only used for small graphs, to avoid repelling your neighbors * For large sparse graphs, it's not necessary. For large dense graphs, you should * not be doing UMAP. */ igraph_vector_int_t neis, negative_vertices; - const igraph_integer_t n_negative_vertices = + const igraph_int_t n_negative_vertices = (no_of_vertices - 1 < negative_sampling_rate) ? (no_of_vertices - 1) : negative_sampling_rate; /* Initialize vectors */ @@ -772,8 +772,8 @@ static igraph_error_t igraph_i_umap_apply_forces( } /* Iterate over edges. Stronger edges are sampled more often */ - for (igraph_integer_t eid = 0; eid < no_of_edges; eid++) { - igraph_integer_t from, to; + for (igraph_int_t eid = 0; eid < no_of_edges; eid++) { + igraph_int_t from, to; igraph_real_t force, dsq, force_d; /* Zero-weight edges do not affect vertex positions. They can @@ -810,7 +810,7 @@ static igraph_error_t igraph_i_umap_apply_forces( /* Current coordinates of both vertices */ dsq = 0; - for (igraph_integer_t d = 0; d != ndim; d++) { + for (igraph_int_t d = 0; d != ndim; d++) { VECTOR(from_emb)[d] = MATRIX(*layout, from, d); VECTOR(to_emb)[d] = MATRIX(*layout, to, d); VECTOR(delta)[d] = MATRIX(*layout, from, d) - MATRIX(*layout, to, d); @@ -821,7 +821,7 @@ static igraph_error_t igraph_i_umap_apply_forces( /* NOTE: If they are already together, no force needed */ if (dsq >= UMAP_MIN_DISTANCE_ATTRACTION * UMAP_MIN_DISTANCE_ATTRACTION) { force = igraph_i_umap_attract(dsq, a, b); - for (igraph_integer_t d = 0; d != ndim; d++) { + for (igraph_int_t d = 0; d != ndim; d++) { force_d = force * VECTOR(delta)[d]; /* clip force to avoid too rapid change */ force_d = igraph_i_umap_clip_force(force_d, UMAP_FORCE_LIMIT); @@ -837,7 +837,7 @@ static igraph_error_t igraph_i_umap_apply_forces( /* Random other nodes repel the focal vertex */ IGRAPH_CHECK(igraph_random_sample(&negative_vertices, 0, no_of_vertices - 2, n_negative_vertices)); - for (igraph_integer_t j = 0; j < n_negative_vertices; j++) { + for (igraph_int_t j = 0; j < n_negative_vertices; j++) { IGRAPH_ALLOW_INTERRUPTION(); @@ -854,11 +854,11 @@ static igraph_error_t igraph_i_umap_apply_forces( /* NOTE: the efficiency of this step could be improved but it * should be only used for small graphs anyway, so it's fine */ igraph_bool_t skip = false; - IGRAPH_CHECK(igraph_incident(graph, &neis, from, IGRAPH_ALL)); - const igraph_integer_t nneis = igraph_vector_int_size(&neis); - for (igraph_integer_t k = 0; k < nneis; k++) { - igraph_integer_t eid2 = VECTOR(neis)[k]; - igraph_integer_t from2, to2; + IGRAPH_CHECK(igraph_incident(graph, &neis, from, IGRAPH_ALL, IGRAPH_LOOPS)); + const igraph_int_t nneis = igraph_vector_int_size(&neis); + for (igraph_int_t k = 0; k < nneis; k++) { + igraph_int_t eid2 = VECTOR(neis)[k]; + igraph_int_t from2, to2; from2 = IGRAPH_FROM(graph, eid2); to2 = IGRAPH_TO(graph, eid2); if (((from2 == from) && (to2 == to)) || ((from2 == to) && (from == to2))) { @@ -873,7 +873,7 @@ static igraph_error_t igraph_i_umap_apply_forces( /* Get layout of random neighbor and gradient in embedding */ dsq = 0; - for (igraph_integer_t d = 0; d != ndim; d++) { + for (igraph_int_t d = 0; d != ndim; d++) { VECTOR(to_emb)[d] = MATRIX(*layout, to, d); VECTOR(delta)[d] = MATRIX(*layout, from, d) - MATRIX(*layout, to, d); dsq += VECTOR(delta)[d] * VECTOR(delta)[d]; @@ -883,7 +883,7 @@ static igraph_error_t igraph_i_umap_apply_forces( * that is no weight, no edge */ force = igraph_i_umap_repel(dsq, a, b); /* The repulsive force is already *away* from the other (non-neighbor) vertex */ - for (igraph_integer_t d = 0; d != ndim; d++) { + for (igraph_int_t d = 0; d != ndim; d++) { force_d = force * VECTOR(delta)[d]; /* clip force to avoid too rapid change */ @@ -926,11 +926,11 @@ static igraph_error_t igraph_i_umap_optimize_layout_stochastic_gradient( igraph_real_t a, igraph_real_t b, igraph_matrix_t *layout, - igraph_integer_t epochs, - igraph_integer_t negative_sampling_rate) { + igraph_int_t epochs, + igraph_int_t negative_sampling_rate) { igraph_real_t learning_rate = 1; - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_t next_epoch_sample_per_edge; #ifdef UMAP_DEBUG @@ -963,7 +963,7 @@ static igraph_error_t igraph_i_umap_optimize_layout_stochastic_gradient( graph, umap_weights, layout, a, b, &cross_entropy); #endif - for (igraph_integer_t e = 0; e < epochs; e++) { + for (igraph_int_t e = 0; e < epochs; e++) { /* Apply (stochastic) forces */ IGRAPH_CHECK(igraph_i_umap_apply_forces( graph, @@ -997,11 +997,11 @@ static igraph_error_t igraph_i_umap_optimize_layout_stochastic_gradient( /* Center 2D layout around (0,0) at the end, just for convenience */ static void igraph_i_umap_center_layout(igraph_matrix_t *layout) { - igraph_integer_t no_of_vertices = igraph_matrix_nrow(layout); + igraph_int_t no_of_vertices = igraph_matrix_nrow(layout); igraph_real_t xm = 0, ym = 0; /* Compute center */ - for (igraph_integer_t i = 0; i < no_of_vertices; i++) { + for (igraph_int_t i = 0; i < no_of_vertices; i++) { xm += MATRIX(*layout, i, 0); ym += MATRIX(*layout, i, 1); } @@ -1009,7 +1009,7 @@ static void igraph_i_umap_center_layout(igraph_matrix_t *layout) { ym /= no_of_vertices; /* Shift vertices */ - for (igraph_integer_t i = 0; i < no_of_vertices; i++) { + for (igraph_int_t i = 0; i < no_of_vertices; i++) { MATRIX(*layout, i, 0) -= xm; MATRIX(*layout, i, 1) -= ym; } @@ -1017,11 +1017,11 @@ static void igraph_i_umap_center_layout(igraph_matrix_t *layout) { /* Center 3D layout around (0,0,0) at the end, just for convenience */ static void igraph_i_umap_center_layout_3d(igraph_matrix_t *layout) { - igraph_integer_t no_of_vertices = igraph_matrix_nrow(layout); + igraph_int_t no_of_vertices = igraph_matrix_nrow(layout); igraph_real_t xm = 0, ym = 0, zm = 0; /* Compute center */ - for (igraph_integer_t i = 0; i < no_of_vertices; i++) { + for (igraph_int_t i = 0; i < no_of_vertices; i++) { xm += MATRIX(*layout, i, 0); ym += MATRIX(*layout, i, 1); zm += MATRIX(*layout, i, 2); @@ -1031,7 +1031,7 @@ static void igraph_i_umap_center_layout_3d(igraph_matrix_t *layout) { zm /= no_of_vertices; /* Shift vertices */ - for (igraph_integer_t i = 0; i < no_of_vertices; i++) { + for (igraph_int_t i = 0; i < no_of_vertices; i++) { MATRIX(*layout, i, 0) -= xm; MATRIX(*layout, i, 1) -= ym; MATRIX(*layout, i, 2) -= zm; @@ -1047,19 +1047,19 @@ static igraph_error_t igraph_i_layout_umap( igraph_bool_t use_seed, const igraph_vector_t *distances, igraph_real_t min_dist, - igraph_integer_t epochs, - igraph_integer_t ndim, + igraph_int_t epochs, + igraph_int_t ndim, igraph_bool_t distances_are_weights) { - const igraph_integer_t no_of_edges = igraph_ecount(graph); - const igraph_integer_t no_of_vertices = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_vertices = igraph_vcount(graph); /* probabilities of each edge being a real connection */ igraph_vector_t weights; igraph_vector_t *weightsp; /* The smoothing parameters given min_dist */ igraph_real_t a, b; /* How many repulsions for each attraction */ - igraph_integer_t negative_sampling_rate = 5; + igraph_int_t negative_sampling_rate = 5; /* Check input arguments */ if (min_dist < 0) { @@ -1138,8 +1138,6 @@ static igraph_error_t igraph_i_layout_umap( } } - RNG_BEGIN(); - /* Fit a and b parameter to find smooth approximation to * probability distribution in embedding space */ IGRAPH_CHECK(igraph_i_umap_fit_ab(min_dist, &a, &b)); @@ -1154,8 +1152,6 @@ static igraph_error_t igraph_i_layout_umap( epochs, negative_sampling_rate)); - RNG_END(); - if (!distances_are_weights) { igraph_vector_destroy(&weights); IGRAPH_FINALLY_CLEAN(1); @@ -1237,7 +1233,7 @@ igraph_error_t igraph_layout_umap(const igraph_t *graph, igraph_bool_t use_seed, const igraph_vector_t *distances, igraph_real_t min_dist, - igraph_integer_t epochs, + igraph_int_t epochs, igraph_bool_t distances_are_weights) { return igraph_i_layout_umap(graph, res, use_seed, distances, min_dist, epochs, 2, distances_are_weights); @@ -1282,7 +1278,7 @@ igraph_error_t igraph_layout_umap_3d(const igraph_t *graph, igraph_bool_t use_seed, const igraph_vector_t *distances, igraph_real_t min_dist, - igraph_integer_t epochs, + igraph_int_t epochs, igraph_bool_t distances_are_weights) { return igraph_i_layout_umap(graph, res, use_seed, distances, min_dist, epochs, 3, distances_are_weights); diff --git a/src/vendor/cigraph/src/linalg/arpack.c b/src/vendor/cigraph/src/linalg/arpack.c index 1908ecb4b5c..0877d08c583 100644 --- a/src/vendor/cigraph/src/linalg/arpack.c +++ b/src/vendor/cigraph/src/linalg/arpack.c @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* vim:set ts=4 sw=4 sts=4 noet: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -37,90 +36,16 @@ /* The ARPACK example file dssimp.f is used as a template */ -static igraph_error_t igraph_i_arpack_err_dsaupd(int error) { - switch (error) { - case 1: return IGRAPH_ARPACK_MAXIT; - case 3: return IGRAPH_ARPACK_NOSHIFT; - case -1: return IGRAPH_ARPACK_NPOS; - case -2: return IGRAPH_ARPACK_NEVNPOS; - case -3: return IGRAPH_ARPACK_NCVSMALL; - case -4: return IGRAPH_ARPACK_NONPOSI; - case -5: return IGRAPH_ARPACK_WHICHINV; - case -6: return IGRAPH_ARPACK_BMATINV; - case -7: return IGRAPH_ARPACK_WORKLSMALL; - case -8: return IGRAPH_ARPACK_TRIDERR; - case -9: return IGRAPH_ARPACK_ZEROSTART; - case -10: return IGRAPH_ARPACK_MODEINV; - case -11: return IGRAPH_ARPACK_MODEBMAT; - case -12: return IGRAPH_ARPACK_ISHIFT; - case -13: return IGRAPH_ARPACK_NEVBE; - case -9999: return IGRAPH_ARPACK_NOFACT; - default: return IGRAPH_ARPACK_UNKNOWN; - } -} +static igraph_arpack_error_t igraph_i_arpack_err_dsaupd(int error); +static igraph_arpack_error_t igraph_i_arpack_err_dseupd(int error); +static igraph_arpack_error_t igraph_i_arpack_err_dnaupd(int error); +static igraph_arpack_error_t igraph_i_arpack_err_dneupd(int error); -static igraph_error_t igraph_i_arpack_err_dseupd(int error) { - switch (error) { - case -1: return IGRAPH_ARPACK_NPOS; - case -2: return IGRAPH_ARPACK_NEVNPOS; - case -3: return IGRAPH_ARPACK_NCVSMALL; - case -5: return IGRAPH_ARPACK_WHICHINV; - case -6: return IGRAPH_ARPACK_BMATINV; - case -7: return IGRAPH_ARPACK_WORKLSMALL; - case -8: return IGRAPH_ARPACK_TRIDERR; - case -9: return IGRAPH_ARPACK_ZEROSTART; - case -10: return IGRAPH_ARPACK_MODEINV; - case -11: return IGRAPH_ARPACK_MODEBMAT; - case -12: return IGRAPH_ARPACK_NEVBE; - case -14: return IGRAPH_ARPACK_FAILED; - case -15: return IGRAPH_ARPACK_HOWMNY; - case -16: return IGRAPH_ARPACK_HOWMNYS; - case -17: return IGRAPH_ARPACK_EVDIFF; - default: return IGRAPH_ARPACK_UNKNOWN; - } +static igraph_arpack_error_t last_arpack_error = IGRAPH_ARPACK_NO_ERROR; -} - -static igraph_error_t igraph_i_arpack_err_dnaupd(int error) { - switch (error) { - case 1: return IGRAPH_ARPACK_MAXIT; - case 3: return IGRAPH_ARPACK_NOSHIFT; - case -1: return IGRAPH_ARPACK_NPOS; - case -2: return IGRAPH_ARPACK_NEVNPOS; - case -3: return IGRAPH_ARPACK_NCVSMALL; - case -4: return IGRAPH_ARPACK_NONPOSI; - case -5: return IGRAPH_ARPACK_WHICHINV; - case -6: return IGRAPH_ARPACK_BMATINV; - case -7: return IGRAPH_ARPACK_WORKLSMALL; - case -8: return IGRAPH_ARPACK_TRIDERR; - case -9: return IGRAPH_ARPACK_ZEROSTART; - case -10: return IGRAPH_ARPACK_MODEINV; - case -11: return IGRAPH_ARPACK_MODEBMAT; - case -12: return IGRAPH_ARPACK_ISHIFT; - case -9999: return IGRAPH_ARPACK_NOFACT; - default: return IGRAPH_ARPACK_UNKNOWN; - } -} - -static igraph_error_t igraph_i_arpack_err_dneupd(int error) { - switch (error) { - case 1: return IGRAPH_ARPACK_REORDER; - case -1: return IGRAPH_ARPACK_NPOS; - case -2: return IGRAPH_ARPACK_NEVNPOS; - case -3: return IGRAPH_ARPACK_NCVSMALL; - case -5: return IGRAPH_ARPACK_WHICHINV; - case -6: return IGRAPH_ARPACK_BMATINV; - case -7: return IGRAPH_ARPACK_WORKLSMALL; - case -8: return IGRAPH_ARPACK_SHUR; - case -9: return IGRAPH_ARPACK_LAPACK; - case -10: return IGRAPH_ARPACK_MODEINV; - case -11: return IGRAPH_ARPACK_MODEBMAT; - case -12: return IGRAPH_ARPACK_HOWMNYS; - case -13: return IGRAPH_ARPACK_HOWMNY; - case -14: return IGRAPH_ARPACK_FAILED; - case -15: return IGRAPH_ARPACK_EVDIFF; - default: return IGRAPH_ARPACK_UNKNOWN; - } +#define IGRAPH_ARPACK_ERROR(code) { \ + last_arpack_error = code; \ + IGRAPH_ERROR(igraph_arpack_error_to_string(code), IGRAPH_EARPACK); \ } /* Pristine ARPACK options object that is not exposed to the user; this is used @@ -258,8 +183,8 @@ igraph_arpack_options_t* igraph_arpack_options_get_default(void) { * Time complexity: O(maxncv*(maxldv+maxn)). */ -igraph_error_t igraph_arpack_storage_init(igraph_arpack_storage_t *s, igraph_integer_t maxn, - igraph_integer_t maxncv, igraph_integer_t maxldv, +igraph_error_t igraph_arpack_storage_init(igraph_arpack_storage_t *s, igraph_int_t maxn, + igraph_int_t maxncv, igraph_int_t maxldv, igraph_bool_t symm) { /* TODO: check arguments */ @@ -346,7 +271,7 @@ static igraph_error_t igraph_i_arpack_rssolve_1x1(igraph_arpack_function_t *fun, int nev = options->nev; if (nev <= 0) { - IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_NEVNPOS); + IGRAPH_ARPACK_ERROR(IGRAPH_ARPACK_NEVNPOS); } /* Probe the value in the matrix */ @@ -379,7 +304,7 @@ static igraph_error_t igraph_i_arpack_rnsolve_1x1(igraph_arpack_function_t *fun, int nev = options->nev; if (nev <= 0) { - IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_NEVNPOS); + IGRAPH_ARPACK_ERROR(IGRAPH_ARPACK_NEVNPOS); } /* Probe the value in the matrix */ @@ -418,7 +343,7 @@ static igraph_error_t igraph_i_arpack_rnsolve_2x2(igraph_arpack_function_t *fun, int nev = options->nev; if (nev <= 0) { - IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_NEVNPOS); + IGRAPH_ARPACK_ERROR(IGRAPH_ARPACK_NEVNPOS); } if (nev > 2) { nev = 2; @@ -478,7 +403,7 @@ static igraph_error_t igraph_i_arpack_rnsolve_2x2(igraph_arpack_function_t *fun, /* eval1 must be the one with the smallest imaginary part */ swap_evals = (IGRAPH_IMAG(eval1) > IGRAPH_IMAG(eval2)); } else { - IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_WHICHINV); + IGRAPH_ARPACK_ERROR(IGRAPH_ARPACK_WHICHINV); } } else if (options->which[0] == 'L') { if (options->which[1] == 'M') { @@ -491,13 +416,13 @@ static igraph_error_t igraph_i_arpack_rnsolve_2x2(igraph_arpack_function_t *fun, /* eval1 must be the one with the largest imaginary part */ swap_evals = (IGRAPH_IMAG(eval1) < IGRAPH_IMAG(eval2)); } else { - IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_WHICHINV); + IGRAPH_ARPACK_ERROR(IGRAPH_ARPACK_WHICHINV); } } else if (options->which[0] == 'X' && options->which[1] == 'X') { /* No preference on the ordering of eigenvectors */ } else { /* fprintf(stderr, "%c%c\n", options->which[0], options->which[1]); */ - IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_WHICHINV); + IGRAPH_ARPACK_ERROR(IGRAPH_ARPACK_WHICHINV); } options->nconv = nev; @@ -563,7 +488,7 @@ static igraph_error_t igraph_i_arpack_rssolve_2x2(igraph_arpack_function_t *fun, int nev = options->nev; if (nev <= 0) { - IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_NEVNPOS); + IGRAPH_ARPACK_ERROR(IGRAPH_ARPACK_NEVNPOS); } if (nev > 2) { nev = 2; @@ -612,7 +537,7 @@ static igraph_error_t igraph_i_arpack_rssolve_2x2(igraph_arpack_function_t *fun, } else if (options->which[0] == 'X' && options->which[1] == 'X') { /* No preference on the ordering of eigenvectors */ } else { - IGRAPH_ERROR("ARPACK error", IGRAPH_ARPACK_WHICHINV); + IGRAPH_ARPACK_ERROR(IGRAPH_ARPACK_WHICHINV); } options->nconv = nev; @@ -1049,11 +974,9 @@ igraph_error_t igraph_arpack_rssolve(igraph_arpack_function_t *fun, void *extra, } else { // we need to generate a random vector on our own; let's not rely on // ARPACK to do so because we want to use our own RNG - RNG_BEGIN(); for (i = 0; i < options->n; i++) { resid[i] = RNG_UNIF(-1, 1); } - RNG_END(); } /* Ok, we have everything */ @@ -1099,7 +1022,7 @@ igraph_error_t igraph_arpack_rssolve(igraph_arpack_function_t *fun, void *extra, igraph_i_arpack_report_no_convergence(options); } if (options->info != 0) { - IGRAPH_ERROR("ARPACK error", igraph_i_arpack_err_dsaupd(options->info)); + IGRAPH_ARPACK_ERROR(igraph_i_arpack_err_dsaupd(options->info)); } options->ierr = 0; @@ -1121,7 +1044,7 @@ igraph_error_t igraph_arpack_rssolve(igraph_arpack_function_t *fun, void *extra, #endif if (options->ierr != 0) { - IGRAPH_ERROR("ARPACK error", igraph_i_arpack_err_dseupd(options->ierr)); + IGRAPH_ARPACK_ERROR(igraph_i_arpack_err_dseupd(options->ierr)); } /* Save the result */ @@ -1329,11 +1252,9 @@ igraph_error_t igraph_arpack_rnsolve(igraph_arpack_function_t *fun, void *extra, } else { // we need to generate a random vector on our own; let's not rely on // ARPACK to do so because we want to use our own RNG - RNG_BEGIN(); for (i = 0; i < options->n; i++) { resid[i] = RNG_UNIF(-1, 1); } - RNG_END(); } /* Ok, we have everything */ @@ -1384,7 +1305,7 @@ igraph_error_t igraph_arpack_rnsolve(igraph_arpack_function_t *fun, void *extra, igraph_i_arpack_report_no_convergence(options); } if (options->info != 0 && options->info != -9999) { - IGRAPH_ERROR("ARPACK error", igraph_i_arpack_err_dnaupd(options->info)); + IGRAPH_ARPACK_ERROR(igraph_i_arpack_err_dnaupd(options->info)); } options->ierr = 0; @@ -1406,7 +1327,7 @@ igraph_error_t igraph_arpack_rnsolve(igraph_arpack_function_t *fun, void *extra, #endif if (options->ierr != 0) { - IGRAPH_ERROR("ARPACK error", igraph_i_arpack_err_dneupd(options->ierr)); + IGRAPH_ARPACK_ERROR(igraph_i_arpack_err_dneupd(options->ierr)); } /* Save the result */ @@ -1485,12 +1406,12 @@ igraph_error_t igraph_arpack_rnsolve(igraph_arpack_function_t *fun, void *extra, */ igraph_error_t igraph_arpack_unpack_complex(igraph_matrix_t *vectors, igraph_matrix_t *values, - igraph_integer_t nev) { + igraph_int_t nev) { - igraph_integer_t nodes = igraph_matrix_nrow(vectors); - igraph_integer_t no_evs = igraph_matrix_nrow(values); - igraph_integer_t i, j; - igraph_integer_t new_vector_pos, vector_pos; + igraph_int_t nodes = igraph_matrix_nrow(vectors); + igraph_int_t no_evs = igraph_matrix_nrow(values); + igraph_int_t i, j; + igraph_int_t new_vector_pos, vector_pos; igraph_matrix_t new_vectors; /* Error checks */ @@ -1554,3 +1475,160 @@ igraph_error_t igraph_arpack_unpack_complex(igraph_matrix_t *vectors, igraph_mat return IGRAPH_SUCCESS; } + +/* ************************************************************************* */ + +/* Helper functions to map ARPACK error codes to \c igraph_arpack_error_t */ + +static igraph_arpack_error_t igraph_i_arpack_err_dsaupd(int error) { + switch (error) { + case 0: return IGRAPH_ARPACK_NO_ERROR; + case 1: return IGRAPH_ARPACK_MAXIT; + case 3: return IGRAPH_ARPACK_NOSHIFT; + case -1: return IGRAPH_ARPACK_NPOS; + case -2: return IGRAPH_ARPACK_NEVNPOS; + case -3: return IGRAPH_ARPACK_NCVSMALL; + case -4: return IGRAPH_ARPACK_NONPOSI; + case -5: return IGRAPH_ARPACK_WHICHINV; + case -6: return IGRAPH_ARPACK_BMATINV; + case -7: return IGRAPH_ARPACK_WORKLSMALL; + case -8: return IGRAPH_ARPACK_TRIDERR; + case -9: return IGRAPH_ARPACK_ZEROSTART; + case -10: return IGRAPH_ARPACK_MODEINV; + case -11: return IGRAPH_ARPACK_MODEBMAT; + case -12: return IGRAPH_ARPACK_ISHIFT; + case -13: return IGRAPH_ARPACK_NEVBE; + case -9999: return IGRAPH_ARPACK_NOFACT; + default: return IGRAPH_ARPACK_UNKNOWN; + } +} + +static igraph_arpack_error_t igraph_i_arpack_err_dseupd(int error) { + switch (error) { + case 0: return IGRAPH_ARPACK_NO_ERROR; + case -1: return IGRAPH_ARPACK_NPOS; + case -2: return IGRAPH_ARPACK_NEVNPOS; + case -3: return IGRAPH_ARPACK_NCVSMALL; + case -5: return IGRAPH_ARPACK_WHICHINV; + case -6: return IGRAPH_ARPACK_BMATINV; + case -7: return IGRAPH_ARPACK_WORKLSMALL; + case -8: return IGRAPH_ARPACK_TRIDERR; + case -9: return IGRAPH_ARPACK_ZEROSTART; + case -10: return IGRAPH_ARPACK_MODEINV; + case -11: return IGRAPH_ARPACK_MODEBMAT; + case -12: return IGRAPH_ARPACK_NEVBE; + case -14: return IGRAPH_ARPACK_FAILED; + case -15: return IGRAPH_ARPACK_HOWMNY; + case -16: return IGRAPH_ARPACK_HOWMNYS; + case -17: return IGRAPH_ARPACK_EVDIFF; + default: return IGRAPH_ARPACK_UNKNOWN; + } + +} + +static igraph_arpack_error_t igraph_i_arpack_err_dnaupd(int error) { + switch (error) { + case 0: return IGRAPH_ARPACK_NO_ERROR; + case 1: return IGRAPH_ARPACK_MAXIT; + case 3: return IGRAPH_ARPACK_NOSHIFT; + case -1: return IGRAPH_ARPACK_NPOS; + case -2: return IGRAPH_ARPACK_NEVNPOS; + case -3: return IGRAPH_ARPACK_NCVSMALL; + case -4: return IGRAPH_ARPACK_NONPOSI; + case -5: return IGRAPH_ARPACK_WHICHINV; + case -6: return IGRAPH_ARPACK_BMATINV; + case -7: return IGRAPH_ARPACK_WORKLSMALL; + case -8: return IGRAPH_ARPACK_TRIDERR; + case -9: return IGRAPH_ARPACK_ZEROSTART; + case -10: return IGRAPH_ARPACK_MODEINV; + case -11: return IGRAPH_ARPACK_MODEBMAT; + case -12: return IGRAPH_ARPACK_ISHIFT; + case -9999: return IGRAPH_ARPACK_NOFACT; + default: return IGRAPH_ARPACK_UNKNOWN; + } +} + +static igraph_arpack_error_t igraph_i_arpack_err_dneupd(int error) { + switch (error) { + case 0: return IGRAPH_ARPACK_NO_ERROR; + case 1: return IGRAPH_ARPACK_REORDER; + case -1: return IGRAPH_ARPACK_NPOS; + case -2: return IGRAPH_ARPACK_NEVNPOS; + case -3: return IGRAPH_ARPACK_NCVSMALL; + case -5: return IGRAPH_ARPACK_WHICHINV; + case -6: return IGRAPH_ARPACK_BMATINV; + case -7: return IGRAPH_ARPACK_WORKLSMALL; + case -8: return IGRAPH_ARPACK_SHUR; + case -9: return IGRAPH_ARPACK_LAPACK; + case -10: return IGRAPH_ARPACK_MODEINV; + case -11: return IGRAPH_ARPACK_MODEBMAT; + case -12: return IGRAPH_ARPACK_HOWMNYS; + case -13: return IGRAPH_ARPACK_HOWMNY; + case -14: return IGRAPH_ARPACK_FAILED; + case -15: return IGRAPH_ARPACK_EVDIFF; + default: return IGRAPH_ARPACK_UNKNOWN; + } +} + +static const char* igraph_i_arpack_error_strings[] = { + /* 15 */ "Matrix-vector product failed", + /* 16 */ "N must be positive", + /* 17 */ "NEV must be positive", + /* 18 */ "NCV must be greater than NEV and less than or equal to N " + "(and for the non-symmetric solver NCV-NEV >=2 must also hold)", + /* 19 */ "Maximum number of iterations should be positive", + /* 20 */ "Invalid WHICH parameter", + /* 21 */ "Invalid BMAT parameter", + /* 22 */ "WORKL is too small", + /* 23 */ "LAPACK error in tridiagonal eigenvalue calculation", + /* 24 */ "Starting vector is zero", + /* 25 */ "MODE is invalid", + /* 26 */ "MODE and BMAT are not compatible", + /* 27 */ "ISHIFT must be 0 or 1", + /* 28 */ "NEV and WHICH='BE' are incompatible", + /* 29 */ "Could not build an Arnoldi factorization", + /* 30 */ "No eigenvalues to sufficient accuracy", + /* 31 */ "HOWMNY is invalid", + /* 32 */ "HOWMNY='S' is not implemented", + /* 33 */ "Different number of converged Ritz values", + /* 34 */ "Error from calculation of a real Schur form", + /* 35 */ "LAPACK (dtrevc) error for calculating eigenvectors", + /* 36 */ "Unknown ARPACK error", + /* 37 */ 0, + /* 38 */ 0, + /* 39 */ "Maximum number of iterations reached", + /* 40 */ "No shifts could be applied during a cycle of the " + "Implicitly restarted Arnoldi iteration. One possibility " + "is to increase the size of NCV relative to NEV", + /* 41 */ "The Schur form computed by LAPACK routine dlahqr " + "could not be reordered by LAPACK routine dtrsen." +}; + +/** + * \function igraph_arpack_error_to_string + * \brief Convert an ARPACK error code to a human-readable representation. + */ +const char* igraph_arpack_error_to_string(igraph_arpack_error_t error) { + if (error == IGRAPH_ARPACK_NO_ERROR) { + return "No error"; + } + + int index = (error >= IGRAPH_ARPACK_PROD) + ? error - IGRAPH_ARPACK_PROD + : -1; + const char* message = 0; + + if (index >= 0 && index < sizeof(igraph_i_arpack_error_strings) / sizeof(igraph_i_arpack_error_strings[0])) { + message = igraph_i_arpack_error_strings[index]; + } + + return message ? message : "Unknown ARPACK error"; +} + +/** + * \function igraph_arpack_get_last_error + * \brief Returns the last error code returned from an ARPACK function. + */ +igraph_arpack_error_t igraph_arpack_get_last_error(void) { + return last_arpack_error; +} diff --git a/src/vendor/cigraph/src/linalg/arpack_internal.h b/src/vendor/cigraph/src/linalg/arpack_internal.h index 0392624d179..c7f7e54c135 100644 --- a/src/vendor/cigraph/src/linalg/arpack_internal.h +++ b/src/vendor/cigraph/src/linalg/arpack_internal.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -31,7 +30,7 @@ #include "igraph_decls.h" #include "config.h" /* INTERNAL_ARPACK */ -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS #ifndef INTERNAL_ARPACK #define igraphdsaupd_ dsaupd_ @@ -228,6 +227,6 @@ int igraphdsortc_(char *which, int *apply, int* n, double *xreal, #endif -__END_DECLS +IGRAPH_END_C_DECLS #endif /* ARPACK_INTERNAL_H */ diff --git a/src/vendor/cigraph/src/linalg/blas.c b/src/vendor/cigraph/src/linalg/blas.c index 19fe8ad3ba5..3e46ee1a69e 100644 --- a/src/vendor/cigraph/src/linalg/blas.c +++ b/src/vendor/cigraph/src/linalg/blas.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -115,10 +113,10 @@ igraph_error_t igraph_blas_dgemm(igraph_bool_t transpose_a, igraph_bool_t transp char trans_a = transpose_a ? 'T' : 'N'; char trans_b = transpose_b ? 'T' : 'N'; int m, n, k, lda, ldb, ldc; - igraph_integer_t nrow_oa = transpose_a ? igraph_matrix_ncol(a) : igraph_matrix_nrow(a); - igraph_integer_t ncol_oa = transpose_a ? igraph_matrix_nrow(a) : igraph_matrix_ncol(a); - igraph_integer_t nrow_ob = transpose_b ? igraph_matrix_ncol(b) : igraph_matrix_nrow(b); - igraph_integer_t ncol_ob = transpose_b ? igraph_matrix_nrow(b) : igraph_matrix_ncol(b); + igraph_int_t nrow_oa = transpose_a ? igraph_matrix_ncol(a) : igraph_matrix_nrow(a); + igraph_int_t ncol_oa = transpose_a ? igraph_matrix_nrow(a) : igraph_matrix_ncol(a); + igraph_int_t nrow_ob = transpose_b ? igraph_matrix_ncol(b) : igraph_matrix_nrow(b); + igraph_int_t ncol_ob = transpose_b ? igraph_matrix_nrow(b) : igraph_matrix_ncol(b); if (ncol_oa != nrow_ob) { IGRAPH_ERRORF("%" IGRAPH_PRId "-by-%" IGRAPH_PRId " and %" IGRAPH_PRId "-by-%" IGRAPH_PRId diff --git a/src/vendor/cigraph/src/linalg/blas_internal.h b/src/vendor/cigraph/src/linalg/blas_internal.h index ab1bd693c27..485fcad53a1 100644 --- a/src/vendor/cigraph/src/linalg/blas_internal.h +++ b/src/vendor/cigraph/src/linalg/blas_internal.h @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -32,7 +30,7 @@ #include "igraph_decls.h" #include "config.h" /* INTERNAL_BLAS */ -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS #ifndef INTERNAL_BLAS #define igraphdaxpy_ daxpy_ @@ -89,6 +87,6 @@ double igraphdnrm2_(int *n, double *x, int *incx); double igraphddot_(int *n, double *dx, int *incx, double *dy, int *incy); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/linalg/eigen.c b/src/vendor/cigraph/src/linalg/eigen.c index 337e1294d21..d999d0a8ff2 100644 --- a/src/vendor/cigraph/src/linalg/eigen.c +++ b/src/vendor/cigraph/src/linalg/eigen.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -482,9 +481,8 @@ static igraph_error_t igraph_i_eigen_matrix_sym_arpack_cb(igraph_real_t *to, IGRAPH_CHECK(igraph_blas_dgemv_array(/*transpose=*/ 0, /*alpha=*/ 1.0, data->A, from, /*beta=*/ 0.0, to)); } else { /* data->sA */ - igraph_vector_t vto, vfrom; - igraph_vector_view(&vto, to, n); - igraph_vector_view(&vfrom, from, n); + const igraph_vector_t vfrom = igraph_vector_view(from, n); + igraph_vector_t vto = igraph_vector_view(to, n); igraph_vector_null(&vto); igraph_sparsemat_gaxpy(data->sA, &vfrom, &vto); } @@ -674,8 +672,8 @@ typedef struct igraph_i_eml_cmp_t { static int igraph_i_eigen_matrix_lapack_cmp_lm(void *extra, const void *a, const void *b) { igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra; - igraph_integer_t *aa = (igraph_integer_t*) a; - igraph_integer_t *bb = (igraph_integer_t*) b; + igraph_int_t *aa = (igraph_int_t*) a; + igraph_int_t *bb = (igraph_int_t*) b; igraph_real_t a_m = VECTOR(*myextra->mag)[*aa]; igraph_real_t b_m = VECTOR(*myextra->mag)[*bb]; @@ -720,8 +718,8 @@ static int igraph_i_eigen_matrix_lapack_cmp_lm(void *extra, const void *a, static int igraph_i_eigen_matrix_lapack_cmp_sm(void *extra, const void *a, const void *b) { igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra; - igraph_integer_t *aa = (igraph_integer_t*) a; - igraph_integer_t *bb = (igraph_integer_t*) b; + igraph_int_t *aa = (igraph_int_t*) a; + igraph_int_t *bb = (igraph_int_t*) b; igraph_real_t a_m = VECTOR(*myextra->mag)[*aa]; igraph_real_t b_m = VECTOR(*myextra->mag)[*bb]; @@ -765,8 +763,8 @@ static int igraph_i_eigen_matrix_lapack_cmp_lr(void *extra, const void *a, const void *b) { igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra; - igraph_integer_t *aa = (igraph_integer_t*) a; - igraph_integer_t *bb = (igraph_integer_t*) b; + igraph_int_t *aa = (igraph_int_t*) a; + igraph_int_t *bb = (igraph_int_t*) b; igraph_real_t a_r = VECTOR(*myextra->real)[*aa]; igraph_real_t b_r = VECTOR(*myextra->real)[*bb]; @@ -805,8 +803,8 @@ static int igraph_i_eigen_matrix_lapack_cmp_sr(void *extra, const void *a, const void *b) { igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra; - igraph_integer_t *aa = (igraph_integer_t*) a; - igraph_integer_t *bb = (igraph_integer_t*) b; + igraph_int_t *aa = (igraph_int_t*) a; + igraph_int_t *bb = (igraph_int_t*) b; igraph_real_t a_r = VECTOR(*myextra->real)[*aa]; igraph_real_t b_r = VECTOR(*myextra->real)[*bb]; @@ -843,8 +841,8 @@ static int igraph_i_eigen_matrix_lapack_cmp_li(void *extra, const void *a, const void *b) { igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra; - igraph_integer_t *aa = (igraph_integer_t*) a; - igraph_integer_t *bb = (igraph_integer_t*) b; + igraph_int_t *aa = (igraph_int_t*) a; + igraph_int_t *bb = (igraph_int_t*) b; igraph_real_t a_i = VECTOR(*myextra->imag)[*aa]; igraph_real_t b_i = VECTOR(*myextra->imag)[*bb]; @@ -882,8 +880,8 @@ static int igraph_i_eigen_matrix_lapack_cmp_si(void *extra, const void *a, const void *b) { igraph_i_eml_cmp_t *myextra = (igraph_i_eml_cmp_t *) extra; - igraph_integer_t *aa = (igraph_integer_t*) a; - igraph_integer_t *bb = (igraph_integer_t*) b; + igraph_int_t *aa = (igraph_int_t*) a; + igraph_int_t *bb = (igraph_int_t*) b; igraph_real_t a_i = VECTOR(*myextra->imag)[*aa]; igraph_real_t b_i = VECTOR(*myextra->imag)[*bb]; @@ -939,7 +937,7 @@ static igraph_error_t igraph_i_eigen_matrix_lapack_reorder(const igraph_vector_t igraph_bool_t hasmag = false; int nev; int howmany = 0, start = 0; - igraph_integer_t i; + igraph_int_t i; igraph_i_eigen_matrix_lapack_cmp_t cmpfunc = 0; igraph_i_eml_cmp_t vextra; void *extra; @@ -1013,17 +1011,17 @@ static igraph_error_t igraph_i_eigen_matrix_lapack_reorder(const igraph_vector_t if (values) { IGRAPH_CHECK(igraph_vector_complex_resize(values, howmany)); for (i = 0; i < howmany; i++) { - igraph_integer_t x = VECTOR(idx)[start + i]; + igraph_int_t x = VECTOR(idx)[start + i]; VECTOR(*values)[i] = igraph_complex(VECTOR(*real)[x], VECTOR(*imag)[x]); } } if (vectors) { - igraph_integer_t n = igraph_matrix_nrow(compressed); + igraph_int_t n = igraph_matrix_nrow(compressed); IGRAPH_CHECK(igraph_matrix_complex_resize(vectors, n, howmany)); for (i = 0; i < howmany; i++) { - igraph_integer_t j, x = VECTOR(idx)[start + i]; + igraph_int_t j, x = VECTOR(idx)[start + i]; if (VECTOR(*imag)[x] == 0) { /* real eigenvalue */ for (j = 0; j < n; j++) { @@ -1059,7 +1057,7 @@ static igraph_error_t igraph_i_eigen_matrix_lapack_common(const igraph_matrix_t igraph_vector_t valuesreal, valuesimag; igraph_matrix_t vectorsright, *myvectors = vectors ? &vectorsright : 0; - igraph_integer_t n = igraph_matrix_nrow(A); + igraph_int_t n = igraph_matrix_nrow(A); int info = 1; IGRAPH_VECTOR_INIT_FINALLY(&valuesreal, n); @@ -1143,11 +1141,11 @@ static igraph_error_t igraph_i_eigen_checks(const igraph_matrix_t *A, if (A) { if (n != igraph_matrix_ncol(A) || n != igraph_matrix_nrow(A)) { - IGRAPH_ERROR("Invalid matrix", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Eigenvector calculations need a square matrix.", IGRAPH_EINVAL); } } else if (sA) { if (n != igraph_sparsemat_ncol(sA) || n != igraph_sparsemat_nrow(sA)) { - IGRAPH_ERROR("Invalid matrix", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Eigenvector calculations need a square matrix.", IGRAPH_EINVAL); } } @@ -1286,14 +1284,14 @@ static igraph_error_t igraph_i_eigen_adjacency_arpack_sym_cb(igraph_real_t *to, int n, void *extra) { igraph_adjlist_t *adjlist = (igraph_adjlist_t *) extra; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; for (i = 0; i < n; i++) { neis = igraph_adjlist_get(adjlist, i); nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; to[i] += from[nei]; } } @@ -1315,7 +1313,7 @@ static igraph_error_t igraph_i_eigen_adjacency_arpack(const igraph_t *graph, igraph_adjlist_t adjlist; void *extra = (void*) &adjlist; - igraph_integer_t n = igraph_vcount(graph); + igraph_int_t n = igraph_vcount(graph); if (!options) { IGRAPH_ERROR("`options' must be given for ARPACK algorithm", diff --git a/src/vendor/cigraph/src/linalg/lapack.c b/src/vendor/cigraph/src/linalg/lapack.c index ed5d64cc1df..aa6f9c34df3 100644 --- a/src/vendor/cigraph/src/linalg/lapack.c +++ b/src/vendor/cigraph/src/linalg/lapack.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -38,11 +37,11 @@ static igraph_error_t igraph_vector_int_update_from_fortran( igraph_vector_int_t* vec, const igraph_vector_fortran_int_t* fortran_vec ) { - igraph_integer_t size = igraph_vector_fortran_int_size(fortran_vec); + igraph_int_t size = igraph_vector_fortran_int_size(fortran_vec); IGRAPH_CHECK(igraph_vector_int_resize(vec, size)); - for (igraph_integer_t i = 0; i < size; i++) { + for (igraph_int_t i = 0; i < size; i++) { VECTOR(*vec)[i] = VECTOR(*fortran_vec)[i]; } @@ -53,7 +52,7 @@ static igraph_error_t igraph_vector_int_update_from_fortran( static igraph_error_t igraph_vector_int_copy_to_fortran( const igraph_vector_int_t* vec, igraph_vector_fortran_int_t* fortran_vec ) { - igraph_integer_t i, size = igraph_vector_int_size(vec); + igraph_int_t i, size = igraph_vector_int_size(vec); IGRAPH_CHECK(igraph_vector_fortran_int_resize(fortran_vec, size)); @@ -128,25 +127,25 @@ igraph_error_t igraph_lapack_dgetrf(igraph_matrix_t *a, igraph_vector_int_t *ipi } else if (*info < 0) { switch (*info) { case -1: - IGRAPH_ERROR("Invalid number of rows.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid number of rows.", IGRAPH_FAILURE); break; case -2: - IGRAPH_ERROR("Invalid number of columns.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid number of columns.", IGRAPH_FAILURE); break; case -3: - IGRAPH_ERROR("Invalid input matrix.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid input matrix.", IGRAPH_FAILURE); break; case -4: - IGRAPH_ERROR("Invalid LDA parameter.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid LDA parameter.", IGRAPH_FAILURE); break; case -5: - IGRAPH_ERROR("Invalid pivot vector.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid pivot vector.", IGRAPH_FAILURE); break; case -6: - IGRAPH_ERROR("Invalid info argument.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid info argument.", IGRAPH_FAILURE); break; default: - IGRAPH_ERROR("Unknown LAPACK error.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Unknown LAPACK error.", IGRAPH_FAILURE); break; } } @@ -208,7 +207,7 @@ igraph_error_t igraph_lapack_dgetrs(igraph_bool_t transpose, const igraph_matrix ldb = n > 0 ? n : 1; if (n != igraph_matrix_ncol(a)) { - IGRAPH_ERROR("Cannot LU solve matrix.", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Cannot LU solve non-square matrix.", IGRAPH_EINVAL); } if (n != igraph_matrix_nrow(b)) { IGRAPH_ERROR("Cannot LU solve matrix, RHS of wrong size.", IGRAPH_EINVAL); @@ -233,34 +232,34 @@ igraph_error_t igraph_lapack_dgetrs(igraph_bool_t transpose, const igraph_matrix if (info < 0) { switch (info) { case -1: - IGRAPH_ERROR("Invalid transpose argument.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid transpose argument.", IGRAPH_FAILURE); break; case -2: - IGRAPH_ERROR("Invalid number of rows/columns.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid number of rows/columns.", IGRAPH_FAILURE); break; case -3: - IGRAPH_ERROR("Invalid number of RHS vectors.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid number of RHS vectors.", IGRAPH_FAILURE); break; case -4: - IGRAPH_ERROR("Invalid LU matrix.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid LU matrix.", IGRAPH_FAILURE); break; case -5: - IGRAPH_ERROR("Invalid LDA parameter.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid LDA parameter.", IGRAPH_FAILURE); break; case -6: - IGRAPH_ERROR("Invalid pivot vector.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid pivot vector.", IGRAPH_FAILURE); break; case -7: - IGRAPH_ERROR("Invalid RHS matrix.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid RHS matrix.", IGRAPH_FAILURE); break; case -8: - IGRAPH_ERROR("Invalid LDB parameter.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid LDB parameter.", IGRAPH_FAILURE); break; case -9: - IGRAPH_ERROR("Invalid info argument.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid info argument.", IGRAPH_FAILURE); break; default: - IGRAPH_ERROR("Unknown LAPACK error.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Unknown LAPACK error.", IGRAPH_FAILURE); break; } } @@ -320,7 +319,7 @@ igraph_error_t igraph_lapack_dgesv(igraph_matrix_t *a, igraph_vector_int_t *ipiv igraph_vector_fortran_int_t vipiv; if (n != igraph_matrix_ncol(a)) { - IGRAPH_ERROR("Cannot LU solve matrix.", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Cannot LU solve non-square matrix.", IGRAPH_EINVAL); } if (n != igraph_matrix_nrow(b)) { IGRAPH_ERROR("Cannot LU solve matrix, RHS of wrong size.", IGRAPH_EINVAL); @@ -337,31 +336,31 @@ igraph_error_t igraph_lapack_dgesv(igraph_matrix_t *a, igraph_vector_int_t *ipiv } else if (*info < 0) { switch (*info) { case -1: - IGRAPH_ERROR("Invalid number of rows/column.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid number of rows/column.", IGRAPH_FAILURE); break; case -2: - IGRAPH_ERROR("Invalid number of RHS vectors.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid number of RHS vectors.", IGRAPH_FAILURE); break; case -3: - IGRAPH_ERROR("Invalid input matrix.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid input matrix.", IGRAPH_FAILURE); break; case -4: - IGRAPH_ERROR("Invalid LDA parameter.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid LDA parameter.", IGRAPH_FAILURE); break; case -5: - IGRAPH_ERROR("Invalid pivot vector.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid pivot vector.", IGRAPH_FAILURE); break; case -6: - IGRAPH_ERROR("Invalid RHS matrix.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid RHS matrix.", IGRAPH_FAILURE); break; case -7: - IGRAPH_ERROR("Invalid LDB parameter.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid LDB parameter.", IGRAPH_FAILURE); break; case -8: - IGRAPH_ERROR("Invalid info argument.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Invalid info argument.", IGRAPH_FAILURE); break; default: - IGRAPH_ERROR("Unknown LAPACK error.", IGRAPH_ELAPACK); + IGRAPH_ERROR("Unknown LAPACK error.", IGRAPH_FAILURE); break; } } @@ -459,7 +458,7 @@ igraph_error_t igraph_lapack_dsyevr(const igraph_matrix_t *A, int lwork = -1, liwork = -1; if (n != igraph_matrix_ncol(A)) { - IGRAPH_ERROR("Cannot find eigenvalues/vectors.", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Cannot find eigenvalues/vectors of non-square matrix.", IGRAPH_EINVAL); } if (which == IGRAPH_LAPACK_DSYEV_INTERVAL && (vestimate < 1 || vestimate > n)) { @@ -641,7 +640,7 @@ igraph_error_t igraph_lapack_dgeev(const igraph_matrix_t *A, int error = *info; if (igraph_matrix_ncol(A) != n) { - IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev).", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Cannot calculate eigenvalues of non-square matrix.", IGRAPH_EINVAL); } IGRAPH_CHECK(igraph_matrix_init_copy(&Acopy, A)); @@ -684,10 +683,10 @@ igraph_error_t igraph_lapack_dgeev(const igraph_matrix_t *A, VECTOR(work), &lwork, info); if (*info < 0) { - IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev).", IGRAPH_ELAPACK); + IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev).", IGRAPH_FAILURE); } else if (*info > 0) { if (error) { - IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev).", IGRAPH_ELAPACK); + IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev).", IGRAPH_FAILURE); } else { IGRAPH_WARNING("Cannot calculate eigenvalues (dgeev)."); } @@ -868,7 +867,7 @@ igraph_error_t igraph_lapack_dgeevx(igraph_lapack_dgeevx_balance_t balance, ihi = &ihi_dummy; } if (igraph_matrix_ncol(A) != n) { - IGRAPH_ERROR("Cannot calculate eigenvalues (dgeevx).", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Cannot calculate eigenvalues of non-square matrix.", IGRAPH_EINVAL); } switch (balance) { @@ -953,10 +952,10 @@ igraph_error_t igraph_lapack_dgeevx(igraph_lapack_dgeevx_balance_t balance, VECTOR(work), &lwork, VECTOR(iwork), info); if (*info < 0) { - IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev).", IGRAPH_ELAPACK); + IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev).", IGRAPH_FAILURE); } else if (*info > 0) { if (error) { - IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev).", IGRAPH_ELAPACK); + IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev).", IGRAPH_FAILURE); } else { IGRAPH_WARNING("Cannot calculate eigenvalues (dgeev)."); } @@ -1003,7 +1002,7 @@ igraph_error_t igraph_lapack_dgehrd(const igraph_matrix_t *A, int i; if (igraph_matrix_ncol(A) != n) { - IGRAPH_ERROR("Hessenberg reduction failed.", IGRAPH_NONSQUARE); + IGRAPH_ERROR("Hessenberg reduction failed on non-square matrix.", IGRAPH_EINVAL); } if (ilo < 1 || ihi > n || ilo > ihi) { diff --git a/src/vendor/cigraph/src/linalg/lapack_internal.h b/src/vendor/cigraph/src/linalg/lapack_internal.h index b95885d1b8a..459a64c451e 100644 --- a/src/vendor/cigraph/src/linalg/lapack_internal.h +++ b/src/vendor/cigraph/src/linalg/lapack_internal.h @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -32,7 +30,7 @@ #include "igraph_decls.h" #include "config.h" /* INTERNAL_LAPACK */ -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS #ifndef INTERNAL_LAPACK #define igraphdgeevx_ dgeevx_ @@ -181,6 +179,6 @@ int igraphdgehrd_(int *n, int *ilo, int *ihi, double *A, int *lda, double igraphddot_(int *n, double *dx, int *incx, double *dy, int *incy); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/math/complex.c b/src/vendor/cigraph/src/math/complex.c index 10ee36f61a1..60f96e87c85 100644 --- a/src/vendor/cigraph/src/math/complex.c +++ b/src/vendor/cigraph/src/math/complex.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2010-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -43,20 +42,6 @@ igraph_complex_t igraph_complex_polar(igraph_real_t r, igraph_real_t theta) { return res; } -/** - * Deprecated in favour of igraph_complex_almost_equals(), which uses relative - * tolerances. Will be removed in 0.11. - */ -igraph_bool_t igraph_complex_eq_tol(igraph_complex_t z1, - igraph_complex_t z2, - igraph_real_t tol) { - if (fabs(IGRAPH_REAL(z1) - IGRAPH_REAL(z2)) > tol || - fabs(IGRAPH_IMAG(z1) - IGRAPH_IMAG(z2)) > tol) { - return false; - } - return true; -} - igraph_real_t igraph_complex_arg(igraph_complex_t z) { igraph_real_t x = IGRAPH_REAL(z); igraph_real_t y = IGRAPH_IMAG(z); diff --git a/src/vendor/cigraph/src/math/safe_intop.c b/src/vendor/cigraph/src/math/safe_intop.c index 15ac4e4d1fb..f1aefbff66d 100644 --- a/src/vendor/cigraph/src/math/safe_intop.c +++ b/src/vendor/cigraph/src/math/safe_intop.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team it under the terms of the GNU General Public License as published by @@ -20,22 +20,22 @@ #include "math/safe_intop.h" /* Use IGRAPH_SAFE_ADD() instead unless there is a need to intercept errors. */ -igraph_error_t igraph_i_safe_add(igraph_integer_t a, igraph_integer_t b, igraph_integer_t *res) { +igraph_error_t igraph_i_safe_add(igraph_int_t a, igraph_int_t b, igraph_int_t *res) { IGRAPH_SAFE_ADD(a, b, res); return IGRAPH_SUCCESS; } /* Use IGRAPH_SAFE_MULT() instead unless there is a need to intercept errors. */ -igraph_error_t igraph_i_safe_mult(igraph_integer_t a, igraph_integer_t b, igraph_integer_t *res) { +igraph_error_t igraph_i_safe_mult(igraph_int_t a, igraph_int_t b, igraph_int_t *res) { IGRAPH_SAFE_MULT(a, b, res); return IGRAPH_SUCCESS; } /* Overflow-safe sum of integer vector elements. */ -igraph_error_t igraph_i_safe_vector_int_sum(const igraph_vector_int_t *vec, igraph_integer_t *res) { - const igraph_integer_t n = igraph_vector_int_size(vec); - igraph_integer_t sum = 0; - for (igraph_integer_t i=0; i < n; ++i) { +igraph_error_t igraph_i_safe_vector_int_sum(const igraph_vector_int_t *vec, igraph_int_t *res) { + const igraph_int_t n = igraph_vector_int_size(vec); + igraph_int_t sum = 0; + for (igraph_int_t i=0; i < n; ++i) { IGRAPH_SAFE_ADD(sum, VECTOR(*vec)[i], &sum); } *res = sum; @@ -43,10 +43,10 @@ igraph_error_t igraph_i_safe_vector_int_sum(const igraph_vector_int_t *vec, igra } /* Overflow-safe product of integer vector elements. */ -igraph_error_t igraph_i_safe_vector_int_prod(const igraph_vector_int_t *vec, igraph_integer_t *res) { - const igraph_integer_t n = igraph_vector_int_size(vec); - igraph_integer_t prod = 1; - for (igraph_integer_t i=0; i < n; ++i) { +igraph_error_t igraph_i_safe_vector_int_prod(const igraph_vector_int_t *vec, igraph_int_t *res) { + const igraph_int_t n = igraph_vector_int_size(vec); + igraph_int_t prod = 1; + for (igraph_int_t i=0; i < n; ++i) { IGRAPH_SAFE_MULT(prod, VECTOR(*vec)[i], &prod); } *res = prod; @@ -59,7 +59,7 @@ igraph_error_t igraph_i_safe_vector_int_prod(const igraph_vector_int_t *vec, igr * This function must not be called with negative input. * Based on https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */ -igraph_error_t igraph_i_safe_next_pow_2(igraph_integer_t k, igraph_integer_t *res) { +igraph_error_t igraph_i_safe_next_pow_2(igraph_int_t k, igraph_int_t *res) { IGRAPH_ASSERT(k >= 0); if (k == 0) { *res = 0; @@ -93,18 +93,18 @@ igraph_error_t igraph_i_safe_next_pow_2(igraph_integer_t k, igraph_integer_t *re * Computes 2^k as an integer, with overflow check. * This function must not be called with negative input. */ -igraph_error_t igraph_i_safe_exp2(igraph_integer_t k, igraph_integer_t *res) { +igraph_error_t igraph_i_safe_exp2(igraph_int_t k, igraph_int_t *res) { IGRAPH_ASSERT(k >= 0); if (k > IGRAPH_INTEGER_SIZE-2) { IGRAPH_ERRORF("Overflow when raising 2 to power %" IGRAPH_PRId ".", IGRAPH_EOVERFLOW, k); } - *res = (igraph_integer_t) 1 << k; + *res = (igraph_int_t) 1 << k; return IGRAPH_SUCCESS; } /** - * Checks if an igraph_real_t with no fractional part is representable as an igraph_integer_t. + * Checks if an igraph_real_t with no fractional part is representable as an igraph_int_t. * Avoids invoking undefined behaviour. * Must not be called with an input that has a non-zero fractional part. */ @@ -129,13 +129,13 @@ igraph_bool_t igraph_i_is_real_representable_as_integer(igraph_real_t value) { } /** - * Converts an igraph_real_t into an igraph_integer_t with range checks to + * Converts an igraph_real_t into an igraph_int_t with range checks to * protect from undefined behaviour. The input value is assumed to have no * fractional part. */ -static igraph_error_t igraph_i_safe_real_to_int(igraph_real_t value, igraph_integer_t *result) { +static igraph_error_t igraph_i_safe_real_to_int(igraph_real_t value, igraph_int_t *result) { if (igraph_i_is_real_representable_as_integer(value)) { - *result = (igraph_integer_t) value; + *result = (igraph_int_t) value; return IGRAPH_SUCCESS; } else if (isnan(value)) { IGRAPH_ERROR("NaN cannot be converted to an integer.", IGRAPH_EINVAL); @@ -146,41 +146,41 @@ static igraph_error_t igraph_i_safe_real_to_int(igraph_real_t value, igraph_inte } /** - * Converts an igraph_real_t into an igraph_integer_t with range checks to + * Converts an igraph_real_t into an igraph_int_t with range checks to * protect from undefined behaviour. The input value is converted into an * integer with ceil(). */ -igraph_error_t igraph_i_safe_ceil(igraph_real_t value, igraph_integer_t *result) { +igraph_error_t igraph_i_safe_ceil(igraph_real_t value, igraph_int_t *result) { return igraph_i_safe_real_to_int(ceil(value), result); } /** - * Converts an igraph_real_t into an igraph_integer_t with range checks to + * Converts an igraph_real_t into an igraph_int_t with range checks to * protect from undefined behaviour. The input value is converted into an * integer with floor(). */ -igraph_error_t igraph_i_safe_floor(igraph_real_t value, igraph_integer_t *result) { +igraph_error_t igraph_i_safe_floor(igraph_real_t value, igraph_int_t *result) { return igraph_i_safe_real_to_int(floor(value), result); } /** - * Converts an igraph_real_t into an igraph_integer_t with range checks to + * Converts an igraph_real_t into an igraph_int_t with range checks to * protect from undefined behaviour. The input value is converted into an * integer with round(). * * This is typically the slowest of this set of functions. */ -igraph_error_t igraph_i_safe_round(igraph_real_t value, igraph_integer_t* result) { +igraph_error_t igraph_i_safe_round(igraph_real_t value, igraph_int_t* result) { return igraph_i_safe_real_to_int(round(value), result); } /** - * Converts an igraph_real_t into an igraph_integer_t with range checks to + * Converts an igraph_real_t into an igraph_int_t with range checks to * protect from undefined behaviour. The input value is converted into an * integer with trunc(). * * This is typically the fastest of this set of functions. */ -igraph_error_t igraph_i_safe_trunc(igraph_real_t value, igraph_integer_t* result) { +igraph_error_t igraph_i_safe_trunc(igraph_real_t value, igraph_int_t* result) { return igraph_i_safe_real_to_int(trunc(value), result); } diff --git a/src/vendor/cigraph/src/math/safe_intop.h b/src/vendor/cigraph/src/math/safe_intop.h index 79db3ddd9c3..ed917233170 100644 --- a/src/vendor/cigraph/src/math/safe_intop.h +++ b/src/vendor/cigraph/src/math/safe_intop.h @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2020 The igraph development team it under the terms of the GNU General Public License as published by @@ -29,7 +29,7 @@ #include -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS /* Largest positive value for igraph_real_t that can safely represent integers. */ #define IGRAPH_MAX_EXACT_REAL ((double)(1LL << DBL_MANT_DIG)) @@ -45,8 +45,8 @@ __BEGIN_DECLS #define IGRAPH_SAFE_ADD(a, b, res) \ do { \ - igraph_integer_t _safe_a = (a), _safe_b = (b); \ - igraph_integer_t _safe_sum; \ + igraph_int_t _safe_a = (a), _safe_b = (b); \ + igraph_int_t _safe_sum; \ if (__builtin_add_overflow(_safe_a, _safe_b, &_safe_sum)) { \ IGRAPH_ERRORF("Overflow when adding %" IGRAPH_PRId " and %" IGRAPH_PRId ".", IGRAPH_EOVERFLOW, _safe_a, _safe_b); \ } \ @@ -55,8 +55,8 @@ __BEGIN_DECLS #define IGRAPH_SAFE_MULT(a, b, res) \ do { \ - igraph_integer_t _safe_a = (a), _safe_b = (b); \ - igraph_integer_t _safe_prod; \ + igraph_int_t _safe_a = (a), _safe_b = (b); \ + igraph_int_t _safe_prod; \ if (__builtin_mul_overflow(_safe_a, _safe_b, &_safe_prod)) { \ IGRAPH_ERRORF("Overflow when multiplying %" IGRAPH_PRId " and %" IGRAPH_PRId ".", IGRAPH_EOVERFLOW, _safe_a, _safe_b); \ } \ @@ -67,8 +67,8 @@ __BEGIN_DECLS #define IGRAPH_SAFE_ADD(a, b, res) \ do { \ - igraph_integer_t _safe_a = (a), _safe_b = (b); \ - igraph_integer_t _safe_sum; \ + igraph_int_t _safe_a = (a), _safe_b = (b); \ + igraph_int_t _safe_sum; \ if (((_safe_b > 0) && (_safe_a > (IGRAPH_INTEGER_MAX - _safe_b))) || \ ((_safe_b < 0) && (_safe_a < (IGRAPH_INTEGER_MIN - _safe_b)))) { \ IGRAPH_ERRORF("Overflow when adding %" IGRAPH_PRId " and %" IGRAPH_PRId ".", IGRAPH_EOVERFLOW, _safe_a, _safe_b); \ @@ -79,8 +79,8 @@ __BEGIN_DECLS #define IGRAPH_SAFE_MULT(a, b, res) \ do { \ - igraph_integer_t _safe_a = (a), _safe_b = (b); \ - igraph_integer_t _safe_prod; \ + igraph_int_t _safe_a = (a), _safe_b = (b); \ + igraph_int_t _safe_prod; \ int err=0; \ if (_safe_a > 0) { /* _safe_a is positive */ \ if (_safe_b > 0) { /* _safe_a and _safe_b are positive */ \ @@ -115,25 +115,25 @@ __BEGIN_DECLS /* Overflow-safe calculation of "n choose 2" = n*(n-1) / 2, assuming that n >= 0. */ #define IGRAPH_SAFE_N_CHOOSE_2(n, res) \ do { \ - igraph_integer_t _safe_n = (n); \ + igraph_int_t _safe_n = (n); \ if (_safe_n % 2 == 0) IGRAPH_SAFE_MULT(_safe_n / 2, _safe_n - 1, res); \ else IGRAPH_SAFE_MULT(_safe_n, (_safe_n - 1) / 2, res); \ } while (0) IGRAPH_FUNCATTR_CONST igraph_bool_t igraph_i_is_real_representable_as_integer(igraph_real_t value); -igraph_error_t igraph_i_safe_ceil(igraph_real_t value, igraph_integer_t* result); -igraph_error_t igraph_i_safe_floor(igraph_real_t value, igraph_integer_t* result); -igraph_error_t igraph_i_safe_round(igraph_real_t value, igraph_integer_t* result); -igraph_error_t igraph_i_safe_trunc(igraph_real_t value, igraph_integer_t* result); +igraph_error_t igraph_i_safe_ceil(igraph_real_t value, igraph_int_t* result); +igraph_error_t igraph_i_safe_floor(igraph_real_t value, igraph_int_t* result); +igraph_error_t igraph_i_safe_round(igraph_real_t value, igraph_int_t* result); +igraph_error_t igraph_i_safe_trunc(igraph_real_t value, igraph_int_t* result); -igraph_error_t igraph_i_safe_next_pow_2(igraph_integer_t k, igraph_integer_t *res); -igraph_error_t igraph_i_safe_exp2(igraph_integer_t k, igraph_integer_t *res); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_safe_add(igraph_integer_t a, igraph_integer_t b, igraph_integer_t *res); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_safe_mult(igraph_integer_t a, igraph_integer_t b, igraph_integer_t *res); -igraph_error_t igraph_i_safe_vector_int_sum(const igraph_vector_int_t *vec, igraph_integer_t *res); -igraph_error_t igraph_i_safe_vector_int_prod(const igraph_vector_int_t *vec, igraph_integer_t *res); +igraph_error_t igraph_i_safe_next_pow_2(igraph_int_t k, igraph_int_t *res); +igraph_error_t igraph_i_safe_exp2(igraph_int_t k, igraph_int_t *res); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_safe_add(igraph_int_t a, igraph_int_t b, igraph_int_t *res); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_safe_mult(igraph_int_t a, igraph_int_t b, igraph_int_t *res); +igraph_error_t igraph_i_safe_vector_int_sum(const igraph_vector_int_t *vec, igraph_int_t *res); +igraph_error_t igraph_i_safe_vector_int_prod(const igraph_vector_int_t *vec, igraph_int_t *res); -__END_DECLS +IGRAPH_END_C_DECLS #endif /* IGRAPH_MATH_SAFE_INTOP_H */ diff --git a/src/vendor/cigraph/src/math/utils.c b/src/vendor/cigraph/src/math/utils.c index 7c0be5baf4f..48d822def0c 100644 --- a/src/vendor/cigraph/src/math/utils.c +++ b/src/vendor/cigraph/src/math/utils.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2007-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -28,26 +27,6 @@ #include #include -int igraph_finite(double x) { - return isfinite(x); -} - -int igraph_is_nan(double x) { - return isnan(x); -} - -int igraph_is_inf(double x) { - return isinf(x) != 0; -} - -int igraph_is_posinf(double x) { - return isinf(x) && x > 0; -} - -int igraph_is_neginf(double x) { - return isinf(x) && x < 0; -} - /** * \function igraph_almost_equals * \brief Compare two double-precision floats with a tolerance. diff --git a/src/vendor/cigraph/src/misc/bipartite.c b/src/vendor/cigraph/src/misc/bipartite.c index 04b7bdf3bf2..83bcbab8a4b 100644 --- a/src/vendor/cigraph/src/misc/bipartite.c +++ b/src/vendor/cigraph/src/misc/bipartite.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2008-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -31,8 +30,10 @@ #include "core/interruption.h" #include "graph/attributes.h" -#include "random/random_internal.h" +#include "internal/utils.h" #include "math/safe_intop.h" +#include "misc/graphicality.h" +#include "random/random_internal.h" /** * \section about_bipartite Bipartite networks in igraph @@ -68,16 +69,16 @@ * * \param graph The input graph. * \param types Boolean vector giving the vertex types of the graph. - * \param vcount1 Pointer to an \c igraph_integer_t, the number of + * \param vcount1 Pointer to an \c igraph_int_t, the number of * vertices in the first projection is stored here. May be \c NULL * if not needed. - * \param ecount1 Pointer to an \c igraph_integer_t, the number of + * \param ecount1 Pointer to an \c igraph_int_t, the number of * edges in the first projection is stored here. May be \c NULL * if not needed. - * \param vcount2 Pointer to an \c igraph_integer_t, the number of + * \param vcount2 Pointer to an \c igraph_int_t, the number of * vertices in the second projection is stored here. May be \c NULL * if not needed. - * \param ecount2 Pointer to an \c igraph_integer_t, the number of + * \param ecount2 Pointer to an \c igraph_int_t, the number of * edges in the second projection is stored here. May be \c NULL * if not needed. * \return Error code. @@ -92,13 +93,13 @@ igraph_error_t igraph_bipartite_projection_size(const igraph_t *graph, const igraph_vector_bool_t *types, - igraph_integer_t *vcount1, - igraph_integer_t *ecount1, - igraph_integer_t *vcount2, - igraph_integer_t *ecount2) { + igraph_int_t *vcount1, + igraph_int_t *ecount1, + igraph_int_t *vcount2, + igraph_int_t *ecount2) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t vc1 = 0, ec1 = 0, vc2 = 0, ec2 = 0; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t vc1 = 0, ec1 = 0, vc2 = 0, ec2 = 0; igraph_adjlist_t adjlist; igraph_vector_int_t added; @@ -111,10 +112,10 @@ igraph_error_t igraph_bipartite_projection_size(const igraph_t *graph, IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL, IGRAPH_LOOPS_TWICE, IGRAPH_MULTIPLE)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { igraph_vector_int_t *neis1; - igraph_integer_t neilen1; - igraph_integer_t *ecptr; + igraph_int_t neilen1; + igraph_int_t *ecptr; if (VECTOR(*types)[i]) { vc2++; ecptr = &ec2; @@ -124,16 +125,16 @@ igraph_error_t igraph_bipartite_projection_size(const igraph_t *graph, } neis1 = igraph_adjlist_get(&adjlist, i); neilen1 = igraph_vector_int_size(neis1); - for (igraph_integer_t j = 0; j < neilen1; j++) { - igraph_integer_t neilen2, nei = VECTOR(*neis1)[j]; + for (igraph_int_t j = 0; j < neilen1; j++) { + igraph_int_t neilen2, nei = VECTOR(*neis1)[j]; const igraph_vector_int_t *neis2 = igraph_adjlist_get(&adjlist, nei); if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) { IGRAPH_ERROR("Non-bipartite edge found in bipartite projection.", IGRAPH_EINVAL); } neilen2 = igraph_vector_int_size(neis2); - for (igraph_integer_t k = 0; k < neilen2; k++) { - igraph_integer_t nei2 = VECTOR(*neis2)[k]; + for (igraph_int_t k = 0; k < neilen2; k++) { + igraph_int_t nei2 = VECTOR(*neis2)[k]; if (nei2 <= i) { continue; } @@ -175,13 +176,13 @@ static igraph_error_t igraph_i_bipartite_projection(const igraph_t *graph, int which, igraph_vector_int_t *multiplicity) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t remaining_nodes = 0; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t remaining_nodes = 0; igraph_vector_int_t vertex_perm, vertex_index; igraph_vector_int_t edges; igraph_adjlist_t adjlist; const igraph_vector_int_t *neis1, *neis2; - igraph_integer_t neilen1, neilen2; + igraph_int_t neilen1, neilen2; igraph_vector_int_t added; igraph_vector_int_t mult; @@ -206,28 +207,28 @@ static igraph_error_t igraph_i_bipartite_projection(const igraph_t *graph, igraph_vector_int_clear(multiplicity); } - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(*types)[i] == which) { VECTOR(vertex_index)[i] = remaining_nodes++; - igraph_vector_int_push_back(&vertex_perm, i); + igraph_vector_int_push_back(&vertex_perm, i); /* reserved */ } } - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(*types)[i] == which) { - igraph_integer_t new_i = VECTOR(vertex_index)[i]; - igraph_integer_t iedges = 0; + igraph_int_t new_i = VECTOR(vertex_index)[i]; + igraph_int_t iedges = 0; neis1 = igraph_adjlist_get(&adjlist, i); neilen1 = igraph_vector_int_size(neis1); - for (igraph_integer_t j = 0; j < neilen1; j++) { - igraph_integer_t nei = VECTOR(*neis1)[j]; + for (igraph_int_t j = 0; j < neilen1; j++) { + igraph_int_t nei = VECTOR(*neis1)[j]; if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) { IGRAPH_ERROR("Non-bipartite edge found in bipartite projection.", IGRAPH_EINVAL); } neis2 = igraph_adjlist_get(&adjlist, nei); neilen2 = igraph_vector_int_size(neis2); - for (igraph_integer_t k = 0; k < neilen2; k++) { - igraph_integer_t nei2 = VECTOR(*neis2)[k], new_nei2; + for (igraph_int_t k = 0; k < neilen2; k++) { + igraph_int_t nei2 = VECTOR(*neis2)[k], new_nei2; if (nei2 <= i) { continue; } @@ -257,12 +258,12 @@ static igraph_error_t igraph_i_bipartite_projection(const igraph_t *graph, if (multiplicity) { /* OK, we need to go through all the edges added for vertex new_i and check their multiplicity */ - igraph_integer_t now = igraph_vector_int_size(&edges); - igraph_integer_t from = now - iedges * 2; - for (igraph_integer_t j = from; j < now; j += 2) { - igraph_integer_t nei2 = VECTOR(edges)[j + 1]; - igraph_integer_t new_nei2 = VECTOR(vertex_index)[nei2]; - igraph_integer_t m = VECTOR(mult)[nei2]; + igraph_int_t now = igraph_vector_int_size(&edges); + igraph_int_t from = now - iedges * 2; + for (igraph_int_t j = from; j < now; j += 2) { + igraph_int_t nei2 = VECTOR(edges)[j + 1]; + igraph_int_t new_nei2 = VECTOR(vertex_index)[nei2]; + igraph_int_t m = VECTOR(mult)[nei2]; VECTOR(edges)[j + 1] = new_nei2; IGRAPH_CHECK(igraph_vector_int_push_back(multiplicity, m)); } @@ -284,8 +285,7 @@ static igraph_error_t igraph_i_bipartite_projection(const igraph_t *graph, IGRAPH_FINALLY(igraph_destroy, proj); /* copy graph attributes */ - IGRAPH_I_ATTRIBUTE_DESTROY(proj); - IGRAPH_I_ATTRIBUTE_COPY(proj, graph, /* graph */ true, /* vertex */ false, /* edge */ false); + IGRAPH_CHECK(igraph_i_attribute_copy(proj, graph, true, /* vertex= */ false, /* edge= */ false)); /* copy vertex attributes */ IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, proj, &vertex_perm)); @@ -353,9 +353,9 @@ igraph_error_t igraph_bipartite_projection(const igraph_t *graph, igraph_t *proj2, igraph_vector_int_t *multiplicity1, igraph_vector_int_t *multiplicity2, - igraph_integer_t probe1) { + igraph_int_t probe1) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); /* t1 is -1 if proj1 is omitted, it is 0 if it belongs to type zero, it is 1 if it belongs to type one. The same for t2 */ @@ -447,13 +447,13 @@ igraph_error_t igraph_bipartite_projection(const igraph_t *graph, igraph_error_t igraph_full_bipartite(igraph_t *graph, igraph_vector_bool_t *types, - igraph_integer_t n1, igraph_integer_t n2, + igraph_int_t n1, igraph_int_t n2, igraph_bool_t directed, igraph_neimode_t mode) { - igraph_integer_t no_of_nodes, no_of_edges; + igraph_int_t no_of_nodes, no_of_edges; igraph_vector_int_t edges; - igraph_integer_t ptr; + igraph_int_t ptr; if (n1 < 0 || n2 < 0) { IGRAPH_ERROR("Invalid number of vertices for bipartite graph.", IGRAPH_EINVAL); @@ -481,8 +481,8 @@ igraph_error_t igraph_full_bipartite(igraph_t *graph, if (!directed || mode == IGRAPH_OUT) { - for (igraph_integer_t i = 0; i < n1; i++) { - for (igraph_integer_t j = 0; j < n2; j++) { + for (igraph_int_t i = 0; i < n1; i++) { + for (igraph_int_t j = 0; j < n2; j++) { VECTOR(edges)[ptr++] = i; VECTOR(edges)[ptr++] = n1 + j; } @@ -490,8 +490,8 @@ igraph_error_t igraph_full_bipartite(igraph_t *graph, } else if (mode == IGRAPH_IN) { - for (igraph_integer_t i = 0; i < n1; i++) { - for (igraph_integer_t j = 0; j < n2; j++) { + for (igraph_int_t i = 0; i < n1; i++) { + for (igraph_int_t j = 0; j < n2; j++) { VECTOR(edges)[ptr++] = n1 + j; VECTOR(edges)[ptr++] = i; } @@ -499,8 +499,8 @@ igraph_error_t igraph_full_bipartite(igraph_t *graph, } else { - for (igraph_integer_t i = 0; i < n1; i++) { - for (igraph_integer_t j = 0; j < n2; j++) { + for (igraph_int_t i = 0; i < n1; i++) { + for (igraph_int_t j = 0; j < n2; j++) { VECTOR(edges)[ptr++] = i; VECTOR(edges)[ptr++] = n1 + j; VECTOR(edges)[ptr++] = n1 + j; @@ -517,7 +517,7 @@ igraph_error_t igraph_full_bipartite(igraph_t *graph, if (types) { IGRAPH_CHECK(igraph_vector_bool_resize(types, no_of_nodes)); igraph_vector_bool_null(types); - for (igraph_integer_t i = n1; i < no_of_nodes; i++) { + for (igraph_int_t i = n1; i < no_of_nodes; i++) { VECTOR(*types)[i] = true; } } @@ -557,12 +557,12 @@ igraph_error_t igraph_create_bipartite(igraph_t *graph, const igraph_vector_bool const igraph_vector_int_t *edges, igraph_bool_t directed) { - igraph_integer_t no_of_nodes = igraph_vector_bool_size(types); - igraph_integer_t no_of_edges = igraph_vector_int_size(edges); - igraph_integer_t i; + igraph_int_t no_of_nodes = igraph_vector_bool_size(types); + igraph_int_t no_of_edges = igraph_vector_int_size(edges); + igraph_int_t i; if (no_of_edges % 2 != 0) { - IGRAPH_ERROR("Invalid (odd) edges vector", IGRAPH_EINVEVECTOR); + IGRAPH_ERROR("Invalid (odd) edges vector", IGRAPH_EINVAL); } no_of_edges /= 2; @@ -572,8 +572,8 @@ igraph_error_t igraph_create_bipartite(igraph_t *graph, const igraph_vector_bool /* Check bipartiteness */ for (i = 0; i < no_of_edges * 2; i += 2) { - igraph_integer_t from = VECTOR(*edges)[i]; - igraph_integer_t to = VECTOR(*edges)[i + 1]; + igraph_int_t from = VECTOR(*edges)[i]; + igraph_int_t to = VECTOR(*edges)[i + 1]; igraph_bool_t t1 = VECTOR(*types)[from]; igraph_bool_t t2 = VECTOR(*types)[to]; if ( (t1 && t2) || (!t1 && !t2) ) { @@ -589,21 +589,6 @@ igraph_error_t igraph_create_bipartite(igraph_t *graph, const igraph_vector_bool return IGRAPH_SUCCESS; } -/** - * \function igraph_incidence - * \brief Creates a bipartite graph from a bipartite adjacency matrix (deprecated alias). - * - * \deprecated-by igraph_biadjacency 0.10.5 - */ - -igraph_error_t igraph_incidence( - igraph_t *graph, igraph_vector_bool_t *types, - const igraph_matrix_t *incidence, igraph_bool_t directed, - igraph_neimode_t mode, igraph_bool_t multiple -) { - return igraph_biadjacency(graph, types, incidence, directed, mode, multiple); -} - /** * \function igraph_biadjacency * \brief Creates a bipartite graph from a bipartite adjacency matrix. @@ -615,64 +600,63 @@ igraph_error_t igraph_incidence( * edges between the two corresponding vertices. * * - * Note that this function can operate in two modes, depending on the + * This function can operate in two modes, depending on the * \p multiple argument. If it is \c false, then a single edge is - * created for every non-zero element in the bipartite adjacency matrix. If \p - * multiple is \c true, then the matrix elements are rounded up - * to the closest non-negative integer to get the number of edges to - * create between a pair of vertices. - * - * - * This function does not create multiple edges if \p multiple is - * \c false, but might create some if it is \c true. + * created for every non-zero element in the bipartite adjacency matrix. If + * \p multiple is \c true, then as many edges are created between two + * vertices as the corresponding matrix element. When \p multiple + * is set to \c true, matrix elements should be whole numbers. + * Otherwise their fractional part will be discarded. * * \param graph Pointer to an uninitialized graph object. * \param types Pointer to an initialized boolean vector, or a null * pointer. If not a null pointer, then the vertex types are stored * here. It is resized as needed. - * \param input The bipartite adjacency matrix that serves as an input + * \param biadjmatrix The bipartite adjacency matrix that serves as an input * to this function. * \param directed Specifies whether to create an undirected or a directed * graph. * \param mode Specifies the direction of the edges in a directed * graph. If \c IGRAPH_OUT, then edges point from vertices * of the first kind (corresponding to rows) to vertices of the - * second kind (corresponding to columns); if \c - * IGRAPH_IN, then the opposite direction is realized; if \c - * IGRAPH_ALL, then mutual edges will be created. - * \param multiple How to interpret the matrix elements. See details above. + * second kind (corresponding to columns); if \c IGRAPH_IN, + * then the opposite direction is realized; if \c IGRAPH_ALL, + * then mutual edges will be created. + * \param multiple Whether to interpret matrix entries as edge multiplicities, + * see details above. * \return Error code. * * Time complexity: O(n*m), the size of the bipartite adjacency matrix. */ igraph_error_t igraph_biadjacency( - igraph_t *graph, igraph_vector_bool_t *types, - const igraph_matrix_t *input, igraph_bool_t directed, - igraph_neimode_t mode, igraph_bool_t multiple -) { - - igraph_integer_t n1 = igraph_matrix_nrow(input); - igraph_integer_t n2 = igraph_matrix_ncol(input); - igraph_integer_t no_of_nodes = n1 + n2; + igraph_t *graph, + igraph_vector_bool_t *types, + const igraph_matrix_t *biadjmatrix, + igraph_bool_t directed, + igraph_neimode_t mode, + igraph_bool_t multiple) { + + const igraph_int_t n1 = igraph_matrix_nrow(biadjmatrix); + const igraph_int_t n2 = igraph_matrix_ncol(biadjmatrix); + const igraph_int_t no_of_nodes = n1 + n2; igraph_vector_int_t edges; - igraph_integer_t i, j, k; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - if (n1 > 0 && n2 > 0 && igraph_matrix_min(input) < 0) { - IGRAPH_ERRORF( - "Bipartite adjacencey matrix elements should be non-negative, found %g.", - IGRAPH_EINVAL, igraph_matrix_min(input) - ); - } - if (multiple) { - for (i = 0; i < n1; i++) { - for (j = 0; j < n2; j++) { - igraph_integer_t elem = ceil(MATRIX(*input, i, j)); - igraph_integer_t from, to; + if (n1 > 0 && n2 > 0 && igraph_matrix_min(biadjmatrix) < 0) { + IGRAPH_ERRORF( + "Bipartite adjacency matrix elements should be non-negative, found %g.", + IGRAPH_EINVAL, igraph_matrix_min(biadjmatrix) + ); + } + + for (igraph_int_t j = 0; j < n2; j++) { + for (igraph_int_t i = 0; i < n1; i++) { + igraph_int_t elem = MATRIX(*biadjmatrix, i, j); + igraph_int_t from, to; if (elem == 0) { continue; @@ -687,12 +671,12 @@ igraph_error_t igraph_biadjacency( } if (mode != IGRAPH_ALL || !directed) { - for (k = 0; k < elem; k++) { + for (igraph_int_t k = 0; k < elem; k++) { IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to)); } } else { - for (k = 0; k < elem; k++) { + for (igraph_int_t k = 0; k < elem; k++) { IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to)); @@ -704,11 +688,11 @@ igraph_error_t igraph_biadjacency( } else { - for (i = 0; i < n1; i++) { - for (j = 0; j < n2; j++) { - igraph_integer_t from, to; + for (igraph_int_t j = 0; j < n2; j++) { + for (igraph_int_t i = 0; i < n1; i++) { + igraph_int_t from, to; - if (MATRIX(*input, i, j) != 0) { + if (MATRIX(*biadjmatrix, i, j) != 0) { if (mode == IGRAPH_IN) { from = n1 + j; to = i; @@ -734,33 +718,116 @@ igraph_error_t igraph_biadjacency( IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed)); igraph_vector_int_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); + IGRAPH_FINALLY(igraph_destroy, graph); if (types) { IGRAPH_CHECK(igraph_vector_bool_resize(types, no_of_nodes)); igraph_vector_bool_null(types); - for (i = n1; i < no_of_nodes; i++) { - VECTOR(*types)[i] = 1; + for (igraph_int_t i = n1; i < no_of_nodes; i++) { + VECTOR(*types)[i] = true; } } IGRAPH_FINALLY_CLEAN(1); + return IGRAPH_SUCCESS; } + /** - * \function igraph_get_incidence - * \brief Convert a bipartite graph into a bipartite adjacency matrix (deprecated alias). + * \function igraph_weighted_biadjacency + * \brief Creates a bipartite graph from a weighted bipartite adjacency matrix. + * + * A bipartite (or two-mode) graph contains two types of vertices and + * edges always connect vertices of different types. A bipartite adjacency + * matrix is an \em n x \em m matrix, \em n and \em m are the number of vertices + * of the two types, respectively. Nonzero elements in the matrix denote + * edges between the two corresponding vertices. * - * \deprecated-by igraph_get_biadjacency 0.10.5 + * \param graph Pointer to an uninitialized graph object. + * \param types Pointer to an initialized boolean vector, or a null + * pointer. If not a null pointer, then the vertex types are stored + * here. It is resized as needed. + * \param weights Pointer to an initialized vector, the weights will be stored here. + * \param biadjmatrix The bipartite adjacency matrix that serves as an input + * to this function. + * \param directed Specifies whether to create an undirected or a directed + * graph. + * \param mode Specifies the direction of the edges in a directed + * graph. If \c IGRAPH_OUT, then edges point from vertices + * of the first kind (corresponding to rows) to vertices of the + * second kind (corresponding to columns); if \c IGRAPH_IN, + * then the opposite direction is realized; if \c IGRAPH_ALL, + * then mutual edges will be created. + * \return Error code. + * + * Time complexity: O(n*m), the size of the bipartite adjacency matrix. */ -igraph_error_t igraph_get_incidence(const igraph_t *graph, - const igraph_vector_bool_t *types, - igraph_matrix_t *res, - igraph_vector_int_t *row_ids, - igraph_vector_int_t *col_ids) { - return igraph_get_biadjacency(graph, types, res, row_ids, col_ids); +igraph_error_t igraph_weighted_biadjacency( + igraph_t *graph, + igraph_vector_bool_t *types, + igraph_vector_t *weights, + const igraph_matrix_t *biadjmatrix, + igraph_bool_t directed, + igraph_neimode_t mode) { + + const igraph_int_t n1 = igraph_matrix_nrow(biadjmatrix); + const igraph_int_t n2 = igraph_matrix_ncol(biadjmatrix); + const igraph_int_t no_of_nodes = n1 + n2; + igraph_vector_int_t edges; + + IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); + igraph_vector_clear(weights); + + for (igraph_int_t j = 0; j < n2; j++) { + for (igraph_int_t i = 0; i < n1; i++) { + igraph_real_t weight = MATRIX(*biadjmatrix, i, j); + igraph_int_t from, to; + + if (weight != 0) { + if (mode == IGRAPH_IN) { + from = n1 + j; + to = i; + } else { + from = i; + to = n1 + j; + } + if (mode != IGRAPH_ALL || !directed) { + IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from)); + IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to)); + IGRAPH_CHECK(igraph_vector_push_back(weights, weight)); + } else { + IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from)); + IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to)); + IGRAPH_CHECK(igraph_vector_push_back(weights, weight)); + + IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to)); + IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from)); + IGRAPH_CHECK(igraph_vector_push_back(weights, weight)); + } + } + } + } + + IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed)); + igraph_vector_int_destroy(&edges); + IGRAPH_FINALLY_CLEAN(1); + + IGRAPH_FINALLY(igraph_destroy, graph); + + if (types) { + IGRAPH_CHECK(igraph_vector_bool_resize(types, no_of_nodes)); + igraph_vector_bool_null(types); + for (igraph_int_t i = n1; i < no_of_nodes; i++) { + VECTOR(*types)[i] = true; + } + } + + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; } /** @@ -779,11 +846,14 @@ igraph_error_t igraph_get_incidence(const igraph_t *graph, * \param types Boolean vector containing the vertex types. Vertices belonging * to the first partition have type \c false, the one in the second * partition type \c true. + * \param weights A vector specifying a weight for each edge or \c NULL. + * If \c NULL, all edges are assumed to have weight 1. * \param res Pointer to an initialized matrix, the result is stored * here. An element of the matrix gives the number of edges - * (irrespectively of their direction) between the two corresponding - * vertices. The rows will correspond to vertices with type \c false, - * the columns correspond to vertices with type \c true. + * (irrespectively of their direction), or sum of edge weights, + * between the two corresponding vertices. The rows will correspond + * to vertices with type \c false, the columns correspond to vertices + * with type \c true. * \param row_ids Pointer to an initialized vector or \c NULL. * If not a null pointer, then the IDs of vertices with type \c false * are stored here, with the same ordering as the rows of the @@ -801,49 +871,57 @@ igraph_error_t igraph_get_incidence(const igraph_t *graph, igraph_error_t igraph_get_biadjacency( const igraph_t *graph, const igraph_vector_bool_t *types, + const igraph_vector_t *weights, igraph_matrix_t *res, igraph_vector_int_t *row_ids, igraph_vector_int_t *col_ids ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t n1 = 0, n2 = 0, i; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t n1 = 0, n2 = 0; + igraph_int_t ignored_edges = 0; igraph_vector_int_t perm; - igraph_integer_t p1, p2; - igraph_integer_t ignored_edges = 0; if (igraph_vector_bool_size(types) != no_of_nodes) { IGRAPH_ERRORF("Vertex type vector size (%" IGRAPH_PRId ") not equal to number of vertices (%" IGRAPH_PRId ").", IGRAPH_EINVAL, igraph_vector_bool_size(types), no_of_nodes); } - for (i = 0; i < no_of_nodes; i++) { + if (weights) { + if (igraph_vector_size(weights) != no_of_edges) { + IGRAPH_ERRORF("Edge weight vector size (%" IGRAPH_PRId ") not equal to number of edges (%" IGRAPH_PRId ").", + IGRAPH_EINVAL, igraph_vector_size(weights), no_of_edges); + } + } + + for (igraph_int_t i = 0; i < no_of_nodes; i++) { n1 += VECTOR(*types)[i] == false ? 1 : 0; } n2 = no_of_nodes - n1; IGRAPH_VECTOR_INT_INIT_FINALLY(&perm, no_of_nodes); - for (i = 0, p1 = 0, p2 = n1; i < no_of_nodes; i++) { + for (igraph_int_t i = 0, p1 = 0, p2 = n1; i < no_of_nodes; i++) { VECTOR(perm)[i] = VECTOR(*types)[i] ? p2++ : p1++; } IGRAPH_CHECK(igraph_matrix_resize(res, n1, n2)); igraph_matrix_null(res); - for (i = 0; i < no_of_edges; i++) { - igraph_integer_t from = IGRAPH_FROM(graph, i); - igraph_integer_t to = IGRAPH_TO(graph, i); - igraph_integer_t from2 = VECTOR(perm)[from]; - igraph_integer_t to2 = VECTOR(perm)[to]; + for (igraph_int_t i = 0; i < no_of_edges; i++) { + igraph_int_t from = IGRAPH_FROM(graph, i); + igraph_int_t to = IGRAPH_TO(graph, i); + igraph_int_t from2 = VECTOR(perm)[from]; + igraph_int_t to2 = VECTOR(perm)[to]; if (VECTOR(*types)[from] == VECTOR(*types)[to]) { ignored_edges++; } else if (! VECTOR(*types)[from]) { - MATRIX(*res, from2, to2 - n1) += 1; + MATRIX(*res, from2, to2 - n1) += weights ? VECTOR(*weights)[i] : 1; } else { - MATRIX(*res, to2, from2 - n1) += 1; + MATRIX(*res, to2, from2 - n1) += weights ? VECTOR(*weights)[i] : 1; } } - if (ignored_edges) { + + if (ignored_edges > 0) { IGRAPH_WARNINGF("%" IGRAPH_PRId " edges running within partitions were ignored.", ignored_edges); } @@ -854,15 +932,15 @@ igraph_error_t igraph_get_biadjacency( IGRAPH_CHECK(igraph_vector_int_resize(col_ids, n2)); } if (row_ids || col_ids) { - for (i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (! VECTOR(*types)[i]) { if (row_ids) { - igraph_integer_t i2 = VECTOR(perm)[i]; + igraph_int_t i2 = VECTOR(perm)[i]; VECTOR(*row_ids)[i2] = i; } } else { if (col_ids) { - igraph_integer_t i2 = VECTOR(perm)[i]; + igraph_int_t i2 = VECTOR(perm)[i]; VECTOR(*col_ids)[i2 - n1] = i; } } @@ -904,7 +982,7 @@ igraph_error_t igraph_get_biadjacency( * Time complexity: O(|V|+|E|), linear in the number of vertices and * edges. * - * \sa igraph_is_bipartite_coloring() do determine if all edges connect + * \sa igraph_is_bipartite_coloring() to determine if all edges connect * vertices of different types, given a specific type vector. */ @@ -920,7 +998,7 @@ igraph_error_t igraph_is_bipartite(const igraph_t *graph, 2 means type 2. */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_char_t seen; igraph_dqueue_int_t Q; igraph_vector_int_t neis; @@ -950,7 +1028,7 @@ igraph_error_t igraph_is_bipartite(const igraph_t *graph, IGRAPH_DQUEUE_INT_INIT_FINALLY(&Q, 100); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); - for (igraph_integer_t i = 0; bi && i < no_of_nodes; i++) { + for (igraph_int_t i = 0; bi && i < no_of_nodes; i++) { if (VECTOR(seen)[i]) { continue; @@ -960,14 +1038,16 @@ igraph_error_t igraph_is_bipartite(const igraph_t *graph, VECTOR(seen)[i] = 1; while (bi && !igraph_dqueue_int_empty(&Q)) { - igraph_integer_t n, j; - igraph_integer_t actnode = igraph_dqueue_int_pop(&Q); + igraph_int_t n, j; + igraph_int_t actnode = igraph_dqueue_int_pop(&Q); char acttype = VECTOR(seen)[actnode]; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, actnode, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); n = igraph_vector_int_size(&neis); for (j = 0; j < n; j++) { - igraph_integer_t nei = VECTOR(neis)[j]; + igraph_int_t nei = VECTOR(neis)[j]; if (VECTOR(seen)[nei]) { char neitype = VECTOR(seen)[nei]; if (neitype == acttype) { @@ -998,7 +1078,7 @@ igraph_error_t igraph_is_bipartite(const igraph_t *graph, if (types && bi) { IGRAPH_CHECK(igraph_vector_bool_resize(types, no_of_nodes)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { VECTOR(*types)[i] = VECTOR(seen)[i] - 1; } } @@ -1009,16 +1089,441 @@ igraph_error_t igraph_is_bipartite(const igraph_t *graph, return IGRAPH_SUCCESS; } + +static igraph_error_t bipartite_iea_game( + igraph_t *graph, + igraph_int_t n1, igraph_int_t n2, + igraph_int_t m, + igraph_bool_t directed, igraph_neimode_t mode) { + + igraph_vector_int_t edges; + igraph_int_t n = n1 + n2; /* overflow checked by caller */ + + IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); + IGRAPH_CHECK(igraph_vector_int_reserve(&edges, m * 2)); + + for (igraph_int_t i = 0; i < m; i++) { + igraph_int_t to, from; + + to = RNG_INTEGER(n1, n - 1); + from = RNG_INTEGER(0, n1 - 1); + + /* flip unconditionally for IGRAPH_IN, + * or with probability 0.5 for IGRAPH_ALL */ + if (mode == IGRAPH_IN || (mode == IGRAPH_ALL && RNG_BOOL())) { + igraph_vector_int_push_back(&edges, to); /* reserved */ + igraph_vector_int_push_back(&edges, from); /* reserved */ + } else { + igraph_vector_int_push_back(&edges, from); /* reserved */ + igraph_vector_int_push_back(&edges, to); /* reserved */ + } + + } + + IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); + igraph_vector_int_destroy(&edges); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} + +static igraph_error_t bipartite_gnm_multi( + igraph_t *graph, + igraph_int_t n1, igraph_int_t n2, + igraph_int_t m, + igraph_bool_t directed, igraph_neimode_t mode) { + + /* See igraph_erdos_renyi_game_gnm() for how the sampling works. */ + + igraph_vector_int_t edges; + igraph_int_t nrow, ncol; + igraph_int_t last; + igraph_int_t offset1 = 0, offset2 = n1; + igraph_int_t n = n1 + n2; /* overflow checked by caller */ + + /* The larger partition is associated with columns, the smaller + * with rows. This setup helps avoid integer overflow. We swap + * n1 and n2 so that n1 is smaller. */ + if (n1 > n2) { + igraph_int_t tmp = n1; + n1 = n2; + n2 = tmp; + + offset1 = n2; offset2 = 0; + + mode = IGRAPH_REVERSE_MODE(mode); + } + + IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 2*m); + + if (!directed || mode != IGRAPH_ALL) { + nrow = n1; + ncol = n2; + last = ncol-1; + for (igraph_int_t i=0; i < m; i++) { + while (true) { + igraph_int_t r = RNG_INTEGER(0, nrow-1); + igraph_int_t c = RNG_INTEGER(0, ncol-1); + + if (r >= n1) { + igraph_int_t j = (r - n1) * ncol + c; + if (j >= i) continue; /* rejection sampling */ + VECTOR(edges)[2*i] = VECTOR(edges)[2*j]; + VECTOR(edges)[2*i+1] = VECTOR(edges)[2*j+1]; + } else { + if (directed && mode == IGRAPH_IN) { + VECTOR(edges)[2*i] = c + offset2; + VECTOR(edges)[2*i+1] = r + offset1; + } else { + VECTOR(edges)[2*i] = r + offset1; + VECTOR(edges)[2*i+1] = c + offset2; + } + } + + last += 1; + if (last >= ncol) { + last -= ncol; + nrow++; + } + + break; + } + } + } else /* directed, mutual allowed */ { + nrow = 2*n1; + ncol = n2; + last = ncol-1; + for (igraph_int_t i=0; i < m; i++) { + while (true) { + igraph_int_t r = RNG_INTEGER(0, nrow-1); + igraph_int_t c = RNG_INTEGER(0, ncol-1); + + if (r >= 2*n1) { + igraph_int_t j = (r - 2*n1) * ncol + c; + if (j >= i) continue; /* rejection sampling */ + VECTOR(edges)[2*i] = VECTOR(edges)[2*j]; + VECTOR(edges)[2*i+1] = VECTOR(edges)[2*j+1]; + } else { + if (r < n1) { + VECTOR(edges)[2*i] = r + offset1; + VECTOR(edges)[2*i+1] = c + offset2; + } else { + VECTOR(edges)[2*i] = c + offset2; + VECTOR(edges)[2*i+1] = r - n1 + offset1; + } + } + + last += 1; + if (last >= ncol) { + last -= ncol; + nrow++; + } + + break; + } + } + } + + IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); + + igraph_vector_int_destroy(&edges); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} + +static igraph_error_t bipartite_gnm_simple( + igraph_t *graph, + igraph_int_t n1, igraph_int_t n2, + igraph_int_t m, + igraph_bool_t directed, igraph_neimode_t mode, + igraph_bool_t edge_labeled) { + + igraph_vector_int_t edges; + igraph_vector_t s; + igraph_real_t n1_real = (igraph_real_t) n1, n2_real = (igraph_real_t) n2; /* for floating-point operations */ + igraph_int_t n = n1 + n2; /* overflow checked by caller */ + igraph_real_t maxedges; + int iter = 0; + + if (!directed || mode != IGRAPH_ALL) { + maxedges = n1_real * n2_real; + } else { + maxedges = 2.0 * n1_real * n2_real; + } + + if (m > maxedges) { + IGRAPH_ERROR("Too many edges requested compared to the number of vertices.", IGRAPH_EINVAL); + } + + if (maxedges == m && ! edge_labeled) { + /* TODO: Cannot use igraph_full_bipartite() when edge_labeled as we must shuffle edges. */ + IGRAPH_CHECK(igraph_full_bipartite(graph, NULL, n1, n2, directed, mode)); + } else { + igraph_int_t to, from; + + IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); + IGRAPH_VECTOR_INIT_FINALLY(&s, 0); + IGRAPH_CHECK(igraph_i_random_sample_real(&s, 0, maxedges - 1, m)); + IGRAPH_CHECK(igraph_vector_int_reserve(&edges, m * 2)); + + for (igraph_int_t i = 0; i < m; i++) { + if (!directed || mode != IGRAPH_ALL) { + to = trunc(VECTOR(s)[i] / n1_real); + from = VECTOR(s)[i] - to * n1_real; + to += n1; + } else { + igraph_real_t n1n2 = n1_real * n2_real; + if (VECTOR(s)[i] < n1n2) { + to = trunc(VECTOR(s)[i] / n1_real); + from = VECTOR(s)[i] - to * n1_real; + to += n1; + } else { + to = trunc((VECTOR(s)[i] - n1n2) / n2_real); + from = VECTOR(s)[i] - n1n2 - to * n2_real; + from += n1; + } + } + + if (mode != IGRAPH_IN) { + igraph_vector_int_push_back(&edges, from); /* reserved */ + igraph_vector_int_push_back(&edges, to); /* reserved */ + } else { + igraph_vector_int_push_back(&edges, to); /* reserved */ + igraph_vector_int_push_back(&edges, from); /* reserved */ + } + + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); + } + + igraph_vector_destroy(&s); + IGRAPH_FINALLY_CLEAN(1); + + if (edge_labeled) { + IGRAPH_CHECK(igraph_i_vector_int_shuffle_pairs(&edges)); + } + + IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); + + igraph_vector_int_destroy(&edges); + IGRAPH_FINALLY_CLEAN(1); + } + + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_bipartite_game_gnm + * \brief Generate a random bipartite graph with a fixed number of edges. + * + * The G(n1, n2, m) model uniformly samples bipartite graphs with + * \p n1 bottom vertices and \p n2 top vertices, and precisely \p m edges. + * + * \param graph Pointer to an uninitialized igraph graph, the result + * is stored here. + * \param types Pointer to an initialized boolean vector, or a null + * pointer. If not a null pointer, then the vertex types are stored + * here. Bottom vertices come first, \p n1 of them, then \p n2 top + * vertices. + * \param n1 The number of bottom vertices. + * \param n2 The number of top vertices. + * \param m The number of edges. + * \param directed Boolean, whether to generate a directed graph. See + * also the \p mode argument. + * \param mode Specifies how to direct the edges in directed + * graphs. If it is \c IGRAPH_OUT, then directed edges point from + * bottom vertices to top vertices. If it is \c IGRAPH_IN, edges + * point from top vertices to bottom vertices. \c IGRAPH_OUT and + * \c IGRAPH_IN do not generate mutual edges. If this argument is + * \c IGRAPH_ALL, then each edge direction is considered + * independently and mutual edges might be generated. This + * argument is ignored for undirected graphs. +* \param allowed_edge_types The types of edges to allow in the graph. + * \clist + * \cli IGRAPH_SIMPLE_SW + * simple graph (i.e. no multi-edges allowed). + * \cli IGRAPH_MULTI_SW + * multi-edges are allowed + * \endclist + * \param edge_labeled If true, the sampling is done uniformly from the set + * of ordered edge lists. See \ref igraph_bipartite_iea_game() for more + * information. Set this to \c false to select the classic Erdős-Rényi model. + * The constants \c IGRAPH_EDGE_UNLABELED and \c IGRAPH_EDGE_LABELED + * may be used instead of \c false and \c true for better readability. + * \return Error code. + * + * \sa \ref igraph_erdos_renyi_game_gnm() for the unipartite version, + * \ref igraph_bipartite_game_gnp() for the G(n1, n2, p) + * model. + * + * Time complexity: O(|V|+|E|), linear in the number of vertices and + * edges. + */ + +igraph_error_t igraph_bipartite_game_gnm( + igraph_t *graph, + igraph_vector_bool_t *types, + igraph_int_t n1, igraph_int_t n2, igraph_int_t m, + igraph_bool_t directed, igraph_neimode_t mode, + igraph_edge_type_sw_t allowed_edge_types, + igraph_bool_t edge_labeled) { + + igraph_int_t n; + igraph_bool_t loops, multiple; + + if (n1 < 0 || n2 < 0) { + IGRAPH_ERROR("Invalid number of vertices for bipartite G(n,m) model.", IGRAPH_EINVAL); + } + if (m < 0 || m > IGRAPH_ECOUNT_MAX) { + IGRAPH_ERROR("Invalid number of edges for bipartite G(n,m) model.", IGRAPH_EINVAL); + } + if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) { + IGRAPH_ERROR("Invalid mode for bipartite G(n,m) model.", IGRAPH_EINVAL); + } + + /* Bipartite graphs cannot have self-loops. We ignore them. */ + IGRAPH_CHECK(igraph_i_edge_type_to_loops_multiple(allowed_edge_types, &loops, &multiple)); + + IGRAPH_SAFE_ADD(n1, n2, &n); /* overflow check */ + + if (types) { + IGRAPH_CHECK(igraph_vector_bool_resize(types, n)); + igraph_vector_bool_null(types); + for (igraph_int_t i = n1; i < n; i++) { + VECTOR(*types)[i] = true; + } + } + + if (m == 0 || n1 == 0 || n2 == 0) { + if (m > 0) { + IGRAPH_ERROR("Too many edges requested compared to the number of vertices.", IGRAPH_EINVAL); + } + return igraph_empty(graph, n, directed); + } else if (multiple) { + if (edge_labeled) { + return bipartite_iea_game(graph, n1, n2, m, directed, mode); + } else { + return bipartite_gnm_multi(graph, n1, n2, m, directed, mode); + } + } else { + return bipartite_gnm_simple(graph, n1, n2, m, directed, mode, edge_labeled); + } + + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_bipartite_iea_game + * \brief Generates a random bipartite multigraph through independent edge assignment. + * + * \experimental + * + * This model generates random multigraphs with \p n1 bottom vertices, + * \p n2 top vertices and \p m edges through independent edge assignment (IEA). + * Each of the \p m edges is assigned uniformly at random to a vertex pair, + * independently of each other. + * + * + * This model does not sample multigraphs uniformly. Undirected graphs are + * generated with probability proportional to + * + * + * (prod_(i<j) A_ij !)^(-1), + * + * + * where \c A denotes the adjacency matrix. The corresponding expression for + * directed graphs is + * + * + * (prod_(i,j) A_ij !)^(-1). + * + * + * Thus the probability of all simple graphs (which only have 0s and 1s in the + * adjacency matrix) is the same, while that of non-simple ones depends on + * their edge and self-loop multiplicities. + * + * \param graph Pointer to an uninitialized igraph graph, the result + * is stored here. + * \param types Pointer to an initialized boolean vector, or a \c NULL + * pointer. If not \c NULL, then the vertex types are stored + * here. Bottom vertices come first, \p n1 of them, then \p n2 top + * vertices. + * \param n1 The number of bottom vertices. + * \param n2 The number of top vertices. + * \param m The number of edges. + * \param directed Whether to generate a directed graph. See + * also the \p mode argument. + * \param mode Specifies how to direct the edges in directed + * graphs. If it is \c IGRAPH_OUT, then directed edges point from + * bottom vertices to top vertices. If it is \c IGRAPH_IN, edges + * point from top vertices to bottom vertices. \c IGRAPH_OUT and + * \c IGRAPH_IN do not generate mutual edges. If this argument is + * \c IGRAPH_ALL, then each edge direction is considered + * independently and mutual edges might be generated. This + * argument is ignored for undirected graphs. + * \return Error code. + * + * \sa \ref igraph_iea_game() for the unipartite version; + * \ref igraph_bipartite_game_gnm() to uniformly sample bipartite graphs + * with a given number of vertices and edges. + * + * Time complexity: O(|V|+|E|), linear in the number of vertices and + * edges. + */ + +igraph_error_t igraph_bipartite_iea_game( + igraph_t *graph, igraph_vector_bool_t *types, + igraph_int_t n1, igraph_int_t n2, igraph_int_t m, + igraph_bool_t directed, igraph_neimode_t mode) { + + return igraph_bipartite_game_gnm( + graph, types, n1, n2, m, directed, mode, + IGRAPH_MULTI_SW, IGRAPH_EDGE_UNLABELED); +} + + +static igraph_error_t bipartite_gnp_edge_labeled( + igraph_t *graph, + igraph_int_t n1, igraph_int_t n2, igraph_real_t p, + igraph_bool_t directed, igraph_neimode_t mode, + igraph_bool_t multiple) { + + if (multiple) { + igraph_real_t maxedges; + + if (!directed || mode != IGRAPH_ALL) { + maxedges = (igraph_real_t) n1 * (igraph_real_t) n2; + } else { + maxedges = 2.0 * (igraph_real_t) n1 * (igraph_real_t) n2; + } + + igraph_real_t m; + do { + m = RNG_GEOM( 1.0 / (1.0 + maxedges * p) ); + } while (m > (igraph_real_t) IGRAPH_INTEGER_MAX); + + return bipartite_iea_game(graph, n1, n2, m, directed, mode); + } else { + IGRAPH_ERROR("The edge-labeled bipartite G(n,p) model is not yet implemented for graphs without multi-edges.", + IGRAPH_UNIMPLEMENTED); + } +} + /* This implementation is used only with very large vertex counts, when the * default implementation would fail due to overflow. While this version * avoids overflow and uses less memory, it is also slower than the default - * implementation. */ + * implementation. + * + * This function expects that when multiple=true, the p parameter has already + * been transformed by p = p / (1 + p). This is currently done by the caller. + */ static igraph_error_t gnp_bipartite_large( igraph_t *graph, - igraph_integer_t n1, igraph_integer_t n2, + igraph_int_t n1, igraph_int_t n2, igraph_real_t p, igraph_bool_t directed, igraph_neimode_t mode, - igraph_integer_t ecount_estimate) { + igraph_bool_t multiple, + igraph_int_t ecount_estimate) { igraph_vector_int_t edges; int iter = 0; @@ -1035,9 +1540,8 @@ static igraph_error_t gnp_bipartite_large( IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, 2*ecount_estimate)); - RNG_BEGIN(); - for (igraph_integer_t i = 0; i < n1; i++) { - igraph_integer_t j = 0; + for (igraph_int_t i = 0; i < n1; i++) { + igraph_int_t j = 0; while (true) { igraph_real_t gap = RNG_GEOM(p); @@ -1068,12 +1572,11 @@ static igraph_error_t gnp_bipartite_large( IGRAPH_CHECK(igraph_vector_int_push_back(&edges, i)); } - j++; + j += ! multiple; /* 1 for simple graph, 0 for multigraph */ IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); } } - RNG_END(); /* n1 + n2 has already been checked for overflow in the caller function. */ IGRAPH_CHECK(igraph_create(graph, &edges, n1 + n2, directed)); @@ -1090,7 +1593,11 @@ static igraph_error_t gnp_bipartite_large( * * In the G(n1, n2, p) model, every possible edge between the \p n1 * bottom vertices and \p n2 top vertices is realized independently with - * probability \p p. + * probability \p p. This is equivalent to a maximum entropy model with + * a constraint on the \em expected total edge count. This view allows + * a multigraph extension, in which case \p is interpreted as the expected + * number of edges between any vertex pair. See \ref igraph_erdos_renyi_game_gnp() + * for more details. * * \param graph Pointer to an uninitialized igraph graph, the result * is stored here. @@ -1100,9 +1607,11 @@ static igraph_error_t gnp_bipartite_large( * vertices. * \param n1 The number of bottom vertices. * \param n2 The number of top vertices. - * \param p The connection probability. - * \param directed Boolean, whether to generate a directed graph. See - * also the \p mode argument. + * \param p The expected number of edges between any vertex pair. + * When multi-edges are disallowed, this is equivalent to the probability + * of having a connection between any two vertices. + * \param directed Whether to generate a directed graph. See also + * the \p mode argument. * \param mode Specifies how to direct the edges in directed * graphs. If it is \c IGRAPH_OUT, then directed edges point from * bottom vertices to top vertices. If it is \c IGRAPH_IN, edges @@ -1111,6 +1620,18 @@ static igraph_error_t gnp_bipartite_large( * \c IGRAPH_ALL, then each edge direction is considered * independently and mutual edges might be generated. This * argument is ignored for undirected graphs. +* \param allowed_edge_types The types of edges to allow in the graph. + * \clist + * \cli IGRAPH_SIMPLE_SW + * simple graph (i.e. no multi-edges allowed). + * \cli IGRAPH_MULTI_SW + * multi-edges are allowed + * \endclist + * \param edge_labeled If true, the model is defined over the set of ordered + * edge lists, i.e. over the set of edge-labeled graphs. Set it to + * \c false to select the classic bipartite Erdős-Rényi model. + * The constants \c IGRAPH_EDGE_UNLABELED and \c IGRAPH_EDGE_LABELED + * may be used instead of \c false and \c true for better readability. * \return Error code. * * \sa \ref igraph_erdos_renyi_game_gnp() for the unipartite version, @@ -1120,23 +1641,45 @@ static igraph_error_t gnp_bipartite_large( * edges. */ -igraph_error_t igraph_bipartite_game_gnp(igraph_t *graph, igraph_vector_bool_t *types, - igraph_integer_t n1, igraph_integer_t n2, - igraph_real_t p, igraph_bool_t directed, - igraph_neimode_t mode) { +igraph_error_t igraph_bipartite_game_gnp( + igraph_t *graph, + igraph_vector_bool_t *types, + igraph_int_t n1, igraph_int_t n2, igraph_real_t p, + igraph_bool_t directed, igraph_neimode_t mode, + igraph_edge_type_sw_t allowed_edge_types, + igraph_bool_t edge_labeled) { igraph_vector_int_t edges; igraph_vector_t s; - igraph_integer_t n; + igraph_int_t n; igraph_real_t n1_real = (igraph_real_t) n1, n2_real = (igraph_real_t) n2; /* for floating-point operations */ + igraph_bool_t loops, multiple; int iter = 0; if (n1 < 0 || n2 < 0) { - IGRAPH_ERROR("Invalid number of vertices for bipartite graph.", IGRAPH_EINVAL); + IGRAPH_ERROR("Invalid number of vertices for bipartite G(n,p) model.", IGRAPH_EINVAL); } - if (p < 0.0 || p > 1.0) { - IGRAPH_ERROR("Invalid connection probability.", IGRAPH_EINVAL); + /* Bipartite graphs cannot have self-loops. We ignore them. */ + IGRAPH_CHECK(igraph_i_edge_type_to_loops_multiple(allowed_edge_types, &loops, &multiple)); + + if (multiple) { + if (p < 0.0) { + IGRAPH_ERROR( + "Invalid expected edge multiplicity given for " + "bipartite G(n,p) multigraph model.", + IGRAPH_EINVAL); + } + } else { + if (p < 0.0 || p > 1.0) { + IGRAPH_ERROR( + "Invalid connection probability given for bipartite G(n,p) model.", + IGRAPH_EINVAL); + } + } + + if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) { + IGRAPH_ERROR("Invalid mode for bipartite G(n,p) model.", IGRAPH_EINVAL); } IGRAPH_SAFE_ADD(n1, n2, &n); @@ -1144,20 +1687,31 @@ igraph_error_t igraph_bipartite_game_gnp(igraph_t *graph, igraph_vector_bool_t * if (types) { IGRAPH_CHECK(igraph_vector_bool_resize(types, n)); igraph_vector_bool_null(types); - for (igraph_integer_t i = n1; i < n; i++) { + for (igraph_int_t i = n1; i < n; i++) { VECTOR(*types)[i] = true; } } + if (edge_labeled) { + return bipartite_gnp_edge_labeled(graph, n1, n2, p, directed, mode, multiple); + } + + if (multiple) { + /* Convert the expected edge count to the appropriate probability parameter + * of the geometric distribution when sampling lengths of runs of 0s in the + * adjacency matrix. */ + p = p / (1 + p); + } + if (p == 0 || n1 == 0 || n2 == 0) { IGRAPH_CHECK(igraph_empty(graph, n, directed)); } else if (p == 1.0) { IGRAPH_CHECK(igraph_full_bipartite(graph, types, n1, n2, directed, mode)); } else { - igraph_integer_t to, from, slen; + igraph_int_t to, from, slen; igraph_real_t maxedges, last; - igraph_integer_t ecount_estimate; + igraph_int_t ecount_estimate; if (!directed || mode != IGRAPH_ALL) { maxedges = n1_real * n2_real; @@ -1169,29 +1723,25 @@ igraph_error_t igraph_bipartite_game_gnp(igraph_t *graph, igraph_vector_bool_t * if (maxedges > IGRAPH_MAX_EXACT_REAL) { /* Use a slightly slower, but overflow-free implementation. */ - return gnp_bipartite_large(graph, n1, n2, p, directed, mode, ecount_estimate); + return gnp_bipartite_large(graph, n1, n2, p, directed, mode, multiple, ecount_estimate); } IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INIT_FINALLY(&s, 0); IGRAPH_CHECK(igraph_vector_reserve(&s, ecount_estimate)); - RNG_BEGIN(); - last = RNG_GEOM(p); while (last < maxedges) { IGRAPH_CHECK(igraph_vector_push_back(&s, last)); last += RNG_GEOM(p); - last += 1; + last += ! multiple; /* 1 for simple graph, 0 for multigraph */ IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); } - RNG_END(); - slen = igraph_vector_size(&s); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, slen * 2)); - for (igraph_integer_t i = 0; i < slen; i++) { + for (igraph_int_t i = 0; i < slen; i++) { if (!directed || mode != IGRAPH_ALL) { to = trunc(VECTOR(s)[i] / n1_real); from = VECTOR(s)[i] - to * n1_real; @@ -1230,201 +1780,3 @@ igraph_error_t igraph_bipartite_game_gnp(igraph_t *graph, igraph_vector_bool_t * return IGRAPH_SUCCESS; } - -/** - * \function igraph_bipartite_game_gnm - * \brief Generate a random bipartite graph with a fixed number of edges. - * - * The G(n1, n2, m) model uniformly samples bipartite graphs with - * \p n1 bottom vertices and \p n2 top vertices, and precisely \p m edges. - * - * \param graph Pointer to an uninitialized igraph graph, the result - * is stored here. - * \param types Pointer to an initialized boolean vector, or a null - * pointer. If not a null pointer, then the vertex types are stored - * here. Bottom vertices come first, \p n1 of them, then \p n2 top - * vertices. - * \param n1 The number of bottom vertices. - * \param n2 The number of top vertices. - * \param m The number of edges. - * \param directed Boolean, whether to generate a directed graph. See - * also the \p mode argument. - * \param mode Specifies how to direct the edges in directed - * graphs. If it is \c IGRAPH_OUT, then directed edges point from - * bottom vertices to top vertices. If it is \c IGRAPH_IN, edges - * point from top vertices to bottom vertices. \c IGRAPH_OUT and - * \c IGRAPH_IN do not generate mutual edges. If this argument is - * \c IGRAPH_ALL, then each edge direction is considered - * independently and mutual edges might be generated. This - * argument is ignored for undirected graphs. - * \return Error code. - * - * \sa \ref igraph_erdos_renyi_game_gnm() for the unipartite version, - * \ref igraph_bipartite_game_gnp() for the G(n1, n2, p) - * model. - * - * Time complexity: O(|V|+|E|), linear in the number of vertices and - * edges. - */ - -igraph_error_t igraph_bipartite_game_gnm(igraph_t *graph, igraph_vector_bool_t *types, - igraph_integer_t n1, igraph_integer_t n2, - igraph_integer_t m, igraph_bool_t directed, - igraph_neimode_t mode) { - igraph_vector_int_t edges; - igraph_vector_t s; - igraph_integer_t n; - igraph_real_t n1_real = (igraph_real_t) n1, n2_real = (igraph_real_t) n2; /* for floating-point operations */ - int iter = 0; - - if (n1 < 0 || n2 < 0) { - IGRAPH_ERROR("Invalid number of vertices for bipartite graph.", IGRAPH_EINVAL); - } - if (m < 0 || m > IGRAPH_ECOUNT_MAX) { - IGRAPH_ERROR("Invalid number of edges.", IGRAPH_EINVAL); - } - - IGRAPH_SAFE_ADD(n1, n2, &n); - - if (types) { - igraph_integer_t i; - IGRAPH_CHECK(igraph_vector_bool_resize(types, n)); - igraph_vector_bool_null(types); - for (i = n1; i < n; i++) { - VECTOR(*types)[i] = true; - } - } - - if (m == 0 || n1 == 0 || n2 == 0) { - if (m > 0) { - IGRAPH_ERROR("Too many edges requested compared to the number of vertices.", IGRAPH_EINVAL); - } - IGRAPH_CHECK(igraph_empty(graph, n, directed)); - } else { - igraph_integer_t i; - igraph_real_t maxedges; - - if (!directed || mode != IGRAPH_ALL) { - maxedges = n1_real * n2_real; - } else { - maxedges = 2.0 * n1_real * n2_real; - } - - if (m > maxedges) { - IGRAPH_ERROR("Too many edges requested compared to the number of vertices.", IGRAPH_EINVAL); - } - - if (maxedges == m) { - IGRAPH_CHECK(igraph_full_bipartite(graph, types, n1, n2, directed, mode)); - } else { - - igraph_integer_t to, from; - - IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - IGRAPH_VECTOR_INIT_FINALLY(&s, 0); - IGRAPH_CHECK(igraph_random_sample_real(&s, 0, maxedges - 1, m)); - IGRAPH_CHECK(igraph_vector_int_reserve(&edges, m * 2)); - - for (i = 0; i < m; i++) { - if (!directed || mode != IGRAPH_ALL) { - to = floor(VECTOR(s)[i] / n1_real); - from = VECTOR(s)[i] - to * n1_real; - to += n1; - } else { - igraph_real_t n1n2 = n1_real * n2_real; - if (VECTOR(s)[i] < n1n2) { - to = floor(VECTOR(s)[i] / n1_real); - from = VECTOR(s)[i] - to * n1_real; - to += n1; - } else { - to = floor((VECTOR(s)[i] - n1n2) / n2_real); - from = VECTOR(s)[i] - n1n2 - to * n2_real; - from += n1; - } - } - - if (mode != IGRAPH_IN) { - igraph_vector_int_push_back(&edges, from); /* reserved */ - igraph_vector_int_push_back(&edges, to); /* reserved */ - } else { - igraph_vector_int_push_back(&edges, to); /* reserved */ - igraph_vector_int_push_back(&edges, from); /* reserved */ - } - - IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14); - } - - igraph_vector_destroy(&s); - IGRAPH_FINALLY_CLEAN(1); - IGRAPH_CHECK(igraph_create(graph, &edges, n, directed)); - igraph_vector_int_destroy(&edges); - IGRAPH_FINALLY_CLEAN(1); - } - } - - return IGRAPH_SUCCESS; -} - -/** - * \function igraph_bipartite_game - * \brief Generate a bipartite random graph (similar to Erdős-Rényi). - * - * This function is deprecated; use \ref igraph_bipartite_game_gnm() or - * \ref igraph_bipartite_game_gnp() instead. - * - * \param graph Pointer to an uninitialized igraph graph, the result - * is stored here. - * \param types Pointer to an initialized boolean vector, or a null - * pointer. If not a null pointer, then the vertex types are stored - * here. Bottom vertices come first, n1 of them, then n2 top - * vertices. - * \param type The type of the random graph, possible values: - * \clist - * \cli IGRAPH_ERDOS_RENYI_GNM - * G(n,m) graph, - * m edges are - * selected uniformly randomly in a graph with - * n vertices. - * \cli IGRAPH_ERDOS_RENYI_GNP - * G(n,p) graph, - * every possible edge is included in the graph with - * probability p. - * \endclist - * \param n1 The number of bottom vertices. - * \param n2 The number of top vertices. - * \param p The connection probability for G(n,p) graphs. It is - * ignored for G(n,m) graphs. - * \param m The number of edges for G(n,m) graphs. It is ignored for - * G(n,p) graphs. - * \param directed Boolean, whether to generate a directed graph. See - * also the \p mode argument. - * \param mode Specifies how to direct the edges in directed - * graphs. If it is \c IGRAPH_OUT, then directed edges point from - * bottom vertices to top vertices. If it is \c IGRAPH_IN, edges - * point from top vertices to bottom vertices. \c IGRAPH_OUT and - * \c IGRAPH_IN do not generate mutual edges. If this argument is - * \c IGRAPH_ALL, then each edge direction is considered - * independently and mutual edges might be generated. This - * argument is ignored for undirected graphs. - * \return Error code. - * - * \sa \ref igraph_bipartite_game_gnm(), \ref igraph_bipartite_game_gnp(). - * - * Time complexity: O(|V|+|E|), linear in the number of vertices and - * edges. - */ - -igraph_error_t igraph_bipartite_game(igraph_t *graph, igraph_vector_bool_t *types, - igraph_erdos_renyi_t type, - igraph_integer_t n1, igraph_integer_t n2, - igraph_real_t p, igraph_integer_t m, - igraph_bool_t directed, igraph_neimode_t mode) { - - if (type == IGRAPH_ERDOS_RENYI_GNP) { - return igraph_bipartite_game_gnp(graph, types, n1, n2, p, directed, mode); - } else if (type == IGRAPH_ERDOS_RENYI_GNM) { - return igraph_bipartite_game_gnm(graph, types, n1, n2, m, directed, mode); - } else { - IGRAPH_ERROR("Invalid bipartite game type.", IGRAPH_EINVAL); - } -} diff --git a/src/vendor/cigraph/src/misc/chordality.c b/src/vendor/cigraph/src/misc/chordality.c index 85056b7566a..ff90cb7aec8 100644 --- a/src/vendor/cigraph/src/misc/chordality.c +++ b/src/vendor/cigraph/src/misc/chordality.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2008-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -69,17 +68,17 @@ igraph_error_t igraph_maximum_cardinality_search(const igraph_t *graph, igraph_vector_int_t *alpha, igraph_vector_int_t *alpham1) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t size; igraph_vector_int_t head, next, prev; /* doubly linked list with head */ - igraph_integer_t i; + igraph_int_t i; igraph_adjlist_t adjlist; /***************/ /* local j, v; */ /***************/ - igraph_integer_t j, v; + igraph_int_t j, v; if (no_of_nodes == 0) { igraph_vector_int_clear(alpha); @@ -131,7 +130,7 @@ igraph_error_t igraph_maximum_cardinality_search(const igraph_t *graph, /**************/ while (i >= 1) { - igraph_integer_t x, k, len; + igraph_int_t x, k, len; igraph_vector_int_t *neis; /********************************/ @@ -162,16 +161,16 @@ igraph_error_t igraph_maximum_cardinality_search(const igraph_t *graph, neis = igraph_adjlist_get(&adjlist, v); len = igraph_vector_int_size(neis); for (k = 0; k < len; k++) { - igraph_integer_t w = VECTOR(*neis)[k]; - igraph_integer_t ws = VECTOR(size)[w]; + igraph_int_t w = VECTOR(*neis)[k]; + igraph_int_t ws = VECTOR(size)[w]; if (ws >= 0) { /******************************/ /* delete w from set(size(w)) */ /******************************/ - igraph_integer_t nw = VECTOR(next)[w]; - igraph_integer_t pw = VECTOR(prev)[w]; + igraph_int_t nw = VECTOR(next)[w]; + igraph_int_t pw = VECTOR(prev)[w]; if (nw != 0) { VECTOR(prev)[nw - 1] = pw; } @@ -279,11 +278,11 @@ igraph_error_t igraph_is_chordal(const igraph_t *graph, igraph_vector_int_t *fill_in, igraph_t *newgraph) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); const igraph_vector_int_t *my_alpha = alpha, *my_alpham1 = alpham1; igraph_vector_int_t v_alpha, v_alpham1; igraph_vector_int_t f, index; - igraph_integer_t i; + igraph_int_t i; igraph_adjlist_t adjlist; igraph_vector_int_t mark; igraph_bool_t calc_edges = fill_in || newgraph; @@ -293,7 +292,7 @@ igraph_error_t igraph_is_chordal(const igraph_t *graph, /* local v, w, x */ /*****************/ - igraph_integer_t v, w, x; + igraph_int_t v, w, x; if (alpha && (igraph_vector_int_size(alpha) != no_of_nodes)) { IGRAPH_ERRORF("Alpha vector size (%" IGRAPH_PRId ") not equal to number of nodes (%" IGRAPH_PRId ").", @@ -321,15 +320,15 @@ igraph_error_t igraph_is_chordal(const igraph_t *graph, } else if (alpha && !alpham1) { IGRAPH_VECTOR_INT_INIT_FINALLY(&v_alpham1, no_of_nodes); my_alpham1 = &v_alpham1; - for (igraph_integer_t v = 0; v < no_of_nodes; v++) { - igraph_integer_t i = VECTOR(*my_alpha)[v]; + for (igraph_int_t v = 0; v < no_of_nodes; v++) { + igraph_int_t i = VECTOR(*my_alpha)[v]; VECTOR(*my_alpham1)[i] = v; } } else if (!alpha && alpham1) { IGRAPH_VECTOR_INT_INIT_FINALLY(&v_alpha, no_of_nodes); my_alpha = &v_alpha; - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t v = VECTOR(*my_alpham1)[i]; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t v = VECTOR(*my_alpham1)[i]; VECTOR(*my_alpha)[v] = i; } } @@ -358,7 +357,7 @@ igraph_error_t igraph_is_chordal(const igraph_t *graph, for (i = 0; i < no_of_nodes; i++) { igraph_vector_int_t *neis; - igraph_integer_t j, len; + igraph_int_t j, len; /**********************************************/ /* w := alpham1(i); f(w) := w; index(w) := i; */ diff --git a/src/vendor/cigraph/src/misc/cocitation.c b/src/vendor/cigraph/src/misc/cocitation.c index 9657162ec58..9eb4586ab9e 100644 --- a/src/vendor/cigraph/src/misc/cocitation.c +++ b/src/vendor/cigraph/src/misc/cocitation.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2005-2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -170,7 +170,7 @@ igraph_error_t igraph_similarity_inverse_log_weighted(const igraph_t *graph, igraph_vector_t weights; igraph_vector_int_t degrees; igraph_neimode_t mode0 = IGRAPH_REVERSE_MODE(mode); - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) { IGRAPH_ERROR("Invalid mode for inverse log weighted similarity.", IGRAPH_EINVMODE); @@ -178,8 +178,8 @@ igraph_error_t igraph_similarity_inverse_log_weighted(const igraph_t *graph, IGRAPH_VECTOR_INIT_FINALLY(&weights, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(°rees, no_of_nodes); - IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), mode0, true)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), mode0, IGRAPH_LOOPS)); + for (igraph_int_t i = 0; i < no_of_nodes; i++) { VECTOR(weights)[i] = VECTOR(degrees)[i]; if (VECTOR(weights)[i] > 1) { VECTOR(weights)[i] = 1.0 / log(VECTOR(weights)[i]); @@ -199,9 +199,9 @@ static igraph_error_t igraph_i_cocitation_real(const igraph_t *graph, igraph_mat igraph_neimode_t mode, igraph_vector_t *weights) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_vids; - igraph_integer_t i; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_vids; + igraph_int_t i; igraph_vector_int_t neis; igraph_vector_int_t vid_reverse_index; igraph_vit_t vit; @@ -216,7 +216,7 @@ static igraph_error_t igraph_i_cocitation_real(const igraph_t *graph, igraph_mat IGRAPH_VECTOR_INT_INIT_FINALLY(&vid_reverse_index, no_of_nodes); igraph_vector_int_fill(&vid_reverse_index, -1); for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t v = IGRAPH_VIT_GET(vit); + igraph_int_t v = IGRAPH_VIT_GET(vit); if (v < 0 || v >= no_of_nodes) { IGRAPH_ERROR("Invalid vertex ID in vertex selector.", IGRAPH_EINVVID); } @@ -229,20 +229,20 @@ static igraph_error_t igraph_i_cocitation_real(const igraph_t *graph, igraph_mat /* The result */ - for (igraph_integer_t from = 0; from < no_of_nodes; from++) { + for (igraph_int_t from = 0; from < no_of_nodes; from++) { IGRAPH_ALLOW_INTERRUPTION(); const igraph_real_t weight = weights ? VECTOR(*weights)[from] : 1; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, from, mode)); - const igraph_integer_t nei_count = igraph_vector_int_size(&neis); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, from, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); + const igraph_int_t nei_count = igraph_vector_int_size(&neis); for (i = 0; i < nei_count - 1; i++) { - igraph_integer_t u = VECTOR(neis)[i]; - igraph_integer_t k = VECTOR(vid_reverse_index)[u]; - for (igraph_integer_t j = i + 1; j < nei_count; j++) { - igraph_integer_t v = VECTOR(neis)[j]; - igraph_integer_t l = VECTOR(vid_reverse_index)[v]; + igraph_int_t u = VECTOR(neis)[i]; + igraph_int_t k = VECTOR(vid_reverse_index)[u]; + for (igraph_int_t j = i + 1; j < nei_count; j++) { + igraph_int_t v = VECTOR(neis)[j]; + igraph_int_t l = VECTOR(vid_reverse_index)[v]; if (k != -1) { MATRIX(*res, k, v) += weight; } @@ -265,10 +265,10 @@ static igraph_error_t igraph_i_cocitation_real(const igraph_t *graph, igraph_mat static igraph_error_t igraph_i_neisets_intersect( const igraph_vector_int_t *v1, const igraph_vector_int_t *v2, - igraph_integer_t *len_union, igraph_integer_t *len_intersection + igraph_int_t *len_union, igraph_int_t *len_intersection ) { /* ASSERT: v1 and v2 are sorted */ - igraph_integer_t n1 = igraph_vector_int_size(v1), n2 = igraph_vector_int_size(v2); + igraph_int_t n1 = igraph_vector_int_size(v1), n2 = igraph_vector_int_size(v2); *len_intersection = igraph_vector_int_intersection_size_sorted(v1, v2); *len_union = n1 + n2 - *len_intersection; return IGRAPH_SUCCESS; @@ -287,9 +287,11 @@ static igraph_error_t igraph_i_neisets_intersect( * \param graph The graph object to analyze * \param res Pointer to a matrix, the result of the calculation will * be stored here. The number of its rows and columns is the same - * as the number of vertex IDs in \p vids. - * \param vids The vertex IDs of the vertices for which the - * calculation will be done. + * as the number of vertex IDs in \p from and \p to, respectively. + * \param from The vertex IDs of the first set of vertices of the + * pairs for which the calculation will be done. + * \param to The vertex IDs of the second set of vertices of the + * pairs for which the calculation will be done. * \param mode The type of neighbors to be used for the calculation in * directed graphs. Possible values: * \clist @@ -323,27 +325,27 @@ static igraph_error_t igraph_i_neisets_intersect( * \example examples/simple/igraph_similarity.c */ igraph_error_t igraph_similarity_jaccard(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t vids, igraph_neimode_t mode, igraph_bool_t loops) { + const igraph_vs_t from, const igraph_vs_t to, igraph_neimode_t mode, igraph_bool_t loops) { igraph_lazy_adjlist_t al; - igraph_vit_t vit, vit2; - igraph_integer_t i, j; - igraph_integer_t len_union, len_intersection; + igraph_vit_t vit_from, vit_to; + igraph_int_t i, j; + igraph_int_t len_union, len_intersection; igraph_vector_int_t *v1, *v2; - igraph_integer_t k; + igraph_int_t k; - IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); - IGRAPH_FINALLY(igraph_vit_destroy, &vit); - IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit2)); - IGRAPH_FINALLY(igraph_vit_destroy, &vit2); + IGRAPH_CHECK(igraph_vit_create(graph, from, &vit_from)); + IGRAPH_FINALLY(igraph_vit_destroy, &vit_from); + IGRAPH_CHECK(igraph_vit_create(graph, to, &vit_to)); + IGRAPH_FINALLY(igraph_vit_destroy, &vit_to); IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &al, mode, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &al); - IGRAPH_CHECK(igraph_matrix_resize(res, IGRAPH_VIT_SIZE(vit), IGRAPH_VIT_SIZE(vit))); + IGRAPH_CHECK(igraph_matrix_resize(res, IGRAPH_VIT_SIZE(vit_from), IGRAPH_VIT_SIZE(vit_to))); if (loops) { - for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) { - i = IGRAPH_VIT_GET(vit); + for (IGRAPH_VIT_RESET(vit_from); !IGRAPH_VIT_END(vit_from); IGRAPH_VIT_NEXT(vit_from)) { + i = IGRAPH_VIT_GET(vit_from); v1 = igraph_lazy_adjlist_get(&al, i); IGRAPH_CHECK_OOM(v1, "Failed to query neighbors."); if (!igraph_vector_int_binsearch(v1, i, &k)) { @@ -352,18 +354,18 @@ igraph_error_t igraph_similarity_jaccard(const igraph_t *graph, igraph_matrix_t } } - for (IGRAPH_VIT_RESET(vit), i = 0; - !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { + for (IGRAPH_VIT_RESET(vit_from), i = 0; + !IGRAPH_VIT_END(vit_from); IGRAPH_VIT_NEXT(vit_from), i++) { MATRIX(*res, i, i) = 1.0; - for (IGRAPH_VIT_RESET(vit2), j = 0; - !IGRAPH_VIT_END(vit2); IGRAPH_VIT_NEXT(vit2), j++) { + for (IGRAPH_VIT_RESET(vit_to), j = 0; + !IGRAPH_VIT_END(vit_to); IGRAPH_VIT_NEXT(vit_to), j++) { if (j <= i) { continue; } - v1 = igraph_lazy_adjlist_get(&al, IGRAPH_VIT_GET(vit)); + v1 = igraph_lazy_adjlist_get(&al, IGRAPH_VIT_GET(vit_from)); IGRAPH_CHECK_OOM(v1, "Failed to query neighbors."); - v2 = igraph_lazy_adjlist_get(&al, IGRAPH_VIT_GET(vit2)); + v2 = igraph_lazy_adjlist_get(&al, IGRAPH_VIT_GET(vit_to)); IGRAPH_CHECK_OOM(v2, "Failed to query neighbors."); IGRAPH_CHECK(igraph_i_neisets_intersect(v1, v2, &len_union, &len_intersection)); @@ -377,8 +379,8 @@ igraph_error_t igraph_similarity_jaccard(const igraph_t *graph, igraph_matrix_t } igraph_lazy_adjlist_destroy(&al); - igraph_vit_destroy(&vit); - igraph_vit_destroy(&vit2); + igraph_vit_destroy(&vit_from); + igraph_vit_destroy(&vit_to); IGRAPH_FINALLY_CLEAN(3); return IGRAPH_SUCCESS; @@ -437,13 +439,13 @@ igraph_error_t igraph_similarity_jaccard(const igraph_t *graph, igraph_matrix_t */ igraph_error_t igraph_similarity_jaccard_pairs(const igraph_t *graph, igraph_vector_t *res, const igraph_vector_int_t *pairs, igraph_neimode_t mode, igraph_bool_t loops) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_lazy_adjlist_t al; - igraph_integer_t u, v; - igraph_integer_t len_union, len_intersection; + igraph_int_t u, v; + igraph_int_t len_union, len_intersection; igraph_vector_int_t *v1, *v2; - igraph_integer_t k = igraph_vector_int_size(pairs); + igraph_int_t k = igraph_vector_int_size(pairs); if (k % 2 != 0) { IGRAPH_ERROR("Number of elements in `pairs' must be even.", IGRAPH_EINVAL); } @@ -461,8 +463,8 @@ igraph_error_t igraph_similarity_jaccard_pairs(const igraph_t *graph, igraph_vec igraph_bitset_t seen; IGRAPH_BITSET_INIT_FINALLY(&seen, no_of_nodes); - for (igraph_integer_t i = 0; i < k; i++) { - igraph_integer_t j = VECTOR(*pairs)[i]; + for (igraph_int_t i = 0; i < k; i++) { + igraph_int_t j = VECTOR(*pairs)[i]; if (IGRAPH_BIT_TEST(seen, j)) { continue; } @@ -478,7 +480,7 @@ igraph_error_t igraph_similarity_jaccard_pairs(const igraph_t *graph, igraph_vec IGRAPH_FINALLY_CLEAN(1); } - for (igraph_integer_t i = 0, j = 0; i < k; i += 2, j++) { + for (igraph_int_t i = 0, j = 0; i < k; i += 2, j++) { u = VECTOR(*pairs)[i]; v = VECTOR(*pairs)[i + 1]; @@ -563,7 +565,7 @@ igraph_error_t igraph_similarity_jaccard_es(const igraph_t *graph, igraph_vector igraph_vector_int_t pairs; IGRAPH_VECTOR_INT_INIT_FINALLY(&pairs, 0); - IGRAPH_CHECK(igraph_edges(graph, es, &pairs)); + IGRAPH_CHECK(igraph_edges(graph, es, &pairs, 0)); IGRAPH_CHECK(igraph_similarity_jaccard_pairs(graph, res, &pairs, mode, loops)); igraph_vector_int_destroy(&pairs); IGRAPH_FINALLY_CLEAN(1); @@ -583,9 +585,11 @@ igraph_error_t igraph_similarity_jaccard_es(const igraph_t *graph, igraph_vector * \param graph The graph object to analyze. * \param res Pointer to a matrix, the result of the calculation will * be stored here. The number of its rows and columns is the same - * as the number of vertex IDs in \p vids. - * \param vids The vertex IDs of the vertices for which the - * calculation will be done. + * as the number of vertex IDs in \p from and \p to, respectively. + * \param from The vertex IDs of the first vertices of the + * pairs for which the calculation will be done. + * \param to The vertex IDs of the second vertices of the + * pairs for which the calculation will be done. * \param mode The type of neighbors to be used for the calculation in * directed graphs. Possible values: * \clist @@ -619,15 +623,15 @@ igraph_error_t igraph_similarity_jaccard_es(const igraph_t *graph, igraph_vector * \example examples/simple/igraph_similarity.c */ igraph_error_t igraph_similarity_dice(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t vids, + const igraph_vs_t from, const igraph_vs_t to, igraph_neimode_t mode, igraph_bool_t loops) { - IGRAPH_CHECK(igraph_similarity_jaccard(graph, res, vids, mode, loops)); + IGRAPH_CHECK(igraph_similarity_jaccard(graph, res, from, to, mode, loops)); - igraph_integer_t nr = igraph_matrix_nrow(res); - igraph_integer_t nc = igraph_matrix_ncol(res); - for (igraph_integer_t i = 0; i < nr; i++) { - for (igraph_integer_t j = 0; j < nc; j++) { + igraph_int_t nr = igraph_matrix_nrow(res); + igraph_int_t nc = igraph_matrix_ncol(res); + for (igraph_int_t i = 0; i < nr; i++) { + for (igraph_int_t j = 0; j < nc; j++) { igraph_real_t x = MATRIX(*res, i, j); MATRIX(*res, i, j) = 2 * x / (1 + x); } @@ -690,8 +694,8 @@ igraph_error_t igraph_similarity_dice_pairs(const igraph_t *graph, igraph_vector const igraph_vector_int_t *pairs, igraph_neimode_t mode, igraph_bool_t loops) { IGRAPH_CHECK(igraph_similarity_jaccard_pairs(graph, res, pairs, mode, loops)); - igraph_integer_t n = igraph_vector_size(res); - for (igraph_integer_t i = 0; i < n; i++) { + igraph_int_t n = igraph_vector_size(res); + for (igraph_int_t i = 0; i < n; i++) { igraph_real_t x = VECTOR(*res)[i]; VECTOR(*res)[i] = 2 * x / (1 + x); } @@ -753,8 +757,8 @@ igraph_error_t igraph_similarity_dice_es(const igraph_t *graph, igraph_vector_t const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops) { IGRAPH_CHECK(igraph_similarity_jaccard_es(graph, res, es, mode, loops)); - igraph_integer_t n = igraph_vector_size(res); - for (igraph_integer_t i = 0; i < n; i++) { + igraph_int_t n = igraph_vector_size(res); + for (igraph_int_t i = 0; i < n; i++) { igraph_real_t x = VECTOR(*res)[i]; VECTOR(*res)[i] = 2 * x / (1 + x); } diff --git a/src/vendor/cigraph/src/misc/coloring.c b/src/vendor/cigraph/src/misc/coloring.c index 9594e237a8b..a4081e8d37e 100644 --- a/src/vendor/cigraph/src/misc/coloring.c +++ b/src/vendor/cigraph/src/misc/coloring.c @@ -26,13 +26,12 @@ #include "core/genheap.h" #include "core/indheap.h" #include "core/interruption.h" -#include "graph/internal.h" /* igraph_i_incident() */ /* COLORED_NEIGHBORS: Choose vertices based on the number of already coloured neighbours. */ static igraph_error_t igraph_i_vertex_coloring_greedy_cn(const igraph_t *graph, igraph_vector_int_t *colors) { - igraph_integer_t i, vertex, maxdeg; - igraph_integer_t vc = igraph_vcount(graph); + igraph_int_t i, vertex, maxdeg; + igraph_int_t vc = igraph_vcount(graph); igraph_2wheap_t cn; /* indexed heap storing number of already coloured neighbours */ igraph_vector_int_t neighbors, nei_colors; @@ -52,7 +51,7 @@ static igraph_error_t igraph_i_vertex_coloring_greedy_cn(const igraph_t *graph, igraph_vector_int_t degree; IGRAPH_VECTOR_INT_INIT_FINALLY(°ree, 0); - IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL, false)); + IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL, IGRAPH_NO_LOOPS)); vertex = igraph_vector_int_which_max(°ree); maxdeg = VECTOR(degree)[vertex]; @@ -80,15 +79,15 @@ static igraph_error_t igraph_i_vertex_coloring_greedy_cn(const igraph_t *graph, * At the beginning, all vertices are set as "uncolored", see the vector_int_fill() call above. * Colors will be decremented to start at 0 later. */ while (true) { - IGRAPH_CHECK(igraph_neighbors(graph, &neighbors, vertex, IGRAPH_ALL)); - igraph_integer_t nei_count = igraph_vector_int_size(&neighbors); + IGRAPH_CHECK(igraph_neighbors(graph, &neighbors, vertex, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); + igraph_int_t nei_count = igraph_vector_int_size(&neighbors); /* Colour current vertex by finding the smallest available non-0 color. * Note that self-loops are effectively skipped as they merely prevent * the current vertex from being colored with the color value it presently * has, which is 0 (meaning uncolored). */ { - igraph_integer_t col; + igraph_int_t col; IGRAPH_CHECK(igraph_vector_int_resize(&nei_colors, nei_count)); for (i = 0; i < nei_count; ++i) { @@ -110,7 +109,7 @@ static igraph_error_t igraph_i_vertex_coloring_greedy_cn(const igraph_t *graph, /* increment number of coloured neighbours for each neighbour of vertex */ for (i = 0; i < nei_count; ++i) { - igraph_integer_t idx = VECTOR(neighbors)[i]; + igraph_int_t idx = VECTOR(neighbors)[i]; if (igraph_2wheap_has_elem(&cn, idx)) { igraph_2wheap_modify(&cn, idx, igraph_2wheap_get(&cn, idx) + 1); } @@ -141,8 +140,8 @@ static igraph_error_t igraph_i_vertex_coloring_greedy_cn(const igraph_t *graph, /* DSATUR: Choose vertices based on the number of adjacent colours, i.e. "saturation degree" */ typedef struct { - igraph_integer_t saturation_degree; /* number of colors used by neighbors */ - igraph_integer_t edge_degree; /* degree in the subgraph induced by uncolored vertices */ + igraph_int_t saturation_degree; /* number of colors used by neighbors */ + igraph_int_t edge_degree; /* degree in the subgraph induced by uncolored vertices */ } dsatur_t; static int dsatur_t_compare(const void *left, const void *right) { @@ -161,13 +160,13 @@ static int dsatur_t_compare(const void *left, const void *right) { } static igraph_bool_t dsatur_is_color_used_by_neighbour( - const igraph_vector_int_t *colors, igraph_integer_t color, + const igraph_vector_int_t *colors, igraph_int_t color, const igraph_vector_int_t *neighbors ) { - igraph_integer_t nei_count = igraph_vector_int_size(neighbors); + igraph_int_t nei_count = igraph_vector_int_size(neighbors); - for (igraph_integer_t i=0; i < nei_count; i++) { - igraph_integer_t nei = VECTOR(*neighbors)[i]; + for (igraph_int_t i=0; i < nei_count; i++) { + igraph_int_t nei = VECTOR(*neighbors)[i]; if (VECTOR(*colors)[nei] == color) { return true; } @@ -179,12 +178,12 @@ static igraph_bool_t dsatur_is_color_used_by_neighbour( static void dsatur_update_heap( const igraph_adjlist_t *adjlist, igraph_gen2wheap_t *node_degrees_heap, const igraph_vector_int_t *neighbors, const igraph_vector_int_t *colors, - igraph_integer_t color + igraph_int_t color ) { igraph_gen2wheap_delete_max(node_degrees_heap); - igraph_integer_t nei_count = igraph_vector_int_size(neighbors); - for (igraph_integer_t i=0; i < nei_count; i++) { - igraph_integer_t nei = VECTOR(*neighbors)[i]; + igraph_int_t nei_count = igraph_vector_int_size(neighbors); + for (igraph_int_t i=0; i < nei_count; i++) { + igraph_int_t nei = VECTOR(*neighbors)[i]; if (!igraph_gen2wheap_has_elem(node_degrees_heap, nei)) { continue; } @@ -197,10 +196,10 @@ static void dsatur_update_heap( } } -static igraph_integer_t dsatur_get_first_viable_color(const igraph_vector_int_t *used_colors_sorted) { - igraph_integer_t color_count = igraph_vector_int_size(used_colors_sorted); - igraph_integer_t i = 0; - igraph_integer_t col = 0; +static igraph_int_t dsatur_get_first_viable_color(const igraph_vector_int_t *used_colors_sorted) { + igraph_int_t color_count = igraph_vector_int_size(used_colors_sorted); + igraph_int_t i = 0; + igraph_int_t col = 0; while (i < color_count && VECTOR(*used_colors_sorted)[i] == col) { while (i < color_count && VECTOR(*used_colors_sorted)[i] == col) { i++; @@ -213,7 +212,7 @@ static igraph_integer_t dsatur_get_first_viable_color(const igraph_vector_int_t static igraph_error_t igraph_i_vertex_coloring_dsatur( const igraph_t *graph, igraph_vector_int_t *colors ) { - igraph_integer_t vcount = igraph_vcount(graph); + igraph_int_t vcount = igraph_vcount(graph); IGRAPH_CHECK(igraph_vector_int_resize(colors, vcount)); if (vcount == 0) { @@ -237,7 +236,7 @@ static igraph_error_t igraph_i_vertex_coloring_dsatur( IGRAPH_CHECK(igraph_gen2wheap_init(&node_degrees_heap, dsatur_t_compare, sizeof(dsatur_t), vcount)); IGRAPH_FINALLY(igraph_gen2wheap_destroy, &node_degrees_heap); - for (igraph_integer_t vertex = 0; vertex < vcount; vertex++) { + for (igraph_int_t vertex = 0; vertex < vcount; vertex++) { dsatur_t dsatur; dsatur.saturation_degree = 0; dsatur.edge_degree = igraph_vector_int_size(igraph_adjlist_get(&adjlist, vertex)); @@ -248,18 +247,18 @@ static igraph_error_t igraph_i_vertex_coloring_dsatur( IGRAPH_VECTOR_INT_INIT_FINALLY(&used_colors_sorted, 0); while (! igraph_gen2wheap_empty(&node_degrees_heap)) { - igraph_integer_t node_to_color = igraph_gen2wheap_max_index(&node_degrees_heap); + igraph_int_t node_to_color = igraph_gen2wheap_max_index(&node_degrees_heap); igraph_vector_int_t *neighbors = igraph_adjlist_get(&adjlist, node_to_color); - igraph_integer_t nei_count = igraph_vector_int_size(neighbors); + igraph_int_t nei_count = igraph_vector_int_size(neighbors); igraph_vector_int_clear(&used_colors_sorted); - for (igraph_integer_t i=0; i < nei_count; i++) { - igraph_integer_t nei = VECTOR(*neighbors)[i]; + for (igraph_int_t i=0; i < nei_count; i++) { + igraph_int_t nei = VECTOR(*neighbors)[i]; if (VECTOR(*colors)[nei] != -1) { IGRAPH_CHECK(igraph_vector_int_push_back(&used_colors_sorted, VECTOR(*colors)[nei])); } } igraph_vector_int_sort(&used_colors_sorted); - igraph_integer_t color = dsatur_get_first_viable_color(&used_colors_sorted); + igraph_int_t color = dsatur_get_first_viable_color(&used_colors_sorted); dsatur_update_heap(&adjlist, &node_degrees_heap, neighbors, colors, color); VECTOR(*colors)[node_to_color] = color; @@ -315,8 +314,6 @@ igraph_error_t igraph_vertex_coloring_greedy(const igraph_t *graph, igraph_vecto * \function igraph_is_vertex_coloring * \brief Checks whether a vertex coloring is valid. * - * \experimental - * * This function checks whether the given vertex type/color assignment is a valid * vertex coloring, i.e., no two adjacent vertices have the same color. * Self-loops are ignored. @@ -335,8 +332,8 @@ igraph_error_t igraph_is_vertex_coloring( const igraph_vector_int_t *types, igraph_bool_t *res) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); int iter = 0; if (igraph_vector_int_size(types) != vcount) { @@ -345,9 +342,9 @@ igraph_error_t igraph_is_vertex_coloring( *res = true; - for (igraph_integer_t e = 0; e < ecount; e++) { - igraph_integer_t from = IGRAPH_FROM(graph, e); - igraph_integer_t to = IGRAPH_TO(graph, e); + for (igraph_int_t e = 0; e < ecount; e++) { + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); /* Skip self-loops */ if (from == to) { @@ -369,8 +366,6 @@ igraph_error_t igraph_is_vertex_coloring( * \function igraph_is_bipartite_coloring * \brief Checks whether a bipartite vertex coloring is valid. * - * \experimental - * * This function checks whether the given vertex type assignment is a valid * bipartite coloring, i.e., no two adjacent vertices have the same type. * Additionally, for directed graphs, it determines the mode of edge directions. @@ -396,8 +391,8 @@ igraph_error_t igraph_is_bipartite_coloring( igraph_bool_t *res, igraph_neimode_t *mode) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); int iter = 0; if (igraph_vector_bool_size(types) != vcount) { @@ -413,9 +408,9 @@ igraph_error_t igraph_is_bipartite_coloring( igraph_bool_t has_false_to_true = false; igraph_bool_t has_true_to_false = false; - for (igraph_integer_t e = 0; e < ecount; e++) { - igraph_integer_t from = IGRAPH_FROM(graph, e); - igraph_integer_t to = IGRAPH_TO(graph, e); + for (igraph_int_t e = 0; e < ecount; e++) { + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); /* Skip self-loops */ if (from == to) { @@ -461,8 +456,6 @@ igraph_error_t igraph_is_bipartite_coloring( * \function igraph_is_edge_coloring * \brief Checks whether an edge coloring is valid. * - * \experimental - * * This function checks whether the given edge color assignment is a valid * edge coloring, i.e., no two adjacent edges have the same color. * @@ -482,8 +475,8 @@ igraph_error_t igraph_is_edge_coloring( const igraph_vector_int_t *types, igraph_bool_t *res) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_vector_int_t edges, edge_colors; int iter = 0; @@ -498,16 +491,16 @@ igraph_error_t igraph_is_edge_coloring( IGRAPH_VECTOR_INT_INIT_FINALLY(&edge_colors, 0); /* For each vertex, check that all incident edges have different colors */ - for (igraph_integer_t v = 0; v < vcount; v++) { - IGRAPH_CHECK(igraph_i_incident(graph, &edges, v, IGRAPH_ALL, IGRAPH_LOOPS_ONCE)); + for (igraph_int_t v = 0; v < vcount; v++) { + IGRAPH_CHECK(igraph_incident(graph, &edges, v, IGRAPH_ALL, IGRAPH_LOOPS_ONCE)); /* Get sorted edge color list */ IGRAPH_CHECK(igraph_vector_int_index(types, &edge_colors, &edges)); igraph_vector_int_sort(&edge_colors); /* Look for consecutive duplicates in edge color list */ - igraph_integer_t edge_color_count = igraph_vector_int_size(&edge_colors); - for (igraph_integer_t i = 0; i < edge_color_count - 1; i++) { + igraph_int_t edge_color_count = igraph_vector_int_size(&edge_colors); + for (igraph_int_t i = 0; i < edge_color_count - 1; i++) { if (VECTOR(edge_colors)[i] == VECTOR(edge_colors)[i + 1]) { *res = false; goto done; diff --git a/src/vendor/cigraph/src/misc/conversion.c b/src/vendor/cigraph/src/misc/conversion.c index 74ec04d2b84..364fc8378b3 100644 --- a/src/vendor/cigraph/src/misc/conversion.c +++ b/src/vendor/cigraph/src/misc/conversion.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -95,10 +94,10 @@ igraph_error_t igraph_get_adjacency( const igraph_t *graph, igraph_matrix_t *res, igraph_get_adjacency_t type, const igraph_vector_t *weights, igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t directed = igraph_is_directed(graph); - igraph_integer_t i, from, to; + igraph_int_t i, from, to; IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, no_of_nodes)); igraph_matrix_null(res); @@ -212,11 +211,11 @@ igraph_error_t igraph_get_adjacency_sparse( const igraph_vector_t *weights, igraph_loops_t loops ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t directed = igraph_is_directed(graph); - igraph_integer_t nzmax = directed ? no_of_edges : no_of_edges * 2; - igraph_integer_t i, from, to; + igraph_int_t nzmax = directed ? no_of_edges : no_of_edges * 2; + igraph_int_t i, from, to; IGRAPH_CHECK(igraph_sparsemat_resize(res, no_of_nodes, no_of_nodes, nzmax)); @@ -302,33 +301,6 @@ igraph_error_t igraph_get_adjacency_sparse( #undef WEIGHT_OF -/** - * \function igraph_get_sparsemat - * \brief Converts an igraph graph to a sparse matrix (deprecated). - * - * If the graph is undirected, then a symmetric matrix is created. - * - * - * This function is deprecated in favour of \ref igraph_get_adjacency_sparse(), - * but does not work in an identical way. This function takes an \em uninitialized - * \c igraph_sparsemat_t while \ref igraph_get_adjacency_sparse() takes - * an already initialized one. - * - * \param graph The input graph. - * \param res Pointer to an \em uninitialized sparse matrix. The result - * will be stored here. - * \return Error code. - * - * \deprecated-by igraph_get_adjacency_sparse 0.10.0 - */ - -igraph_error_t igraph_get_sparsemat(const igraph_t *graph, igraph_sparsemat_t *res) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t nzmax = igraph_is_directed(graph) ? no_of_edges : 2*no_of_edges; - IGRAPH_CHECK(igraph_sparsemat_init(res, no_of_nodes, no_of_nodes, nzmax)); - return igraph_get_adjacency_sparse(graph, res, IGRAPH_GET_ADJACENCY_BOTH, NULL, IGRAPH_LOOPS_ONCE); -} /** * \ingroup conversion @@ -353,37 +325,7 @@ igraph_error_t igraph_get_sparsemat(const igraph_t *graph, igraph_sparsemat_t *r */ igraph_error_t igraph_get_edgelist(const igraph_t *graph, igraph_vector_int_t *res, igraph_bool_t bycol) { - - igraph_eit_t edgeit; - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t vptr = 0; - igraph_integer_t from, to; - - IGRAPH_CHECK(igraph_vector_int_resize(res, no_of_edges * 2)); - IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), - &edgeit)); - IGRAPH_FINALLY(igraph_eit_destroy, &edgeit); - - if (bycol) { - while (!IGRAPH_EIT_END(edgeit)) { - igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &from, &to); - VECTOR(*res)[vptr] = from; - VECTOR(*res)[vptr + no_of_edges] = to; - vptr++; - IGRAPH_EIT_NEXT(edgeit); - } - } else { - while (!IGRAPH_EIT_END(edgeit)) { - igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &from, &to); - VECTOR(*res)[vptr++] = from; - VECTOR(*res)[vptr++] = to; - IGRAPH_EIT_NEXT(edgeit); - } - } - - igraph_eit_destroy(&edgeit); - IGRAPH_FINALLY_CLEAN(1); - return IGRAPH_SUCCESS; + return igraph_edges(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), res, bycol); } /** @@ -419,8 +361,8 @@ igraph_error_t igraph_get_edgelist(const igraph_t *graph, igraph_vector_int_t *r igraph_error_t igraph_to_directed(igraph_t *graph, igraph_to_directed_t mode) { - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (igraph_is_directed(graph)) { return IGRAPH_SUCCESS; @@ -433,23 +375,19 @@ igraph_error_t igraph_to_directed(igraph_t *graph, { igraph_t newgraph; igraph_vector_int_t edges; - igraph_integer_t size = no_of_edges * 2; + igraph_int_t size = no_of_edges * 2; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, size); IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); if (mode == IGRAPH_TO_DIRECTED_RANDOM) { - RNG_BEGIN(); - - for (igraph_integer_t i=0; i < no_of_edges; ++i) { + for (igraph_int_t i=0; i < no_of_edges; ++i) { if (RNG_INTEGER(0,1)) { - igraph_integer_t temp = VECTOR(edges)[2*i]; + igraph_int_t temp = VECTOR(edges)[2*i]; VECTOR(edges)[2*i] = VECTOR(edges)[2*i+1]; VECTOR(edges)[2*i+1] = temp; } } - - RNG_END(); } else if (mode == IGRAPH_TO_DIRECTED_ACYCLIC) { /* Currently, the endpoints of undirected edges are ordered in the internal graph datastructure, i.e. it is always true that from < to. @@ -458,9 +396,9 @@ igraph_error_t igraph_to_directed(igraph_t *graph, the implementation of the minimal API in type_indexededgelist.c. Therefore, we order the edge endpoints anyway in the following loop: */ - for (igraph_integer_t i=0; i < no_of_edges; ++i) { + for (igraph_int_t i=0; i < no_of_edges; ++i) { if (VECTOR(edges)[2*i] > VECTOR(edges)[2*i+1]) { - igraph_integer_t temp = VECTOR(edges)[2*i]; + igraph_int_t temp = VECTOR(edges)[2*i]; VECTOR(edges)[2*i] = VECTOR(edges)[2*i+1]; VECTOR(edges)[2*i+1] = temp; } @@ -471,8 +409,7 @@ igraph_error_t igraph_to_directed(igraph_t *graph, no_of_nodes, IGRAPH_DIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); - IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); - IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, true, true, true); + IGRAPH_CHECK(igraph_i_attribute_copy(&newgraph, graph, true, true, true)); igraph_vector_int_destroy(&edges); IGRAPH_FINALLY_CLEAN(2); @@ -486,7 +423,7 @@ igraph_error_t igraph_to_directed(igraph_t *graph, igraph_t newgraph; igraph_vector_int_t edges; igraph_vector_int_t index; - igraph_integer_t size; + igraph_int_t size; IGRAPH_SAFE_MULT(no_of_edges, 4, &size); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); @@ -494,7 +431,7 @@ igraph_error_t igraph_to_directed(igraph_t *graph, IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); IGRAPH_CHECK(igraph_vector_int_resize(&edges, size)); IGRAPH_VECTOR_INT_INIT_FINALLY(&index, no_of_edges * 2); - for (igraph_integer_t i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { VECTOR(edges)[no_of_edges * 2 + i * 2] = VECTOR(edges)[i * 2 + 1]; VECTOR(edges)[no_of_edges * 2 + i * 2 + 1] = VECTOR(edges)[i * 2]; VECTOR(index)[i] = VECTOR(index)[no_of_edges + i] = i; @@ -504,8 +441,7 @@ igraph_error_t igraph_to_directed(igraph_t *graph, no_of_nodes, IGRAPH_DIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); - IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); - IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, true, true, /*edges=*/false); + IGRAPH_CHECK(igraph_i_attribute_copy(&newgraph, graph, true, true, /* edges= */ false)); IGRAPH_CHECK(igraph_i_attribute_permute_edges(graph, &newgraph, &index)); igraph_vector_int_destroy(&index); @@ -561,8 +497,8 @@ igraph_error_t igraph_to_undirected(igraph_t *graph, igraph_to_undirected_t mode, const igraph_attribute_combination_t *edge_comb) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_int_t edges; igraph_t newgraph; igraph_bool_t attr = edge_comb && igraph_has_attribute_table(); @@ -590,7 +526,7 @@ igraph_error_t igraph_to_undirected(igraph_t *graph, IGRAPH_FINALLY(igraph_eit_destroy, &eit); while (!IGRAPH_EIT_END(eit)) { - igraph_integer_t edge = IGRAPH_EIT_GET(eit); + igraph_int_t edge = IGRAPH_EIT_GET(eit); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, IGRAPH_FROM(graph, edge))); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, IGRAPH_TO(graph, edge))); IGRAPH_EIT_NEXT(eit); @@ -605,8 +541,7 @@ igraph_error_t igraph_to_undirected(igraph_t *graph, IGRAPH_UNDIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); igraph_vector_int_destroy(&edges); - IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); - IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, true, true, true); + IGRAPH_CHECK(igraph_i_attribute_copy(&newgraph, graph, true, true, true)); IGRAPH_FINALLY_CLEAN(2); igraph_destroy(graph); *graph = newgraph; @@ -614,7 +549,7 @@ igraph_error_t igraph_to_undirected(igraph_t *graph, } else if (mode == IGRAPH_TO_UNDIRECTED_COLLAPSE) { igraph_vector_int_t inadj, outadj; igraph_vector_int_t mergeinto; - igraph_integer_t actedge = 0; + igraph_int_t actedge = 0; if (attr) { IGRAPH_VECTOR_INT_INIT_FINALLY(&mergeinto, no_of_edges); @@ -624,12 +559,12 @@ igraph_error_t igraph_to_undirected(igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&inadj, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&outadj, 0); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t n_out, n_in; - igraph_integer_t p1 = -1, p2 = -1; - igraph_integer_t e1 = 0, e2 = 0, n1 = 0, n2 = 0, last; - IGRAPH_CHECK(igraph_incident(graph, &outadj, i, IGRAPH_OUT)); - IGRAPH_CHECK(igraph_incident(graph, &inadj, i, IGRAPH_IN)); + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t n_out, n_in; + igraph_int_t p1 = -1, p2 = -1; + igraph_int_t e1 = 0, e2 = 0, n1 = 0, n2 = 0, last; + IGRAPH_CHECK(igraph_incident(graph, &outadj, i, IGRAPH_OUT, IGRAPH_LOOPS)); + IGRAPH_CHECK(igraph_incident(graph, &inadj, i, IGRAPH_IN, IGRAPH_LOOPS)); n_out = igraph_vector_int_size(&outadj); n_in = igraph_vector_int_size(&inadj); @@ -703,8 +638,7 @@ igraph_error_t igraph_to_undirected(igraph_t *graph, IGRAPH_UNDIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); igraph_vector_int_destroy(&edges); - IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); - IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, true, true, /*edges*/ false); /* no edge attributes */ + IGRAPH_CHECK(igraph_i_attribute_copy(&newgraph, graph, true, true, /* edges= */ false)); if (attr) { igraph_fixed_vectorlist_t vl; @@ -728,7 +662,7 @@ igraph_error_t igraph_to_undirected(igraph_t *graph, } else if (mode == IGRAPH_TO_UNDIRECTED_MUTUAL) { igraph_vector_int_t inadj, outadj; igraph_vector_int_t mergeinto; - igraph_integer_t actedge = 0; + igraph_int_t actedge = 0; if (attr) { IGRAPH_VECTOR_INT_INIT_FINALLY(&mergeinto, no_of_edges); @@ -739,14 +673,12 @@ igraph_error_t igraph_to_undirected(igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&inadj, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&outadj, 0); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t n_out, n_in; - igraph_integer_t p1 = -1, p2 = -1; - igraph_integer_t e1 = 0, e2 = 0, n1 = 0, n2 = 0; - IGRAPH_CHECK(igraph_incident(graph, &outadj, i, - IGRAPH_OUT)); - IGRAPH_CHECK(igraph_incident(graph, &inadj, i, - IGRAPH_IN)); + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t n_out, n_in; + igraph_int_t p1 = -1, p2 = -1; + igraph_int_t e1 = 0, e2 = 0, n1 = 0, n2 = 0; + IGRAPH_CHECK(igraph_incident(graph, &outadj, i, IGRAPH_OUT, IGRAPH_LOOPS)); + IGRAPH_CHECK(igraph_incident(graph, &inadj, i, IGRAPH_IN, IGRAPH_LOOPS)); n_out = igraph_vector_int_size(&outadj); n_in = igraph_vector_int_size(&inadj); @@ -793,8 +725,7 @@ igraph_error_t igraph_to_undirected(igraph_t *graph, IGRAPH_UNDIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); igraph_vector_int_destroy(&edges); - IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); - IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, true, true, /*edges*/ false); /* no edge attributes */ + IGRAPH_CHECK(igraph_i_attribute_copy(&newgraph, graph, true, true, /* edges= */ false)); if (attr) { igraph_fixed_vectorlist_t vl; @@ -827,19 +758,29 @@ igraph_error_t igraph_to_undirected(igraph_t *graph, * \brief Stochastic adjacency matrix of a graph. * * Stochastic matrix of a graph. The stochastic matrix of a graph is - * its adjacency matrix, normalized row-wise or column-wise, such that - * the sum of each row (or column) is one. + * its adjacency matrix, normalized row-wise (or column-wise), such that + * the sum of each row (or column) is one. The row-wise normalized matrix + * is also called a \em right-stochastic and contains the transition + * probabilities of a random walk that follows edge directions in a directed + * graph. The column-wise normalized matrix is called \em left-stochastic and + * is related to random walks moving against edge directions. + * + * + * When the out-degree (or in-degree) of a vertex is zero, the corresponding + * row (or column) of the row-wise (or column-wise) normalized stochastic + * matrix will be zero. * * \param graph The input graph. * \param res Pointer to an initialized matrix, the result is stored here. * It will be resized as needed. - * \param column_wise Whether to normalize column-wise. + * \param column_wise If \c false, row-wise normalization is used. + * If \c true, column-wise normalization is used. * \param weights An optional vector containing the weight of each edge * in the graph. Supply a null pointer here to make all edges have * the same weight of 1. * \return Error code. * - * Time complexity: O(|V||V|), |V| is the number of vertices in the graph. + * Time complexity: O(|V|^2), |V| is the number of vertices in the graph. * * \sa \ref igraph_get_stochastic_sparse(), the sparse version of this * function. @@ -849,10 +790,10 @@ igraph_error_t igraph_get_stochastic( const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t column_wise, const igraph_vector_t *weights ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t directed = igraph_is_directed(graph); - igraph_integer_t i, from, to; + igraph_int_t from, to; igraph_vector_t sums; igraph_real_t sum; @@ -862,25 +803,29 @@ igraph_error_t igraph_get_stochastic( IGRAPH_VECTOR_INIT_FINALLY(&sums, no_of_nodes); if (directed) { + /* Directed */ + IGRAPH_CHECK(igraph_strength( graph, &sums, igraph_vss_all(), column_wise ? IGRAPH_IN : IGRAPH_OUT, - /* loops = */ true, weights + IGRAPH_LOOPS, weights )); - for (i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { from = IGRAPH_FROM(graph, i); to = IGRAPH_TO(graph, i); sum = VECTOR(sums)[column_wise ? to : from]; MATRIX(*res, from, to) += WEIGHT_OF(i) / sum; } } else { + /* Undirected */ + IGRAPH_CHECK(igraph_strength( graph, &sums, igraph_vss_all(), IGRAPH_ALL, - /* loops = */ true, weights + IGRAPH_LOOPS, weights )); - for (i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { from = IGRAPH_FROM(graph, i); to = IGRAPH_TO(graph, i); MATRIX(*res, from, to) += WEIGHT_OF(i) / VECTOR(sums)[column_wise ? to : from]; @@ -900,14 +845,14 @@ igraph_error_t igraph_get_stochastic( * \function igraph_get_stochastic_sparse * \brief The stochastic adjacency matrix of a graph. * - * Stochastic matrix of a graph. The stochastic matrix of a graph is - * its adjacency matrix, normalized row-wise or column-wise, such that - * the sum of each row (or column) is one. + * Stochastic matrix of a graph in sparse format. See \ref igraph_get_stochastic() + * for the information on stochastic matrices. * * \param graph The input graph. * \param res Pointer to an \em initialized sparse matrix, the * result is stored here. The matrix will be resized as needed. - * \param column_wise Whether to normalize column-wise. + * \param column_wise If \c false, row-wise normalization is used. + * If \c true, column-wise normalization is used. * \param weights An optional vector containing the weight of each edge * in the graph. Supply a null pointer here to make all edges have * the same weight of 1. @@ -926,46 +871,15 @@ igraph_error_t igraph_get_stochastic_sparse( IGRAPH_CHECK(igraph_get_adjacency_sparse(graph, res, IGRAPH_GET_ADJACENCY_BOTH, weights, IGRAPH_LOOPS_TWICE)); if (column_wise) { - IGRAPH_CHECK(igraph_sparsemat_normalize_cols(res, /* allow_zeros = */ false)); + IGRAPH_CHECK(igraph_sparsemat_normalize_cols(res, /* allow_zeros = */ true)); } else { - IGRAPH_CHECK(igraph_sparsemat_normalize_rows(res, /* allow_zeros = */ false)); + IGRAPH_CHECK(igraph_sparsemat_normalize_rows(res, /* allow_zeros = */ true)); } return IGRAPH_SUCCESS; } -/** - * \function igraph_get_stochastic_sparsemat - * \brief Stochastic adjacency matrix of a graph (deprecated). - * - * This function is deprecated in favour of \ref igraph_get_stochastic_sparse(), - * but does not work in an identical way. This function takes an \em uninitialized - * \c igraph_sparsemat_t while \ref igraph_get_stochastic_sparse() takes - * an already initialized one. - * - * \param graph The input graph. - * \param res Pointer to an \em uninitialized sparse matrix, the - * result is stored here. The matrix will be resized as needed. - * \param column_wise Whether to normalize column-wise. For undirected - * graphs this argument does not have any effect. - * \return Error code. - * - * \deprecated-by igraph_get_stochastic_sparse 0.10.0 - */ - -igraph_error_t igraph_get_stochastic_sparsemat(const igraph_t *graph, - igraph_sparsemat_t *res, - igraph_bool_t column_wise) { - - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t nzmax = igraph_is_directed(graph) ? no_of_edges : 2*no_of_edges; - IGRAPH_CHECK(igraph_sparsemat_init(res, no_of_nodes, no_of_nodes, nzmax)); - return igraph_get_stochastic_sparse(graph, res, column_wise, NULL); -} - - /** * \ingroup conversion * \function igraph_to_prufer @@ -998,11 +912,11 @@ igraph_error_t igraph_to_prufer(const igraph_t *graph, igraph_vector_int_t* pruf If u is a leaf, we remove it and add its unique neighbor to the Prüfer sequence. If the removal of u turns the neighbor into a leaf which is < u, we repeat the procedure for the new leaf and so on. */ - igraph_integer_t u; + igraph_int_t u; igraph_vector_int_t degrees; igraph_vector_int_t neighbors; - igraph_integer_t prufer_index = 0; - igraph_integer_t n = igraph_vcount(graph); + igraph_int_t prufer_index = 0; + igraph_int_t n = igraph_vcount(graph); igraph_bool_t is_tree = false; IGRAPH_CHECK(igraph_is_tree(graph, &is_tree, NULL, IGRAPH_ALL)); @@ -1022,20 +936,22 @@ igraph_error_t igraph_to_prufer(const igraph_t *graph, igraph_vector_int_t* pruf IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), IGRAPH_ALL, IGRAPH_NO_LOOPS)); for (u = 0; u < n; ++u) { - igraph_integer_t degree = VECTOR(degrees)[u]; - igraph_integer_t leaf = u; + igraph_int_t degree = VECTOR(degrees)[u]; + igraph_int_t leaf = u; while (degree == 1 && leaf <= u) { - igraph_integer_t neighbor = 0; - igraph_integer_t neighbor_count = 0; + igraph_int_t neighbor = 0; + igraph_int_t neighbor_count = 0; VECTOR(degrees)[leaf] = 0; /* mark leaf v as deleted */ - IGRAPH_CHECK(igraph_neighbors(graph, &neighbors, leaf, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neighbors, leaf, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); /* Find the unique remaining neighbor of the leaf */ neighbor_count = igraph_vector_int_size(&neighbors); - for (igraph_integer_t i = 0; i < neighbor_count; i++) { + for (igraph_int_t i = 0; i < neighbor_count; i++) { neighbor = VECTOR(neighbors)[i]; if (VECTOR(degrees)[neighbor] > 0) { break; diff --git a/src/vendor/cigraph/src/misc/degree_sequence.cpp b/src/vendor/cigraph/src/misc/degree_sequence.cpp index e273d978965..5907383d97a 100644 --- a/src/vendor/cigraph/src/misc/degree_sequence.cpp +++ b/src/vendor/cigraph/src/misc/degree_sequence.cpp @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Constructing realizations of degree sequences and bi-degree sequences. Copyright (C) 2018-2024 The igraph development team @@ -21,6 +21,7 @@ #include "core/exceptions.h" #include "math/safe_intop.h" +#include "misc/graphicality.h" #include #include @@ -29,31 +30,28 @@ #include #include -#define IGRAPH_I_MULTI_EDGES_SW 0x02 /* 010, more than one edge allowed between distinct vertices */ -#define IGRAPH_I_MULTI_LOOPS_SW 0x04 /* 100, more than one self-loop allowed on the same vertex */ - /******************************/ /***** Helper constructs ******/ /******************************/ // (vertex, degree) pair struct vd_pair { - igraph_integer_t vertex; - igraph_integer_t degree; + igraph_int_t vertex; + igraph_int_t degree; vd_pair() = default; - vd_pair(igraph_integer_t vertex, igraph_integer_t degree) : vertex(vertex), degree(degree) {} + vd_pair(igraph_int_t vertex, igraph_int_t degree) : vertex(vertex), degree(degree) {} }; // (indegree, outdegree) -typedef std::pair bidegree; +typedef std::pair bidegree; // (vertex, bidegree) pair struct vbd_pair { - igraph_integer_t vertex; + igraph_int_t vertex; bidegree degree; - vbd_pair(igraph_integer_t vertex, bidegree degree) : vertex(vertex), degree(degree) {} + vbd_pair(igraph_int_t vertex, bidegree degree) : vertex(vertex), degree(degree) {} }; // Comparison function for vertex-degree pairs. @@ -73,16 +71,16 @@ template inline bool degree_less(const T &a, const T &b) { // "Bucket Node" for nodes of the same degree struct BNode { - igraph_integer_t count = 0; + igraph_int_t count = 0; std::stack nodes; - igraph_integer_t next; // next bucket (higher degree) - igraph_integer_t prev; // prev bucket (lower degree) + igraph_int_t next; // next bucket (higher degree) + igraph_int_t prev; // prev bucket (lower degree) bool is_empty() const { return count == 0; } }; struct HavelHakimiList { - igraph_integer_t n_buckets; // no of buckets, INCLUDING sentinels + igraph_int_t n_buckets; // no of buckets, INCLUDING sentinels std::vector buckets; // Given degree sequence, sets up linked list of BNodes (degree buckets) @@ -91,8 +89,8 @@ struct HavelHakimiList { explicit HavelHakimiList(const igraph_vector_int_t *degseq) : n_buckets(igraph_vector_int_size(degseq)+1), buckets(n_buckets) { - igraph_integer_t n_nodes = igraph_vector_int_size(degseq); - for (igraph_integer_t i = 0; i <= n_nodes; i++) { + igraph_int_t n_nodes = igraph_vector_int_size(degseq); + for (igraph_int_t i = 0; i <= n_nodes; i++) { if (i == 0) { buckets[i].prev = -1; } else { @@ -106,8 +104,8 @@ struct HavelHakimiList { } } - for (igraph_integer_t i = 0; i < n_nodes; i++) { - igraph_integer_t degree = VECTOR(*degseq)[i]; + for (igraph_int_t i = 0; i < n_nodes; i++) { + igraph_int_t degree = VECTOR(*degseq)[i]; buckets[degree].nodes.push(vd_pair{i, degree}); buckets[degree].count++; } @@ -119,9 +117,9 @@ struct HavelHakimiList { // gets the largest non-empty bucket below 'degree', // or 0 if one does not exist - igraph_integer_t get_prev(igraph_integer_t degree) { + igraph_int_t get_prev(igraph_int_t degree) { assert(0 < degree && degree <= n_buckets - 1); // upper sentinel allowed as input - igraph_integer_t curr = buckets[degree].prev; + igraph_int_t curr = buckets[degree].prev; while (curr > 0 && buckets[curr].is_empty()) { remove_bucket(curr); curr = buckets[degree].prev; @@ -131,7 +129,7 @@ struct HavelHakimiList { // returns max degree non-empty bucket, // or 0 (sentinel) if all buckets are empty - igraph_integer_t get_max_bucket() { + igraph_int_t get_max_bucket() { // TODO: either change get_prev to take a BNode, or change // head()/tail() to return integers return get_prev(n_buckets - 1); @@ -139,8 +137,8 @@ struct HavelHakimiList { // returns min degree non-empty bucket, // or n_buckets - 1 (sentinel) if all buckets are empty - igraph_integer_t get_min_bucket() { - igraph_integer_t curr = head().next; + igraph_int_t get_min_bucket() { + igraph_int_t curr = head().next; while (curr < n_buckets - 1 && buckets[curr].is_empty()) { remove_bucket(curr); curr = head().next; @@ -148,12 +146,12 @@ struct HavelHakimiList { return curr; } - void remove_bucket(igraph_integer_t degree) { + void remove_bucket(igraph_int_t degree) { // bounds check and prevent accidental removal of sentinels assert(0 < degree && degree < n_buckets - 1); - igraph_integer_t &prev_idx = buckets[degree].prev; - igraph_integer_t &next_idx = buckets[degree].next; + igraph_int_t &prev_idx = buckets[degree].prev; + igraph_int_t &next_idx = buckets[degree].next; if (prev_idx != -1) buckets[prev_idx].next = next_idx; if (next_idx != -1) buckets[next_idx].prev = prev_idx; @@ -161,11 +159,11 @@ struct HavelHakimiList { next_idx = -1; } - void insert_bucket(igraph_integer_t degree) { + void insert_bucket(igraph_int_t degree) { assert(0 <= degree && degree < n_buckets - 1); // can insert into zero-degree bucket - igraph_integer_t &prev_idx = buckets[degree].prev; - igraph_integer_t &next_idx = buckets[degree].next; + igraph_int_t &prev_idx = buckets[degree].prev; + igraph_int_t &next_idx = buckets[degree].next; if (prev_idx == -1 && next_idx == -1) { next_idx = degree + 1; @@ -183,7 +181,7 @@ struct HavelHakimiList { } bool get_max_node(vd_pair &max_node) { - igraph_integer_t max_bucket = get_max_bucket(); + igraph_int_t max_bucket = get_max_bucket(); if (max_bucket <= 0) { return false; } @@ -192,14 +190,14 @@ struct HavelHakimiList { } void remove_max_node() { - igraph_integer_t max_bucket = get_max_bucket(); + igraph_int_t max_bucket = get_max_bucket(); if (max_bucket <= 0) return; buckets[max_bucket].nodes.pop(); buckets[max_bucket].count--; } bool get_min_node(vd_pair &min_node) { - igraph_integer_t min_bucket = get_min_bucket(); + igraph_int_t min_bucket = get_min_bucket(); if (min_bucket >= n_buckets - 1) { return false; } @@ -208,7 +206,7 @@ struct HavelHakimiList { } void remove_min_node() { - igraph_integer_t min_bucket = get_min_bucket(); + igraph_int_t min_bucket = get_min_bucket(); if (min_bucket >= n_buckets - 1) return; buckets[min_bucket].nodes.pop(); buckets[min_bucket].count--; @@ -216,11 +214,11 @@ struct HavelHakimiList { // Given degree of selected "hub" node, returns degree many "spoke" nodes to connect to // amortized O(alpha(n)) - igraph_error_t get_spokes(igraph_integer_t degree, const igraph_vector_int_t &seq, + igraph_error_t get_spokes(igraph_int_t degree, const igraph_vector_int_t &seq, igraph_vector_int_t &spokes) { - std::stack buckets_req; // stack of needed degree buckets - igraph_integer_t num_nodes = 0; - igraph_integer_t curr = get_max_bucket(); // starts with max_bucket + std::stack buckets_req; // stack of needed degree buckets + igraph_int_t num_nodes = 0; + igraph_int_t curr = get_max_bucket(); // starts with max_bucket igraph_vector_int_clear(&spokes); IGRAPH_CHECK(igraph_vector_int_reserve(&spokes, degree)); @@ -234,12 +232,12 @@ struct HavelHakimiList { IGRAPH_ERROR("The given degree sequence cannot be realized as a simple graph.", IGRAPH_EINVAL); } - igraph_integer_t num_skip = num_nodes - degree; + igraph_int_t num_skip = num_nodes - degree; while (!buckets_req.empty()) { // starting from the smallest degree - igraph_integer_t bucket = buckets_req.top(); + igraph_int_t bucket = buckets_req.top(); buckets_req.pop(); - igraph_integer_t to_get = buckets[bucket].count - num_skip; + igraph_int_t to_get = buckets[bucket].count - num_skip; while (to_get > 0) { vd_pair node = buckets[bucket].nodes.top(); if (VECTOR(seq)[node.vertex] != 0) { // if "not marked for removal" @@ -320,15 +318,15 @@ struct HavelHakimiList { static igraph_error_t igraph_i_havel_hakimi(const igraph_vector_int_t *degseq, igraph_vector_int_t *edges, igraph_realize_degseq_t method) { - igraph_integer_t n_nodes = igraph_vector_int_size(degseq); + igraph_int_t n_nodes = igraph_vector_int_size(degseq); // ----- upfront error/graphicality checks ----- // if (n_nodes == 0 || (n_nodes == 1 && VECTOR(*degseq)[0] == 0)) { return IGRAPH_SUCCESS; } - for (igraph_integer_t i = 0; i < n_nodes; i++) { - igraph_integer_t deg = VECTOR(*degseq)[i]; + for (igraph_int_t i = 0; i < n_nodes; i++) { + igraph_int_t deg = VECTOR(*degseq)[i]; if (deg >= n_nodes) { IGRAPH_ERROR("The given degree sequence cannot be realized as a simple graph.", IGRAPH_EINVAL); } @@ -343,11 +341,11 @@ static igraph_error_t igraph_i_havel_hakimi(const igraph_vector_int_t *degseq, HavelHakimiList vault(&seq); - igraph_integer_t n_edges_added = 0; + igraph_int_t n_edges_added = 0; igraph_vector_int_t spokes; IGRAPH_VECTOR_INT_INIT_FINALLY(&spokes, 0); - for (igraph_integer_t i = 0; i < n_nodes; i++) { + for (igraph_int_t i = 0; i < n_nodes; i++) { // hub node selection vd_pair hub; if (method == IGRAPH_REALIZE_DEGSEQ_SMALLEST) { @@ -359,7 +357,7 @@ static igraph_error_t igraph_i_havel_hakimi(const igraph_vector_int_t *degseq, vault.remove_max_node(); } else if (method == IGRAPH_REALIZE_DEGSEQ_INDEX) { - igraph_integer_t degree = VECTOR(seq)[i]; + igraph_int_t degree = VECTOR(seq)[i]; hub = vd_pair{i, degree}; vault.buckets[degree].count--; } else { @@ -372,9 +370,9 @@ static igraph_error_t igraph_i_havel_hakimi(const igraph_vector_int_t *degseq, // spoke nodes selection IGRAPH_CHECK(vault.get_spokes(hub.degree, seq, spokes)); - igraph_integer_t n_spokes = igraph_vector_int_size(&spokes); - for (igraph_integer_t j = 0; j < n_spokes; j++) { - igraph_integer_t spoke_idx = VECTOR(spokes)[j]; + igraph_int_t n_spokes = igraph_vector_int_size(&spokes); + for (igraph_int_t j = 0; j < n_spokes; j++) { + igraph_int_t spoke_idx = VECTOR(spokes)[j]; VECTOR(*edges)[2*n_edges_added] = hub.vertex; VECTOR(*edges)[2*n_edges_added + 1] = spoke_idx; n_edges_added++; @@ -421,7 +419,7 @@ static void bubble_up(It first, It last, Compare comp) { // graph will be connected. // O(V * E + V log V) static igraph_error_t igraph_i_realize_undirected_multi(const igraph_vector_int_t *deg, igraph_vector_int_t *edges, bool loops, bool largest) { - igraph_integer_t vcount = igraph_vector_int_size(deg); + igraph_int_t vcount = igraph_vector_int_size(deg); if (vcount == 0) { return IGRAPH_SUCCESS; @@ -429,8 +427,8 @@ static igraph_error_t igraph_i_realize_undirected_multi(const igraph_vector_int_ std::vector vertices; vertices.reserve(vcount); - for (igraph_integer_t i = 0; i < vcount; ++i) { - igraph_integer_t d = VECTOR(*deg)[i]; + for (igraph_int_t i = 0; i < vcount; ++i) { + igraph_int_t d = VECTOR(*deg)[i]; vertices.push_back(vd_pair(i, d)); } @@ -438,7 +436,7 @@ static igraph_error_t igraph_i_realize_undirected_multi(const igraph_vector_int_ // O (V log V) std::stable_sort(vertices.begin(), vertices.end(), degree_greater); - igraph_integer_t ec = 0; + igraph_int_t ec = 0; while (! vertices.empty()) { // Remove any zero degrees, and error on negative ones. @@ -454,7 +452,7 @@ static igraph_error_t igraph_i_realize_undirected_multi(const igraph_vector_int_ // or throw an error, depending on the 'loops' setting. if (vertices.size() == 1) { if (loops) { - for (igraph_integer_t i = 0; i < w.degree / 2; ++i) { + for (igraph_int_t i = 0; i < w.degree / 2; ++i) { VECTOR(*edges)[2 * ec] = w.vertex; VECTOR(*edges)[2 * ec + 1] = w.vertex; ec++; @@ -497,7 +495,7 @@ static igraph_error_t igraph_i_realize_undirected_multi(const igraph_vector_int_ // O(V * E + V log V) static igraph_error_t igraph_i_realize_undirected_multi_index(const igraph_vector_int_t *deg, igraph_vector_int_t *edges, bool loops) { - igraph_integer_t vcount = igraph_vector_int_size(deg); + igraph_int_t vcount = igraph_vector_int_size(deg); if (vcount == 0) { return IGRAPH_SUCCESS; @@ -505,7 +503,7 @@ static igraph_error_t igraph_i_realize_undirected_multi_index(const igraph_vecto typedef std::list vlist; vlist vertices; - for (igraph_integer_t i = 0; i < vcount; ++i) { + for (igraph_int_t i = 0; i < vcount; ++i) { vertices.push_back(vd_pair(i, VECTOR(*deg)[i])); } @@ -518,7 +516,7 @@ static igraph_error_t igraph_i_realize_undirected_multi_index(const igraph_vecto // Initial sort vertices.sort(degree_greater); - igraph_integer_t ec = 0; + igraph_int_t ec = 0; for (const auto &pt : pointers) { vd_pair vd = *pt; vertices.erase(pt); @@ -529,7 +527,7 @@ static igraph_error_t igraph_i_realize_undirected_multi_index(const igraph_vecto if (vertices.empty() || uit->degree == 0) { // We are out of non-zero degree vertices to connect to. if (loops) { - for (igraph_integer_t i = 0; i < vd.degree / 2; ++i) { + for (igraph_int_t i = 0; i < vd.degree / 2; ++i) { VECTOR(*edges)[2 * ec] = vd.vertex; VECTOR(*edges)[2 * ec + 1] = vd.vertex; ec++; @@ -581,13 +579,13 @@ inline bool is_nonzero_outdeg(const vbd_pair &vd) { // otherwise choose the "largest" (based on lexicographic bi-degree ordering). // O(E + V^2 log V) static igraph_error_t igraph_i_kleitman_wang(const igraph_vector_int_t *outdeg, const igraph_vector_int_t *indeg, igraph_vector_int_t *edges, bool smallest) { - igraph_integer_t n = igraph_vector_int_size(indeg); // number of vertices + igraph_int_t n = igraph_vector_int_size(indeg); // number of vertices - igraph_integer_t ec = 0; // number of edges added so far + igraph_int_t ec = 0; // number of edges added so far std::vector vertices; vertices.reserve(n); - for (igraph_integer_t i = 0; i < n; ++i) { + for (igraph_int_t i = 0; i < n; ++i) { vertices.push_back(vbd_pair(i, bidegree(VECTOR(*indeg)[i], VECTOR(*outdeg)[i]))); } @@ -619,12 +617,12 @@ static igraph_error_t igraph_i_kleitman_wang(const igraph_vector_int_t *outdeg, } // are there a sufficient number of other vertices to connect to? - if (static_cast(vertices.size()) - 1 < vdp->degree.second) { + if (static_cast(vertices.size()) - 1 < vdp->degree.second) { goto fail; } // create the connections - igraph_integer_t k = 0; + igraph_int_t k = 0; for (auto it = vertices.begin(); k < vdp->degree.second; ++it) { @@ -655,13 +653,13 @@ static igraph_error_t igraph_i_kleitman_wang(const igraph_vector_int_t *outdeg, // Choose vertices in the order of their IDs. // O(E + V^2 log V) static igraph_error_t igraph_i_kleitman_wang_index(const igraph_vector_int_t *outdeg, const igraph_vector_int_t *indeg, igraph_vector_int_t *edges) { - igraph_integer_t n = igraph_vector_int_size(indeg); // number of vertices + igraph_int_t n = igraph_vector_int_size(indeg); // number of vertices - igraph_integer_t ec = 0; // number of edges added so far + igraph_int_t ec = 0; // number of edges added so far typedef std::list vlist; vlist vertices; - for (igraph_integer_t i = 0; i < n; ++i) { + for (igraph_int_t i = 0; i < n; ++i) { vertices.push_back(vbd_pair(i, bidegree(VECTOR(*indeg)[i], VECTOR(*outdeg)[i]))); } @@ -683,7 +681,7 @@ static igraph_error_t igraph_i_kleitman_wang_index(const igraph_vector_int_t *ou continue; } - igraph_integer_t k = 0; + igraph_int_t k = 0; vlist::iterator it; for (it = vertices.begin(); k != vd.degree.second && it != vertices.end(); @@ -725,8 +723,8 @@ static igraph_error_t igraph_i_realize_undirected_degree_sequence( const igraph_vector_int_t *deg, igraph_edge_type_sw_t allowed_edge_types, igraph_realize_degseq_t method) { - igraph_integer_t node_count = igraph_vector_int_size(deg); - igraph_integer_t deg_sum; + igraph_int_t node_count = igraph_vector_int_size(deg); + igraph_int_t deg_sum; IGRAPH_CHECK(igraph_i_safe_vector_int_sum(deg, °_sum)); @@ -820,8 +818,8 @@ static igraph_error_t igraph_i_realize_directed_degree_sequence( const igraph_vector_int_t *indeg, igraph_edge_type_sw_t allowed_edge_types, igraph_realize_degseq_t method) { - igraph_integer_t node_count = igraph_vector_int_size(outdeg); - igraph_integer_t edge_count, edge_count2, indeg_sum; + igraph_int_t node_count = igraph_vector_int_size(outdeg); + igraph_int_t edge_count, edge_count2, indeg_sum; IGRAPH_CHECK(igraph_i_safe_vector_int_sum(outdeg, &edge_count)); @@ -944,8 +942,9 @@ static igraph_error_t igraph_i_realize_directed_degree_sequence( * or the out-degree sequence of a directed graph (if \p indeg is given). * \param indeg The in-degree sequence of a directed graph. Pass \c NULL to * generate an undirected graph. - * \param allowed_edge_types The types of edges to allow in the graph. For - * directed graphs, only \c IGRAPH_SIMPLE_SW is implemented at this moment. + * \param allowed_edge_types The types of edges to allow in the graph. See \ref + * igraph_edge_type_sw_t. For directed graphs, only \c IGRAPH_SIMPLE_SW is + * implemented at this moment. * For undirected graphs, the following values are valid: * \clist * \cli IGRAPH_SIMPLE_SW @@ -979,7 +978,7 @@ static igraph_error_t igraph_i_realize_directed_degree_sequence( * the \c INDEX method is not equivalent to the \c SMALLEST method above, * as \c SMALLEST uses the smallest \em remaining degree for selecting * vertices, not the smallest \em initial degree. - * \endclist + * \endclist * \return Error code: * \clist * \cli IGRAPH_UNIMPLEMENTED @@ -1029,12 +1028,12 @@ static igraph_error_t igraph_i_realize_undirected_bipartite_index( const igraph_vector_int_t *degree1, const igraph_vector_int_t *degree2, igraph_bool_t multiedges ) { - igraph_integer_t ec = 0; // The number of edges added so far - igraph_integer_t n1 = igraph_vector_int_size(degree1); - igraph_integer_t n2 = igraph_vector_int_size(degree2); + igraph_int_t ec = 0; // The number of edges added so far + igraph_int_t n1 = igraph_vector_int_size(degree1); + igraph_int_t n2 = igraph_vector_int_size(degree2); igraph_vector_int_t edges; - igraph_integer_t ds1_sum; - igraph_integer_t ds2_sum; + igraph_int_t ds1_sum; + igraph_int_t ds2_sum; std::vector vertices1; std::vector vertices2; @@ -1058,10 +1057,10 @@ static igraph_error_t igraph_i_realize_undirected_bipartite_index( vertices1.reserve(n1); vertices2.reserve(n2); - for (igraph_integer_t i = 0; i < n1; i++) { + for (igraph_int_t i = 0; i < n1; i++) { vertices1.push_back(vd_pair(i, VECTOR(*degree1)[i])); } - for (igraph_integer_t i = 0; i < n2; i++) { + for (igraph_int_t i = 0; i < n2; i++) { vertices2.push_back(vd_pair(i + n1, VECTOR(*degree2)[i])); } @@ -1085,7 +1084,7 @@ static igraph_error_t igraph_i_realize_undirected_bipartite_index( goto fail; } - for (igraph_integer_t i = 0; i < vd_src.degree; i++) { + for (igraph_int_t i = 0; i < vd_src.degree; i++) { if ((*dest_vs)[i].degree == 0) { // Not enough non-zero remaining degree vertices in opposite partition. // Not graphical. @@ -1142,8 +1141,6 @@ static igraph_error_t igraph_i_realize_undirected_bipartite_index( * \function igraph_realize_bipartite_degree_sequence * \brief Generates a bipartite graph with the given bidegree sequence. * - * \experimental - * * This function generates a bipartite graph with the given bidegree sequence, * using a Havel-Hakimi-like construction algorithm. The order in which vertices * are connected up is controlled by the \p method parameter. When using the @@ -1190,12 +1187,12 @@ igraph_error_t igraph_realize_bipartite_degree_sequence( ) { IGRAPH_HANDLE_EXCEPTIONS_BEGIN; - igraph_integer_t ec = 0; // The number of edges added so far - igraph_integer_t n1 = igraph_vector_int_size(degrees1); - igraph_integer_t n2 = igraph_vector_int_size(degrees2); + igraph_int_t ec = 0; // The number of edges added so far + igraph_int_t n1 = igraph_vector_int_size(degrees1); + igraph_int_t n2 = igraph_vector_int_size(degrees2); igraph_vector_int_t edges; - igraph_integer_t ds1_sum; - igraph_integer_t ds2_sum; + igraph_int_t ds1_sum; + igraph_int_t ds2_sum; igraph_bool_t multiedges; igraph_bool_t largest; std::vector vertices1; @@ -1241,10 +1238,10 @@ igraph_error_t igraph_realize_bipartite_degree_sequence( vertices1.reserve(n1); vertices2.reserve(n2); - for (igraph_integer_t i = 0; i < n1; i++) { + for (igraph_int_t i = 0; i < n1; i++) { vertices1.push_back(vd_pair(i, VECTOR(*degrees1)[i])); } - for (igraph_integer_t i = 0; i < n2; i++) { + for (igraph_int_t i = 0; i < n2; i++) { vertices2.push_back(vd_pair(i + n1, VECTOR(*degrees2)[i])); } @@ -1308,7 +1305,7 @@ igraph_error_t igraph_realize_bipartite_degree_sequence( if (dest_vs->size() < size_t(vd_src.degree)) { goto fail; } - for (igraph_integer_t i = 0; i < vd_src.degree; i++) { + for (igraph_int_t i = 0; i < vd_src.degree; i++) { // Decrement the degree of the delta largest vertices in the opposite partition if ((*dest_vs)[i].degree == 0) { diff --git a/src/vendor/cigraph/src/misc/embedding.c b/src/vendor/cigraph/src/misc/embedding.c index 732f67e667d..2b427572a79 100644 --- a/src/vendor/cigraph/src/misc/embedding.c +++ b/src/vendor/cigraph/src/misc/embedding.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2013 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -29,8 +28,6 @@ #include "igraph_random.h" #include "igraph_structural.h" -#include "core/math.h" - #include typedef struct { @@ -51,7 +48,7 @@ static igraph_error_t igraph_i_asembeddingu(igraph_real_t *to, const igraph_real igraph_adjlist_t *outlist = data->outlist; const igraph_vector_t *cvec = data->cvec; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* to = (A+cD) from */ for (i = 0; i < n; i++) { @@ -59,7 +56,7 @@ static igraph_error_t igraph_i_asembeddingu(igraph_real_t *to, const igraph_real nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; to[i] += from[nei]; } to[i] += VECTOR(*cvec)[i] * from[i]; @@ -78,7 +75,7 @@ static igraph_error_t igraph_i_asembeddinguw(igraph_real_t *to, const igraph_rea const igraph_vector_t *weights = data->weights; const igraph_t *graph = data->graph; igraph_vector_int_t *incs; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* to = (A+cD) from */ for (i = 0; i < n; i++) { @@ -86,8 +83,8 @@ static igraph_error_t igraph_i_asembeddinguw(igraph_real_t *to, const igraph_rea nlen = igraph_vector_int_size(incs); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*incs)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, i); + igraph_int_t edge = VECTOR(*incs)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, i); igraph_real_t w = VECTOR(*weights)[edge]; to[i] += w * from[nei]; } @@ -106,7 +103,7 @@ static igraph_error_t igraph_i_asembedding(igraph_real_t *to, const igraph_real_ const igraph_vector_t *cvec = data->cvec; igraph_vector_t *tmp = data->tmp; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* tmp = (A+cD)' from */ for (i = 0; i < n; i++) { @@ -114,7 +111,7 @@ static igraph_error_t igraph_i_asembedding(igraph_real_t *to, const igraph_real_ nlen = igraph_vector_int_size(neis); VECTOR(*tmp)[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; VECTOR(*tmp)[i] += from[nei]; } VECTOR(*tmp)[i] += VECTOR(*cvec)[i] * from[i]; @@ -126,7 +123,7 @@ static igraph_error_t igraph_i_asembedding(igraph_real_t *to, const igraph_real_ nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; to[i] += VECTOR(*tmp)[nei]; } to[i] += VECTOR(*cvec)[i] * VECTOR(*tmp)[i]; @@ -142,7 +139,7 @@ static igraph_error_t igraph_i_asembedding_right(igraph_real_t *to, const igraph igraph_adjlist_t *inlist = data->inlist; const igraph_vector_t *cvec = data->cvec; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* to = (A+cD)' from */ for (i = 0; i < n; i++) { @@ -150,7 +147,7 @@ static igraph_error_t igraph_i_asembedding_right(igraph_real_t *to, const igraph nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; to[i] += from[nei]; } to[i] += VECTOR(*cvec)[i] * from[i]; @@ -170,7 +167,7 @@ static igraph_error_t igraph_i_asembeddingw(igraph_real_t *to, const igraph_real const igraph_t *graph = data->graph; igraph_vector_t *tmp = data->tmp; igraph_vector_int_t *incs; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* tmp = (A+cD)' from */ for (i = 0; i < n; i++) { @@ -178,8 +175,8 @@ static igraph_error_t igraph_i_asembeddingw(igraph_real_t *to, const igraph_real nlen = igraph_vector_int_size(incs); VECTOR(*tmp)[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*incs)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, i); + igraph_int_t edge = VECTOR(*incs)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, i); igraph_real_t w = VECTOR(*weights)[edge]; VECTOR(*tmp)[i] += w * from[nei]; } @@ -192,8 +189,8 @@ static igraph_error_t igraph_i_asembeddingw(igraph_real_t *to, const igraph_real nlen = igraph_vector_int_size(incs); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*incs)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, i); + igraph_int_t edge = VECTOR(*incs)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, i); igraph_real_t w = VECTOR(*weights)[edge]; to[i] += w * VECTOR(*tmp)[nei]; } @@ -212,7 +209,7 @@ static igraph_error_t igraph_i_asembeddingw_right(igraph_real_t *to, const igrap const igraph_vector_t *weights = data->weights; const igraph_t *graph = data->graph; igraph_vector_int_t *incs; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* to = (A+cD)' from */ for (i = 0; i < n; i++) { @@ -220,8 +217,8 @@ static igraph_error_t igraph_i_asembeddingw_right(igraph_real_t *to, const igrap nlen = igraph_vector_int_size(incs); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*incs)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, i); + igraph_int_t edge = VECTOR(*incs)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, i); igraph_real_t w = VECTOR(*weights)[edge]; to[i] += w * from[nei]; } @@ -238,7 +235,7 @@ static igraph_error_t igraph_i_lsembedding_da(igraph_real_t *to, const igraph_re igraph_adjlist_t *outlist = data->outlist; const igraph_vector_t *cvec = data->cvec; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* to = (D-A) from */ for (i = 0; i < n; i++) { @@ -246,7 +243,7 @@ static igraph_error_t igraph_i_lsembedding_da(igraph_real_t *to, const igraph_re nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; to[i] -= from[nei]; } to[i] += VECTOR(*cvec)[i] * from[i]; @@ -264,7 +261,7 @@ static igraph_error_t igraph_i_lsembedding_daw(igraph_real_t *to, const igraph_r const igraph_vector_t *weights = data->weights; const igraph_t *graph = data->graph; igraph_vector_int_t *incs; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* to = (D-A) from */ for (i = 0; i < n; i++) { @@ -272,8 +269,8 @@ static igraph_error_t igraph_i_lsembedding_daw(igraph_real_t *to, const igraph_r nlen = igraph_vector_int_size(incs); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*incs)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, i); + igraph_int_t edge = VECTOR(*incs)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, i); igraph_real_t w = VECTOR(*weights)[edge]; to[i] -= w * from[nei]; } @@ -292,7 +289,7 @@ static igraph_error_t igraph_i_lsembedding_dad(igraph_real_t *to, const igraph_r const igraph_vector_t *cvec = data->cvec; igraph_vector_t *tmp = data->tmp; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* to = D^1/2 from */ for (i = 0; i < n; i++) { @@ -305,7 +302,7 @@ static igraph_error_t igraph_i_lsembedding_dad(igraph_real_t *to, const igraph_r nlen = igraph_vector_int_size(neis); VECTOR(*tmp)[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; VECTOR(*tmp)[i] += to[nei]; } } @@ -328,7 +325,7 @@ static igraph_error_t igraph_i_lsembedding_dadw(igraph_real_t *to, const igraph_ const igraph_t *graph = data->graph; igraph_vector_t *tmp = data->tmp; igraph_vector_int_t *incs; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* to = D^-1/2 from */ for (i = 0; i < n; i++) { @@ -341,8 +338,8 @@ static igraph_error_t igraph_i_lsembedding_dadw(igraph_real_t *to, const igraph_ nlen = igraph_vector_int_size(incs); VECTOR(*tmp)[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*incs)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, i); + igraph_int_t edge = VECTOR(*incs)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, i); igraph_real_t w = VECTOR(*weights)[edge]; VECTOR(*tmp)[i] += w * to[nei]; } @@ -359,8 +356,8 @@ static igraph_error_t igraph_i_lsembedding_dadw(igraph_real_t *to, const igraph_ nlen = igraph_vector_int_size(incs); VECTOR(*tmp)[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*incs)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, i); + igraph_int_t edge = VECTOR(*incs)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, i); igraph_real_t w = VECTOR(*weights)[edge]; VECTOR(*tmp)[i] += w * to[nei]; } @@ -408,7 +405,7 @@ static igraph_error_t igraph_i_lseembedding_oap(igraph_real_t *to, const igraph_ const igraph_vector_t *deg_out = data->cvec2; igraph_vector_t *tmp = data->tmp; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* tmp = O' from */ for (i = 0; i < n; i++) { @@ -421,7 +418,7 @@ static igraph_error_t igraph_i_lseembedding_oap(igraph_real_t *to, const igraph_ nlen = igraph_vector_int_size(neis); to[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; to[i] += VECTOR(*tmp)[nei]; } } @@ -442,7 +439,7 @@ static igraph_error_t igraph_i_lseembedding_oap(igraph_real_t *to, const igraph_ nlen = igraph_vector_int_size(neis); VECTOR(*tmp)[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; VECTOR(*tmp)[i] += to[nei]; } } @@ -465,7 +462,7 @@ static igraph_error_t igraph_i_lseembedding_oap_right(igraph_real_t *to, const igraph_vector_t *deg_out = data->cvec2; igraph_vector_t *tmp = data->tmp; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; + igraph_int_t i, j, nlen; /* to = O' from */ for (i = 0; i < n; i++) { @@ -478,7 +475,7 @@ static igraph_error_t igraph_i_lseembedding_oap_right(igraph_real_t *to, nlen = igraph_vector_int_size(neis); VECTOR(*tmp)[i] = 0.0; for (j = 0; j < nlen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; VECTOR(*tmp)[i] += to[nei]; } } @@ -504,8 +501,8 @@ static igraph_error_t igraph_i_lseembedding_oapw(igraph_real_t *to, const igraph const igraph_t *graph = data->graph; igraph_vector_t *tmp = data->tmp; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; - igraph_integer_t edge, nei; + igraph_int_t i, j, nlen; + igraph_int_t edge, nei; igraph_real_t w; /* tmp = O' from */ @@ -569,8 +566,8 @@ static igraph_error_t igraph_i_lseembedding_oapw_right(igraph_real_t *to, const igraph_t *graph = data->graph; igraph_vector_t *tmp = data->tmp; igraph_vector_int_t *neis; - igraph_integer_t i, j, nlen; - igraph_integer_t edge, nei; + igraph_int_t i, j, nlen; + igraph_int_t edge, nei; igraph_real_t w; /* to = O' from */ @@ -600,7 +597,7 @@ static igraph_error_t igraph_i_lseembedding_oapw_right(igraph_real_t *to, } static igraph_error_t igraph_i_spectral_embedding(const igraph_t *graph, - igraph_integer_t no, + igraph_int_t no, const igraph_vector_t *weights, igraph_eigen_which_position_t which, igraph_bool_t scaled, @@ -616,11 +613,11 @@ static igraph_error_t igraph_i_spectral_embedding(const igraph_t *graph, igraph_bool_t eigen, igraph_bool_t zapsmall) { - igraph_integer_t vc = igraph_vcount(graph); + igraph_int_t vc = igraph_vcount(graph); igraph_vector_t tmp; igraph_adjlist_t outlist, inlist; igraph_inclist_t eoutlist, einlist; - igraph_integer_t i, j, cveclen = igraph_vector_size(cvec); + igraph_int_t i, j, cveclen = igraph_vector_size(cvec); igraph_i_asembedding_data_t data; igraph_vector_t tmpD; @@ -721,11 +718,9 @@ static igraph_error_t igraph_i_spectral_embedding(const igraph_t *graph, /* We provide a random start vector to ARPACK on our own to ensure that * we use igraph's RNG and not the one from ARPACK (which relies on LAPACK) */ - RNG_BEGIN(); for (i = 0; i < vc; i++) { MATRIX(*X, i, 0) = RNG_UNIF(-1, 1); } - RNG_END(); IGRAPH_CHECK(igraph_arpack_rssolve(callback, &data, options, 0, &tmpD, X)); @@ -734,9 +729,8 @@ static igraph_error_t igraph_i_spectral_embedding(const igraph_t *graph, IGRAPH_CHECK(igraph_matrix_resize(Y, vc, no)); for (i = 0; i < no; i++) { igraph_real_t norm; - igraph_vector_t v; + igraph_vector_t v = igraph_vector_view(&MATRIX(*Y, 0, i), vc); callback_right(&MATRIX(*Y, 0, i), &MATRIX(*X, 0, i), (int) vc, &data); - igraph_vector_view(&v, &MATRIX(*Y, 0, i), vc); norm = 1.0 / igraph_blas_dnrm2(&v); igraph_vector_scale(&v, norm); } @@ -876,7 +870,7 @@ static igraph_error_t igraph_i_spectral_embedding(const igraph_t *graph, */ igraph_error_t igraph_adjacency_spectral_embedding(const igraph_t *graph, - igraph_integer_t n, + igraph_int_t n, const igraph_vector_t *weights, igraph_eigen_which_position_t which, igraph_bool_t scaled, @@ -910,7 +904,7 @@ igraph_error_t igraph_adjacency_spectral_embedding(const igraph_t *graph, } static igraph_error_t igraph_i_lse_und(const igraph_t *graph, - igraph_integer_t no, + igraph_int_t no, const igraph_vector_t *weights, igraph_eigen_which_position_t which, igraph_laplacian_spectral_embedding_type_t type, @@ -940,14 +934,14 @@ static igraph_error_t igraph_i_lse_und(const igraph_t *graph, } IGRAPH_VECTOR_INIT_FINALLY(°, 0); - IGRAPH_CHECK(igraph_strength(graph, °, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1, weights)); + IGRAPH_CHECK(igraph_strength(graph, °, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS, weights)); switch (type) { case IGRAPH_EMBEDDING_D_A: break; case IGRAPH_EMBEDDING_DAD: case IGRAPH_EMBEDDING_I_DAD: { - igraph_integer_t i, n = igraph_vector_size(°); + igraph_int_t i, n = igraph_vector_size(°); for (i = 0; i < n; i++) { VECTOR(deg)[i] = 1.0 / sqrt(VECTOR(deg)[i]); } @@ -969,7 +963,7 @@ static igraph_error_t igraph_i_lse_und(const igraph_t *graph, } static igraph_error_t igraph_i_lse_dir(const igraph_t *graph, - igraph_integer_t no, + igraph_int_t no, const igraph_vector_t *weights, igraph_eigen_which_position_t which, igraph_laplacian_spectral_embedding_type_t type, @@ -985,7 +979,7 @@ static igraph_error_t igraph_i_lse_dir(const igraph_t *graph, weights ? igraph_i_lseembedding_oapw_right : igraph_i_lseembedding_oap_right; igraph_vector_t deg_in, deg_out; - igraph_integer_t i, n = igraph_vcount(graph); + igraph_int_t i, n = igraph_vcount(graph); if (type != IGRAPH_EMBEDDING_OAP) { IGRAPH_ERROR("Invalid Laplacian spectral embedding type", IGRAPH_EINVAL); @@ -993,8 +987,8 @@ static igraph_error_t igraph_i_lse_dir(const igraph_t *graph, IGRAPH_VECTOR_INIT_FINALLY(°_in, n); IGRAPH_VECTOR_INIT_FINALLY(°_out, n); - IGRAPH_CHECK(igraph_strength(graph, °_in, igraph_vss_all(), IGRAPH_IN, /*loops=*/ 1, weights)); - IGRAPH_CHECK(igraph_strength(graph, °_out, igraph_vss_all(), IGRAPH_OUT, /*loops=*/ 1, weights)); + IGRAPH_CHECK(igraph_strength(graph, °_in, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS, weights)); + IGRAPH_CHECK(igraph_strength(graph, °_out, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS, weights)); for (i = 0; i < n; i++) { VECTOR(deg_in)[i] = 1.0 / sqrt(VECTOR(deg_in)[i]); @@ -1075,7 +1069,7 @@ static igraph_error_t igraph_i_lse_dir(const igraph_t *graph, */ igraph_error_t igraph_laplacian_spectral_embedding(const igraph_t *graph, - igraph_integer_t n, + igraph_int_t n, const igraph_vector_t *weights, igraph_eigen_which_position_t which, igraph_laplacian_spectral_embedding_type_t type, @@ -1133,9 +1127,9 @@ igraph_error_t igraph_laplacian_spectral_embedding(const igraph_t *graph, * \sa \ref igraph_adjacency_spectral_embedding(). */ -igraph_error_t igraph_dim_select(const igraph_vector_t *sv, igraph_integer_t *dim) { +igraph_error_t igraph_dim_select(const igraph_vector_t *sv, igraph_int_t *dim) { - igraph_integer_t i, n = igraph_vector_size(sv); + igraph_int_t i, n = igraph_vector_size(sv); igraph_real_t x, x2, sum1 = 0.0, sum2 = igraph_vector_sum(sv); igraph_real_t sumsq1 = 0.0, sumsq2 = 0.0; /* to be set */ igraph_real_t oldmean1, oldmean2, mean1 = 0.0, mean2 = sum2 / n; @@ -1159,7 +1153,7 @@ igraph_error_t igraph_dim_select(const igraph_vector_t *sv, igraph_integer_t *di } for (i = 0; i < n - 1; i++) { - igraph_integer_t n1 = i + 1, n2 = n - i - 1, n1m1 = n1 - 1, n2m1 = n2 - 1; + igraph_int_t n1 = i + 1, n2 = n - i - 1, n1m1 = n1 - 1, n2m1 = n2 - 1; x = VECTOR(*sv)[i]; x2 = x * x; sum1 += x; sum2 -= x; sumsq1 += x2; sumsq2 -= x2; diff --git a/src/vendor/cigraph/src/misc/graphicality.c b/src/vendor/cigraph/src/misc/graphicality.c index 8cc3f343b9a..30412a74d78 100644 --- a/src/vendor/cigraph/src/misc/graphicality.c +++ b/src/vendor/cigraph/src/misc/graphicality.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -20,8 +18,27 @@ #include "igraph_graphicality.h" -#define IGRAPH_I_MULTI_EDGES_SW 0x02 /* 010, more than one edge allowed between distinct vertices */ -#define IGRAPH_I_MULTI_LOOPS_SW 0x04 /* 100, more than one self-loop allowed on the same vertex */ +#include "misc/graphicality.h" + + +igraph_error_t igraph_i_edge_type_to_loops_multiple( + igraph_edge_type_sw_t allowed_edge_types, + igraph_bool_t *loops, igraph_bool_t *multiple) { + + *loops = (allowed_edge_types & IGRAPH_LOOPS_SW) ? true : false; + *multiple = (allowed_edge_types & IGRAPH_I_MULTI_EDGES_SW) ? true : false; + + if (*loops) { + igraph_bool_t multi_loops = (allowed_edge_types & IGRAPH_I_MULTI_LOOPS_SW); + if (*multiple != multi_loops) { + IGRAPH_ERROR("Either both multi-edges and multi-loops should be allowed or neither.", + IGRAPH_EINVAL); + } + } + + return IGRAPH_SUCCESS; +} + static igraph_error_t igraph_i_is_graphical_undirected_multi_loops(const igraph_vector_int_t *degrees, igraph_bool_t *res); static igraph_error_t igraph_i_is_graphical_undirected_loopless_multi(const igraph_vector_int_t *degrees, igraph_bool_t *res); @@ -90,7 +107,8 @@ static igraph_error_t igraph_i_is_bigraphical_simple(const igraph_vector_int_t * * undirected graphs or the out-degree sequence for directed graphs. * \param in_degrees A vector of integers specifying the in-degree sequence for * directed graphs. For undirected graphs, it must be \c NULL. - * \param allowed_edge_types The types of edges to allow in the graph: + * \param allowed_edge_types The types of edges to allow in the graph. See + * \ref igraph_edge_type_sw_t for details. * \clist * \cli IGRAPH_SIMPLE_SW * simple graphs (i.e. no self-loops or multi-edges allowed). @@ -239,12 +257,12 @@ igraph_error_t igraph_is_bigraphical(const igraph_vector_int_t *degrees1, * These conditions are valid regardless of whether multi-edges are allowed between distinct vertices. */ static igraph_error_t igraph_i_is_graphical_undirected_multi_loops(const igraph_vector_int_t *degrees, igraph_bool_t *res) { - igraph_integer_t sum_parity = 0; /* 0 if the degree sum is even, 1 if it is odd */ - igraph_integer_t n = igraph_vector_int_size(degrees); - igraph_integer_t i; + igraph_int_t sum_parity = 0; /* 0 if the degree sum is even, 1 if it is odd */ + igraph_int_t n = igraph_vector_int_size(degrees); + igraph_int_t i; for (i = 0; i < n; ++i) { - igraph_integer_t d = VECTOR(*degrees)[i]; + igraph_int_t d = VECTOR(*degrees)[i]; if (d < 0) { *res = false; @@ -265,9 +283,9 @@ static igraph_error_t igraph_i_is_graphical_undirected_multi_loops(const igraph_ * - The sum of degrees must be no smaller than 2*d_max. */ static igraph_error_t igraph_i_is_graphical_undirected_loopless_multi(const igraph_vector_int_t *degrees, igraph_bool_t *res) { - igraph_integer_t i; - igraph_integer_t n = igraph_vector_int_size(degrees); - igraph_integer_t dsum, dmax; + igraph_int_t i; + igraph_int_t n = igraph_vector_int_size(degrees); + igraph_int_t dsum, dmax; /* Zero-length sequences are considered graphical. */ if (n == 0) { @@ -277,7 +295,7 @@ static igraph_error_t igraph_i_is_graphical_undirected_loopless_multi(const igra dsum = 0; dmax = 0; for (i = 0; i < n; ++i) { - igraph_integer_t d = VECTOR(*degrees)[i]; + igraph_int_t d = VECTOR(*degrees)[i]; if (d < 0) { *res = false; @@ -302,7 +320,7 @@ static igraph_error_t igraph_i_is_graphical_undirected_loopless_multi(const igra */ static igraph_error_t igraph_i_is_graphical_undirected_loopy_simple(const igraph_vector_int_t *degrees, igraph_bool_t *res) { igraph_vector_int_t num_degs; - igraph_integer_t w, b, s, c, n, k, wd, kd; + igraph_int_t w, b, s, c, n, k, wd, kd; n = igraph_vector_int_size(degrees); @@ -344,8 +362,8 @@ static igraph_error_t igraph_i_is_graphical_undirected_loopy_simple(const igraph IGRAPH_VECTOR_INT_INIT_FINALLY(&num_degs, n+2); - for (igraph_integer_t i = 0; i < n; ++i) { - igraph_integer_t degree = VECTOR(*degrees)[i]; + for (igraph_int_t i = 0; i < n; ++i) { + igraph_int_t degree = VECTOR(*degrees)[i]; /* Negative degrees are already checked in igraph_i_is_graphical_undirected_multi_loops() */ if (degree > n+1) { @@ -357,7 +375,7 @@ static igraph_error_t igraph_i_is_graphical_undirected_loopy_simple(const igraph } /* Convert num_degs to a cumulative sum array. */ - for (igraph_integer_t d = n; d >= 0; --d) { + for (igraph_int_t d = n; d >= 0; --d) { VECTOR(num_degs)[d] += VECTOR(num_degs)[d+1]; } @@ -403,12 +421,12 @@ static igraph_error_t igraph_i_is_graphical_undirected_loopy_simple(const igraph */ static igraph_error_t igraph_i_is_graphical_undirected_simple(const igraph_vector_int_t *degrees, igraph_bool_t *res) { igraph_vector_int_t num_degs; /* num_degs[d] is the # of vertices with degree d */ - const igraph_integer_t p = igraph_vector_int_size(degrees); - igraph_integer_t dmin, dmax, dsum; - igraph_integer_t n; /* number of non-zero degrees */ - igraph_integer_t k, sum_deg, sum_ni, sum_ini; - igraph_integer_t i, dk; - igraph_integer_t zverovich_bound; + const igraph_int_t p = igraph_vector_int_size(degrees); + igraph_int_t dmin, dmax, dsum; + igraph_int_t n; /* number of non-zero degrees */ + igraph_int_t k, sum_deg, sum_ni, sum_ini; + igraph_int_t i, dk; + igraph_int_t zverovich_bound; if (p == 0) { *res = true; @@ -429,7 +447,7 @@ static igraph_error_t igraph_i_is_graphical_undirected_simple(const igraph_vecto dmin = p; dmax = 0; dsum = 0; n = 0; for (i = 0; i < p; ++i) { - igraph_integer_t d = VECTOR(*degrees)[i]; + igraph_int_t d = VECTOR(*degrees)[i]; if (d < 0 || d >= p) { *res = false; @@ -485,7 +503,7 @@ static igraph_error_t igraph_i_is_graphical_undirected_simple(const igraph_vecto k = 0; sum_deg = 0; sum_ni = 0; sum_ini = 0; for (dk = dmax; dk >= dmin; --dk) { - igraph_integer_t run_size, v; + igraph_int_t run_size, v; if (dk < k+1) { *res = true; @@ -527,16 +545,16 @@ static igraph_error_t igraph_i_is_graphical_undirected_simple(const igraph_vecto * - The sum of in- and out-degrees must be the same. */ static igraph_error_t igraph_i_is_graphical_directed_loopy_multi(const igraph_vector_int_t *out_degrees, const igraph_vector_int_t *in_degrees, igraph_bool_t *res) { - igraph_integer_t sumdiff; /* difference between sum of in- and out-degrees */ - igraph_integer_t n = igraph_vector_int_size(out_degrees); - igraph_integer_t i; + igraph_int_t sumdiff; /* difference between sum of in- and out-degrees */ + igraph_int_t n = igraph_vector_int_size(out_degrees); + igraph_int_t i; IGRAPH_ASSERT(igraph_vector_int_size(in_degrees) == n); sumdiff = 0; for (i = 0; i < n; ++i) { - igraph_integer_t dout = VECTOR(*out_degrees)[i]; - igraph_integer_t din = VECTOR(*in_degrees)[i]; + igraph_int_t dout = VECTOR(*out_degrees)[i]; + igraph_int_t din = VECTOR(*in_degrees)[i]; if (dout < 0 || din < 0) { *res = false; @@ -559,17 +577,17 @@ static igraph_error_t igraph_i_is_graphical_directed_loopy_multi(const igraph_ve * where d_max is the largest total degree. */ static igraph_error_t igraph_i_is_graphical_directed_loopless_multi(const igraph_vector_int_t *out_degrees, const igraph_vector_int_t *in_degrees, igraph_bool_t *res) { - igraph_integer_t i, sumin, sumout, dmax; - igraph_integer_t n = igraph_vector_int_size(out_degrees); + igraph_int_t i, sumin, sumout, dmax; + igraph_int_t n = igraph_vector_int_size(out_degrees); IGRAPH_ASSERT(igraph_vector_int_size(in_degrees) == n); sumin = 0; sumout = 0; dmax = 0; for (i = 0; i < n; ++i) { - igraph_integer_t dout = VECTOR(*out_degrees)[i]; - igraph_integer_t din = VECTOR(*in_degrees)[i]; - igraph_integer_t d = dout + din; + igraph_int_t dout = VECTOR(*out_degrees)[i]; + igraph_int_t din = VECTOR(*in_degrees)[i]; + igraph_int_t d = dout + din; if (dout < 0 || din < 0) { *res = false; @@ -607,7 +625,7 @@ static igraph_error_t igraph_i_is_graphical_directed_simple(const igraph_vector_ igraph_vector_int_t in_degree_cumcounts, in_degree_counts; igraph_vector_int_t sorted_in_degrees, sorted_out_degrees; igraph_vector_int_t left_pq, right_pq; - igraph_integer_t lhs, rhs, left_pq_size, right_pq_size, left_i, right_i, left_sum, right_sum; + igraph_int_t lhs, rhs, left_pq_size, right_pq_size, left_i, right_i, left_sum, right_sum; /* The conditions from the loopy multigraph case are necessary here as well. */ IGRAPH_CHECK(igraph_i_is_graphical_directed_loopy_multi(out_degrees, in_degrees, res)); @@ -615,7 +633,7 @@ static igraph_error_t igraph_i_is_graphical_directed_simple(const igraph_vector_ return IGRAPH_SUCCESS; } - const igraph_integer_t vcount = igraph_vector_int_size(out_degrees); + const igraph_int_t vcount = igraph_vector_int_size(out_degrees); if (vcount == 0) { *res = true; return IGRAPH_SUCCESS; @@ -625,9 +643,9 @@ static igraph_error_t igraph_i_is_graphical_directed_simple(const igraph_vector_ IGRAPH_VECTOR_INT_INIT_FINALLY(&in_degree_cumcounts, vcount+1); /* Compute in_degree_cumcounts[d+1] to be the no. of in-degrees == d */ - for (igraph_integer_t v = 0; v < vcount; v++) { - igraph_integer_t indeg = VECTOR(*in_degrees)[v]; - igraph_integer_t outdeg = VECTOR(*out_degrees)[v]; + for (igraph_int_t v = 0; v < vcount; v++) { + igraph_int_t indeg = VECTOR(*in_degrees)[v]; + igraph_int_t outdeg = VECTOR(*out_degrees)[v]; if (indeg >= vcount || outdeg >= vcount) { *res = false; igraph_vector_int_destroy(&in_degree_cumcounts); @@ -638,7 +656,7 @@ static igraph_error_t igraph_i_is_graphical_directed_simple(const igraph_vector_ } /* Compute in_degree_cumcounts[d] to be the no. of in-degrees < d */ - for (igraph_integer_t indeg = 0; indeg < vcount; indeg++) { + for (igraph_int_t indeg = 0; indeg < vcount; indeg++) { VECTOR(in_degree_cumcounts)[indeg+1] += VECTOR(in_degree_cumcounts)[indeg]; } @@ -649,10 +667,10 @@ static igraph_error_t igraph_i_is_graphical_directed_simple(const igraph_vector_ * with in-degree d that were already placed. */ IGRAPH_VECTOR_INT_INIT_FINALLY(&in_degree_counts, vcount); - for (igraph_integer_t v = 0; v < vcount; v++) { - igraph_integer_t outdeg = VECTOR(*out_degrees)[v]; - igraph_integer_t indeg = VECTOR(*in_degrees)[v]; - igraph_integer_t idx = VECTOR(in_degree_cumcounts)[indeg] + VECTOR(in_degree_counts)[indeg]; + for (igraph_int_t v = 0; v < vcount; v++) { + igraph_int_t outdeg = VECTOR(*out_degrees)[v]; + igraph_int_t indeg = VECTOR(*in_degrees)[v]; + igraph_int_t idx = VECTOR(in_degree_cumcounts)[indeg] + VECTOR(in_degree_counts)[indeg]; VECTOR(sorted_out_degrees)[vcount - idx - 1] = outdeg; VECTOR(sorted_in_degrees)[vcount - idx - 1] = indeg; VECTOR(in_degree_counts)[indeg]++; @@ -683,14 +701,14 @@ static igraph_error_t igraph_i_is_graphical_directed_simple(const igraph_vector_ right_i = 0; left_sum = 0; right_sum = 0; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { VECTOR(right_pq)[OUTDEGREE(i)]++; } *res = true; lhs = 0; rhs = 0; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { lhs += INDEGREE(i); /* It is enough to check for indexes where the in-degree is about to @@ -758,13 +776,13 @@ static igraph_error_t igraph_i_is_graphical_directed_simple(const igraph_vector_ * - Sum of degrees must be the same in the two partitions. */ static igraph_error_t igraph_i_is_bigraphical_multi(const igraph_vector_int_t *degrees1, const igraph_vector_int_t *degrees2, igraph_bool_t *res) { - igraph_integer_t i; - igraph_integer_t sum1, sum2; - igraph_integer_t n1 = igraph_vector_int_size(degrees1), n2 = igraph_vector_int_size(degrees2); + igraph_int_t i; + igraph_int_t sum1, sum2; + igraph_int_t n1 = igraph_vector_int_size(degrees1), n2 = igraph_vector_int_size(degrees2); sum1 = 0; for (i = 0; i < n1; ++i) { - igraph_integer_t d = VECTOR(*degrees1)[i]; + igraph_int_t d = VECTOR(*degrees1)[i]; if (d < 0) { *res = false; @@ -776,7 +794,7 @@ static igraph_error_t igraph_i_is_bigraphical_multi(const igraph_vector_int_t *d sum2 = 0; for (i = 0; i < n2; ++i) { - igraph_integer_t d = VECTOR(*degrees2)[i]; + igraph_int_t d = VECTOR(*degrees2)[i]; if (d < 0) { *res = false; @@ -798,10 +816,10 @@ static igraph_error_t igraph_i_is_bigraphical_multi(const igraph_vector_int_t *d * - Use the Gale-Ryser theorem. */ static igraph_error_t igraph_i_is_bigraphical_simple(const igraph_vector_int_t *degrees1, const igraph_vector_int_t *degrees2, igraph_bool_t *res) { - igraph_integer_t n1 = igraph_vector_int_size(degrees1), n2 = igraph_vector_int_size(degrees2); + igraph_int_t n1 = igraph_vector_int_size(degrees1), n2 = igraph_vector_int_size(degrees2); igraph_vector_int_t deg_freq1, deg_freq2; - igraph_integer_t lhs_sum, partial_rhs_sum, partial_rhs_count; - igraph_integer_t a, b, k; + igraph_int_t lhs_sum, partial_rhs_sum, partial_rhs_count; + igraph_int_t a, b, k; if (n1 == 0 && n2 == 0) { *res = true; @@ -817,7 +835,7 @@ static igraph_error_t igraph_i_is_bigraphical_simple(const igraph_vector_int_t * /* Ensure that degrees1 is the shorter vector as a minor optimization: */ if (n2 < n1) { const igraph_vector_int_t *tmp; - igraph_integer_t n; + igraph_int_t n; tmp = degrees1; degrees1 = degrees2; @@ -833,16 +851,16 @@ static igraph_error_t igraph_i_is_bigraphical_simple(const igraph_vector_int_t * IGRAPH_VECTOR_INT_INIT_FINALLY(°_freq1, n2+1); IGRAPH_VECTOR_INT_INIT_FINALLY(°_freq2, n1+1); - for (igraph_integer_t i = 0; i < n1; ++i) { - igraph_integer_t degree = VECTOR(*degrees1)[i]; + for (igraph_int_t i = 0; i < n1; ++i) { + igraph_int_t degree = VECTOR(*degrees1)[i]; if (degree > n2) { *res = false; goto bigraphical_simple_done; } ++VECTOR(deg_freq1)[degree]; } - for (igraph_integer_t i = 0; i < n2; ++i) { - igraph_integer_t degree = VECTOR(*degrees2)[i]; + for (igraph_int_t i = 0; i < n2; ++i) { + igraph_int_t degree = VECTOR(*degrees2)[i]; if (degree > n1) { *res = false; goto bigraphical_simple_done; @@ -882,12 +900,12 @@ static igraph_error_t igraph_i_is_bigraphical_simple(const igraph_vector_int_t * b = 0; /* index in deg_freq2 */ k = -1; for (a = n2; a >= 0; --a) { - igraph_integer_t acount = VECTOR(deg_freq1)[a]; + igraph_int_t acount = VECTOR(deg_freq1)[a]; lhs_sum += a * acount; k += acount; while (b <= k + 1) { - igraph_integer_t bcount = VECTOR(deg_freq2)[b]; + igraph_int_t bcount = VECTOR(deg_freq2)[b]; partial_rhs_sum += b * bcount; partial_rhs_count += bcount; diff --git a/src/vendor/cigraph/src/misc/graphicality.h b/src/vendor/cigraph/src/misc/graphicality.h new file mode 100644 index 00000000000..eedb6d52bf0 --- /dev/null +++ b/src/vendor/cigraph/src/misc/graphicality.h @@ -0,0 +1,36 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef IGRAPH_MISC_GRAPHICALITY_H +#define IGRAPH_MISC_GRAPHICALITY_H + +#include "igraph_decls.h" +#include "igraph_graphicality.h" + +#define IGRAPH_I_MULTI_EDGES_SW 0x02 /* 010, more than one edge allowed between distinct vertices */ +#define IGRAPH_I_MULTI_LOOPS_SW 0x04 /* 100, more than one self-loop allowed on the same vertex */ + +IGRAPH_BEGIN_C_DECLS + +igraph_error_t igraph_i_edge_type_to_loops_multiple( + igraph_edge_type_sw_t allowed_edge_type, + igraph_bool_t *loops, igraph_bool_t *multiple); + +IGRAPH_END_C_DECLS + +#endif /* IGRAPH_MISC_GRAPHICALITY_H */ diff --git a/src/vendor/cigraph/src/misc/matching.c b/src/vendor/cigraph/src/misc/matching.c index 6f2190943b2..6b8e1794bd7 100644 --- a/src/vendor/cigraph/src/misc/matching.c +++ b/src/vendor/cigraph/src/misc/matching.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2012 Tamas Nepusz This program is free software; you can redistribute it and/or modify @@ -34,24 +32,11 @@ /* #define MATCHING_DEBUG */ -#ifdef _MSC_VER -/* MSVC does not support variadic macros */ -#include -static void debug(const char* fmt, ...) { - va_list args; - va_start(args, fmt); -#ifdef MATCHING_DEBUG - vfprintf(stderr, fmt, args); -#endif - va_end(args); -} -#else #ifdef MATCHING_DEBUG #define debug(...) fprintf(stderr, __VA_ARGS__) #else #define debug(...) #endif -#endif /** * \function igraph_is_matching @@ -86,7 +71,7 @@ static void debug(const char* fmt, ...) { igraph_error_t igraph_is_matching(const igraph_t *graph, const igraph_vector_bool_t *types, const igraph_vector_int_t *matching, igraph_bool_t *result) { - igraph_integer_t i, j, no_of_nodes = igraph_vcount(graph); + igraph_int_t i, j, no_of_nodes = igraph_vcount(graph); igraph_bool_t conn; /* Checking match vector length */ @@ -170,7 +155,7 @@ igraph_error_t igraph_is_maximal_matching(const igraph_t *graph, const igraph_vector_bool_t *types, const igraph_vector_int_t *matching, igraph_bool_t *result) { - igraph_integer_t i, j, n, no_of_nodes = igraph_vcount(graph); + igraph_int_t i, j, n, no_of_nodes = igraph_vcount(graph); igraph_vector_int_t neis; igraph_bool_t valid; @@ -188,8 +173,9 @@ igraph_error_t igraph_is_maximal_matching(const igraph_t *graph, continue; } - IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, - IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, i, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); n = igraph_vector_int_size(&neis); for (j = 0; j < n; j++) { if (VECTOR(*matching)[VECTOR(neis)[j]] == -1) { @@ -210,12 +196,12 @@ igraph_error_t igraph_is_maximal_matching(const igraph_t *graph, static igraph_error_t igraph_i_maximum_bipartite_matching_unweighted( const igraph_t *graph, - const igraph_vector_bool_t *types, igraph_integer_t *matching_size, + const igraph_vector_bool_t *types, igraph_int_t *matching_size, igraph_vector_int_t *matching); static igraph_error_t igraph_i_maximum_bipartite_matching_weighted( const igraph_t *graph, - const igraph_vector_bool_t *types, igraph_integer_t *matching_size, + const igraph_vector_bool_t *types, igraph_int_t *matching_size, igraph_real_t *matching_weight, igraph_vector_int_t *matching, const igraph_vector_t *weights, igraph_real_t eps); @@ -284,7 +270,7 @@ static igraph_error_t igraph_i_maximum_bipartite_matching_weighted( * \example examples/simple/igraph_maximum_bipartite_matching.c */ igraph_error_t igraph_maximum_bipartite_matching(const igraph_t *graph, - const igraph_vector_bool_t *types, igraph_integer_t *matching_size, + const igraph_vector_bool_t *types, igraph_int_t *matching_size, igraph_real_t *matching_weight, igraph_vector_int_t *matching, const igraph_vector_t *weights, igraph_real_t eps) { @@ -330,17 +316,17 @@ static igraph_error_t igraph_i_maximum_bipartite_matching_unweighted_relabel( */ static igraph_error_t igraph_i_maximum_bipartite_matching_unweighted( const igraph_t *graph, - const igraph_vector_bool_t *types, igraph_integer_t *matching_size, + const igraph_vector_bool_t *types, igraph_int_t *matching_size, igraph_vector_int_t *matching) { - igraph_integer_t i, j, k, n, no_of_nodes = igraph_vcount(graph); - igraph_integer_t num_matched; /* number of matched vertex pairs */ + igraph_int_t i, j, k, n, no_of_nodes = igraph_vcount(graph); + igraph_int_t num_matched; /* number of matched vertex pairs */ igraph_vector_int_t match; /* will store the matching */ igraph_vector_int_t labels; /* will store the labels */ igraph_vector_int_t neis; /* used to retrieve the neighbors of a node */ igraph_dqueue_int_t q; /* a FIFO for push ordering */ igraph_bool_t smaller_set; /* denotes which part of the bipartite graph is smaller */ - igraph_integer_t label_changed = 0; /* Counter to decide when to run a global relabeling */ - igraph_integer_t relabeling_freq = no_of_nodes / 2; + igraph_int_t label_changed = 0; /* Counter to decide when to run a global relabeling */ + igraph_int_t relabeling_freq = no_of_nodes / 2; /* We will use: * - FIFO push ordering @@ -369,8 +355,9 @@ static igraph_error_t igraph_i_maximum_bipartite_matching_unweighted( if (MATCHED(i)) { continue; } - IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, - IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, i, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); n = igraph_vector_int_size(&neis); for (j = 0; j < n; j++) { k = VECTOR(neis)[j]; @@ -402,9 +389,9 @@ static igraph_error_t igraph_i_maximum_bipartite_matching_unweighted( /* (6) Main loop from the referenced tech report -- lines 4--13 */ label_changed = 0; while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t v = igraph_dqueue_int_pop(&q); /* Line 13 */ - igraph_integer_t u = -1, label_u = 2 * no_of_nodes; - igraph_integer_t w; + igraph_int_t v = igraph_dqueue_int_pop(&q); /* Line 13 */ + igraph_int_t u = -1, label_u = 2 * no_of_nodes; + igraph_int_t w; if (label_changed >= relabeling_freq) { /* Run global relabeling */ @@ -416,8 +403,9 @@ static igraph_error_t igraph_i_maximum_bipartite_matching_unweighted( debug("Considering vertex %ld\n", v); /* Line 5: find row u among the neighbors of v s.t. label(u) is minimal */ - IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, - IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, v, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); n = igraph_vector_int_size(&neis); for (i = 0; i < n; i++) { if (VECTOR(labels)[VECTOR(neis)[i]] < label_u) { @@ -470,7 +458,7 @@ static igraph_error_t igraph_i_maximum_bipartite_matching_unweighted_relabel( const igraph_t *graph, const igraph_vector_bool_t *types, igraph_vector_int_t *labels, igraph_vector_int_t *match, igraph_bool_t smaller_set) { - igraph_integer_t i, j, n, no_of_nodes = igraph_vcount(graph), matched_to; + igraph_int_t i, j, n, no_of_nodes = igraph_vcount(graph), matched_to; igraph_dqueue_int_t q; igraph_vector_int_t neis; @@ -495,11 +483,12 @@ static igraph_error_t igraph_i_maximum_bipartite_matching_unweighted_relabel( /* Run the BFS */ while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t v = igraph_dqueue_int_pop(&q); - igraph_integer_t w; + igraph_int_t v = igraph_dqueue_int_pop(&q); + igraph_int_t w; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, - IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, v, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); n = igraph_vector_int_size(&neis); for (j = 0; j < n; j++) { @@ -538,11 +527,11 @@ static igraph_error_t igraph_i_maximum_bipartite_matching_unweighted_relabel( */ static igraph_error_t igraph_i_maximum_bipartite_matching_weighted( const igraph_t *graph, - const igraph_vector_bool_t *types, igraph_integer_t *matching_size, + const igraph_vector_bool_t *types, igraph_int_t *matching_size, igraph_real_t *matching_weight, igraph_vector_int_t *matching, const igraph_vector_t *weights, igraph_real_t eps) { - igraph_integer_t i, j, k, n, no_of_nodes, no_of_edges; - igraph_integer_t u, v, w, msize; + igraph_int_t i, j, k, n, no_of_nodes, no_of_edges; + igraph_int_t u, v, w, msize; igraph_t newgraph; igraph_vector_int_t match; /* will store the matching */ igraph_vector_t slack; /* will store the slack on each edge */ @@ -553,12 +542,12 @@ static igraph_error_t igraph_i_maximum_bipartite_matching_weighted( igraph_bool_t smaller_set_type; /* denotes which part of the bipartite graph is smaller */ igraph_vector_t smaller_set; /* stores the vertex IDs of the smaller set */ igraph_vector_t larger_set; /* stores the vertex IDs of the larger set */ - igraph_integer_t smaller_set_size; /* size of the smaller set */ - igraph_integer_t larger_set_size; /* size of the larger set */ + igraph_int_t smaller_set_size; /* size of the smaller set */ + igraph_int_t larger_set_size; /* size of the larger set */ igraph_real_t dual; /* solution of the dual problem */ IGRAPH_UNUSED(dual); /* We mark it as unused to prevent warnings about unused-but-set-variables. */ igraph_adjlist_t tight_phantom_edges; /* adjacency list to manage tight phantom edges */ - igraph_integer_t alternating_path_endpoint; + igraph_int_t alternating_path_endpoint; igraph_vector_int_t* neis; igraph_vector_int_t *neis2; igraph_inclist_t inclist; /* incidence list of the original graph */ @@ -670,7 +659,7 @@ static igraph_error_t igraph_i_maximum_bipartite_matching_weighted( /* (5) Main loop until the matching becomes maximal */ while (msize < smaller_set_size) { igraph_real_t min_slack, min_slack_2; - igraph_integer_t min_slack_u, min_slack_v; + igraph_int_t min_slack_u, min_slack_v; /* mark min_slack_u as unused; it is actually used when debugging, but * gcc complains when we are not debugging */ diff --git a/src/vendor/cigraph/src/misc/microscopic_update.c b/src/vendor/cigraph/src/misc/microscopic_update.c deleted file mode 100644 index 0cced87d827..00000000000 --- a/src/vendor/cigraph/src/misc/microscopic_update.c +++ /dev/null @@ -1,1209 +0,0 @@ -/* -*- mode: C -*- */ -/* - Microscopic update rules for dealing with agent-level strategy revision. - Copyright (C) 2011 Minh Van Nguyen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA -*/ - -#include "igraph_microscopic_update.h" - -#include "igraph_iterators.h" -#include "igraph_interface.h" -#include "igraph_random.h" -#include "igraph_error.h" - -/** - * Internal use only. - * Compute the cumulative proportionate values of a vector. The vector is - * assumed to hold values associated with edges. - * - * \param graph The graph object representing the game network. No error - * checks will be performed on this graph. You are responsible for - * ensuring that this is a valid graph for the particular - * microscopic update rule at hand. - * \param U A vector of edge values for which we want to compute cumulative - * proportionate values. So U[i] is the value of the edge with ID i. - * With a local perspective, we would only compute cumulative - * proportionate values for some combination of U. This vector could - * be, for example, a vector of weights for edges in \p graph. It is - * assumed that each value of U is nonnegative; it is your - * responsibility to ensure this. Furthermore, this vector must have a - * length the same as the number of edges in \p graph; you are - * responsible for ensuring this condition holds. - * \param V Pointer to an initialized vector. The cumulative proportionate - * values will be computed and stored here. No error checks will be - * performed on this parameter. - * \param islocal Boolean; this flag controls which perspective to use. If - * true then we use the local perspective; otherwise we use the global - * perspective. In the context of this function, the local perspective - * for a vertex v consists of all edges incident on v. In contrast, the - * global perspective for v consists of all edges in \p graph. - * \param vid The vertex to use if we are considering a local perspective, - * i.e. if \p islocal is true. This vertex will be ignored if - * \p islocal is false. That is, if \p islocal is false then it is safe - * pass the value -1 here. On the other hand, if \p islocal is true then - * it is assumed that this is indeed a vertex of \p graph. - * \param mode Defines the sort of neighbourhood to consider for \p vid. This - * is only relevant if we are considering the local perspective, i.e. if - * \p islocal is true. If we are considering the global perspective, - * then this parameter would be ignored. In other words, if \p islocal - * is false then it is safe to pass the value \p IGRAPH_ALL here. If - * \p graph is undirected, then we use all the immediate neighbours of - * \p vid. Thus if you know that \p graph is undirected, then it is - * safe to pass the value \p IGRAPH_ALL here. Supported values are: - * \clist - * \cli IGRAPH_OUT - * Use the out-neighbours of \p vid. This option is only relevant - * when \p graph is a digraph and we are considering the local - * perspective. - * \cli IGRAPH_IN - * Use the in-neighbours of \p vid. Again this option is only relevant - * when \p graph is a directed graph and we are considering the local - * perspective. - * \cli IGRAPH_ALL - * Use both the in- and out-neighbours of \p vid. This option is only - * relevant if \p graph is a digraph and we are considering a local - * perspective. Also use this value if \p graph is undirected or we - * are considering the global perspective. - * \endclist - * \return Codes: - * \clist - * \cli IGRAPH_EINVAL - * This error code is returned in the following case: The vector - * \p U, or some combination of its values, sums to zero. - * \cli IGRAPH_SUCCESS - * This signal is returned if the cumulative proportionate values - * were successfully computed. - * \endclist - * - * Time complexity: O(2n) where n is the number of edges in the perspective - * of \p vid. - */ - -static igraph_error_t igraph_i_ecumulative_proportionate_values(const igraph_t *graph, - const igraph_vector_t *U, - igraph_vector_t *V, - igraph_bool_t islocal, - igraph_integer_t vid, - igraph_neimode_t mode) { - igraph_eit_t A; /* all edges in v's perspective */ - igraph_es_t es; - igraph_integer_t e; - igraph_real_t C; /* cumulative probability */ - igraph_real_t P; /* probability */ - igraph_real_t S; /* sum of values */ - igraph_integer_t i; - - /* Set the perspective. Let v be the vertex under consideration. The local */ - /* perspective for v consists of edges incident on it. In contrast, the */ - /* global perspective for v are all edges in the given graph. Hence in the */ - /* global perspective, we will ignore the given vertex and the given */ - /* neighbourhood type, but instead consider all edges in the given graph. */ - if (islocal) { - IGRAPH_CHECK(igraph_es_incident(&es, vid, mode)); - } else { - IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID)); - } - IGRAPH_FINALLY(igraph_es_destroy, &es); - - /* Sum up all the values of vector U in the perspective for v. This sum */ - /* will be used in normalizing each value. */ - /* NOTE: Here we assume that each value to be summed is nonnegative, */ - /* and at least one of the values is nonzero. The behaviour resulting */ - /* from all values being zero would be division by zero later on when */ - /* we normalize each value. We check to see that the values sum to zero. */ - /* NOTE: In this function, the order in which we iterate through the */ - /* edges of interest should be the same as the order in which we do so */ - /* in the caller function. If the caller function doesn't care about the */ - /* order of values in the resulting vector V, then there's no need to take */ - /* special notice of that order. But in some cases the order of values in */ - /* V is taken into account, for example, in the Moran process. */ - S = 0.0; - IGRAPH_CHECK(igraph_eit_create(graph, es, &A)); - IGRAPH_FINALLY(igraph_eit_destroy, &A); - while (!IGRAPH_EIT_END(A)) { - e = IGRAPH_EIT_GET(A); - S += VECTOR(*U)[e]; - IGRAPH_EIT_NEXT(A); - } - /* avoid division by zero later on */ - if (S == 0.0) { - igraph_eit_destroy(&A); - igraph_es_destroy(&es); - IGRAPH_FINALLY_CLEAN(2); - IGRAPH_ERROR("Vector of values sums to zero", IGRAPH_EINVAL); - } - - /* Get cumulative probability and relative value for each edge in the */ - /* perspective of v. The vector V holds the cumulative proportionate */ - /* values of all edges in v's perspective. The value V[0] is the */ - /* cumulative proportionate value of the first edge in the edge iterator */ - /* A. The value V[1] is the cumulative proportionate value of the second */ - /* edge in the iterator A. And so on. */ - C = 0.0; - i = 0; - IGRAPH_EIT_RESET(A); - IGRAPH_CHECK(igraph_vector_resize(V, IGRAPH_EIT_SIZE(A))); - while (!IGRAPH_EIT_END(A)) { - e = IGRAPH_EIT_GET(A); - /* NOTE: Beware of division by zero here. This can happen if the vector */ - /* of values, or the combination of interest, sums to zero. */ - P = VECTOR(*U)[e] / S; - C += P; - VECTOR(*V)[i] = C; - i++; - IGRAPH_EIT_NEXT(A); - } - - igraph_eit_destroy(&A); - igraph_es_destroy(&es); - - /* Pop A and es from the finally stack -- that's three items */ - IGRAPH_FINALLY_CLEAN(2); - - return IGRAPH_SUCCESS; -} - -/** - * Internal use only. - * Compute the cumulative proportionate values of a vector. The vector is - * assumed to hold values associated with vertices. - * - * \param graph The graph object representing the game network. No error - * checks will be performed on this graph. You are responsible for - * ensuring that this is a valid graph for the particular - * microscopic update rule at hand. - * \param U A vector of vertex values for which we want to compute cumulative - * proportionate values. The vector could be, for example, a vector of - * fitness for vertices of \p graph. It is assumed that each value of U - * is nonnegative; it is your responsibility to ensure this. Also U, or - * a combination of interest, is assumed to sum to a positive value; - * this condition will be checked. - * \param V Pointer to an initialized vector. The cumulative proportionate - * values will be computed and stored here. No error checks will be - * performed on this parameter. - * \param islocal Boolean; this flag controls which perspective to use. If - * true then we use the local perspective; otherwise we use the global - * perspective. The local perspective for a vertex v is the set of all - * immediate neighbours of v. In contrast, the global perspective - * for v is the vertex set of \p graph. - * \param vid The vertex to use if we are considering a local perspective, - * i.e. if \p islocal is true. This vertex will be ignored if - * \p islocal is false. That is, if \p islocal is false then it is safe - * pass the value -1 here. On the other hand, if \p islocal is true then - * it is assumed that this is indeed a vertex of \p graph. - * \param mode Defines the sort of neighbourhood to consider for \p vid. This - * is only relevant if we are considering the local perspective, i.e. if - * \p islocal is true. If we are considering the global perspective, - * then this parameter would be ignored. In other words, if \p islocal - * is false then it is safe to pass the value \p IGRAPH_ALL here. If - * \p graph is undirected, then we use all the immediate neighbours of - * \p vid. Thus if you know that \p graph is undirected, then it is - * safe to pass the value \p IGRAPH_ALL here. Supported values are: - * \clist - * \cli IGRAPH_OUT - * Use the out-neighbours of \p vid. This option is only relevant - * when \p graph is a digraph and we are considering the local - * perspective. - * \cli IGRAPH_IN - * Use the in-neighbours of \p vid. Again this option is only relevant - * when \p graph is a directed graph and we are considering the local - * perspective. - * \cli IGRAPH_ALL - * Use both the in- and out-neighbours of \p vid. This option is only - * relevant if \p graph is a digraph and we are considering a local - * perspective. Also use this value if \p graph is undirected or we - * are considering the global perspective. - * \endclist - * \return Codes: - * \clist - * \cli IGRAPH_EINVAL - * This error code is returned in the following case: The vector - * \p U, or some combination of its values, sums to zero. - * \cli IGRAPH_SUCCESS - * This signal is returned if the cumulative proportionate values - * were successfully computed. - * \endclist - * - * Time complexity: O(2n) where n is the number of vertices in the - * perspective of vid. - */ - -static igraph_error_t igraph_i_vcumulative_proportionate_values(const igraph_t *graph, - const igraph_vector_t *U, - igraph_vector_t *V, - igraph_bool_t islocal, - igraph_integer_t vid, - igraph_neimode_t mode) { - igraph_integer_t v; - igraph_real_t C; /* cumulative probability */ - igraph_real_t P; /* probability */ - igraph_real_t S; /* sum of values */ - igraph_vit_t A; /* all vertices in v's perspective */ - igraph_vs_t vs; - igraph_integer_t i; - - /* Set the perspective. Let v be the vertex under consideration; it might */ - /* be that we want to update v's strategy. The local perspective for v */ - /* consists of its immediate neighbours. In contrast, the global */ - /* perspective for v are all the vertices in the given graph. Hence in the */ - /* global perspective, we will ignore the given vertex and the given */ - /* neighbourhood type, but instead consider all vertices in the given */ - /* graph. */ - if (islocal) { - IGRAPH_CHECK(igraph_vs_adj(&vs, vid, mode)); - } else { - IGRAPH_CHECK(igraph_vs_all(&vs)); - } - IGRAPH_FINALLY(igraph_vs_destroy, &vs); - - /* Sum up all the values of vector U in the perspective for v. This */ - /* sum will be used in normalizing each value. If we are using a local */ - /* perspective, then we also need to consider the quantity of v in */ - /* computing the sum. */ - /* NOTE: Here we assume that each value to be summed is nonnegative, */ - /* and at least one of the values is nonzero. The behaviour resulting */ - /* from all values being zero would be division by zero later on when */ - /* we normalize each value. We check to see that the values sum to zero. */ - /* NOTE: In this function, the order in which we iterate through the */ - /* vertices of interest should be the same as the order in which we do so */ - /* in the caller function. If the caller function doesn't care about the */ - /* order of values in the resulting vector V, then there's no need to take */ - /* special notice of that order. But in some cases the order of values in */ - /* V is taken into account, for example, in roulette wheel selection. */ - S = 0.0; - IGRAPH_CHECK(igraph_vit_create(graph, vs, &A)); - IGRAPH_FINALLY(igraph_vit_destroy, &A); - while (!IGRAPH_VIT_END(A)) { - v = IGRAPH_VIT_GET(A); - S += VECTOR(*U)[v]; - IGRAPH_VIT_NEXT(A); - } - if (islocal) { - S += VECTOR(*U)[vid]; - } - /* avoid division by zero later on */ - if (S == 0.0) { - igraph_vit_destroy(&A); - igraph_vs_destroy(&vs); - IGRAPH_FINALLY_CLEAN(2); - IGRAPH_ERROR("Vector of values sums to zero", IGRAPH_EINVAL); - } - - /* Get cumulative probability and relative value for each vertex in the */ - /* perspective of v. The vector V holds the cumulative proportionate */ - /* values of all vertices in v's perspective. The value V[0] is the */ - /* cumulative proportionate value of the first vertex in the vertex */ - /* iterator A. The value V[1] is the cumulative proportionate value of */ - /* the second vertex in the iterator A. And so on. If we are using the */ - /* local perspective, then we also need to consider the cumulative */ - /* proportionate value of v. In the case of the local perspective, we */ - /* don't need to compute and store v's cumulative proportionate value, */ - /* but we pretend that such value is appended to the vector V. */ - C = 0.0; - i = 0; - IGRAPH_VIT_RESET(A); - IGRAPH_CHECK(igraph_vector_resize(V, IGRAPH_VIT_SIZE(A))); - while (!IGRAPH_VIT_END(A)) { - v = IGRAPH_VIT_GET(A); - /* NOTE: Beware of division by zero here. This can happen if the vector */ - /* of values, or a combination of interest, sums to zero. */ - P = VECTOR(*U)[v] / S; - C += P; - VECTOR(*V)[i] = C; - i++; - IGRAPH_VIT_NEXT(A); - } - - igraph_vit_destroy(&A); - igraph_vs_destroy(&vs); - - /* Pop A and vs from the finally stack -- that's two items */ - IGRAPH_FINALLY_CLEAN(2); - - return IGRAPH_SUCCESS; -} - -/** - * Internal use only. - * A set of standard tests to be performed prior to strategy updates. The - * tests contained in this function are common to many strategy revision - * functions in this file. This function is meant to be invoked from within - * a specific strategy update function in order to perform certain common - * tests, including sanity checks and conditions under which no strategy - * updates are necessary. - * - * \param graph The graph object representing the game network. This cannot - * be the empty or trivial graph, but must have at least two vertices - * and one edge. If \p graph has one vertex, then no strategy update - * would take place. Furthermore, if \p graph has at least two vertices - * but zero edges, then strategy update would also not take place. - * \param vid The vertex whose strategy is to be updated. It is assumed that - * \p vid represents a vertex in \p graph. No checking is performed and - * it is your responsibility to ensure that \p vid is indeed a vertex - * of \p graph. If an isolated vertex is provided, i.e. the input - * vertex has degree 0, then no strategy update would take place and - * \p vid would retain its current strategy. Strategy update would also - * not take place if the local neighbourhood of \p vid are its - * in-neighbours (respectively out-neighbours), but \p vid has zero - * in-neighbours (respectively out-neighbours). Loops are ignored in - * computing the degree (in, out, all) of \p vid. - * \param quantities A vector of quantities providing the quantity of each - * vertex in \p graph. Think of each entry of the vector as being - * generated by a function such as the fitness function for the game. - * So if the vector represents fitness quantities, then each vector - * entry is the fitness of some vertex. The length of this vector must - * be the same as the number of vertices in the vertex set of \p graph. - * \param strategies A vector of the current strategies for the vertex - * population. Each strategy is identified with a nonnegative integer, - * whose interpretation depends on the payoff matrix of the game. - * Generally we use the strategy ID as a row or column index of the - * payoff matrix. The length of this vector must be the same as the - * number of vertices in the vertex set of \p graph. - * \param mode Defines the sort of neighbourhood to consider for \p vid. If - * \p graph is undirected, then we use all the immediate neighbours of - * \p vid. Thus if you know that \p graph is undirected, then it is safe - * to pass the value \p IGRAPH_ALL here. Supported values are: - * \clist - * \cli IGRAPH_OUT - * Use the out-neighbours of \p vid. This option is only relevant - * when \p graph is a directed graph. - * \cli IGRAPH_IN - * Use the in-neighbours of \p vid. Again this option is only relevant - * when \p graph is a directed graph. - * \cli IGRAPH_ALL - * Use both the in- and out-neighbours of \p vid. This option is only - * relevant if \p graph is a digraph. Also use this value if - * \p graph is undirected. - * \endclist - * \param updates Boolean; at the end of this test suite, this flag - * indicates whether to proceed with strategy revision. If true then - * strategy revision should proceed; otherwise there is no need to - * continue with revising a vertex's strategy. A caller function that - * invokes this function would use the value of \p updates to - * determine whether to proceed with strategy revision. - * \param islocal Boolean; this flag controls which perspective to use. If - * true then we use the local perspective; otherwise we use the global - * perspective. The local perspective for \p vid is the set of all - * immediate neighbours of \p vid. In contrast, the global perspective - * for \p vid is the vertex set of \p graph. - * \return Codes: - * \clist - * \cli IGRAPH_EINVAL - * This error code is returned in each of the following cases: - * (1) Any of the parameters \p graph, \p quantities, or - * \p strategies is a null pointer. (2) The vector \p quantities - * or \p strategies has a length different from the number of - * vertices in \p graph. (3) The parameter \p graph is the empty - * or null graph, i.e. the graph with zero vertices and edges. - * \cli IGRAPH_SUCCESS - * This signal is returned if no errors were raised. You should use - * the value of the boolean \p updates to decide whether to go - * ahead with updating a vertex's strategy. - * \endclist - */ - -static igraph_error_t igraph_i_microscopic_standard_tests(const igraph_t *graph, - igraph_integer_t vid, - const igraph_vector_t *quantities, - const igraph_vector_int_t *strategies, - igraph_neimode_t mode, - igraph_bool_t *updates, - igraph_bool_t islocal) { - - igraph_integer_t nvert; - igraph_vector_int_t degv; - *updates = true; - - /* sanity checks */ - if (graph == NULL) { - IGRAPH_ERROR("Graph is a null pointer", IGRAPH_EINVAL); - } - if (quantities == NULL) { - IGRAPH_ERROR("Quantities vector is a null pointer", IGRAPH_EINVAL); - } - if (strategies == NULL) { - IGRAPH_ERROR("Strategies vector is a null pointer", IGRAPH_EINVAL); - } - - /* the empty graph */ - nvert = igraph_vcount(graph); - if (nvert < 1) { - IGRAPH_ERROR("Graph cannot be the empty graph", IGRAPH_EINVAL); - } - /* invalid vector length */ - if (nvert != igraph_vector_size(quantities)) { - IGRAPH_ERROR("Size of quantities vector different from number of vertices", - IGRAPH_EINVAL); - } - if (nvert != igraph_vector_int_size(strategies)) { - IGRAPH_ERROR("Size of strategies vector different from number of vertices", - IGRAPH_EINVAL); - } - - /* Various conditions under which no strategy updates will take place. That - * is, the vertex retains its current strategy. - */ - /* given graph has < 2 vertices */ - if (nvert < 2) { - *updates = false; - } - /* graph has >= 2 vertices, but no edges */ - if (igraph_ecount(graph) < 1) { - *updates = false; - } - - /* Test for vertex isolation, depending on the perspective given. For - * undirected graphs, a given vertex v is isolated if its degree is zero. - * If we are considering in-neighbours (respectively out-neighbours), then - * we say that v is isolated if its in-degree (respectively out-degree) is - * zero. In general, this vertex isolation test is only relevant if we are - * using a local perspective, i.e. if we only consider the immediate - * neighbours (local perspective) of v as opposed to all vertices in the - * vertex set of the graph (global perspective). - */ - if (islocal) { - /* Moving on ahead with vertex isolation test, since local perspective */ - /* is requested. */ - IGRAPH_VECTOR_INT_INIT_FINALLY(°v, 1); - IGRAPH_CHECK(igraph_degree(graph, °v, igraph_vss_1(vid), - mode, IGRAPH_NO_LOOPS)); - if (VECTOR(degv)[0] < 1) { - *updates = false; - } - igraph_vector_int_destroy(°v); - IGRAPH_FINALLY_CLEAN(1); - } - - return IGRAPH_SUCCESS; -} - -/** - * \ingroup spatialgames - * \function igraph_deterministic_optimal_imitation - * \brief Adopt a strategy via deterministic optimal imitation. - * - * A simple deterministic imitation strategy where a vertex revises its - * strategy to that which yields a local optimum. Here "local" is with - * respect to the immediate neighbours of the vertex. The vertex retains its - * current strategy where this strategy yields a locally optimal quantity. - * The quantity in this case could be a measure such as fitness. - * - * \param graph The graph object representing the game network. This cannot - * be the empty or trivial graph, but must have at least two vertices - * and one edge. If \p graph has one vertex, then no strategy update - * would take place. Furthermore, if \p graph has at least two vertices - * but zero edges, then strategy update would also not take place. - * \param vid The vertex whose strategy is to be updated. It is assumed that - * \p vid represents a vertex in \p graph. No checking is performed and - * it is your responsibility to ensure that \p vid is indeed a vertex - * of \p graph. If an isolated vertex is provided, i.e. the input - * vertex has degree 0, then no strategy update would take place and - * \p vid would retain its current strategy. Strategy update would also - * not take place if the local neighbourhood of \p vid are its - * in-neighbours (respectively out-neighbours), but \p vid has zero - * in-neighbours (respectively out-neighbours). Loops are ignored in - * computing the degree (in, out, all) of \p vid. - * \param optimality Boolean; controls the type of optimality to be used. - * Supported values are: - * \clist - * \cli IGRAPH_MAXIMUM - * Use maximum deterministic imitation, where the strategy of the - * vertex with maximum quantity (e.g. fitness) would be adopted. We - * update the strategy of \p vid to that which yields a local - * maximum. - * \cli IGRAPH_MINIMUM - * Use minimum deterministic imitation. That is, the strategy of the - * vertex with minimum quantity would be imitated. In other words, - * update to the strategy that yields a local minimum. - * \endclist - * \param quantities A vector of quantities providing the quantity of each - * vertex in \p graph. Think of each entry of the vector as being - * generated by a function such as the fitness function for the game. - * So if the vector represents fitness quantities, then each vector - * entry is the fitness of some vertex. The length of this vector must - * be the same as the number of vertices in the vertex set of \p graph. - * \param strategies A vector of the current strategies for the vertex - * population. The updated strategy for \p vid would be stored here. - * Each strategy is identified with a nonnegative integer, whose - * interpretation depends on the payoff matrix of the game. Generally - * we use the strategy ID as a row or column index of the payoff - * matrix. The length of this vector must be the same as the number of - * vertices in the vertex set of \p graph. - * \param mode Defines the sort of neighbourhood to consider for \p vid. If - * \p graph is undirected, then we use all the immediate neighbours of - * \p vid. Thus if you know that \p graph is undirected, then it is safe - * to pass the value \p IGRAPH_ALL here. Supported values are: - * \clist - * \cli IGRAPH_OUT - * Use the out-neighbours of \p vid. This option is only relevant - * when \p graph is a directed graph. - * \cli IGRAPH_IN - * Use the in-neighbours of \p vid. Again this option is only relevant - * when \p graph is a directed graph. - * \cli IGRAPH_ALL - * Use both the in- and out-neighbours of \p vid. This option is only - * relevant if \p graph is a digraph. Also use this value if - * \p graph is undirected. - * \endclist - * \return The error code \p IGRAPH_EINVAL is returned in each of the - * following cases: (1) Any of the parameters \p graph, \p quantities, - * or \p strategies is a null pointer. (2) The vector \p quantities - * or \p strategies has a length different from the number of vertices - * in \p graph. (3) The parameter \p graph is the empty or null graph, - * i.e. the graph with zero vertices and edges. - * - * Time complexity: O(2d), where d is the degree of the vertex \p vid. - * - * \example examples/simple/igraph_deterministic_optimal_imitation.c - */ - -igraph_error_t igraph_deterministic_optimal_imitation(const igraph_t *graph, - igraph_integer_t vid, - igraph_optimal_t optimality, - const igraph_vector_t *quantities, - igraph_vector_int_t *strategies, - igraph_neimode_t mode) { - igraph_integer_t i, k, v; - igraph_real_t q; - igraph_vector_int_t adj; - igraph_bool_t updates; - - IGRAPH_CHECK(igraph_i_microscopic_standard_tests(graph, vid, quantities, - strategies, mode, &updates, - /*is local?*/ true)); - if (!updates) { - return IGRAPH_SUCCESS; /* Nothing to do */ - } - - /* Choose a locally optimal strategy to imitate. This can be either maximum - * or minimum deterministic imitation. By now we know that the given vertex v - * has degree >= 1 and at least 1 edge. Then within its immediate - * neighbourhood adj(v) and including v itself, there exists a vertex whose - * strategy yields a local optimal quantity. - */ - /* Random permutation of adj(v). This ensures that if there are multiple */ - /* candidates with an optimal strategy, then we choose one such candidate */ - /* at random. */ - IGRAPH_VECTOR_INT_INIT_FINALLY(&adj, 0); - IGRAPH_CHECK(igraph_neighbors(graph, &adj, vid, mode)); - IGRAPH_CHECK(igraph_vector_int_shuffle(&adj)); - /* maximum deterministic imitation */ - i = vid; - q = VECTOR(*quantities)[vid]; - if (optimality == IGRAPH_MAXIMUM) { - for (k = 0; k < igraph_vector_int_size(&adj); k++) { - v = VECTOR(adj)[k]; - if (VECTOR(*quantities)[v] > q) { - i = v; - q = VECTOR(*quantities)[v]; - } - } - } else { /* minimum deterministic imitation */ - for (k = 0; k < igraph_vector_int_size(&adj); k++) { - v = VECTOR(adj)[k]; - if (VECTOR(*quantities)[v] < q) { - i = v; - q = VECTOR(*quantities)[v]; - } - } - } - /* Now i is a vertex with a locally optimal quantity, the value of which */ - /* is q. Update the strategy of vid to that of i. */ - VECTOR(*strategies)[vid] = VECTOR(*strategies)[i]; - igraph_vector_int_destroy(&adj); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} - -/** - * \ingroup spatialgames - * \function igraph_moran_process - * \brief The Moran process in a network setting. - * - * This is an extension of the classic Moran process to a network setting. - * The Moran process is a model of haploid (asexual) reproduction within a - * population having a fixed size. In the network setting, the Moran process - * operates on a weighted graph. At each time step a vertex a is chosen for - * reproduction and another vertex b is chosen for death. Vertex a gives birth - * to an identical clone c, which replaces b. Vertex c is a clone of a in that - * c inherits both the current quantity (e.g. fitness) and current strategy - * of a. - * - * - * The graph G representing the game network is assumed to be simple, - * i.e. free of loops and without multiple edges. If, on the other hand, G has - * a loop incident on some vertex v, then it is possible that when v is chosen - * for reproduction it would forgo this opportunity. In particular, when v is - * chosen for reproduction and v is also chosen for death, the clone of v - * would be v itself with its current vertex ID. In effect v forgoes its - * chance for reproduction. - * - * \param graph The graph object representing the game network. This cannot - * be the empty or trivial graph, but must have at least two vertices - * and one edge. The Moran process will not take place in each of the - * following cases: (1) If \p graph has one vertex. (2) If \p graph has - * at least two vertices but zero edges. - * \param weights A vector of all edge weights for \p graph. Thus weights[i] - * means the weight of the edge with edge ID i. For the purpose of the - * Moran process, each weight is assumed to be positive; it is your - * responsibility to ensure this condition holds. The length of this - * vector must be the same as the number of edges in \p graph. - * \param quantities A vector of quantities providing the quantity of each - * vertex in \p graph. The quantity of the new clone will be stored - * here. Think of each entry of the vector as being generated by a - * function such as the fitness function for the game. So if the vector - * represents fitness quantities, then each vector entry is the fitness - * of some vertex. The length of this vector must be the same as the - * number of vertices in the vertex set of \p graph. For the purpose of - * the Moran process, each vector entry is assumed to be nonnegative; - * no checks will be performed for this. It is your responsibility to - * ensure that at least one entry is positive. Furthermore, this vector - * cannot be a vector of zeros; this condition will be checked. - * \param strategies A vector of the current strategies for the vertex - * population. The strategy of the new clone will be stored here. Each - * strategy is identified with a nonnegative integer, whose - * interpretation depends on the payoff matrix of the game. Generally - * we use the strategy ID as a row or column index of the payoff - * matrix. The length of this vector must be the same as the number of - * vertices in the vertex set of \p graph. - * \param mode Defines the sort of neighbourhood to consider for the vertex a - * chosen for reproduction. This is only relevant if \p graph is - * directed. If \p graph is undirected, then it is safe to pass the - * value \p IGRAPH_ALL here. Supported values are: - * \clist - * \cli IGRAPH_OUT - * Use the out-neighbours of a. This option is only relevant when - * \p graph is directed. - * \cli IGRAPH_IN - * Use the in-neighbours of a. Again this option is only relevant - * when \p graph is directed. - * \cli IGRAPH_ALL - * Use both the in- and out-neighbours of a. This option is only - * relevant if \p graph is directed. Also use this value if - * \p graph is undirected. - * \endclist - * \return The error code \p IGRAPH_EINVAL is returned in each of the following - * cases: (1) Any of the parameters \p graph, \p weights, - * \p quantities or \p strategies is a null pointer. (2) The vector - * \p quantities or \p strategies has a length different from the - * number of vertices in \p graph. (3) The vector \p weights has a - * length different from the number of edges in \p graph. (4) The - * parameter \p graph is the empty or null graph, i.e. the graph with - * zero vertices and edges. (5) The vector \p weights, or the - * combination of interest, sums to zero. (6) The vector \p quantities, - * or the combination of interest, sums to zero. - * - * Time complexity: depends on the random number generator, but is usually - * O(n) where n is the number of vertices in \p graph. - * - * - * References: - * \clist - * \cli (Lieberman et al. 2005) - * E. Lieberman, C. Hauert, and M. A. Nowak. Evolutionary dynamics on - * graphs. \emb Nature, \eme 433(7023):312--316, 2005. - * \cli (Moran 1958) - * P. A. P. Moran. Random processes in genetics. \emb Mathematical - * Proceedings of the Cambridge Philosophical Society, \eme 54(1):60--71, - * 1958. - * \endclist - */ - -igraph_error_t igraph_moran_process(const igraph_t *graph, - const igraph_vector_t *weights, - igraph_vector_t *quantities, - igraph_vector_int_t *strategies, - igraph_neimode_t mode) { - igraph_bool_t updates; - igraph_integer_t a = -1; /* vertex chosen for reproduction */ - igraph_integer_t b = -1; /* vertex chosen for death */ - igraph_integer_t e, nedge, u, v; - igraph_real_t r; /* random number */ - igraph_vector_int_t deg; - igraph_vector_t V; /* vector of cumulative proportionate values */ - igraph_vit_t vA; /* vertex list */ - igraph_eit_t eA; /* edge list */ - igraph_vs_t vs; - igraph_es_t es; - igraph_integer_t i; - - /* don't test for vertex isolation, hence vid = -1 and islocal = 0 */ - IGRAPH_CHECK(igraph_i_microscopic_standard_tests(graph, /*vid*/ -1, - quantities, strategies, mode, - &updates, /*is local?*/ false)); - if (!updates) { - return IGRAPH_SUCCESS; /* nothing more to do */ - } - if (weights == NULL) { - IGRAPH_ERROR("Weights vector is a null pointer", IGRAPH_EINVAL); - } - nedge = igraph_ecount(graph); - if (nedge != igraph_vector_size(weights)) { - IGRAPH_ERROR("Size of weights vector different from number of edges", - IGRAPH_EINVAL); - } - - IGRAPH_VECTOR_INIT_FINALLY(&V, 0); - - /* Cumulative proportionate quantities. We are using the global */ - /* perspective, hence islocal = 0, vid = -1 and mode = IGRAPH_ALL. */ - IGRAPH_CHECK(igraph_i_vcumulative_proportionate_values(graph, quantities, &V, - /*is local?*/ false, - /*vid*/ -1, - /*mode*/ IGRAPH_ALL)); - - /* Choose a vertex for reproduction from among all vertices in the graph. */ - /* The vertex is chosen proportionate to its quantity and such that its */ - /* degree is >= 1. In case we are considering in-neighbours (respectively */ - /* out-neighbours), the chosen vertex must have in-degree (respectively */ - /* out-degree) >= 1. All loops will be ignored. At this point, we know */ - /* that the graph has at least one edge, which may be directed or not. */ - /* Furthermore the quantities of all vertices sum to a positive value. */ - /* Hence at least one vertex will be chosen for reproduction. */ - IGRAPH_CHECK(igraph_vs_all(&vs)); - IGRAPH_FINALLY(igraph_vs_destroy, &vs); - IGRAPH_CHECK(igraph_vit_create(graph, vs, &vA)); - IGRAPH_FINALLY(igraph_vit_destroy, &vA); - RNG_BEGIN(); - r = RNG_UNIF01(); - RNG_END(); - i = 0; - IGRAPH_VECTOR_INT_INIT_FINALLY(°, 1); - while (!IGRAPH_VIT_END(vA)) { - u = IGRAPH_VIT_GET(vA); - IGRAPH_CHECK(igraph_degree(graph, °, igraph_vss_1(u), mode, - IGRAPH_NO_LOOPS)); - if (VECTOR(deg)[0] < 1) { - i++; - IGRAPH_VIT_NEXT(vA); - continue; - } - if (r <= VECTOR(V)[i]) { - /* we have found our candidate vertex for reproduction */ - a = u; - break; - } - i++; - IGRAPH_VIT_NEXT(vA); - } - /* By now we should have chosen a vertex for reproduction. Check this. */ - IGRAPH_ASSERT(a >= 0); - - /* Cumulative proportionate weights. We are using the local perspective */ - /* with respect to vertex a, which has been chosen for reproduction. */ - /* The degree of a is deg(a) >= 1 with respect to the mode "mode", which */ - /* can flag either the in-degree, out-degree or all degree of a. But it */ - /* still might happen that the edge weights of interest would sum to zero. */ - /* An error would be raised in that case. */ - IGRAPH_CHECK(igraph_i_ecumulative_proportionate_values(graph, weights, &V, - /*is local?*/ true, - /*vertex*/ a, mode)); - - /* Choose a vertex for death from among all vertices in a's perspective. */ - /* Let E be all the edges in the perspective of a. If (u,v) \in E is any */ - /* such edge, then we have a = u or a = v. That is, any edge in E has a */ - /* for one of its endpoints. As G is assumed to be a simple graph, then */ - /* exactly one of u or v is the vertex a. Without loss of generality, we */ - /* assume that each edge in E has the form (a, v_i). Then the vertex v_j */ - /* chosen for death is chosen proportionate to the weight of the edge */ - /* (a, v_j). */ - IGRAPH_CHECK(igraph_es_incident(&es, a, mode)); - IGRAPH_FINALLY(igraph_es_destroy, &es); - IGRAPH_CHECK(igraph_eit_create(graph, es, &eA)); - IGRAPH_FINALLY(igraph_eit_destroy, &eA); - RNG_BEGIN(); - r = RNG_UNIF01(); - RNG_END(); - i = 0; - while (!IGRAPH_EIT_END(eA)) { - e = IGRAPH_EIT_GET(eA); - if (r <= VECTOR(V)[i]) { - /* We have found our candidate vertex for death; call this vertex b. */ - /* As G is simple, then a =/= b. Check the latter condition. */ - IGRAPH_CHECK(igraph_edge(graph, /*edge ID*/ e, - /*tail vertex*/ &u, /*head vertex*/ &v)); - if (a == u) { - b = v; - } else { - b = u; - } - IGRAPH_ASSERT(a != b); /* always true if G is simple */ - break; - } - i++; - IGRAPH_EIT_NEXT(eA); - } - - /* By now a vertex a is chosen for reproduction and a vertex b is chosen */ - /* for death. Check that b has indeed been chosen. Clone vertex a and kill */ - /* vertex b. Let the clone c have the vertex ID of b, and the strategy and */ - /* quantity of a. */ - IGRAPH_ASSERT(b >= 0); - VECTOR(*quantities)[b] = VECTOR(*quantities)[a]; - VECTOR(*strategies)[b] = VECTOR(*strategies)[a]; - - igraph_eit_destroy(&eA); - igraph_es_destroy(&es); - igraph_vector_int_destroy(°); - igraph_vit_destroy(&vA); - igraph_vs_destroy(&vs); - igraph_vector_destroy(&V); - IGRAPH_FINALLY_CLEAN(6); - - return IGRAPH_SUCCESS; -} - -/** - * \ingroup spatialgames - * \function igraph_roulette_wheel_imitation - * \brief Adopt a strategy via roulette wheel selection. - * - * A simple stochastic imitation strategy where a vertex revises its - * strategy to that of a vertex u chosen proportionate to u's quantity - * (e.g. fitness). This is a special case of stochastic imitation, where a - * candidate is not chosen uniformly at random but proportionate to its - * quantity. - * - * \param graph The graph object representing the game network. This cannot - * be the empty or trivial graph, but must have at least two vertices - * and one edge. If \p graph has one vertex, then no strategy update - * would take place. Furthermore, if \p graph has at least two vertices - * but zero edges, then strategy update would also not take place. - * \param vid The vertex whose strategy is to be updated. It is assumed that - * \p vid represents a vertex in \p graph. No checking is performed and - * it is your responsibility to ensure that \p vid is indeed a vertex - * of \p graph. If an isolated vertex is provided, i.e. the input - * vertex has degree 0, then no strategy update would take place and - * \p vid would retain its current strategy. Strategy update would also - * not take place if the local neighbourhood of \p vid are its - * in-neighbours (respectively out-neighbours), but \p vid has zero - * in-neighbours (respectively out-neighbours). Loops are ignored in - * computing the degree (in, out, all) of \p vid. - * \param islocal Boolean; this flag controls which perspective to use in - * computing the relative quantity. If true then we use the local - * perspective; otherwise we use the global perspective. The local - * perspective for \p vid is the set of all immediate neighbours of - * \p vid. In contrast, the global perspective for \p vid is the - * vertex set of \p graph. - * \param quantities A vector of quantities providing the quantity of each - * vertex in \p graph. Think of each entry of the vector as being - * generated by a function such as the fitness function for the game. - * So if the vector represents fitness quantities, then each vector - * entry is the fitness of some vertex. The length of this vector must - * be the same as the number of vertices in the vertex set of \p graph. - * For the purpose of roulette wheel selection, each vector entry is - * assumed to be nonnegative; no checks will be performed for this. It - * is your responsibility to ensure that at least one entry is nonzero. - * Furthermore, this vector cannot be a vector of zeros; this condition - * will be checked. - * \param strategies A vector of the current strategies for the vertex - * population. The updated strategy for \p vid would be stored here. - * Each strategy is identified with a nonnegative integer, whose - * interpretation depends on the payoff matrix of the game. Generally - * we use the strategy ID as a row or column index of the payoff - * matrix. The length of this vector must be the same as the number of - * vertices in the vertex set of \p graph. - * \param mode Defines the sort of neighbourhood to consider for \p vid. This - * is only relevant if we are considering the local perspective, i.e. if - * \p islocal is true. If we are considering the global perspective, - * then it is safe to pass the value \p IGRAPH_ALL here. If \p graph is - * undirected, then we use all the immediate neighbours of \p vid. Thus - * if you know that \p graph is undirected, then it is safe to pass the - * value \p IGRAPH_ALL here. Supported values are: - * \clist - * \cli IGRAPH_OUT - * Use the out-neighbours of \p vid. This option is only relevant - * when \p graph is a digraph and we are considering the local - * perspective. - * \cli IGRAPH_IN - * Use the in-neighbours of \p vid. Again this option is only relevant - * when \p graph is a directed graph and we are considering the local - * perspective. - * \cli IGRAPH_ALL - * Use both the in- and out-neighbours of \p vid. This option is only - * relevant if \p graph is a digraph. Also use this value if - * \p graph is undirected or we are considering the global - * perspective. - * \endclist - * \return The error code \p IGRAPH_EINVAL is returned in each of the following - * cases: (1) Any of the parameters \p graph, \p quantities, or - * \p strategies is a null pointer. (2) The vector \p quantities or - * \p strategies has a length different from the number of vertices - * in \p graph. (3) The parameter \p graph is the empty or null graph, - * i.e. the graph with zero vertices and edges. (4) The vector - * \p quantities sums to zero. - * - * Time complexity: O(n) where n is the number of vertices in the perspective - * to consider. If we consider the global perspective, then n is the number - * of vertices in the vertex set of \p graph. On the other hand, for the local - * perspective n is the degree of \p vid, excluding loops. - * - * - * Reference: - * \clist - * \cli (Yu & Gen 2010) - * X. Yu and M. Gen. \emb Introduction to Evolutionary Algorithms. \eme - * Springer, 2010, pages 18--20. - * \endclist - * - * \example examples/simple/igraph_roulette_wheel_imitation.c - */ - -igraph_error_t igraph_roulette_wheel_imitation(const igraph_t *graph, - igraph_integer_t vid, - igraph_bool_t islocal, - const igraph_vector_t *quantities, - igraph_vector_int_t *strategies, - igraph_neimode_t mode) { - igraph_bool_t updates; - igraph_integer_t u; - igraph_real_t r; /* random number */ - igraph_vector_t V; /* vector of cumulative proportionate quantities */ - igraph_vit_t A; /* all vertices in v's perspective */ - igraph_vs_t vs; - igraph_integer_t i; - - IGRAPH_CHECK(igraph_i_microscopic_standard_tests(graph, vid, quantities, - strategies, mode, &updates, - islocal)); - if (!updates) { - return IGRAPH_SUCCESS; /* nothing further to do */ - } - - /* set the perspective */ - if (islocal) { - IGRAPH_CHECK(igraph_vs_adj(&vs, vid, mode)); - } else { - IGRAPH_CHECK(igraph_vs_all(&vs)); - } - IGRAPH_FINALLY(igraph_vs_destroy, &vs); - IGRAPH_CHECK(igraph_vit_create(graph, vs, &A)); - IGRAPH_FINALLY(igraph_vit_destroy, &A); - - IGRAPH_VECTOR_INIT_FINALLY(&V, 0); - - IGRAPH_CHECK(igraph_i_vcumulative_proportionate_values(graph, quantities, &V, - islocal, vid, mode)); - - /* Finally, choose a vertex u to imitate. The vertex u is chosen */ - /* proportionate to its quantity. In the case of a local perspective, we */ - /* pretend that v's cumulative proportionate quantity has been appended to */ - /* the vector V. Let V be of length n so that V[n-1] is the last element */ - /* of V, and let r be a real number chosen uniformly at random from the */ - /* unit interval [0,1]. If r > V[i] for all i < n, then v defaults to */ - /* retaining its current strategy. Similarly in the case of the global */ - /* perspective, if r > V[i] for all i < n - 1 then v would adopt the */ - /* strategy of the vertex whose cumulative proportionate quantity is */ - /* V[n-1]. */ - /* NOTE: Here we assume that the order in which we iterate through the */ - /* vertices in A is the same as the order in which we do so in the */ - /* invoked function igraph_vcumulative_proportionate_values(). */ - /* Otherwise we would incorrectly associate each V[i] with a vertex in A. */ - RNG_BEGIN(); - r = RNG_UNIF01(); - RNG_END(); - i = 0; - while (!IGRAPH_VIT_END(A)) { - if (r <= VECTOR(V)[i]) { - /* We have found our candidate vertex for imitation. Update strategy */ - /* of v to that of u, and exit the selection loop. */ - u = IGRAPH_VIT_GET(A); - VECTOR(*strategies)[vid] = VECTOR(*strategies)[u]; - break; - } - i++; - IGRAPH_VIT_NEXT(A); - } - - /* By now, vertex v should either retain its current strategy or it has */ - /* adopted the strategy of a vertex in its perspective. Nothing else to */ - /* do, but clean up. */ - igraph_vector_destroy(&V); - igraph_vit_destroy(&A); - igraph_vs_destroy(&vs); - IGRAPH_FINALLY_CLEAN(3); - - return IGRAPH_SUCCESS; -} - -/** - * \ingroup spatialgames - * \function igraph_stochastic_imitation - * \brief Adopt a strategy via stochastic imitation with uniform selection. - * - * A simple stochastic imitation strategy where a vertex revises its - * strategy to that of a vertex chosen uniformly at random from its local - * neighbourhood. This is called stochastic imitation via uniform selection, - * where the strategy to imitate is chosen via some random process. For the - * purposes of this function, we use uniform selection from a pool of - * candidates. - * - * \param graph The graph object representing the game network. This cannot - * be the empty or trivial graph, but must have at least two vertices - * and one edge. If \p graph has one vertex, then no strategy update - * would take place. Furthermore, if \p graph has at least two vertices - * but zero edges, then strategy update would also not take place. - * \param vid The vertex whose strategy is to be updated. It is assumed that - * \p vid represents a vertex in \p graph. No checking is performed and - * it is your responsibility to ensure that \p vid is indeed a vertex - * of \p graph. If an isolated vertex is provided, i.e. the input - * vertex has degree 0, then no strategy update would take place and - * \p vid would retain its current strategy. Strategy update would also - * not take place if the local neighbourhood of \p vid are its - * in-neighbours (respectively out-neighbours), but \p vid has zero - * in-neighbours (respectively out-neighbours). Loops are ignored in - * computing the degree (in, out, all) of \p vid. - * \param algo This flag controls which algorithm to use in stochastic - * imitation. Supported values are: - * \clist - * \cli IGRAPH_IMITATE_AUGMENTED - * Augmented imitation. Vertex \p vid imitates the strategy of the - * chosen vertex u provided that doing so would increase the - * quantity (e.g. fitness) of \p vid. Augmented imitation can be - * thought of as "imitate if better". - * \cli IGRAPH_IMITATE_BLIND - * Blind imitation. Vertex \p vid blindly imitates the strategy of - * the chosen vertex u, regardless of whether doing so would - * increase or decrease the quantity of \p vid. - * \cli IGRAPH_IMITATE_CONTRACTED - * Contracted imitation. Here vertex \p vid imitates the strategy of - * the chosen vertex u if doing so would decrease the quantity of - * \p vid. Think of contracted imitation as "imitate if worse". - * \endclist - * \param quantities A vector of quantities providing the quantity of each - * vertex in \p graph. Think of each entry of the vector as being - * generated by a function such as the fitness function for the game. - * So if the vector represents fitness quantities, then each vector - * entry is the fitness of some vertex. The length of this vector must - * be the same as the number of vertices in the vertex set of \p graph. - * \param strategies A vector of the current strategies for the vertex - * population. The updated strategy for \p vid would be stored here. - * Each strategy is identified with a nonnegative integer, whose - * interpretation depends on the payoff matrix of the game. Generally - * we use the strategy ID as a row or column index of the payoff - * matrix. The length of this vector must be the same as the number of - * vertices in the vertex set of \p graph. - * \param mode Defines the sort of neighbourhood to consider for \p vid. If - * \p graph is undirected, then we use all the immediate neighbours of - * \p vid. Thus if you know that \p graph is undirected, then it is safe - * to pass the value \p IGRAPH_ALL here. Supported values are: - * \clist - * \cli IGRAPH_OUT - * Use the out-neighbours of \p vid. This option is only relevant - * when \p graph is a directed graph. - * \cli IGRAPH_IN - * Use the in-neighbours of \p vid. Again this option is only relevant - * when \p graph is a directed graph. - * \cli IGRAPH_ALL - * Use both the in- and out-neighbours of \p vid. This option is only - * relevant if \p graph is a digraph. Also use this value if - * \p graph is undirected. - * \endclist - * \return The error code \p IGRAPH_EINVAL is returned in each of the following - * cases: (1) Any of the parameters \p graph, \p quantities, or - * \p strategies is a null pointer. (2) The vector \p quantities or - * \p strategies has a length different from the number of vertices - * in \p graph. (3) The parameter \p graph is the empty or null graph, - * i.e. the graph with zero vertices and edges. (4) The parameter - * \p algo refers to an unsupported stochastic imitation algorithm. - * - * Time complexity: depends on the uniform random number generator, but should - * usually be O(1). - * - * \example examples/simple/igraph_stochastic_imitation.c - */ - -igraph_error_t igraph_stochastic_imitation(const igraph_t *graph, - igraph_integer_t vid, - igraph_imitate_algorithm_t algo, - const igraph_vector_t *quantities, - igraph_vector_int_t *strategies, - igraph_neimode_t mode) { - igraph_bool_t updates; - igraph_integer_t u; - igraph_vector_int_t adj; - igraph_integer_t i; - - /* sanity checks */ - if (algo != IGRAPH_IMITATE_AUGMENTED && - algo != IGRAPH_IMITATE_BLIND && - algo != IGRAPH_IMITATE_CONTRACTED) { - IGRAPH_ERROR("Unsupported stochastic imitation algorithm", - IGRAPH_EINVAL); - } - IGRAPH_CHECK(igraph_i_microscopic_standard_tests(graph, vid, quantities, - strategies, mode, &updates, - /*is local?*/ true)); - if (!updates) { - return IGRAPH_SUCCESS; /* nothing more to do */ - } - - /* immediate neighbours of v */ - IGRAPH_VECTOR_INT_INIT_FINALLY(&adj, 0); - IGRAPH_CHECK(igraph_neighbors(graph, &adj, vid, mode)); - - /* Blind imitation. Let v be the vertex whose strategy we want to revise. */ - /* Choose a vertex u uniformly at random from the immediate neighbours of */ - /* v, including v itself. Then blindly update the strategy of v to that of */ - /* u, irrespective of whether doing so would increase or decrease the */ - /* quantity (e.g. fitness) of v. Here v retains its current strategy if */ - /* the chosen vertex u is indeed v itself. */ - if (algo == IGRAPH_IMITATE_BLIND) { - IGRAPH_CHECK(igraph_vector_int_push_back(&adj, vid)); - RNG_BEGIN(); - i = RNG_INTEGER(0, igraph_vector_int_size(&adj) - 1); - RNG_END(); - u = VECTOR(adj)[i]; - VECTOR(*strategies)[vid] = VECTOR(*strategies)[u]; - } - /* Augmented imitation. Let v be the vertex whose strategy we want to */ - /* revise. Let f be the quantity function for the game. Choose a vertex u */ - /* uniformly at random from the immediate neighbours of v; do not include */ - /* v. Then v imitates the strategy of u if f(u) > f(v). Otherwise v */ - /* retains its current strategy. */ - else if (algo == IGRAPH_IMITATE_AUGMENTED) { - RNG_BEGIN(); - i = RNG_INTEGER(0, igraph_vector_int_size(&adj) - 1); - RNG_END(); - u = VECTOR(adj)[i]; - if (VECTOR(*quantities)[u] > VECTOR(*quantities)[vid]) { - VECTOR(*strategies)[vid] = VECTOR(*strategies)[u]; - } - } - /* Contracted imitation. Let v be the vertex whose strategy we want to */ - /* update and let f be the quantity function for the game. Choose a vertex */ - /* u uniformly at random from the immediate neighbours of v, excluding v */ - /* itself. Then v imitates the strategy of u provided that f(u) < f(v). */ - /* Otherwise v retains its current strategy. */ - else if (algo == IGRAPH_IMITATE_CONTRACTED) { - RNG_BEGIN(); - i = RNG_INTEGER(0, igraph_vector_int_size(&adj) - 1); - RNG_END(); - u = VECTOR(adj)[i]; - if (VECTOR(*quantities)[u] < VECTOR(*quantities)[vid]) { - VECTOR(*strategies)[vid] = VECTOR(*strategies)[u]; - } - } - - /* clean up */ - igraph_vector_int_destroy(&adj); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} diff --git a/src/vendor/cigraph/src/misc/mixing.c b/src/vendor/cigraph/src/misc/mixing.c index d3b77b84aa8..dffc7635988 100644 --- a/src/vendor/cigraph/src/misc/mixing.c +++ b/src/vendor/cigraph/src/misc/mixing.c @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2009-2023 The igraph development team + igraph library. + Copyright (C) 2009-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -73,6 +72,8 @@ * https://doi.org/10.1093/acprof%3Aoso/9780199206650.001.0001. * * \param graph The input graph, it can be directed or undirected. + * \param weights Weighted nominal assortativity is not currently implemented. + * Pass \c NULL to ignore. * \param types Integer vector giving the vertex categories. The types * are represented by integers starting at zero. * \param res Pointer to a real variable, the result is stored here. @@ -95,19 +96,24 @@ * \example examples/simple/igraph_assortativity_nominal.c */ -igraph_error_t igraph_assortativity_nominal(const igraph_t *graph, - const igraph_vector_int_t *types, - igraph_real_t *res, - igraph_bool_t directed, - igraph_bool_t normalized) { +igraph_error_t igraph_assortativity_nominal( + const igraph_t *graph, const igraph_vector_t *weights, + const igraph_vector_int_t *types, + igraph_real_t *res, + igraph_bool_t directed, igraph_bool_t normalized) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_real_t no_of_edges_real = no_of_edges; /* for divisions */ - igraph_integer_t no_of_types; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_real_t no_of_edges_real = (igraph_real_t) no_of_edges; /* for divisions */ + igraph_int_t no_of_types; igraph_vector_int_t ai, bi, eii; igraph_real_t sumaibi = 0.0, sumeii = 0.0; + if (weights) { + IGRAPH_ERROR("Weighted nominal assortativity is not yet implemented.", + IGRAPH_UNIMPLEMENTED); + } + if (igraph_vector_int_size(types) != no_of_nodes) { IGRAPH_ERROR("Invalid types vector length.", IGRAPH_EINVAL); } @@ -129,11 +135,11 @@ igraph_error_t igraph_assortativity_nominal(const igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&bi, no_of_types); IGRAPH_VECTOR_INT_INIT_FINALLY(&eii, no_of_types); - for (igraph_integer_t e = 0; e < no_of_edges; e++) { - igraph_integer_t from = IGRAPH_FROM(graph, e); - igraph_integer_t to = IGRAPH_TO(graph, e); - igraph_integer_t from_type = VECTOR(*types)[from]; - igraph_integer_t to_type = VECTOR(*types)[to]; + for (igraph_int_t e = 0; e < no_of_edges; e++) { + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); + igraph_int_t from_type = VECTOR(*types)[from]; + igraph_int_t to_type = VECTOR(*types)[to]; VECTOR(ai)[from_type] += 1; VECTOR(bi)[to_type] += 1; @@ -149,7 +155,7 @@ igraph_error_t igraph_assortativity_nominal(const igraph_t *graph, } } - for (igraph_integer_t i = 0; i < no_of_types; i++) { + for (igraph_int_t i = 0; i < no_of_types; i++) { sumaibi += (VECTOR(ai)[i] / no_of_edges_real) * (VECTOR(bi)[i] / no_of_edges_real); sumeii += (VECTOR(eii)[i] / no_of_edges_real); } @@ -208,6 +214,12 @@ igraph_error_t igraph_assortativity_nominal(const igraph_t *graph, * undirected graphs. * * + * When edge weights are given, they are effectively treated as edge multiplicities. + * The above formulas are valid for weighted graph as well when \c m is interpreted + * as the total edge weight (instead of the edge count) and \c k as vertex strengths + * (instead of degrees). + * + * * References: * * @@ -231,6 +243,8 @@ igraph_error_t igraph_assortativity_nominal(const igraph_t *graph, * https://doi.org/10.1093/acprof%3Aoso/9780199206650.001.0001. * * \param graph The input graph, it can be directed or undirected. + * \param weights The edge weights. Pass \c NULL to compute unweighed + * assortativity, which in effect assumes all weights to be 1. * \param values The vertex values, these can be arbitrary numeric * values. * \param values_in A second value vector to be used for the incoming @@ -256,18 +270,24 @@ igraph_error_t igraph_assortativity_nominal(const igraph_t *graph, * based on vertex degrees. */ -igraph_error_t igraph_assortativity(const igraph_t *graph, - const igraph_vector_t *values, - const igraph_vector_t *values_in, - igraph_real_t *res, - igraph_bool_t directed, - igraph_bool_t normalized) { +igraph_error_t igraph_assortativity( + const igraph_t *graph, const igraph_vector_t *weights, + const igraph_vector_t *values, const igraph_vector_t *values_in, + igraph_real_t *res, + igraph_bool_t directed, igraph_bool_t normalized) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_real_t total_weight; directed = directed && igraph_is_directed(graph); + if (weights && igraph_vector_size(weights) != no_of_edges) { + IGRAPH_ERRORF("Weight vector length (%" IGRAPH_PRId ") does not match number of edges (%" IGRAPH_PRId ").", + IGRAPH_EINVAL, + igraph_vector_size(weights), no_of_edges); + } + if (!directed && values_in) { IGRAPH_WARNING( "Incoming vertex values are ignored when calculating undirected assortativity."); @@ -281,27 +301,45 @@ igraph_error_t igraph_assortativity(const igraph_t *graph, IGRAPH_ERROR("Invalid incoming vertex values vector length.", IGRAPH_EINVAL); } + total_weight = weights ? igraph_vector_sum(weights) : no_of_edges; + if (!directed) { igraph_real_t num1 = 0.0, num2 = 0.0, den1 = 0.0; - for (igraph_integer_t e = 0; e < no_of_edges; e++) { - igraph_integer_t from = IGRAPH_FROM(graph, e); - igraph_integer_t to = IGRAPH_TO(graph, e); - igraph_real_t from_value = VECTOR(*values)[from]; - igraph_real_t to_value = VECTOR(*values)[to]; - - num1 += from_value * to_value; - num2 += from_value + to_value; - if (normalized) { - den1 += from_value * from_value + to_value * to_value; + if (weights) { + for (igraph_int_t e = 0; e < no_of_edges; e++) { + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); + igraph_real_t from_value = VECTOR(*values)[from]; + igraph_real_t to_value = VECTOR(*values)[to]; + igraph_real_t w = VECTOR(*weights)[e]; + + num1 += w * from_value * to_value; + num2 += w * (from_value + to_value); + if (normalized) { + den1 += w * (from_value * from_value + to_value * to_value); + } + } + } else { + for (igraph_int_t e = 0; e < no_of_edges; e++) { + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); + igraph_real_t from_value = VECTOR(*values)[from]; + igraph_real_t to_value = VECTOR(*values)[to]; + + num1 += from_value * to_value; + num2 += from_value + to_value; + if (normalized) { + den1 += from_value * from_value + to_value * to_value; + } } } - num1 /= no_of_edges; + num1 /= total_weight; if (normalized) { - den1 /= no_of_edges * 2.0; + den1 /= total_weight * 2.0; } - num2 /= no_of_edges * 2.0; + num2 /= total_weight * 2.0; num2 = num2 * num2; if (normalized) { @@ -319,29 +357,47 @@ igraph_error_t igraph_assortativity(const igraph_t *graph, values_in = values; } - for (igraph_integer_t e = 0; e < no_of_edges; e++) { - igraph_integer_t from = IGRAPH_FROM(graph, e); - igraph_integer_t to = IGRAPH_TO(graph, e); - igraph_real_t from_value = VECTOR(*values)[from]; - igraph_real_t to_value = VECTOR(*values_in)[to]; - - num1 += from_value * to_value; - num2 += from_value; - num3 += to_value; - if (normalized) { - den1 += from_value * from_value; - den2 += to_value * to_value; + if (weights) { + for (igraph_int_t e = 0; e < no_of_edges; e++) { + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); + igraph_real_t from_value = VECTOR(*values)[from]; + igraph_real_t to_value = VECTOR(*values_in)[to]; + igraph_real_t w = VECTOR(*weights)[e]; + + num1 += w * from_value * to_value; + num2 += w * from_value; + num3 += w * to_value; + if (normalized) { + den1 += w * (from_value * from_value); + den2 += w * (to_value * to_value); + } + } + } else { + for (igraph_int_t e = 0; e < no_of_edges; e++) { + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); + igraph_real_t from_value = VECTOR(*values)[from]; + igraph_real_t to_value = VECTOR(*values_in)[to]; + + num1 += from_value * to_value; + num2 += from_value; + num3 += to_value; + if (normalized) { + den1 += from_value * from_value; + den2 += to_value * to_value; + } } } - num = num1 - num2 * num3 / no_of_edges; + num = num1 - num2 * num3 / total_weight; if (normalized) { - den = sqrt(den1 - num2 * num2 / no_of_edges) * - sqrt(den2 - num3 * num3 / no_of_edges); + den = sqrt(den1 - num2 * num2 / total_weight) * + sqrt(den2 - num3 * num3 / total_weight); *res = num / den; } else { - *res = num / no_of_edges; + *res = num / total_weight; } } @@ -389,7 +445,7 @@ igraph_error_t igraph_assortativity_degree(const igraph_t *graph, igraph_bool_t directed) { directed = directed && igraph_is_directed(graph); - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); /* This function uses igraph_strength() instead of igraph_degree() in order to obtain * a vector of reals instead of a vector of integers. */ @@ -399,7 +455,7 @@ igraph_error_t igraph_assortativity_degree(const igraph_t *graph, IGRAPH_VECTOR_INIT_FINALLY(&outdegree, no_of_nodes); IGRAPH_CHECK(igraph_strength(graph, &indegree, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS, NULL)); IGRAPH_CHECK(igraph_strength(graph, &outdegree, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS, NULL)); - IGRAPH_CHECK(igraph_assortativity(graph, &outdegree, &indegree, res, /* directed */ true, /* normalized */ true)); + IGRAPH_CHECK(igraph_assortativity(graph, NULL, &outdegree, &indegree, res, /* directed */ true, /* normalized */ true)); igraph_vector_destroy(&indegree); igraph_vector_destroy(&outdegree); IGRAPH_FINALLY_CLEAN(2); @@ -407,7 +463,7 @@ igraph_error_t igraph_assortativity_degree(const igraph_t *graph, igraph_vector_t degree; IGRAPH_VECTOR_INIT_FINALLY(°ree, no_of_nodes); IGRAPH_CHECK(igraph_strength(graph, °ree, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS, NULL)); - IGRAPH_CHECK(igraph_assortativity(graph, °ree, 0, res, /* directed */ false, /* normalized */ true)); + IGRAPH_CHECK(igraph_assortativity(graph, NULL, °ree, 0, res, /* directed */ false, /* normalized */ true)); igraph_vector_destroy(°ree); IGRAPH_FINALLY_CLEAN(1); } @@ -419,8 +475,6 @@ igraph_error_t igraph_assortativity_degree(const igraph_t *graph, * \function igraph_joint_degree_matrix * \brief The joint degree matrix of a graph. * - * \experimental - * * In graph theory, the joint degree matrix \c J_ij of a graph gives the number * of edges, or sum of edge weights, between vertices of degree \c i and degree * \c j. This function stores \c J_ij into jdm[i-1, j-1]. @@ -458,11 +512,11 @@ igraph_error_t igraph_assortativity_degree(const igraph_t *graph, * \param jdm A pointer to an initialized matrix that will be resized. The values * will be written here. * \param max_out_degree Number of rows in the result, i.e. the largest (out-)degree - * to consider. If negative, the largest (out-)degree of the graph will - * be used. + * to consider. If negative or \ref IGRAPH_UNLIMITED, the largest (out-)degree + * of the graph will be used. * \param max_in_degree Number of columns in the result, i.e. the largest (in-)degree - * to consider. If negative, the largest (in-)degree of the graph will - * be used. + * to consider. If negative or \ref IGRAPH_UNLIMITED, the largest (in-)degree + * of the graph will be used. * \return Error code. * * \sa \ref igraph_joint_degree_distribution() to count ordered vertex pairs instead of @@ -474,16 +528,16 @@ igraph_error_t igraph_assortativity_degree(const igraph_t *graph, igraph_error_t igraph_joint_degree_matrix( const igraph_t *graph, const igraph_vector_t *weights, igraph_matrix_t *jdm, - igraph_integer_t max_out_degree, igraph_integer_t max_in_degree) { + igraph_int_t max_out_degree, igraph_int_t max_in_degree) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_eit_t eit; - igraph_integer_t eid; - igraph_integer_t v1id; - igraph_integer_t v2id; - igraph_integer_t v1deg; - igraph_integer_t v2deg; + igraph_int_t eid; + igraph_int_t v1id; + igraph_int_t v2id; + igraph_int_t v1deg; + igraph_int_t v2deg; if (weights && igraph_vector_size(weights) != no_of_edges) { IGRAPH_ERRORF("Weight vector length (%" IGRAPH_PRId ") does not match number of edges (%" IGRAPH_PRId ").", @@ -498,8 +552,8 @@ igraph_error_t igraph_joint_degree_matrix( // Compute max degrees IGRAPH_VECTOR_INT_INIT_FINALLY(&out_degrees, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&in_degrees, no_of_nodes); - IGRAPH_CHECK(igraph_degree(graph, &out_degrees, igraph_vss_all(), IGRAPH_OUT, true)); - IGRAPH_CHECK(igraph_degree(graph, &in_degrees, igraph_vss_all(), IGRAPH_IN, true)); + IGRAPH_CHECK(igraph_degree(graph, &out_degrees, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS)); + IGRAPH_CHECK(igraph_degree(graph, &in_degrees, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS)); if (max_out_degree < 0) { max_out_degree = no_of_nodes > 0 ? igraph_vector_int_max(&out_degrees) : 0; @@ -532,10 +586,10 @@ igraph_error_t igraph_joint_degree_matrix( } else { igraph_vector_int_t degrees; - igraph_integer_t maxdeg; + igraph_int_t maxdeg; IGRAPH_VECTOR_INT_INIT_FINALLY(°rees, no_of_nodes); - IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), IGRAPH_ALL, true)); + IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS)); // Compute max degree of the graph only if needed if (max_out_degree < 0 || max_in_degree < 0) { @@ -597,12 +651,12 @@ static igraph_error_t mixing_matrix( igraph_matrix_t *p, const igraph_vector_int_t *from_types, const igraph_vector_int_t *to_types, igraph_bool_t directed_neighbors, igraph_bool_t normalized, - igraph_integer_t max_from_type, igraph_integer_t max_to_type, + igraph_int_t max_from_type, igraph_int_t max_to_type, igraph_bool_t check_types) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t nrow, ncol; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t nrow, ncol; igraph_real_t sum; igraph_bool_t negative_weight; @@ -645,7 +699,7 @@ static igraph_error_t mixing_matrix( } if (check_types && no_of_nodes > 0) { - igraph_integer_t min; + igraph_int_t min; min = igraph_vector_int_min(from_types); if (min < 0) { @@ -665,11 +719,11 @@ static igraph_error_t mixing_matrix( sum = 0; negative_weight = false; - for (igraph_integer_t eid=0; eid < no_of_edges; eid++) { - igraph_integer_t from = IGRAPH_FROM(graph, eid); - igraph_integer_t to = IGRAPH_TO(graph, eid); - igraph_integer_t from_type = VECTOR(*from_types)[from]; - igraph_integer_t to_type = VECTOR(*to_types)[to]; + for (igraph_int_t eid=0; eid < no_of_edges; eid++) { + igraph_int_t from = IGRAPH_FROM(graph, eid); + igraph_int_t to = IGRAPH_TO(graph, eid); + igraph_int_t from_type = VECTOR(*from_types)[from]; + igraph_int_t to_type = VECTOR(*to_types)[to]; igraph_real_t w = weights ? VECTOR(*weights)[eid] : 1; if (from_type >= nrow || to_type >= ncol) { @@ -709,8 +763,6 @@ static igraph_error_t mixing_matrix( * \function igraph_joint_degree_distribution * \brief The joint degree distribution of a graph. * - * \experimental - * * Computes the joint degree distribution \c P_ij of a graph, used in the * study of degree correlations. \c P_ij is the probability that a randomly * chosen ordered pair of \em connected vertices have degrees \c i and \c j. @@ -782,12 +834,12 @@ static igraph_error_t mixing_matrix( * \param normalized Whether to normalize the matrix so that entries sum to 1.0. * If false, matrix entries will be connection counts. Normalization is not * meaningful if some edge weights are negative. - * \param max_from_degree The largest source vertex degree to consider. If negative, - * the largest source degree will be used. The row count of the result matrix - * is one larger than this value. - * \param max_to_degree The largest target vertex degree to consider. If negative, - * the largest target degree will be used. The column count of the result matrix - * is one larger than this value. + * \param max_from_degree The largest source vertex degree to consider. If + * negative or \ref IGRAPH_UNLIMITED, the largest source degree will be used. + * The row count of the result matrix is one larger than this value. + * \param max_to_degree The largest target vertex degree to consider. If + * negative or \ref IGRAPH_UNLIMITED, the largest target degree will be used. + * The column count of the result matrix is one larger than this value. * \return Error code. * * \sa \ref igraph_joint_degree_matrix() for computing the joint degree matrix; @@ -803,9 +855,9 @@ igraph_error_t igraph_joint_degree_distribution( igraph_neimode_t from_mode, igraph_neimode_t to_mode, igraph_bool_t directed_neighbors, igraph_bool_t normalized, - igraph_integer_t max_from_degree, igraph_integer_t max_to_degree) { + igraph_int_t max_from_degree, igraph_int_t max_to_degree) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t *deg_from, *deg_to, deg_out, deg_in, deg_all; /* Make sure directionality parameters are consistent for undirected graphs. */ @@ -820,17 +872,17 @@ igraph_error_t igraph_joint_degree_distribution( if (have_out) { IGRAPH_VECTOR_INT_INIT_FINALLY(°_out, no_of_nodes); - IGRAPH_CHECK(igraph_degree(graph, °_out, igraph_vss_all(), IGRAPH_OUT, /* loops */ true)); + IGRAPH_CHECK(igraph_degree(graph, °_out, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS)); } if (have_in) { IGRAPH_VECTOR_INT_INIT_FINALLY(°_in, no_of_nodes); - IGRAPH_CHECK(igraph_degree(graph, °_in, igraph_vss_all(), IGRAPH_IN, /* loops */ true)); + IGRAPH_CHECK(igraph_degree(graph, °_in, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS)); } if (have_all) { IGRAPH_VECTOR_INT_INIT_FINALLY(°_all, no_of_nodes); - IGRAPH_CHECK(igraph_degree(graph, °_all, igraph_vss_all(), IGRAPH_ALL, /* loops */ true)); + IGRAPH_CHECK(igraph_degree(graph, °_all, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS)); } switch (from_mode) { @@ -879,8 +931,6 @@ igraph_error_t igraph_joint_degree_distribution( * \function igraph_joint_type_distribution * \brief Mixing matrix for vertex categories. * - * \experimental - * * Computes the mixing matrix M_ij, i.e. the joint distribution of vertex types * at the endpoints directed of edges. Categories are represented by non-negative integer * indices, passed in \p from_types and \p to_types. The row and column counts of \p m diff --git a/src/vendor/cigraph/src/misc/motifs.c b/src/vendor/cigraph/src/misc/motifs.c index 3a018d5d170..d12e16c8bb3 100644 --- a/src/vendor/cigraph/src/misc/motifs.c +++ b/src/vendor/cigraph/src/misc/motifs.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -40,7 +39,9 @@ */ static igraph_error_t igraph_i_motifs_randesu_update_hist( const igraph_t *graph, - igraph_vector_int_t *vids, igraph_integer_t isoclass, void* extra) { + const igraph_vector_int_t *vids, + igraph_int_t isoclass, void* extra) { + igraph_vector_t *hist = (igraph_vector_t*)extra; IGRAPH_UNUSED(graph); IGRAPH_UNUSED(vids); VECTOR(*hist)[isoclass]++; @@ -115,9 +116,9 @@ static igraph_error_t igraph_i_motifs_randesu_update_hist( * \example examples/simple/igraph_motifs_randesu.c */ igraph_error_t igraph_motifs_randesu(const igraph_t *graph, igraph_vector_t *hist, - igraph_integer_t size, const igraph_vector_t *cut_prob) { + igraph_int_t size, const igraph_vector_t *cut_prob) { igraph_bool_t directed = igraph_is_directed(graph); - igraph_integer_t histlen; + igraph_int_t histlen; if (directed) { switch (size) { @@ -237,22 +238,23 @@ igraph_error_t igraph_motifs_randesu(const igraph_t *graph, igraph_vector_t *his * \example examples/simple/igraph_motifs_randesu.c */ -igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_integer_t size, - const igraph_vector_t *cut_prob, igraph_motifs_handler_t *callback, - void* extra) { +igraph_error_t igraph_motifs_randesu_callback( + const igraph_t *graph, + igraph_int_t size, const igraph_vector_t *cut_prob, + igraph_motifs_handler_t *callback, void* extra) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_adjlist_t allneis, alloutneis; igraph_vector_int_t *neis; - igraph_integer_t father; - igraph_integer_t i, j, s; - igraph_integer_t motifs = 0; + igraph_int_t parent; + igraph_int_t i, j, s; + igraph_int_t motifs = 0; IGRAPH_UNUSED(motifs); /* We mark it as unused to prevent warnings about unused-but-set-variables. */ igraph_vector_int_t vids; /* this is G */ igraph_vector_int_t adjverts; /* this is V_E */ igraph_stack_int_t stack; /* this is S */ - igraph_integer_t *added; + igraph_int_t *added; char *subg; const unsigned int *arr_idx, *arr_code; @@ -310,7 +312,7 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte IGRAPH_EINVAL, igraph_vector_size(cut_prob), size); } - added = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + added = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(added, "Insufficient memory to find motifs."); IGRAPH_FINALLY(igraph_free, added); @@ -328,10 +330,8 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte IGRAPH_CHECK(igraph_stack_int_init(&stack, 0)); IGRAPH_FINALLY(igraph_stack_int_destroy, &stack); - RNG_BEGIN(); - - for (father = 0; father < no_of_nodes; father++) { - igraph_integer_t level; + for (parent = 0; parent < no_of_nodes; parent++) { + igraph_int_t level; IGRAPH_ALLOW_INTERRUPTION(); @@ -343,18 +343,18 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte /* init G */ igraph_vector_int_clear(&vids); level = 0; - IGRAPH_CHECK(igraph_vector_int_push_back(&vids, father)); - subg[father] = 1; added[father] += 1; level += 1; + IGRAPH_CHECK(igraph_vector_int_push_back(&vids, parent)); + subg[parent] = 1; added[parent] += 1; level += 1; /* init V_E */ igraph_vector_int_clear(&adjverts); - neis = igraph_adjlist_get(&allneis, father); + neis = igraph_adjlist_get(&allneis, parent); s = igraph_vector_int_size(neis); for (i = 0; i < s; i++) { - igraph_integer_t nei = VECTOR(*neis)[i]; - if (!added[nei] && nei > father) { + igraph_int_t nei = VECTOR(*neis)[i]; + if (!added[nei] && nei > parent) { IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei)); - IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, father)); + IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, parent)); } added[nei] += 1; } @@ -368,8 +368,8 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte if (level == size - 1) { s = igraph_vector_int_size(&adjverts) / 2; for (i = 0; i < s; i++) { - igraph_integer_t k, s2; - igraph_integer_t last; + igraph_int_t k, s2; + igraph_int_t last; igraph_error_t ret; if (cp != 0 && RNG_UNIF01() < cp) { @@ -383,11 +383,11 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte code = 0; idx = 0; for (k = 0; k < size; k++) { - igraph_integer_t from = VECTOR(vids)[k]; + igraph_int_t from = VECTOR(vids)[k]; neis = igraph_adjlist_get(&alloutneis, from); s2 = igraph_vector_int_size(neis); for (j = 0; j < s2; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; if (subg[nei] && k != subg[nei] - 1) { idx = (unsigned char) (mul * k + (subg[nei] - 1)); code |= arr_idx[idx]; @@ -419,23 +419,23 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte if (level < size - 1 && !igraph_vector_int_empty(&adjverts)) { /* we might step down */ - igraph_integer_t neifather = igraph_vector_int_pop_back(&adjverts); - igraph_integer_t nei = igraph_vector_int_pop_back(&adjverts); + igraph_int_t neiparent = igraph_vector_int_pop_back(&adjverts); + igraph_int_t nei = igraph_vector_int_pop_back(&adjverts); if (cp == 0 || RNG_UNIF01() > cp) { /* yes, step down */ IGRAPH_CHECK(igraph_vector_int_push_back(&vids, nei)); subg[nei] = (char) level + 1; added[nei] += 1; level += 1; - IGRAPH_CHECK(igraph_stack_int_push(&stack, neifather)); + IGRAPH_CHECK(igraph_stack_int_push(&stack, neiparent)); IGRAPH_CHECK(igraph_stack_int_push(&stack, nei)); IGRAPH_CHECK(igraph_stack_int_push(&stack, level)); neis = igraph_adjlist_get(&allneis, nei); s = igraph_vector_int_size(neis); for (i = 0; i < s; i++) { - igraph_integer_t nei2 = VECTOR(*neis)[i]; - if (!added[nei2] && nei2 > father) { + igraph_int_t nei2 = VECTOR(*neis)[i]; + if (!added[nei2] && nei2 > parent) { IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei2)); IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei)); } @@ -444,14 +444,14 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte } } else { /* no, step back */ - igraph_integer_t nei, neifather; + igraph_int_t nei, neiparent; while (!igraph_stack_int_empty(&stack) && level == igraph_stack_int_top(&stack) - 1) { igraph_stack_int_pop(&stack); nei = igraph_stack_int_pop(&stack); - neifather = igraph_stack_int_pop(&stack); - igraph_vector_int_push_back(&adjverts, nei); - igraph_vector_int_push_back(&adjverts, neifather); + neiparent = igraph_stack_int_pop(&stack); + IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei)); + IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, neiparent)); } nei = igraph_vector_int_pop_back(&vids); @@ -476,17 +476,15 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte } /* clear the added vector */ - added[father] -= 1; - subg[father] = 0; - neis = igraph_adjlist_get(&allneis, father); + added[parent] -= 1; + subg[parent] = 0; + neis = igraph_adjlist_get(&allneis, parent); s = igraph_vector_int_size(neis); for (i = 0; i < s; i++) { added[ VECTOR(*neis)[i] ] -= 1; } - } /* for father */ - - RNG_END(); + } /* for parent */ IGRAPH_FREE(added); IGRAPH_FREE(subg); @@ -522,7 +520,10 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte * the search tree. * * \param graph The graph object to study. - * \param est Pointer to an integer, the result will be stored here. + * \param est Pointer to an \c igraph_real_t, the result will be stored here. + * Note that even though the result is an integer, we need to use + * \c igraph_real_t to avoid overflow when igraph is compiled with + * 32-bit integers. * \param size The size of the subgraphs to look for. * \param cut_prob Vector of probabilities for cutting the search tree * at a given level. The first element is the first level, etc. @@ -544,21 +545,21 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte * Time complexity: TODO. */ -igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_integer_t *est, - igraph_integer_t size, const igraph_vector_t *cut_prob, - igraph_integer_t sample_size, +igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_real_t *est, + igraph_int_t size, const igraph_vector_t *cut_prob, + igraph_int_t sample_size, const igraph_vector_int_t *parsample) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t neis; igraph_vector_int_t vids; /* this is G */ igraph_vector_int_t adjverts; /* this is V_E */ igraph_stack_int_t stack; /* this is S */ - igraph_integer_t *added; + igraph_int_t *added; igraph_vector_int_t *sample; - igraph_integer_t sam; - igraph_integer_t i; + igraph_int_t sam; + igraph_int_t i; if (size < 3) { IGRAPH_ERRORF("Motif size must be at least 3, received %" IGRAPH_PRId ".", @@ -579,7 +580,7 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte return IGRAPH_SUCCESS; } - added = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + added = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(added, "Insufficient memory to count motifs."); IGRAPH_FINALLY(igraph_free, added); @@ -608,11 +609,9 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte *est = 0; - RNG_BEGIN(); - for (sam = 0; sam < sample_size; sam++) { - igraph_integer_t father = VECTOR(*sample)[sam]; - igraph_integer_t level, s; + igraph_int_t parent = VECTOR(*sample)[sam]; + igraph_int_t level, s; IGRAPH_ALLOW_INTERRUPTION(); @@ -624,18 +623,20 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte /* init G */ igraph_vector_int_clear(&vids); level = 0; - IGRAPH_CHECK(igraph_vector_int_push_back(&vids, father)); - added[father] += 1; level += 1; + IGRAPH_CHECK(igraph_vector_int_push_back(&vids, parent)); + added[parent] += 1; level += 1; /* init V_E */ igraph_vector_int_clear(&adjverts); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, father, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, parent, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); s = igraph_vector_int_size(&neis); for (i = 0; i < s; i++) { - igraph_integer_t nei = VECTOR(neis)[i]; - if (!added[nei] && nei > father) { + igraph_int_t nei = VECTOR(neis)[i]; + if (!added[nei] && nei > parent) { IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei)); - IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, father)); + IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, parent)); } added[nei] += 1; } @@ -659,23 +660,25 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte if (level < size - 1 && !igraph_vector_int_empty(&adjverts)) { /* We might step down */ - igraph_integer_t neifather = igraph_vector_int_pop_back(&adjverts); - igraph_integer_t nei = igraph_vector_int_pop_back(&adjverts); + igraph_int_t neiparent = igraph_vector_int_pop_back(&adjverts); + igraph_int_t nei = igraph_vector_int_pop_back(&adjverts); if (cp == 0 || RNG_UNIF01() > cp) { /* Yes, step down */ IGRAPH_CHECK(igraph_vector_int_push_back(&vids, nei)); added[nei] += 1; level += 1; - IGRAPH_CHECK(igraph_stack_int_push(&stack, neifather)); + IGRAPH_CHECK(igraph_stack_int_push(&stack, neiparent)); IGRAPH_CHECK(igraph_stack_int_push(&stack, nei)); IGRAPH_CHECK(igraph_stack_int_push(&stack, level)); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, nei, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, nei, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); s = igraph_vector_int_size(&neis); for (i = 0; i < s; i++) { - igraph_integer_t nei2 = VECTOR(neis)[i]; - if (!added[nei2] && nei2 > father) { + igraph_int_t nei2 = VECTOR(neis)[i]; + if (!added[nei2] && nei2 > parent) { IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei2)); IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei)); } @@ -684,19 +687,21 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte } } else { /* no, step back */ - igraph_integer_t nei, neifather; + igraph_int_t nei, neiparent; while (!igraph_stack_int_empty(&stack) && level == igraph_stack_int_top(&stack) - 1) { igraph_stack_int_pop(&stack); nei = igraph_stack_int_pop(&stack); - neifather = igraph_stack_int_pop(&stack); - igraph_vector_int_push_back(&adjverts, nei); - igraph_vector_int_push_back(&adjverts, neifather); + neiparent = igraph_stack_int_pop(&stack); + IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei)); + IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, neiparent)); } nei = igraph_vector_int_pop_back(&vids); added[nei] -= 1; level -= 1; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, nei, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, nei, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); s = igraph_vector_int_size(&neis); for (i = 0; i < s; i++) { added[ VECTOR(neis)[i] ] -= 1; @@ -711,16 +716,16 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte } /* while */ /* clear the added vector */ - added[father] -= 1; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, father, IGRAPH_ALL)); + added[parent] -= 1; + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, parent, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); s = igraph_vector_int_size(&neis); for (i = 0; i < s; i++) { added[ VECTOR(neis)[i] ] -= 1; } - } /* for father */ - - RNG_END(); + } /* for parent */ (*est) *= ((igraph_real_t) no_of_nodes / sample_size); @@ -748,8 +753,10 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte * classes to them. Arbitrarily large motif sizes are supported. * * \param graph The graph object to study. - * \param no Pointer to an integer type, the result will be stored - * here. + * \param no Pointer to an \c igraph_real_t, the result will be stored here. + * Note that even though the result is an integer, we need to use + * \c igraph_real_t to avoid overflow when igraph is compiled with + * 32-bit integers. * \param size The size of the motifs to count. * \param cut_prob Vector of probabilities for cutting the search tree * at a given level. The first element is the first level, etc. @@ -763,17 +770,19 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte * Time complexity: TODO. */ -igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t *no, - igraph_integer_t size, const igraph_vector_t *cut_prob) { +igraph_error_t igraph_motifs_randesu_no( + const igraph_t *graph, igraph_real_t *no, igraph_int_t size, + const igraph_vector_t *cut_prob +) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t neis; igraph_vector_int_t vids; /* this is G */ igraph_vector_int_t adjverts; /* this is V_E */ igraph_stack_int_t stack; /* this is S */ - igraph_integer_t *added; - igraph_integer_t father; - igraph_integer_t i; + igraph_int_t *added; + igraph_int_t parent; + igraph_int_t i; if (size < 3) { IGRAPH_ERRORF("Motif size must be at least 3, received %" IGRAPH_PRId ".", @@ -784,7 +793,7 @@ igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t IGRAPH_ERRORF("Cut probability vector size (%" IGRAPH_PRId ") must agree with motif size (%" IGRAPH_PRId ").", IGRAPH_EINVAL, igraph_vector_size(cut_prob), size); } - added = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + added = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(added, "Insufficient memory to count motifs."); IGRAPH_FINALLY(igraph_free, added); @@ -796,10 +805,8 @@ igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t *no = 0; - RNG_BEGIN(); - - for (father = 0; father < no_of_nodes; father++) { - igraph_integer_t level, s; + for (parent = 0; parent < no_of_nodes; parent++) { + igraph_int_t level, s; IGRAPH_ALLOW_INTERRUPTION(); @@ -811,18 +818,20 @@ igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t /* init G */ igraph_vector_int_clear(&vids); level = 0; - IGRAPH_CHECK(igraph_vector_int_push_back(&vids, father)); - added[father] += 1; level += 1; + IGRAPH_CHECK(igraph_vector_int_push_back(&vids, parent)); + added[parent] += 1; level += 1; /* init V_E */ igraph_vector_int_clear(&adjverts); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, father, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, parent, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); s = igraph_vector_int_size(&neis); for (i = 0; i < s; i++) { - igraph_integer_t nei = VECTOR(neis)[i]; - if (!added[nei] && nei > father) { + igraph_int_t nei = VECTOR(neis)[i]; + if (!added[nei] && nei > parent) { IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei)); - IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, father)); + IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, parent)); } added[nei] += 1; } @@ -846,23 +855,25 @@ igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t if (level < size - 1 && !igraph_vector_int_empty(&adjverts)) { /* We might step down */ - igraph_integer_t neifather = igraph_vector_int_pop_back(&adjverts); - igraph_integer_t nei = igraph_vector_int_pop_back(&adjverts); + igraph_int_t neiparent = igraph_vector_int_pop_back(&adjverts); + igraph_int_t nei = igraph_vector_int_pop_back(&adjverts); if (cp == 0 || RNG_UNIF01() > cp) { /* Yes, step down */ IGRAPH_CHECK(igraph_vector_int_push_back(&vids, nei)); added[nei] += 1; level += 1; - IGRAPH_CHECK(igraph_stack_int_push(&stack, neifather)); + IGRAPH_CHECK(igraph_stack_int_push(&stack, neiparent)); IGRAPH_CHECK(igraph_stack_int_push(&stack, nei)); IGRAPH_CHECK(igraph_stack_int_push(&stack, level)); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, nei, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, nei, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); s = igraph_vector_int_size(&neis); for (i = 0; i < s; i++) { - igraph_integer_t nei2 = VECTOR(neis)[i]; - if (!added[nei2] && nei2 > father) { + igraph_int_t nei2 = VECTOR(neis)[i]; + if (!added[nei2] && nei2 > parent) { IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei2)); IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei)); } @@ -871,19 +882,21 @@ igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t } } else { /* no, step back */ - igraph_integer_t nei, neifather; + igraph_int_t nei, neiparent; while (!igraph_stack_int_empty(&stack) && level == igraph_stack_int_top(&stack) - 1) { igraph_stack_int_pop(&stack); nei = igraph_stack_int_pop(&stack); - neifather = igraph_stack_int_pop(&stack); - igraph_vector_int_push_back(&adjverts, nei); - igraph_vector_int_push_back(&adjverts, neifather); + neiparent = igraph_stack_int_pop(&stack); + IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, nei)); + IGRAPH_CHECK(igraph_vector_int_push_back(&adjverts, neiparent)); } nei = igraph_vector_int_pop_back(&vids); added[nei] -= 1; level -= 1; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, nei, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, nei, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); s = igraph_vector_int_size(&neis); for (i = 0; i < s; i++) { added[ VECTOR(neis)[i] ] -= 1; @@ -898,16 +911,16 @@ igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t } /* while */ /* clear the added vector */ - added[father] -= 1; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, father, IGRAPH_ALL)); + added[parent] -= 1; + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, parent, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); s = igraph_vector_int_size(&neis); for (i = 0; i < s; i++) { added[ VECTOR(neis)[i] ] -= 1; } - } /* for father */ - - RNG_END(); + } /* for parent */ IGRAPH_FREE(added); igraph_vector_int_destroy(&vids); @@ -957,18 +970,18 @@ igraph_error_t igraph_dyad_census(const igraph_t *graph, igraph_real_t *mut, igraph_real_t nonrec = 0, rec = 0; igraph_vector_int_t inneis, outneis; - igraph_integer_t vc = igraph_vcount(graph); - igraph_integer_t i; + igraph_int_t vc = igraph_vcount(graph); + igraph_int_t i; IGRAPH_VECTOR_INT_INIT_FINALLY(&inneis, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&outneis, 0); for (i = 0; i < vc; i++) { - igraph_integer_t ideg, odeg; - igraph_integer_t ip, op; + igraph_int_t ideg, odeg; + igraph_int_t ip, op; - IGRAPH_CHECK(igraph_i_neighbors(graph, &inneis, i, IGRAPH_IN, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); - IGRAPH_CHECK(igraph_i_neighbors(graph, &outneis, i, IGRAPH_OUT, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); + IGRAPH_CHECK(igraph_neighbors(graph, &inneis, i, IGRAPH_IN, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); + IGRAPH_CHECK(igraph_neighbors(graph, &outneis, i, IGRAPH_OUT, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); ideg = igraph_vector_int_size(&inneis); odeg = igraph_vector_int_size(&outneis); @@ -1006,10 +1019,10 @@ static igraph_error_t igraph_i_triad_census_24(const igraph_t *graph, igraph_real_t *res2, igraph_real_t *res4) { - const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_int_t vcount = igraph_vcount(graph); igraph_vector_int_t seen; igraph_vector_int_t *neis, *neis2; - igraph_integer_t s, neilen, neilen2, ign; + igraph_int_t s, neilen, neilen2, ign; igraph_adjlist_t adjlist; int iter = 0; @@ -1018,7 +1031,7 @@ static igraph_error_t igraph_i_triad_census_24(const igraph_t *graph, IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); *res2 = *res4 = 0; - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 12); neis = igraph_adjlist_get(&adjlist, i); @@ -1026,8 +1039,8 @@ static igraph_error_t igraph_i_triad_census_24(const igraph_t *graph, /* mark neighbors of i & i itself */ VECTOR(seen)[i] = i + 1; ign = 0; - for (igraph_integer_t j = 0; j < neilen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + for (igraph_int_t j = 0; j < neilen; j++) { + igraph_int_t nei = VECTOR(*neis)[j]; if (VECTOR(seen)[nei] == i + 1 || VECTOR(seen)[nei] == -(i + 1)) { /* multiple edges or loop edge */ VECTOR(seen)[nei] = -(i + 1); @@ -1037,16 +1050,16 @@ static igraph_error_t igraph_i_triad_census_24(const igraph_t *graph, } } - for (igraph_integer_t j = 0; j < neilen; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + for (igraph_int_t j = 0; j < neilen; j++) { + igraph_int_t nei = VECTOR(*neis)[j]; if (nei <= i || (j > 0 && nei == VECTOR(*neis)[j - 1])) { continue; } neis2 = igraph_adjlist_get(&adjlist, nei); neilen2 = igraph_vector_int_size(neis2); s = 0; - for (igraph_integer_t k = 0; k < neilen2; k++) { - igraph_integer_t nei2 = VECTOR(*neis2)[k]; + for (igraph_int_t k = 0; k < neilen2; k++) { + igraph_int_t nei2 = VECTOR(*neis2)[k]; if (k > 0 && nei2 == VECTOR(*neis2)[k - 1]) { continue; } @@ -1148,7 +1161,7 @@ static igraph_error_t igraph_i_triad_census_24(const igraph_t *graph, igraph_error_t igraph_triad_census(const igraph_t *graph, igraph_vector_t *res) { - const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_int_t vcount = igraph_vcount(graph); igraph_vector_t cut_prob, tmp; igraph_real_t m2, m4; igraph_real_t total; diff --git a/src/vendor/cigraph/src/misc/other.c b/src/vendor/cigraph/src/misc/other.c index efb5c814e45..845145ac05f 100644 --- a/src/vendor/cigraph/src/misc/other.c +++ b/src/vendor/cigraph/src/misc/other.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -49,10 +48,10 @@ */ igraph_error_t igraph_running_mean(const igraph_vector_t *data, igraph_vector_t *res, - igraph_integer_t binwidth) { + igraph_int_t binwidth) { double sum = 0; - igraph_integer_t i; + igraph_int_t i; /* Check */ if (igraph_vector_size(data) < binwidth) { @@ -84,175 +83,6 @@ igraph_error_t igraph_running_mean(const igraph_vector_t *data, igraph_vector_t } -/** - * \ingroup nongraph - * \function igraph_convex_hull_2d - * \brief Determines the convex hull of a given set of points in the 2D plane. - * - * - * The convex hull is determined by the Graham scan algorithm. - * See the following reference for details: - * - * - * Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford - * Stein. Introduction to Algorithms, Second Edition. MIT Press and - * McGraw-Hill, 2001. ISBN 0262032937. Pages 949-955 of section 33.3: - * Finding the convex hull. - * - * \param data vector containing the coordinates. The length of the - * vector must be even, since it contains X-Y coordinate pairs. - * \param resverts the vector containing the result, e.g. the vector of - * vertex indices used as the corners of the convex hull. Supply - * \c NULL here if you are only interested in the coordinates of - * the convex hull corners. - * \param rescoords the matrix containing the coordinates of the selected - * corner vertices. Supply \c NULL here if you are only interested in - * the vertex indices. - * \return Error code: - * \c IGRAPH_ENOMEM: not enough memory - * - * Time complexity: O(n log(n)) where n is the number of vertices. - */ -igraph_error_t igraph_convex_hull_2d( - const igraph_matrix_t *data, igraph_vector_int_t *resverts, - igraph_matrix_t *rescoords -) { - igraph_integer_t no_of_nodes; - igraph_integer_t i, pivot_idx = 0, last_idx, before_last_idx, next_idx, j; - igraph_vector_t angles; - igraph_vector_int_t order, stack; - igraph_real_t px, py, cp; - - no_of_nodes = igraph_matrix_nrow(data); - if (igraph_matrix_ncol(data) != 2) { - IGRAPH_ERROR("Only two-dimensional point sets are supports, matrix must have two columns.", IGRAPH_EINVAL); - } - if (no_of_nodes == 0) { - if (resverts) { - igraph_vector_int_clear(resverts); - } - if (rescoords) { - IGRAPH_CHECK(igraph_matrix_resize(rescoords, 0, 2)); - } - /**************************** this is an exit here *********/ - return IGRAPH_SUCCESS; - } - - IGRAPH_VECTOR_INIT_FINALLY(&angles, no_of_nodes); - IGRAPH_VECTOR_INT_INIT_FINALLY(&stack, 0); - - /* Search for the pivot vertex */ - for (i = 1; i < no_of_nodes; i++) { - if (MATRIX(*data, i, 1) < MATRIX(*data, pivot_idx, 1)) { - pivot_idx = i; - } else if (MATRIX(*data, i, 1) == MATRIX(*data, pivot_idx, 1) && - MATRIX(*data, i, 0) < MATRIX(*data, pivot_idx, 0)) { - pivot_idx = i; - } - } - px = MATRIX(*data, pivot_idx, 0); - py = MATRIX(*data, pivot_idx, 1); - - /* Create angle array */ - for (i = 0; i < no_of_nodes; i++) { - if (i == pivot_idx) { - /* We can't calculate the angle of the pivot point with itself, - * so we use 10 here. This way, after sorting the angle vector, - * the pivot point will always be the first one, since the range - * of atan2 is -3.14..3.14 */ - VECTOR(angles)[i] = 10; - } else { - VECTOR(angles)[i] = atan2(MATRIX(*data, i, 1) - py, MATRIX(*data, i, 0) - px); - } - } - - /* Sort points by angles */ - IGRAPH_VECTOR_INT_INIT_FINALLY(&order, no_of_nodes); - IGRAPH_CHECK(igraph_vector_sort_ind(&angles, &order, IGRAPH_ASCENDING)); - - /* Check if two points have the same angle. If so, keep only the point that - * is farthest from the pivot */ - j = 0; - last_idx = VECTOR(order)[0]; - pivot_idx = VECTOR(order)[no_of_nodes - 1]; - for (i = 1; i < no_of_nodes; i++) { - next_idx = VECTOR(order)[i]; - if (VECTOR(angles)[last_idx] == VECTOR(angles)[next_idx]) { - /* Keep the vertex that is farther from the pivot, drop the one that is - * closer */ - px = pow(MATRIX(*data, last_idx, 0) - MATRIX(*data, pivot_idx, 0), 2) + - pow(MATRIX(*data, last_idx, 1) - MATRIX(*data, pivot_idx, 1), 2); - py = pow(MATRIX(*data, next_idx, 0) - MATRIX(*data, pivot_idx, 0), 2) + - pow(MATRIX(*data, next_idx, 1) - MATRIX(*data, pivot_idx, 1), 2); - if (px > py) { - VECTOR(order)[i] = -1; - } else { - VECTOR(order)[j] = -1; - last_idx = next_idx; - j = i; - } - } else { - last_idx = next_idx; - j = i; - } - } - - j = 0; - last_idx = -1; - before_last_idx = -1; - while (!igraph_vector_int_empty(&order)) { - next_idx = igraph_vector_int_tail(&order); - if (next_idx < 0) { - /* This vertex should be skipped; was excluded in an earlier step */ - igraph_vector_int_pop_back(&order); - continue; - } - /* Determine whether we are at a left or right turn */ - if (j < 2) { - /* Pretend that we are turning into the right direction if we have less - * than two items in the stack */ - cp = -1; - } else { - cp = (MATRIX(*data, last_idx, 0) - MATRIX(*data, before_last_idx, 0)) * - (MATRIX(*data, next_idx, 1) - MATRIX(*data, before_last_idx, 1)) - - (MATRIX(*data, next_idx, 0) - MATRIX(*data, before_last_idx, 0)) * - (MATRIX(*data, last_idx, 1) - MATRIX(*data, before_last_idx, 1)); - } - - if (cp < 0) { - /* We are turning into the right direction */ - igraph_vector_int_pop_back(&order); - IGRAPH_CHECK(igraph_vector_int_push_back(&stack, next_idx)); - before_last_idx = last_idx; - last_idx = next_idx; - j++; - } else { - /* No, skip back and try again in the next iteration */ - igraph_vector_int_pop_back(&stack); - j--; - last_idx = before_last_idx; - before_last_idx = (j >= 2) ? VECTOR(stack)[j - 2] : -1; - } - } - - /* Create result vector */ - if (resverts != 0) { - igraph_vector_int_clear(resverts); - IGRAPH_CHECK(igraph_vector_int_append(resverts, &stack)); - } - if (rescoords != 0) { - igraph_matrix_select_rows(data, rescoords, &stack); - } - - /* Free everything */ - igraph_vector_int_destroy(&order); - igraph_vector_int_destroy(&stack); - igraph_vector_destroy(&angles); - IGRAPH_FINALLY_CLEAN(3); - - return IGRAPH_SUCCESS; -} - /** * \function igraph_expand_path_to_pairs * \brief Helper function to convert a sequence of vertex IDs describing a path into a "pairs" vector. @@ -271,8 +101,8 @@ igraph_error_t igraph_convex_hull_2d( * the vector. */ igraph_error_t igraph_expand_path_to_pairs(igraph_vector_int_t* path) { - igraph_integer_t no_of_vertices = igraph_vector_int_size(path); - igraph_integer_t i, j, no_of_items = (no_of_vertices - 1) * 2; + igraph_int_t no_of_vertices = igraph_vector_int_size(path); + igraph_int_t i, j, no_of_items = (no_of_vertices - 1) * 2; if (no_of_vertices <= 1) { igraph_vector_int_clear(path); @@ -332,11 +162,11 @@ igraph_error_t igraph_expand_path_to_pairs(igraph_vector_int_t* path) { * Time complexity: O(n) where n is the length of the walk. */ igraph_error_t igraph_vertex_path_from_edge_path( - const igraph_t *graph, igraph_integer_t start, + const igraph_t *graph, igraph_int_t start, const igraph_vector_int_t *edge_path, igraph_vector_int_t *vertex_path, igraph_neimode_t mode ) { - const igraph_integer_t no_of_edges = igraph_vector_int_size(edge_path); + const igraph_int_t no_of_edges = igraph_vector_int_size(edge_path); igraph_vector_int_clear(vertex_path); IGRAPH_CHECK(igraph_vector_int_reserve(vertex_path, no_of_edges + 1)); @@ -351,7 +181,7 @@ igraph_error_t igraph_vertex_path_from_edge_path( IGRAPH_ERROR("The path must contain at least one edge in order to " "determine its starting vertex automatically.", IGRAPH_EINVAL); } - const igraph_integer_t edge = VECTOR(*edge_path)[0]; + const igraph_int_t edge = VECTOR(*edge_path)[0]; switch (mode) { case IGRAPH_OUT: start = IGRAPH_FROM(graph, edge); @@ -361,9 +191,9 @@ igraph_error_t igraph_vertex_path_from_edge_path( break; case IGRAPH_ALL: if (no_of_edges > 1) { - const igraph_integer_t from = IGRAPH_FROM(graph, edge); - const igraph_integer_t to = IGRAPH_TO(graph, edge); - const igraph_integer_t next_edge = VECTOR(*edge_path)[1]; + const igraph_int_t from = IGRAPH_FROM(graph, edge); + const igraph_int_t to = IGRAPH_TO(graph, edge); + const igraph_int_t next_edge = VECTOR(*edge_path)[1]; if (to == IGRAPH_FROM(graph, next_edge) || to == IGRAPH_TO(graph, next_edge)) { start = from; } else { @@ -382,12 +212,12 @@ igraph_error_t igraph_vertex_path_from_edge_path( IGRAPH_ERROR("Invalid start vertex.", IGRAPH_EINVVID); } - for (igraph_integer_t i = 0; i < no_of_edges; i++) { - const igraph_integer_t edge = VECTOR(*edge_path)[i]; - const igraph_integer_t from = IGRAPH_FROM(graph, edge); - const igraph_integer_t to = IGRAPH_TO(graph, edge); + for (igraph_int_t i = 0; i < no_of_edges; i++) { + const igraph_int_t edge = VECTOR(*edge_path)[i]; + const igraph_int_t from = IGRAPH_FROM(graph, edge); + const igraph_int_t to = IGRAPH_TO(graph, edge); igraph_bool_t next_edge_ok; - igraph_integer_t next_start; + igraph_int_t next_start; igraph_vector_int_push_back(vertex_path, start); /* reserved */ @@ -429,40 +259,3 @@ igraph_error_t igraph_vertex_path_from_edge_path( return IGRAPH_SUCCESS; } - - -/** - * \ingroup nongraph - * \function igraph_convex_hull - * \brief Determines the convex hull of a given set of points in the 2D plane (deprecated alias) - * - * - * The convex hull is determined by the Graham scan algorithm. - * See the following reference for details: - * - * - * Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford - * Stein. Introduction to Algorithms, Second Edition. MIT Press and - * McGraw-Hill, 2001. ISBN 0262032937. Pages 949-955 of section 33.3: - * Finding the convex hull. - * - * \param data vector containing the coordinates. The length of the - * vector must be even, since it contains X-Y coordinate pairs. - * \param resverts the vector containing the result, e.g. the vector of - * vertex indices used as the corners of the convex hull. Supply - * \c NULL here if you are only interested in the coordinates of - * the convex hull corners. - * \param rescoords the matrix containing the coordinates of the selected - * corner vertices. Supply \c NULL here if you are only interested in - * the vertex indices. - * \return Error code: - * \c IGRAPH_ENOMEM: not enough memory - * - * Time complexity: O(n log(n)) where n is the number of vertices. - */ -igraph_error_t igraph_convex_hull( - const igraph_matrix_t *data, igraph_vector_int_t *resverts, - igraph_matrix_t *rescoords -) { - return igraph_convex_hull_2d(data, resverts, rescoords); -} diff --git a/src/vendor/cigraph/src/misc/power_law_fit.c b/src/vendor/cigraph/src/misc/power_law_fit.c index ae71225a8c3..1f206205274 100644 --- a/src/vendor/cigraph/src/misc/power_law_fit.c +++ b/src/vendor/cigraph/src/misc/power_law_fit.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -198,8 +197,6 @@ igraph_error_t igraph_power_law_fit( } } - RNG_BEGIN(); - plfit_stored_error_handler = plfit_set_error_handler(igraph_i_plfit_error_handler_store); if (discrete) { igraph_i_plfit_prepare_discrete_options(&disc_options, finite_size_correction); @@ -220,8 +217,6 @@ igraph_error_t igraph_power_law_fit( } plfit_set_error_handler(plfit_stored_error_handler); - RNG_END(); - IGRAPH_CHECK(igraph_i_handle_plfit_error(retval)); if (result) { @@ -294,8 +289,6 @@ igraph_error_t igraph_plfit_result_calculate_p_value( finite_size_correction = igraph_i_plfit_should_use_finite_size_correction(model->data); - RNG_BEGIN(); - plfit_stored_error_handler = plfit_set_error_handler(igraph_i_plfit_error_handler_store); if (model->continuous) { igraph_i_plfit_prepare_continuous_options(&cont_options, finite_size_correction); @@ -316,8 +309,6 @@ igraph_error_t igraph_plfit_result_calculate_p_value( } plfit_set_error_handler(plfit_stored_error_handler); - RNG_END(); - IGRAPH_CHECK(igraph_i_handle_plfit_error(retval)); if (result) { diff --git a/src/vendor/cigraph/src/misc/scan.c b/src/vendor/cigraph/src/misc/scan.c index 689ceb33d86..dc24b67556e 100644 --- a/src/vendor/cigraph/src/misc/scan.c +++ b/src/vendor/cigraph/src/misc/scan.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2013 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -26,7 +25,6 @@ #include "igraph_adjlist.h" #include "igraph_dqueue.h" #include "igraph_interface.h" -#include "igraph_memory.h" #include "igraph_operators.h" #include "igraph_stack.h" #include "igraph_structural.h" @@ -65,46 +63,7 @@ igraph_error_t igraph_local_scan_0(const igraph_t *graph, igraph_vector_t *res, const igraph_vector_t *weights, igraph_neimode_t mode) { - return igraph_strength(graph, res, igraph_vss_all(), mode, /*loops=*/ 1, - weights); -} - -/* This removes loop, multiple edges and edges that point - "backwards" according to the rank vector. It works on - edge lists */ - -static igraph_error_t igraph_i_trans4_il_simplify(const igraph_t *graph, igraph_inclist_t *il, - const igraph_vector_int_t *rank) { - - igraph_integer_t i; - igraph_integer_t n = il->length; - igraph_vector_int_t mark; - - IGRAPH_VECTOR_INT_INIT_FINALLY(&mark, n); - - for (i = 0; i < n; i++) { - igraph_vector_int_t *v = &il->incs[i]; - igraph_integer_t j, l = igraph_vector_int_size(v); - igraph_integer_t irank = VECTOR(*rank)[i]; - VECTOR(mark)[i] = i + 1; - for (j = 0; j < l; /* nothing */) { - igraph_integer_t edge = VECTOR(*v)[j]; - igraph_integer_t e = IGRAPH_OTHER(graph, edge, i); - if (VECTOR(*rank)[e] > irank && VECTOR(mark)[e] != i + 1) { - VECTOR(mark)[e] = i + 1; - j++; - } else { - VECTOR(*v)[j] = igraph_vector_int_tail(v); - igraph_vector_int_pop_back(v); - l--; - } - } - } - - igraph_vector_int_destroy(&mark); - IGRAPH_FINALLY_CLEAN(1); - return IGRAPH_SUCCESS; - + return igraph_strength(graph, res, igraph_vss_all(), mode, IGRAPH_LOOPS, weights); } /* This one handles both weighted and unweighted cases */ @@ -114,9 +73,9 @@ static igraph_error_t igraph_i_local_scan_1_directed(const igraph_t *graph, const igraph_vector_t *weights, igraph_neimode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_inclist_t incs; - igraph_integer_t i, node; + igraph_int_t i, node; igraph_vector_int_t neis; @@ -130,15 +89,15 @@ static igraph_error_t igraph_i_local_scan_1_directed(const igraph_t *graph, for (node = 0; node < no_of_nodes; node++) { igraph_vector_int_t *edges1 = igraph_inclist_get(&incs, node); - igraph_integer_t edgeslen1 = igraph_vector_int_size(edges1); + igraph_int_t edgeslen1 = igraph_vector_int_size(edges1); IGRAPH_ALLOW_INTERRUPTION(); /* Mark neighbors and self */ VECTOR(neis)[node] = node + 1; for (i = 0; i < edgeslen1; i++) { - igraph_integer_t e = VECTOR(*edges1)[i]; - igraph_integer_t nei = IGRAPH_OTHER(graph, e, node); + igraph_int_t e = VECTOR(*edges1)[i]; + igraph_int_t nei = IGRAPH_OTHER(graph, e, node); igraph_real_t w = weights ? VECTOR(*weights)[e] : 1; VECTOR(neis)[nei] = node + 1; VECTOR(*res)[node] += w; @@ -146,16 +105,16 @@ static igraph_error_t igraph_i_local_scan_1_directed(const igraph_t *graph, /* Crawl neighbors */ for (i = 0; i < edgeslen1; i++) { - igraph_integer_t e2 = VECTOR(*edges1)[i]; - igraph_integer_t nei = IGRAPH_OTHER(graph, e2, node); + igraph_int_t e2 = VECTOR(*edges1)[i]; + igraph_int_t nei = IGRAPH_OTHER(graph, e2, node); if (nei == node) { break; } igraph_vector_int_t *edges2 = igraph_inclist_get(&incs, nei); - igraph_integer_t j, edgeslen2 = igraph_vector_int_size(edges2); + igraph_int_t j, edgeslen2 = igraph_vector_int_size(edges2); for (j = 0; j < edgeslen2; j++) { - igraph_integer_t e2 = VECTOR(*edges2)[j]; - igraph_integer_t nei2 = IGRAPH_OTHER(graph, e2, nei); + igraph_int_t e2 = VECTOR(*edges2)[j]; + igraph_int_t nei2 = IGRAPH_OTHER(graph, e2, nei); igraph_real_t w2 = weights ? VECTOR(*weights)[e2] : 1; if (VECTOR(neis)[nei2] == node + 1) { VECTOR(*res)[node] += w2; @@ -176,9 +135,9 @@ static igraph_error_t igraph_i_local_scan_1_directed_all(const igraph_t *graph, igraph_vector_t *res, const igraph_vector_t *weights) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_inclist_t incs; - igraph_integer_t i, node; + igraph_int_t i, node; igraph_vector_int_t neis; @@ -192,7 +151,7 @@ static igraph_error_t igraph_i_local_scan_1_directed_all(const igraph_t *graph, for (node = 0; node < no_of_nodes; node++) { igraph_vector_int_t *edges1 = igraph_inclist_get(&incs, node); - igraph_integer_t edgeslen1 = igraph_vector_int_size(edges1); + igraph_int_t edgeslen1 = igraph_vector_int_size(edges1); IGRAPH_ALLOW_INTERRUPTION(); @@ -201,8 +160,8 @@ static igraph_error_t igraph_i_local_scan_1_directed_all(const igraph_t *graph, double count its incident edges later, when we are going over the incident edges of ego's neighbors. */ for (i = 0; i < edgeslen1; i++) { - igraph_integer_t e = VECTOR(*edges1)[i]; - igraph_integer_t nei = IGRAPH_OTHER(graph, e, node); + igraph_int_t e = VECTOR(*edges1)[i]; + igraph_int_t nei = IGRAPH_OTHER(graph, e, node); igraph_real_t w = weights ? VECTOR(*weights)[e] : 1; VECTOR(neis)[nei] = node + 1; VECTOR(*res)[node] += w; @@ -215,18 +174,18 @@ static igraph_error_t igraph_i_local_scan_1_directed_all(const igraph_t *graph, only crawled once. We count all qualifying edges of ego, and then unmark ego to avoid double counting. */ for (i = 0; i < edgeslen1; i++) { - igraph_integer_t e2 = VECTOR(*edges1)[i]; - igraph_integer_t nei = IGRAPH_OTHER(graph, e2, node); + igraph_int_t e2 = VECTOR(*edges1)[i]; + igraph_int_t nei = IGRAPH_OTHER(graph, e2, node); igraph_vector_int_t *edges2; - igraph_integer_t j, edgeslen2; + igraph_int_t j, edgeslen2; if (VECTOR(neis)[nei] != node + 1) { continue; } edges2 = igraph_inclist_get(&incs, nei); edgeslen2 = igraph_vector_int_size(edges2); for (j = 0; j < edgeslen2; j++) { - igraph_integer_t e2 = VECTOR(*edges2)[j]; - igraph_integer_t nei2 = IGRAPH_OTHER(graph, e2, nei); + igraph_int_t e2 = VECTOR(*edges2)[j]; + igraph_int_t nei2 = IGRAPH_OTHER(graph, e2, nei); igraph_real_t w2 = weights ? VECTOR(*weights)[e2] : 1; if (VECTOR(neis)[nei2] == node + 1) { VECTOR(*res)[node] += w2; @@ -284,7 +243,7 @@ static igraph_error_t igraph_i_local_scan_0_them_w(const igraph_t *us, const igr igraph_t is; igraph_vector_int_t map2; igraph_vector_t weights; - igraph_integer_t i, m; + igraph_int_t i, m; if (!weights_them) { IGRAPH_ERROR("Edge weights not given for weighted scan-0", @@ -387,11 +346,11 @@ igraph_error_t igraph_local_scan_1_ecount_them(const igraph_t *us, const igraph_ const igraph_vector_t *weights_them, igraph_neimode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(us); + igraph_int_t no_of_nodes = igraph_vcount(us); igraph_adjlist_t adj_us; igraph_inclist_t incs_them; igraph_vector_int_t neis; - igraph_integer_t node; + igraph_int_t node; if (igraph_vcount(them) != no_of_nodes) { IGRAPH_ERROR("Number of vertices must match in scan-1", IGRAPH_EINVAL); @@ -420,23 +379,23 @@ igraph_error_t igraph_local_scan_1_ecount_them(const igraph_t *us, const igraph_ for (node = 0; node < no_of_nodes; node++) { igraph_vector_int_t *neis_us = igraph_adjlist_get(&adj_us, node); igraph_vector_int_t *edges1_them = igraph_inclist_get(&incs_them, node); - igraph_integer_t len1_us = igraph_vector_int_size(neis_us); - igraph_integer_t len1_them = igraph_vector_int_size(edges1_them); - igraph_integer_t i; + igraph_int_t len1_us = igraph_vector_int_size(neis_us); + igraph_int_t len1_them = igraph_vector_int_size(edges1_them); + igraph_int_t i; IGRAPH_ALLOW_INTERRUPTION(); /* Mark neighbors and self in us */ VECTOR(neis)[node] = node + 1; for (i = 0; i < len1_us; i++) { - igraph_integer_t nei = VECTOR(*neis_us)[i]; + igraph_int_t nei = VECTOR(*neis_us)[i]; VECTOR(neis)[nei] = node + 1; } /* Crawl neighbors in them, first ego */ for (i = 0; i < len1_them; i++) { - igraph_integer_t e = VECTOR(*edges1_them)[i]; - igraph_integer_t nei = IGRAPH_OTHER(them, e, node); + igraph_int_t e = VECTOR(*edges1_them)[i]; + igraph_int_t nei = IGRAPH_OTHER(them, e, node); if (VECTOR(neis)[nei] == node + 1) { igraph_real_t w = weights_them ? VECTOR(*weights_them)[e] : 1; VECTOR(*res)[node] += w; @@ -444,12 +403,12 @@ igraph_error_t igraph_local_scan_1_ecount_them(const igraph_t *us, const igraph_ } /* Then the rest */ for (i = 0; i < len1_us; i++) { - igraph_integer_t nei = VECTOR(*neis_us)[i]; + igraph_int_t nei = VECTOR(*neis_us)[i]; igraph_vector_int_t *edges2_them = igraph_inclist_get(&incs_them, nei); - igraph_integer_t j, len2_them = igraph_vector_int_size(edges2_them); + igraph_int_t j, len2_them = igraph_vector_int_size(edges2_them); for (j = 0; j < len2_them; j++) { - igraph_integer_t e2 = VECTOR(*edges2_them)[j]; - igraph_integer_t nei2 = IGRAPH_OTHER(them, e2, nei); + igraph_int_t e2 = VECTOR(*edges2_them)[j]; + igraph_int_t nei2 = IGRAPH_OTHER(them, e2, nei); if (VECTOR(neis)[nei2] == node + 1) { igraph_real_t w = weights_them ? VECTOR(*weights_them)[e2] : 1; VECTOR(*res)[node] += w; @@ -488,13 +447,13 @@ igraph_error_t igraph_local_scan_1_ecount_them(const igraph_t *us, const igraph_ * */ -igraph_error_t igraph_local_scan_k_ecount(const igraph_t *graph, igraph_integer_t k, +igraph_error_t igraph_local_scan_k_ecount(const igraph_t *graph, igraph_int_t k, igraph_vector_t *res, const igraph_vector_t *weights, igraph_neimode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t node; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t node; igraph_dqueue_int_t Q; igraph_vector_int_t marked; igraph_inclist_t incs; @@ -533,13 +492,13 @@ igraph_error_t igraph_local_scan_k_ecount(const igraph_t *graph, igraph_integer_ IGRAPH_CHECK(igraph_dqueue_int_push(&Q, 0)); VECTOR(marked)[node] = node + 1; while (!igraph_dqueue_int_empty(&Q)) { - igraph_integer_t act = igraph_dqueue_int_pop(&Q); - igraph_integer_t dist = igraph_dqueue_int_pop(&Q) + 1; + igraph_int_t act = igraph_dqueue_int_pop(&Q); + igraph_int_t dist = igraph_dqueue_int_pop(&Q) + 1; igraph_vector_int_t *edges = igraph_inclist_get(&incs, act); - igraph_integer_t i, edgeslen = igraph_vector_int_size(edges); + igraph_int_t i, edgeslen = igraph_vector_int_size(edges); for (i = 0; i < edgeslen; i++) { - igraph_integer_t edge = VECTOR(*edges)[i]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, act); + igraph_int_t edge = VECTOR(*edges)[i]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, act); if (dist <= k || VECTOR(marked)[nei] == node + 1) { igraph_real_t w = weights ? VECTOR(*weights)[edge] : 1; VECTOR(*res)[node] += w; @@ -588,12 +547,12 @@ igraph_error_t igraph_local_scan_k_ecount(const igraph_t *graph, igraph_integer_ */ igraph_error_t igraph_local_scan_k_ecount_them(const igraph_t *us, const igraph_t *them, - igraph_integer_t k, igraph_vector_t *res, + igraph_int_t k, igraph_vector_t *res, const igraph_vector_t *weights_them, igraph_neimode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(us); - igraph_integer_t node; + igraph_int_t no_of_nodes = igraph_vcount(us); + igraph_int_t node; igraph_dqueue_int_t Q; igraph_vector_int_t marked; igraph_stack_int_t ST; @@ -651,13 +610,13 @@ igraph_error_t igraph_local_scan_k_ecount_them(const igraph_t *us, const igraph_ IGRAPH_CHECK(igraph_stack_int_push(&ST, node)); VECTOR(marked)[node] = node + 1; while (!igraph_dqueue_int_empty(&Q)) { - igraph_integer_t act = igraph_dqueue_int_pop(&Q); - igraph_integer_t dist = igraph_dqueue_int_pop(&Q) + 1; + igraph_int_t act = igraph_dqueue_int_pop(&Q); + igraph_int_t dist = igraph_dqueue_int_pop(&Q) + 1; igraph_vector_int_t *edges = igraph_inclist_get(&incs_us, act); - igraph_integer_t i, edgeslen = igraph_vector_int_size(edges); + igraph_int_t i, edgeslen = igraph_vector_int_size(edges); for (i = 0; i < edgeslen; i++) { - igraph_integer_t edge = VECTOR(*edges)[i]; - igraph_integer_t nei = IGRAPH_OTHER(us, edge, act); + igraph_int_t edge = VECTOR(*edges)[i]; + igraph_int_t nei = IGRAPH_OTHER(us, edge, act); if (dist <= k && VECTOR(marked)[nei] != node + 1) { IGRAPH_CHECK(igraph_dqueue_int_push(&Q, nei)); IGRAPH_CHECK(igraph_dqueue_int_push(&Q, dist)); @@ -669,12 +628,12 @@ igraph_error_t igraph_local_scan_k_ecount_them(const igraph_t *us, const igraph_ /* Now check the edges of all nodes in THEM */ while (!igraph_stack_int_empty(&ST)) { - igraph_integer_t act = igraph_stack_int_pop(&ST); + igraph_int_t act = igraph_stack_int_pop(&ST); igraph_vector_int_t *edges = igraph_inclist_get(&incs_them, act); - igraph_integer_t i, edgeslen = igraph_vector_int_size(edges); + igraph_int_t i, edgeslen = igraph_vector_int_size(edges); for (i = 0; i < edgeslen; i++) { - igraph_integer_t edge = VECTOR(*edges)[i]; - igraph_integer_t nei = IGRAPH_OTHER(them, edge, act); + igraph_int_t edge = VECTOR(*edges)[i]; + igraph_int_t nei = IGRAPH_OTHER(them, edge, act); if (VECTOR(marked)[nei] == node + 1) { igraph_real_t w = weights_them ? VECTOR(*weights_them)[edge] : 1; VECTOR(*res)[node] += w; @@ -718,8 +677,8 @@ igraph_error_t igraph_local_scan_subset_ecount(const igraph_t *graph, const igraph_vector_t *weights, const igraph_vector_int_list_t *subsets) { - igraph_integer_t subset, no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_subsets = igraph_vector_int_list_size(subsets); + igraph_int_t subset, no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_subsets = igraph_vector_int_list_size(subsets); igraph_inclist_t incs; igraph_vector_int_t marked; igraph_bool_t directed = igraph_is_directed(graph); @@ -737,9 +696,9 @@ igraph_error_t igraph_local_scan_subset_ecount(const igraph_t *graph, for (subset = 0; subset < no_of_subsets; subset++) { igraph_vector_int_t *nei = igraph_vector_int_list_get_ptr(subsets, subset); - igraph_integer_t i, neilen = igraph_vector_int_size(nei); + igraph_int_t i, neilen = igraph_vector_int_size(nei); for (i = 0; i < neilen; i++) { - igraph_integer_t vertex = VECTOR(*nei)[i]; + igraph_int_t vertex = VECTOR(*nei)[i]; if (vertex < 0 || vertex >= no_of_nodes) { IGRAPH_ERROR("Invalid vertex ID in neighborhood list in local scan.", IGRAPH_EINVAL); @@ -748,12 +707,12 @@ igraph_error_t igraph_local_scan_subset_ecount(const igraph_t *graph, } for (i = 0; i < neilen; i++) { - igraph_integer_t vertex = VECTOR(*nei)[i]; + igraph_int_t vertex = VECTOR(*nei)[i]; igraph_vector_int_t *edges = igraph_inclist_get(&incs, vertex); - igraph_integer_t j, edgeslen = igraph_vector_int_size(edges); + igraph_int_t j, edgeslen = igraph_vector_int_size(edges); for (j = 0; j < edgeslen; j++) { - igraph_integer_t edge = VECTOR(*edges)[j]; - igraph_integer_t nei2 = IGRAPH_OTHER(graph, edge, vertex); + igraph_int_t edge = VECTOR(*edges)[j]; + igraph_int_t nei2 = IGRAPH_OTHER(graph, edge, vertex); if (VECTOR(marked)[nei2] == subset + 1) { igraph_real_t w = weights ? VECTOR(*weights)[edge] : 1; VECTOR(*res)[subset] += w; @@ -796,7 +755,7 @@ igraph_error_t igraph_local_scan_neighborhood_ecount(const igraph_t *graph, const igraph_vector_t *weights, const igraph_vector_int_list_t *neighborhoods) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (igraph_vector_int_list_size(neighborhoods) != no_of_nodes) { IGRAPH_ERROR("Invalid neighborhood list length in local scan.", diff --git a/src/vendor/cigraph/src/misc/sir.c b/src/vendor/cigraph/src/misc/sir.c index fb2a64f7515..6800c32a264 100644 --- a/src/vendor/cigraph/src/misc/sir.c +++ b/src/vendor/cigraph/src/misc/sir.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2014 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -59,7 +58,7 @@ void igraph_sir_destroy(igraph_sir_t *sir) { } static void igraph_i_sir_destroy(igraph_vector_ptr_t *v) { - igraph_integer_t i, n = igraph_vector_ptr_size(v); + igraph_int_t i, n = igraph_vector_ptr_size(v); for (i = 0; i < n; i++) { if ( VECTOR(*v)[i] ) { igraph_sir_destroy( VECTOR(*v)[i]) ; @@ -110,18 +109,18 @@ static void igraph_i_sir_destroy(igraph_vector_ptr_t *v) { */ igraph_error_t igraph_sir(const igraph_t *graph, igraph_real_t beta, - igraph_real_t gamma, igraph_integer_t no_sim, + igraph_real_t gamma, igraph_int_t no_sim, igraph_vector_ptr_t *result) { - igraph_integer_t infected; + igraph_int_t infected; igraph_vector_int_t status; igraph_adjlist_t adjlist; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t i, j, ns, ni, nr; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t i, j, ns, ni, nr; igraph_vector_int_t *neis; igraph_psumtree_t tree; igraph_real_t psum; - igraph_integer_t neilen; + igraph_int_t neilen; igraph_bool_t simple; if (no_of_nodes == 0) { @@ -138,19 +137,13 @@ igraph_error_t igraph_sir(const igraph_t *graph, igraph_real_t beta, IGRAPH_ERROR("Number of SIR simulations must be positive.", IGRAPH_EINVAL); } - IGRAPH_CHECK(igraph_is_simple(graph, &simple)); - if (!simple) { - IGRAPH_ERROR("SIR model only works with simple graphs.", IGRAPH_EINVAL); - } if (igraph_is_directed(graph)) { - igraph_bool_t has_mutual; IGRAPH_WARNING("Edge directions are ignored in SIR model."); - /* When the graph is directed, mutual edges are effectively multi-edges as we - * are ignoring edge directions. */ - IGRAPH_CHECK(igraph_has_mutual(graph, &has_mutual, false)); - if (has_mutual) { - IGRAPH_ERROR("SIR model only works with simple graphs.", IGRAPH_EINVAL); - } + } + + IGRAPH_CHECK(igraph_is_simple(graph, &simple, IGRAPH_UNDIRECTED)); + if (!simple) { + IGRAPH_ERROR("SIR model only works with simple graphs.", IGRAPH_EINVAL); } IGRAPH_CHECK(igraph_vector_int_init(&status, no_of_nodes)); @@ -172,8 +165,6 @@ igraph_error_t igraph_sir(const igraph_t *graph, igraph_real_t beta, VECTOR(*result)[i] = sir; } - RNG_BEGIN(); - for (j = 0; j < no_sim; j++) { igraph_sir_t *sir = VECTOR(*result)[j]; @@ -205,14 +196,14 @@ igraph_error_t igraph_sir(const igraph_t *graph, igraph_real_t beta, neis = igraph_adjlist_get(&adjlist, infected); neilen = igraph_vector_int_size(neis); for (i = 0; i < neilen; i++) { - igraph_integer_t nei = VECTOR(*neis)[i]; + igraph_int_t nei = VECTOR(*neis)[i]; IGRAPH_CHECK(igraph_psumtree_update(&tree, nei, beta)); } while (ni > 0) { igraph_real_t tt; igraph_real_t r; - igraph_integer_t vchange; + igraph_int_t vchange; IGRAPH_ALLOW_INTERRUPTION(); @@ -229,7 +220,7 @@ igraph_error_t igraph_sir(const igraph_t *graph, igraph_real_t beta, ni--; nr++; IGRAPH_CHECK(igraph_psumtree_update(&tree, vchange, 0.0)); for (i = 0; i < neilen; i++) { - igraph_integer_t nei = VECTOR(*neis)[i]; + igraph_int_t nei = VECTOR(*neis)[i]; if (VECTOR(status)[nei] == S_S) { igraph_real_t rate = igraph_psumtree_get(&tree, nei); rate -= beta; @@ -247,7 +238,7 @@ igraph_error_t igraph_sir(const igraph_t *graph, igraph_real_t beta, ns--; ni++; IGRAPH_CHECK(igraph_psumtree_update(&tree, vchange, gamma)); for (i = 0; i < neilen; i++) { - igraph_integer_t nei = VECTOR(*neis)[i]; + igraph_int_t nei = VECTOR(*neis)[i]; if (VECTOR(status)[nei] == S_S) { igraph_real_t rate = igraph_psumtree_get(&tree, nei); rate += beta; @@ -265,8 +256,6 @@ igraph_error_t igraph_sir(const igraph_t *graph, igraph_real_t beta, } /* j < no_sim */ - RNG_END(); - igraph_psumtree_destroy(&tree); igraph_adjlist_destroy(&adjlist); igraph_vector_int_destroy(&status); diff --git a/src/vendor/cigraph/src/misc/spanning_trees.c b/src/vendor/cigraph/src/misc/spanning_trees.c index 77413945a1b..95c8516d167 100644 --- a/src/vendor/cigraph/src/misc/spanning_trees.c +++ b/src/vendor/cigraph/src/misc/spanning_trees.c @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2011-2023 The igraph development team + igraph library. + Copyright (C) 2011-2024 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,204 +21,73 @@ #include "igraph_components.h" #include "igraph_dqueue.h" #include "igraph_interface.h" -#include "igraph_operators.h" #include "igraph_random.h" #include "igraph_structural.h" #include "core/indheap.h" #include "core/interruption.h" -static igraph_error_t igraph_i_minimum_spanning_tree_unweighted( - const igraph_t *graph, igraph_vector_int_t *result); -static igraph_error_t igraph_i_minimum_spanning_tree_prim( - const igraph_t *graph, igraph_vector_int_t *result, const igraph_vector_t *weights); +static igraph_int_t max_tree_edges(igraph_int_t no_of_nodes, igraph_int_t no_of_edges) { + if (no_of_nodes == 0) return 0; + if (no_of_edges < no_of_nodes) return no_of_edges; + return no_of_nodes - 1; +} + + +/* Unweighted case -- just a simple BFS */ /** * \ingroup structural - * \function igraph_minimum_spanning_tree - * \brief Calculates one minimum spanning tree of a graph. + * \function igraph_i_minimum_spanning_tree_unweighted + * \brief A spanning tree of an unweighted graph. * - * Finds a spanning tree of the graph. If the graph is not connected - * then its minimum spanning forest is returned. This is the set of the - * minimum spanning trees of each component. + * Produces an arbitrary spanning tree of the graph. * * - * Directed graphs are considered as undirected for this computation. + * Directed graphs are treated as undirected for this computation. * * - * This function is deterministic, i.e. it always returns the same - * spanning tree. See \ref igraph_random_spanning_tree() for the uniform - * random sampling of spanning trees of a graph. + * If the graph is not connected then a spanning forest is returned. + * This is a set of spanning trees of each component. * - * \param graph The graph object. + * \param graph The graph object. Edge directions will be ignored. * \param res An initialized vector, the IDs of the edges that constitute * a spanning tree will be returned here. Use * \ref igraph_subgraph_from_edges() to extract the spanning tree as * a separate graph object. - * \param weights A vector containing the weights of the edges - * in the same order as the simple edge iterator visits them - * (i.e. in increasing order of edge IDs). - * \return Error code: - * \c IGRAPH_ENOMEM, not enough memory for - * temporary data. - * - * Time complexity: O(|V|+|E|) for the unweighted case, O(|E| log |V|) - * for the weighted case. |V| is the number of vertices, |E| the - * number of edges in the graph. - * - * \sa \ref igraph_minimum_spanning_tree_unweighted() and - * \ref igraph_minimum_spanning_tree_prim() if you only need the - * tree as a separate graph object. - * - * \example examples/simple/igraph_minimum_spanning_tree.c - */ -igraph_error_t igraph_minimum_spanning_tree( - const igraph_t *graph, igraph_vector_int_t *res, const igraph_vector_t *weights -) { - if (weights == NULL) { - IGRAPH_CHECK(igraph_i_minimum_spanning_tree_unweighted(graph, res)); - } else { - IGRAPH_CHECK(igraph_i_minimum_spanning_tree_prim(graph, res, weights)); - } - return IGRAPH_SUCCESS; -} - -/** - * \ingroup structural - * \function igraph_minimum_spanning_tree_unweighted - * \brief Calculates one minimum spanning tree of an unweighted graph. - * - * \deprecated-by igraph_minimum_spanning_tree 0.10.14 - * - * If the graph has more minimum spanning trees (this is always the - * case, except if it is a forest) this implementation returns only - * the same one. - * - * - * Directed graphs are considered as undirected for this computation. - * - * - * If the graph is not connected then its minimum spanning forest is - * returned. This is the set of the minimum spanning trees of each - * component. - * - * \param graph The graph object. Edge directions will be ignored. - * \param mst The minimum spanning tree, another graph object. Do - * \em not initialize this object before passing it to - * this function, but be sure to call \ref igraph_destroy() on it if - * you don't need it any more. * \return Error code: - * \c IGRAPH_ENOMEM, not enough memory for - * temporary data. + * \c IGRAPH_ENOMEM, not enough memory for temporary data. * * Time complexity: O(|V|+|E|), * |V| is the * number of vertices, |E| the number * of edges in the graph. * - * \sa \ref igraph_minimum_spanning_tree_prim() for weighted graphs, - * \ref igraph_minimum_spanning_tree() if you need the IDs of the - * edges that constitute the spanning tree. + * \sa \ref igraph_minimum_spanning_tree() for a common interface to all + * minimum spanning tree algorithms. */ -igraph_error_t igraph_minimum_spanning_tree_unweighted(const igraph_t *graph, - igraph_t *mst) { - igraph_vector_int_t edges; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - - IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_nodes > 0 ? no_of_nodes - 1 : 0); - IGRAPH_CHECK(igraph_i_minimum_spanning_tree_unweighted(graph, &edges)); - IGRAPH_CHECK(igraph_subgraph_from_edges( - graph, mst, igraph_ess_vector(&edges), /* delete_vertices = */ false)); - igraph_vector_int_destroy(&edges); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} - -/** - * \ingroup structural - * \function igraph_minimum_spanning_tree_prim - * \brief Calculates one minimum spanning tree of a weighted graph. - * - * \deprecated-by igraph_minimum_spanning_tree 0.10.14 - * - * Finds a spanning tree or spanning forest for which the sum of edge - * weights is the smallest. This function uses Prim's method for carrying - * out the computation. - * - * - * Directed graphs are considered as undirected for this computation. - * - * - * Reference: - * - * - * Prim, R.C.: Shortest connection networks and some - * generalizations, Bell System Technical - * Journal, Vol. 36, - * 1957, 1389--1401. - * https://doi.org/10.1002/j.1538-7305.1957.tb01515.x - * - * \param graph The graph object. Edge directions will be ignored. - * \param mst The result of the computation, a graph object containing - * the minimum spanning tree of the graph. - * Do \em not initialize this object before passing it to - * this function, but be sure to call \ref igraph_destroy() on it if - * you don't need it any more. - * \param weights A vector containing the weights of the edges - * in the same order as the simple edge iterator visits them - * (i.e. in increasing order of edge IDs). - * \return Error code: - * \c IGRAPH_ENOMEM, not enough memory. - * \c IGRAPH_EINVAL, length of weight vector does not - * match number of edges. - * - * Time complexity: O(|E| log |V|), - * |V| is the number of vertices, - * |E| the number of edges in the - * graph. - * - * \sa \ref igraph_minimum_spanning_tree_unweighted() for unweighted graphs, - * \ref igraph_minimum_spanning_tree() if you need the IDs of the - * edges that constitute the spanning tree. - * - * \example examples/simple/igraph_minimum_spanning_tree.c - */ - -igraph_error_t igraph_minimum_spanning_tree_prim(const igraph_t *graph, igraph_t *mst, - const igraph_vector_t *weights) { - igraph_vector_int_t edges; - - IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, igraph_vcount(graph) - 1); - IGRAPH_CHECK(igraph_i_minimum_spanning_tree_prim(graph, &edges, weights)); - IGRAPH_CHECK(igraph_subgraph_from_edges( - graph, mst, igraph_ess_vector(&edges), /* delete_vertices = */ false)); - igraph_vector_int_destroy(&edges); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} - - -static igraph_error_t igraph_i_minimum_spanning_tree_unweighted(const igraph_t* graph, igraph_vector_int_t* res) { +static igraph_error_t igraph_i_minimum_spanning_tree_unweighted( + const igraph_t* graph, + igraph_vector_int_t* res) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bitset_t already_added, added_edges; igraph_dqueue_int_t q; igraph_vector_int_t eids; - igraph_vector_int_clear(res); - IGRAPH_BITSET_INIT_FINALLY(&added_edges, no_of_edges); IGRAPH_BITSET_INIT_FINALLY(&already_added, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&eids, 0); IGRAPH_DQUEUE_INT_INIT_FINALLY(&q, 100); + igraph_vector_int_clear(res); + IGRAPH_CHECK(igraph_vector_int_reserve(res, max_tree_edges(no_of_nodes, no_of_edges))); + /* Perform a BFS */ - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (IGRAPH_BIT_TEST(already_added, i)) { continue; } @@ -228,19 +97,18 @@ static igraph_error_t igraph_i_minimum_spanning_tree_unweighted(const igraph_t* IGRAPH_BIT_SET(already_added, i); IGRAPH_CHECK(igraph_dqueue_int_push(&q, i)); while (! igraph_dqueue_int_empty(&q)) { - igraph_integer_t eids_size; - igraph_integer_t act_node = igraph_dqueue_int_pop(&q); - IGRAPH_CHECK(igraph_incident(graph, &eids, act_node, - IGRAPH_ALL)); + igraph_int_t eids_size; + igraph_int_t act_node = igraph_dqueue_int_pop(&q); + IGRAPH_CHECK(igraph_incident(graph, &eids, act_node, IGRAPH_ALL, IGRAPH_LOOPS)); eids_size = igraph_vector_int_size(&eids); - for (igraph_integer_t j = 0; j < eids_size; j++) { - igraph_integer_t edge = VECTOR(eids)[j]; + for (igraph_int_t j = 0; j < eids_size; j++) { + igraph_int_t edge = VECTOR(eids)[j]; if (! IGRAPH_BIT_TEST(added_edges, edge)) { - igraph_integer_t to = IGRAPH_OTHER(graph, edge, act_node); + igraph_int_t to = IGRAPH_OTHER(graph, edge, act_node); if (! IGRAPH_BIT_TEST(already_added, to)) { IGRAPH_BIT_SET(already_added, to); IGRAPH_BIT_SET(added_edges, edge); - IGRAPH_CHECK(igraph_vector_int_push_back(res, edge)); + igraph_vector_int_push_back(res, edge); /* reserved */ IGRAPH_CHECK(igraph_dqueue_int_push(&q, to)); } } @@ -257,20 +125,66 @@ static igraph_error_t igraph_i_minimum_spanning_tree_unweighted(const igraph_t* return IGRAPH_SUCCESS; } + +/* Prims' algorithm */ + +/** + * \ingroup structural + * \function igraph_i_minimum_spanning_tree_prim + * \brief A minimum spanning tree of a weighted graph using Prim's method. + * + * Finds a spanning tree or spanning forest for which the sum of edge + * weights is the smallest. This function uses Prim's method for carrying + * out the computation. + * + * + * Directed graphs are treated as undirected for this computation. + * + * + * Reference: + * + * + * Prim, R.C.: Shortest connection networks and some + * generalizations, Bell System Technical + * Journal, Vol. 36, + * 1957, 1389--1401. + * https://doi.org/10.1002/j.1538-7305.1957.tb01515.x + * + * \param graph The graph object. Edge directions will be ignored. + * \param res An initialized vector, the IDs of the edges that constitute + * a spanning tree will be returned here. Use + * \ref igraph_subgraph_from_edges() to extract the spanning tree as + * a separate graph object. + * \param weights A vector containing the weights of the edges in the order + * of edge IDs. Weights must not be NaN. + * \return Error code: + * \c IGRAPH_ENOMEM, not enough memory. + * \c IGRAPH_EINVAL, length of weight vector does not + * match number of edges, or NaN in weights. + * + * Time complexity: O(|E| log |V|), + * |V| is the number of vertices, + * |E| the number of edges in the + * graph. + * + * \sa \ref igraph_minimum_spanning_tree() for a common interface to all + * minimum spanning tree algorithms. + * + * \example examples/simple/igraph_minimum_spanning_tree.c + */ + static igraph_error_t igraph_i_minimum_spanning_tree_prim( - const igraph_t* graph, igraph_vector_int_t* res, const igraph_vector_t *weights) { + const igraph_t* graph, + igraph_vector_int_t* res, + const igraph_vector_t *weights) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bitset_t already_added, added_edges; igraph_d_indheap_t heap; - const igraph_neimode_t mode = IGRAPH_ALL; - igraph_vector_int_t adj; - igraph_vector_int_clear(res); - if (weights == NULL) { return igraph_i_minimum_spanning_tree_unweighted(graph, res); } @@ -280,9 +194,12 @@ static igraph_error_t igraph_i_minimum_spanning_tree_prim( } if (igraph_vector_is_any_nan(weights)) { - IGRAPH_ERROR("Weigths must not contain NaN values.", IGRAPH_EINVAL); + IGRAPH_ERROR("Weights must not contain NaN values.", IGRAPH_EINVAL); } + igraph_vector_int_clear(res); + IGRAPH_CHECK(igraph_vector_int_reserve(res, max_tree_edges(no_of_nodes, no_of_edges))); + IGRAPH_BITSET_INIT_FINALLY(&added_edges, no_of_edges); IGRAPH_BITSET_INIT_FINALLY(&already_added, no_of_nodes); @@ -291,8 +208,8 @@ static igraph_error_t igraph_i_minimum_spanning_tree_prim( IGRAPH_VECTOR_INT_INIT_FINALLY(&adj, 0); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t adj_size; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t adj_size; if (IGRAPH_BIT_TEST(already_added, i)) { continue; } @@ -300,11 +217,11 @@ static igraph_error_t igraph_i_minimum_spanning_tree_prim( IGRAPH_BIT_SET(already_added, i); /* add all edges of the first vertex */ - IGRAPH_CHECK(igraph_incident(graph, &adj, i, mode)); + IGRAPH_CHECK(igraph_incident(graph, &adj, i, IGRAPH_ALL, IGRAPH_LOOPS)); adj_size = igraph_vector_int_size(&adj); - for (igraph_integer_t j = 0; j < adj_size; j++) { - igraph_integer_t edgeno = VECTOR(adj)[j]; - igraph_integer_t neighbor = IGRAPH_OTHER(graph, edgeno, i); + for (igraph_int_t j = 0; j < adj_size; j++) { + igraph_int_t edgeno = VECTOR(adj)[j]; + igraph_int_t neighbor = IGRAPH_OTHER(graph, edgeno, i); if (! IGRAPH_BIT_TEST(already_added, neighbor)) { IGRAPH_CHECK(igraph_d_indheap_push(&heap, -VECTOR(*weights)[edgeno], i, edgeno)); } @@ -312,7 +229,7 @@ static igraph_error_t igraph_i_minimum_spanning_tree_prim( while (! igraph_d_indheap_empty(&heap)) { /* Get minimal edge */ - igraph_integer_t from, edge; + igraph_int_t from, edge; igraph_d_indheap_max_index(&heap, &from, &edge); /* Erase it */ @@ -320,19 +237,19 @@ static igraph_error_t igraph_i_minimum_spanning_tree_prim( /* Is this edge already included? */ if (! IGRAPH_BIT_TEST(added_edges, edge)) { - igraph_integer_t to = IGRAPH_OTHER(graph, edge, from); + const igraph_int_t to = IGRAPH_OTHER(graph, edge, from); /* Does it point to a visited node? */ if (! IGRAPH_BIT_TEST(already_added, to)) { IGRAPH_BIT_SET(already_added, to); IGRAPH_BIT_SET(added_edges, edge); - IGRAPH_CHECK(igraph_vector_int_push_back(res, edge)); + igraph_vector_int_push_back(res, edge); /* reserved */ /* add all outgoing edges */ - IGRAPH_CHECK(igraph_incident(graph, &adj, to, mode)); + IGRAPH_CHECK(igraph_incident(graph, &adj, to, IGRAPH_ALL, IGRAPH_LOOPS)); adj_size = igraph_vector_int_size(&adj); - for (igraph_integer_t j = 0; j < adj_size; j++) { - igraph_integer_t edgeno = VECTOR(adj)[j]; - igraph_integer_t neighbor = IGRAPH_OTHER(graph, edgeno, to); + for (igraph_int_t j = 0; j < adj_size; j++) { + const igraph_int_t edgeno = VECTOR(adj)[j]; + const igraph_int_t neighbor = IGRAPH_OTHER(graph, edgeno, to); if (! IGRAPH_BIT_TEST(already_added, neighbor)) { IGRAPH_CHECK(igraph_d_indheap_push(&heap, -VECTOR(*weights)[edgeno], to, edgeno)); } @@ -352,6 +269,221 @@ static igraph_error_t igraph_i_minimum_spanning_tree_prim( } +/* Kruskal's algorithm */ + +static igraph_int_t get_comp(igraph_vector_int_t *comp, igraph_int_t i) { + igraph_int_t k = i; + for (;;) { + igraph_int_t next = VECTOR(*comp)[k]; + if (next == k) { + VECTOR(*comp)[i] = k; + return k; + } else { + k = next; + } + } +} + +static void merge_comp(igraph_vector_int_t *comp, igraph_int_t i, igraph_int_t j) { + igraph_int_t ci = get_comp(comp, i); + igraph_int_t cj = get_comp(comp, j); + VECTOR(*comp)[ci] = cj; +} + +/** + * \ingroup structural + * \function igraph_i_minimum_spanning_tree_kruskal + * \brief A minimum spanning tree of a weighted graph using Kruskal's method. + * + * Finds a spanning tree or spanning forest for which the sum of edge + * weights is the smallest. This function uses Kruskal's method for carrying + * out the computation. + * + * + * Directed graphs are treated as undirected for this computation. + * + * + * Reference: + * + * + * Kruskal, J. B.: + * On the shortest spanning subtree of a graph and the traveling salesman problem, + * Proc. Amer. Math. Soc. 7 (1956), 48-50 + * https://doi.org/10.1090%2FS0002-9939-1956-0078686-7 + * + * \param graph The graph object. Edge directions will be ignored. + * \param res An initialized vector, the IDs of the edges that constitute + * a spanning tree will be returned here. Use + * \ref igraph_subgraph_from_edges() to extract the spanning tree as + * a separate graph object. + * \param weights A vector containing the weights of the edges in the order + * of edge IDs. Weights must not be NaN. + * \return Error code: + * \c IGRAPH_ENOMEM, not enough memory. + * \c IGRAPH_EINVAL, length of weight vector does not + * match number of edges, or NaN in weights. + * + * Time complexity: O(|E| log |E|), + * |V| is the number of vertices, + * |E| the number of edges in the + * graph. + * + * \sa \ref igraph_minimum_spanning_tree() for a common interface to all + * minimum spanning tree algorithms. + * + * \example examples/simple/igraph_minimum_spanning_tree.c + */ + +static igraph_error_t igraph_i_minimum_spanning_tree_kruskal( + const igraph_t *graph, + igraph_vector_int_t *res, + const igraph_vector_t *weights) { + + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_vector_int_t idx, comp; + igraph_int_t tree_edge_count; + int iter = 0; + + if (weights == NULL) { + return igraph_i_minimum_spanning_tree_unweighted(graph, res); + } + + if (igraph_vector_size(weights) != igraph_ecount(graph)) { + IGRAPH_ERROR("Weight vector length does not match number of edges.", IGRAPH_EINVAL); + } + + if (igraph_vector_is_any_nan(weights)) { + IGRAPH_ERROR("Weights must not contain NaN values.", IGRAPH_EINVAL); + } + + IGRAPH_VECTOR_INT_INIT_FINALLY(&idx, no_of_edges); + IGRAPH_CHECK(igraph_vector_sort_ind(weights, &idx, IGRAPH_ASCENDING)); + + IGRAPH_CHECK(igraph_vector_int_init_range(&comp, 0, no_of_nodes)); + IGRAPH_FINALLY(igraph_vector_int_destroy, &comp); + + igraph_vector_int_clear(res); + IGRAPH_CHECK(igraph_vector_int_reserve(res, max_tree_edges(no_of_nodes, no_of_edges))); + + tree_edge_count = 0; + for (igraph_int_t i=0; i < no_of_edges; i++) { + igraph_int_t edge = VECTOR(idx)[i]; + igraph_int_t u = IGRAPH_FROM(graph, edge); + igraph_int_t v = IGRAPH_TO(graph, edge); + + igraph_int_t cu = get_comp(&comp, u); + igraph_int_t cv = get_comp(&comp, v); + + if (cu != cv) { + merge_comp(&comp, u, v); + igraph_vector_int_push_back(res, edge); /* reserved */ + tree_edge_count++; + } + + if (tree_edge_count == no_of_nodes - 1) { + /* We have enough edges for a tree. */ + break; + } + + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 16); + } + + igraph_vector_int_destroy(&idx); + igraph_vector_int_destroy(&comp); + IGRAPH_FINALLY_CLEAN(2); + + return IGRAPH_SUCCESS; +} + + +/** + * \ingroup structural + * \function igraph_minimum_spanning_tree + * \brief Calculates a minimum spanning tree of a graph. + * + * Finds a minimum weight spanning tree of the graph. If the graph is not + * connected then its minimum spanning forest is returned, i.e. the set + * of the minimum spanning trees of each component. + * + * + * Directed graphs are treated as undirected for this computation. + * + * + * This function is deterministic, i.e. it always returns the same + * spanning tree. See \ref igraph_random_spanning_tree() for the uniform + * random sampling of spanning trees of a graph. + * + * + * References: + * + * + * Prim, R.C.: Shortest connection networks and some + * generalizations, Bell System Technical + * Journal, Vol. 36, + * 1957, 1389--1401. + * https://doi.org/10.1002/j.1538-7305.1957.tb01515.x + * + * + * Kruskal, J. B.: + * On the shortest spanning subtree of a graph and the traveling salesman problem, + * Proc. Amer. Math. Soc. 7 (1956), 48-50 + * https://doi.org/10.1090%2FS0002-9939-1956-0078686-7 + * + * \param graph The graph object. Edge directions will be ignored. + * \param res An initialized vector, the IDs of the edges that constitute + * a spanning tree will be returned here. Use + * \ref igraph_subgraph_from_edges() to extract the spanning tree as + * a separate graph object. + * \param weights A vector containing the weights of the edges in the order + * of edge IDs. Weights must not be NaN. Supply \c NULL to treat all + * edges as having the same weight. + * \param method The type of the algorithm used. + * \clist + * \cli IGRAPH_MST_AUTOMATIC + * tries to select the best performing algorithm for the current graph. + * \cli IGRAPH_MST_UNWEIGHTED + * ignores edge weights and produces an arbitrary spanning tree. + * \cli IGRAPH_MST_PRIM + * uses Prim's algorithm. + * \cli IGRAPH_MST_KRUSKAL + * uses Kruskal's algorithm. + * \endclist + * \return Error code. + * + * Time complexity: See the functions implementing the specific algorithms. + * + * \sa \ref igraph_random_spanning_tree() to compute a random spanning tree + * instead of a minimum one. + * + * \example examples/simple/igraph_minimum_spanning_tree.c + */ +igraph_error_t igraph_minimum_spanning_tree( + const igraph_t *graph, igraph_vector_int_t *res, + const igraph_vector_t *weights, igraph_mst_algorithm_t method) +{ + if (method == IGRAPH_MST_AUTOMATIC) { + /* For now we use igraph_minimum_spanning_tree_kruskal() unconditionally + * for the weighted case; see benchmarks. */ + if (weights == NULL) { + method = IGRAPH_MST_UNWEIGHTED; + } else { + method = IGRAPH_MST_KRUSKAL; + } + } + switch (method) { + case IGRAPH_MST_UNWEIGHTED: + return igraph_i_minimum_spanning_tree_unweighted(graph, res); + case IGRAPH_MST_PRIM: + return igraph_i_minimum_spanning_tree_prim(graph, res, weights); + case IGRAPH_MST_KRUSKAL: + return igraph_i_minimum_spanning_tree_kruskal(graph, res, weights); + default: + IGRAPH_ERROR("Invalid method for minimum spanning tree.", IGRAPH_EINVAL); + } +} + + /* igraph_random_spanning_tree */ /* Loop-erased random walk (LERW) implementation. @@ -361,19 +493,17 @@ static igraph_error_t igraph_i_minimum_spanning_tree_prim( * The walk is started from vertex start. comp_size must be the size of the connected * component containing start. */ -static igraph_error_t igraph_i_lerw(const igraph_t *graph, igraph_vector_int_t *res, igraph_integer_t start, - igraph_integer_t comp_size, igraph_vector_bool_t *visited, const igraph_inclist_t *il) { - igraph_integer_t visited_count; +static igraph_error_t igraph_i_lerw(const igraph_t *graph, igraph_vector_int_t *res, igraph_int_t start, + igraph_int_t comp_size, igraph_vector_bool_t *visited, const igraph_inclist_t *il) { + igraph_int_t visited_count; IGRAPH_CHECK(igraph_vector_int_reserve(res, igraph_vector_int_size(res) + comp_size - 1)); VECTOR(*visited)[start] = true; visited_count = 1; - RNG_BEGIN(); - while (visited_count < comp_size) { - igraph_integer_t degree, edge; + igraph_int_t degree, edge; igraph_vector_int_t *edges; edges = igraph_inclist_get(il, start); @@ -395,8 +525,6 @@ static igraph_error_t igraph_i_lerw(const igraph_t *graph, igraph_vector_int_t * IGRAPH_ALLOW_INTERRUPTION(); } - RNG_END(); - return IGRAPH_SUCCESS; } @@ -430,10 +558,10 @@ static igraph_error_t igraph_i_lerw(const igraph_t *graph, igraph_vector_int_t * * \sa \ref igraph_minimum_spanning_tree(), \ref igraph_random_walk() * */ -igraph_error_t igraph_random_spanning_tree(const igraph_t *graph, igraph_vector_int_t *res, igraph_integer_t vid) { +igraph_error_t igraph_random_spanning_tree(const igraph_t *graph, igraph_vector_int_t *res, igraph_int_t vid) { igraph_inclist_t il; igraph_vector_bool_t visited; - igraph_integer_t vcount = igraph_vcount(graph); + igraph_int_t vcount = igraph_vcount(graph); if (vid >= vcount) { IGRAPH_ERROR("Invalid vertex ID given for random spanning tree.", IGRAPH_EINVVID); @@ -449,7 +577,7 @@ igraph_error_t igraph_random_spanning_tree(const igraph_t *graph, igraph_vector_ if (vid < 0) { /* generate random spanning forest: consider each component separately */ igraph_vector_int_t membership, csize; - igraph_integer_t comp_count; + igraph_int_t comp_count; IGRAPH_VECTOR_INT_INIT_FINALLY(&membership, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&csize, 0); @@ -457,9 +585,9 @@ igraph_error_t igraph_random_spanning_tree(const igraph_t *graph, igraph_vector_ IGRAPH_CHECK(igraph_connected_components(graph, &membership, &csize, &comp_count, IGRAPH_WEAK)); /* for each component ... */ - for (igraph_integer_t i = 0; i < comp_count; ++i) { + for (igraph_int_t i = 0; i < comp_count; ++i) { /* ... find a vertex to start the LERW from */ - igraph_integer_t j = 0; + igraph_int_t j = 0; while (VECTOR(membership)[j] != i) { ++j; } @@ -472,7 +600,7 @@ igraph_error_t igraph_random_spanning_tree(const igraph_t *graph, igraph_vector_ IGRAPH_FINALLY_CLEAN(2); } else { /* consider the component containing vid */ igraph_vector_int_t comp_vertices; - igraph_integer_t comp_size; + igraph_int_t comp_size; /* we measure the size of the component */ IGRAPH_VECTOR_INT_INIT_FINALLY(&comp_vertices, 0); diff --git a/src/vendor/cigraph/src/operators/add_edge.c b/src/vendor/cigraph/src/operators/add_edge.c index 57924919c2f..5c993b8efa8 100644 --- a/src/vendor/cigraph/src/operators/add_edge.c +++ b/src/vendor/cigraph/src/operators/add_edge.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -48,7 +46,7 @@ * Time complexity: O(|V|+|E|), the number of edges plus the number of * vertices. */ -igraph_error_t igraph_add_edge(igraph_t *graph, igraph_integer_t from, igraph_integer_t to) { +igraph_error_t igraph_add_edge(igraph_t *graph, igraph_int_t from, igraph_int_t to) { igraph_vector_int_t edges; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 2); diff --git a/src/vendor/cigraph/src/operators/complementer.c b/src/vendor/cigraph/src/operators/complementer.c index f6a41c6327a..6bbf9f19135 100644 --- a/src/vendor/cigraph/src/operators/complementer.c +++ b/src/vendor/cigraph/src/operators/complementer.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -51,11 +50,11 @@ igraph_error_t igraph_complementer(igraph_t *res, const igraph_t *graph, igraph_bool_t loops) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t edges; igraph_vector_int_t neis; - igraph_integer_t i, j; - igraph_integer_t zero = 0, *limit; + igraph_int_t i, j; + igraph_int_t zero = 0, *limit; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); @@ -68,7 +67,7 @@ igraph_error_t igraph_complementer(igraph_t *res, const igraph_t *graph, for (i = 0; i < no_of_nodes; i++) { IGRAPH_ALLOW_INTERRUPTION(); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, IGRAPH_OUT, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); if (loops) { for (j = no_of_nodes - 1; j >= *limit; j--) { if (igraph_vector_int_empty(&neis) || j > igraph_vector_int_tail(&neis)) { @@ -95,8 +94,7 @@ igraph_error_t igraph_complementer(igraph_t *res, const igraph_t *graph, IGRAPH_CHECK(igraph_create(res, &edges, no_of_nodes, igraph_is_directed(graph))); igraph_vector_int_destroy(&edges); igraph_vector_int_destroy(&neis); - IGRAPH_I_ATTRIBUTE_DESTROY(res); - IGRAPH_I_ATTRIBUTE_COPY(res, graph, /*graph=*/true, /*vertex=*/true, /*edge=*/false); + IGRAPH_CHECK(igraph_i_attribute_copy(res, graph, true, true, /* edges= */ false)); IGRAPH_FINALLY_CLEAN(2); return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/operators/compose.c b/src/vendor/cigraph/src/operators/compose.c index 6c3373c3b3f..3063c585d8c 100644 --- a/src/vendor/cigraph/src/operators/compose.c +++ b/src/vendor/cigraph/src/operators/compose.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -70,10 +69,10 @@ igraph_error_t igraph_compose(igraph_t *res, igraph_vector_int_t *edge_map1, igraph_vector_int_t *edge_map2) { - const igraph_integer_t no_of_nodes_left = igraph_vcount(g1); - const igraph_integer_t no_of_nodes_right = igraph_vcount(g2); + const igraph_int_t no_of_nodes_left = igraph_vcount(g1); + const igraph_int_t no_of_nodes_right = igraph_vcount(g2); const igraph_bool_t directed = igraph_is_directed(g1); - const igraph_integer_t no_of_nodes = no_of_nodes_left > no_of_nodes_right ? + const igraph_int_t no_of_nodes = no_of_nodes_left > no_of_nodes_right ? no_of_nodes_left : no_of_nodes_right; igraph_vector_int_t edges; igraph_vector_int_t neis1, neis2; @@ -94,20 +93,20 @@ igraph_error_t igraph_compose(igraph_t *res, igraph_vector_int_clear(edge_map2); } - for (igraph_integer_t i = 0; i < no_of_nodes_left; i++) { + for (igraph_int_t i = 0; i < no_of_nodes_left; i++) { IGRAPH_ALLOW_INTERRUPTION(); - IGRAPH_CHECK(igraph_incident(g1, &neis1, i, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(g1, &neis1, i, IGRAPH_OUT, IGRAPH_LOOPS)); while (!igraph_vector_int_empty(&neis1)) { - const igraph_integer_t con = igraph_vector_int_pop_back(&neis1); - const igraph_integer_t v1 = IGRAPH_OTHER(g1, con, i); + const igraph_int_t con = igraph_vector_int_pop_back(&neis1); + const igraph_int_t v1 = IGRAPH_OTHER(g1, con, i); if (v1 < no_of_nodes_right) { - IGRAPH_CHECK(igraph_incident(g2, &neis2, v1, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(g2, &neis2, v1, IGRAPH_OUT, IGRAPH_LOOPS)); } else { continue; } while (!igraph_vector_int_empty(&neis2)) { - const igraph_integer_t con2 = igraph_vector_int_pop_back(&neis2); - const igraph_integer_t v2 = IGRAPH_OTHER(g2, con2, v1); + const igraph_int_t con2 = igraph_vector_int_pop_back(&neis2); + const igraph_int_t v2 = IGRAPH_OTHER(g2, con2, v1); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, i)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, v2)); if (edge_map1) { diff --git a/src/vendor/cigraph/src/operators/connect_neighborhood.c b/src/vendor/cigraph/src/operators/connect_neighborhood.c index a0ada48a3e5..06978614a19 100644 --- a/src/vendor/cigraph/src/operators/connect_neighborhood.c +++ b/src/vendor/cigraph/src/operators/connect_neighborhood.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -66,14 +65,14 @@ * Time complexity: O(|V|*d^k), |V| is the number of vertices in the * graph, d is the average degree and k is the \p order argument. */ -igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t order, +igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_int_t order, igraph_neimode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_dqueue_int_t q; igraph_vector_int_t edges; - igraph_integer_t i, j, in; - igraph_integer_t *added; + igraph_int_t i, j, in; + igraph_int_t *added; igraph_vector_int_t neis; if (order < 0) { @@ -90,7 +89,7 @@ igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t ord } IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); - added = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + added = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(added, "Cannot connect neighborhood."); IGRAPH_FINALLY(igraph_free, added); @@ -99,11 +98,11 @@ igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t ord for (i = 0; i < no_of_nodes; i++) { added[i] = i + 1; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); in = igraph_vector_int_size(&neis); if (order > 1) { for (j = 0; j < in; j++) { - igraph_integer_t nei = VECTOR(neis)[j]; + igraph_int_t nei = VECTOR(neis)[j]; added[nei] = i + 1; IGRAPH_CHECK(igraph_dqueue_int_push(&q, nei)); IGRAPH_CHECK(igraph_dqueue_int_push(&q, 1)); @@ -111,15 +110,15 @@ igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t ord } while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); - igraph_integer_t n; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode)); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); + igraph_int_t n; + IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); n = igraph_vector_int_size(&neis); if (actdist < order - 1) { for (j = 0; j < n; j++) { - igraph_integer_t nei = VECTOR(neis)[j]; + igraph_int_t nei = VECTOR(neis)[j]; if (added[nei] != i + 1) { added[nei] = i + 1; IGRAPH_CHECK(igraph_dqueue_int_push(&q, nei)); @@ -137,7 +136,7 @@ igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t ord } } else { for (j = 0; j < n; j++) { - igraph_integer_t nei = VECTOR(neis)[j]; + igraph_int_t nei = VECTOR(neis)[j]; if (added[nei] != i + 1) { added[nei] = i + 1; if (mode != IGRAPH_ALL || i < nei) { @@ -171,11 +170,9 @@ igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t ord /** * \function igraph_graph_power - * \brief The kth power of a graph. + * \brief The k-th power of a graph. * - * \experimental - * - * The kth power of a graph G is a simple graph where vertex \c u is connected to + * The k-th power of a graph G is a simple graph where vertex \c u is connected to * \c v by a single edge if \c v is reachable from \c u in G within at most k steps. * By convention, the zeroth power of a graph has no edges. The first power is * identical to the original graph, except that multiple edges and self-loops @@ -203,10 +200,10 @@ igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t ord * graph, d is the average degree and k is the \p order argument. */ igraph_error_t igraph_graph_power(const igraph_t *graph, igraph_t *res, - igraph_integer_t order, igraph_bool_t directed) { + igraph_int_t order, igraph_bool_t directed) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_int_t edges; igraph_adjlist_t al; igraph_bool_t dir = igraph_is_directed(graph) && directed; @@ -218,8 +215,7 @@ igraph_error_t igraph_graph_power(const igraph_t *graph, igraph_t *res, } IGRAPH_CHECK(igraph_empty(res, no_of_nodes, dir)); - IGRAPH_I_ATTRIBUTE_DESTROY(res); - IGRAPH_I_ATTRIBUTE_COPY(res, graph, /* graph */ true, /* vertex */ true, /* edge */ false); + IGRAPH_CHECK(igraph_i_attribute_copy(res, graph, true, true, /* edges= */ false)); if (order == 0) { return IGRAPH_SUCCESS; } @@ -233,12 +229,12 @@ igraph_error_t igraph_graph_power(const igraph_t *graph, igraph_t *res, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges); igraph_vector_int_clear(&edges); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { igraph_vector_int_t *tmp = igraph_adjlist_get(&al, i); - for (igraph_integer_t j = 0; j < igraph_vector_int_size(tmp); j++) { + for (igraph_int_t j = 0; j < igraph_vector_int_size(tmp); j++) { if (dir || i < VECTOR(*tmp)[j]) { - igraph_vector_int_push_back(&edges, i); - igraph_vector_int_push_back(&edges, VECTOR(*tmp)[j]); + igraph_vector_int_push_back(&edges, i); /* initial space reserved */ + igraph_vector_int_push_back(&edges, VECTOR(*tmp)[j]); /* initial space reserved */ } } } @@ -246,39 +242,39 @@ igraph_error_t igraph_graph_power(const igraph_t *graph, igraph_t *res, if (order > 1) { /* order > 1, so add more edges. */ - igraph_integer_t d_i, d_actnode; - igraph_integer_t *added; + igraph_int_t d_i, d_actnode; + igraph_int_t *added; const igraph_vector_int_t *neis; igraph_dqueue_int_t q; - added = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + added = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(added, "Insufficient memory for graph power."); IGRAPH_FINALLY(igraph_free, added); IGRAPH_DQUEUE_INT_INIT_FINALLY(&q, 100); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { added[i] = i + 1; neis = igraph_adjlist_get(&al, i); d_i = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < d_i; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + for (igraph_int_t j = 0; j < d_i; j++) { + igraph_int_t nei = VECTOR(*neis)[j]; added[nei] = i + 1; IGRAPH_CHECK(igraph_dqueue_int_push(&q, nei)); IGRAPH_CHECK(igraph_dqueue_int_push(&q, 1)); } while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); neis = igraph_adjlist_get(&al, actnode); d_actnode = igraph_vector_int_size(neis); if (actdist < order - 1) { - for (igraph_integer_t j = 0; j < d_actnode; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + for (igraph_int_t j = 0; j < d_actnode; j++) { + igraph_int_t nei = VECTOR(*neis)[j]; if (added[nei] != i + 1) { added[nei] = i + 1; IGRAPH_CHECK(igraph_dqueue_int_push(&q, nei)); @@ -290,8 +286,8 @@ igraph_error_t igraph_graph_power(const igraph_t *graph, igraph_t *res, } } } else { - for (igraph_integer_t j = 0; j < d_actnode; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + for (igraph_int_t j = 0; j < d_actnode; j++) { + igraph_int_t nei = VECTOR(*neis)[j]; if (added[nei] != i + 1) { added[nei] = i + 1; if (dir || i < nei) { diff --git a/src/vendor/cigraph/src/operators/contract.c b/src/vendor/cigraph/src/operators/contract.c index bb965d52a43..1b32de544e0 100644 --- a/src/vendor/cigraph/src/operators/contract.c +++ b/src/vendor/cigraph/src/operators/contract.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -64,12 +63,12 @@ igraph_error_t igraph_contract_vertices(igraph_t *graph, const igraph_vector_int_t *mapping, const igraph_attribute_combination_t *vertex_comb) { igraph_vector_int_t edges; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t vattr = vertex_comb && igraph_has_attribute_table(); igraph_t res; - igraph_integer_t last; - igraph_integer_t no_new_vertices; + igraph_int_t last; + igraph_int_t no_new_vertices; if (igraph_vector_int_size(mapping) != no_of_nodes) { IGRAPH_ERRORF("Mapping vector length (%" IGRAPH_PRId ") " @@ -88,15 +87,15 @@ igraph_error_t igraph_contract_vertices(igraph_t *graph, last = -1; } - for (igraph_integer_t edge = 0; edge < no_of_edges; edge++) { - igraph_integer_t from = IGRAPH_FROM(graph, edge); - igraph_integer_t to = IGRAPH_TO(graph, edge); + for (igraph_int_t edge = 0; edge < no_of_edges; edge++) { + igraph_int_t from = IGRAPH_FROM(graph, edge); + igraph_int_t to = IGRAPH_TO(graph, edge); - igraph_integer_t nfrom = VECTOR(*mapping)[from]; - igraph_integer_t nto = VECTOR(*mapping)[to]; + igraph_int_t nfrom = VECTOR(*mapping)[from]; + igraph_int_t nto = VECTOR(*mapping)[to]; - igraph_vector_int_push_back(&edges, nfrom); - igraph_vector_int_push_back(&edges, nto); + igraph_vector_int_push_back(&edges, nfrom); /* reserved */ + igraph_vector_int_push_back(&edges, nto); /* reserved */ if (nfrom > last) { last = nfrom; @@ -116,8 +115,7 @@ igraph_error_t igraph_contract_vertices(igraph_t *graph, IGRAPH_FINALLY(igraph_destroy, &res); - IGRAPH_I_ATTRIBUTE_DESTROY(&res); - IGRAPH_I_ATTRIBUTE_COPY(&res, graph, /*graph=*/ true, /*vertex=*/ false, /*edge=*/ true); + IGRAPH_CHECK(igraph_i_attribute_copy(&res, graph, true, /* vertex= */ false, true)); if (vattr) { igraph_vector_int_list_t merges; @@ -126,8 +124,8 @@ igraph_error_t igraph_contract_vertices(igraph_t *graph, IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(&merges, no_new_vertices); IGRAPH_VECTOR_INT_INIT_FINALLY(&sizes, no_new_vertices); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t to = VECTOR(*mapping)[i]; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t to = VECTOR(*mapping)[i]; igraph_vector_int_t *v = igraph_vector_int_list_get_ptr(&merges, to); VECTOR(sizes)[to] += 1; IGRAPH_CHECK(igraph_vector_int_push_back(v, i)); diff --git a/src/vendor/cigraph/src/operators/difference.c b/src/vendor/cigraph/src/operators/difference.c index f9c5786d65a..ac6517de994 100644 --- a/src/vendor/cigraph/src/operators/difference.c +++ b/src/vendor/cigraph/src/operators/difference.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -59,17 +58,17 @@ igraph_error_t igraph_difference(igraph_t *res, contains the vertices according to the order of the vertex IDs at the "other" end of the edge. */ - igraph_integer_t no_of_nodes_orig = igraph_vcount(orig); - igraph_integer_t no_of_nodes_sub = igraph_vcount(sub); - igraph_integer_t no_of_nodes = no_of_nodes_orig; - igraph_integer_t smaller_nodes; + igraph_int_t no_of_nodes_orig = igraph_vcount(orig); + igraph_int_t no_of_nodes_sub = igraph_vcount(sub); + igraph_int_t no_of_nodes = no_of_nodes_orig; + igraph_int_t smaller_nodes; igraph_bool_t directed = igraph_is_directed(orig); igraph_vector_int_t edges; igraph_vector_int_t edge_ids; igraph_vector_int_t *nei1, *nei2; igraph_inclist_t inc_orig, inc_sub; - igraph_integer_t i; - igraph_integer_t v1, v2; + igraph_int_t i; + igraph_int_t v1, v2; if (directed != igraph_is_directed(sub)) { IGRAPH_ERROR("Cannot subtract directed and undirected graphs.", @@ -87,7 +86,7 @@ igraph_error_t igraph_difference(igraph_t *res, no_of_nodes_sub : no_of_nodes_orig; for (i = 0; i < smaller_nodes; i++) { - igraph_integer_t n1, n2, e1, e2; + igraph_int_t n1, n2, e1, e2; IGRAPH_ALLOW_INTERRUPTION(); nei1 = igraph_inclist_get(&inc_orig, i); nei2 = igraph_inclist_get(&inc_sub, i); @@ -140,7 +139,7 @@ igraph_error_t igraph_difference(igraph_t *res, /* copy remaining edges, use the previous value of 'i' */ for (; i < no_of_nodes_orig; i++) { - igraph_integer_t n1, e1; + igraph_int_t n1, e1; nei1 = igraph_inclist_get(&inc_orig, i); n1 = igraph_vector_int_size(nei1) - 1; while (n1 >= 0) { @@ -171,8 +170,7 @@ igraph_error_t igraph_difference(igraph_t *res, /* Attributes */ if (orig->attr) { - IGRAPH_I_ATTRIBUTE_DESTROY(res); - IGRAPH_I_ATTRIBUTE_COPY(res, orig, /*graph=*/ true, /*vertex=*/ true, /*edge=*/ false); + IGRAPH_CHECK(igraph_i_attribute_copy(res, orig, true, true, /* edge= */ false)); IGRAPH_CHECK(igraph_i_attribute_permute_edges(orig, res, &edge_ids)); } diff --git a/src/vendor/cigraph/src/operators/disjoint_union.c b/src/vendor/cigraph/src/operators/disjoint_union.c index f6e31ab4cfe..f288925545e 100644 --- a/src/vendor/cigraph/src/operators/disjoint_union.c +++ b/src/vendor/cigraph/src/operators/disjoint_union.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -70,15 +69,15 @@ igraph_error_t igraph_disjoint_union(igraph_t *res, const igraph_t *left, const igraph_t *right) { - const igraph_integer_t no_of_nodes_left = igraph_vcount(left); - const igraph_integer_t no_of_nodes_right = igraph_vcount(right); - const igraph_integer_t no_of_edges_left = igraph_ecount(left); - const igraph_integer_t no_of_edges_right = igraph_ecount(right); - igraph_integer_t no_of_nodes; /* vertex count of the result */ - igraph_integer_t no_of_edges2; /* twice the edge count of the result */ + const igraph_int_t no_of_nodes_left = igraph_vcount(left); + const igraph_int_t no_of_nodes_right = igraph_vcount(right); + const igraph_int_t no_of_edges_left = igraph_ecount(left); + const igraph_int_t no_of_edges_right = igraph_ecount(right); + igraph_int_t no_of_nodes; /* vertex count of the result */ + igraph_int_t no_of_edges2; /* twice the edge count of the result */ igraph_vector_int_t edges; igraph_bool_t directed_left = igraph_is_directed(left); - igraph_integer_t from, to; + igraph_int_t from, to; if (directed_left != igraph_is_directed(right)) { IGRAPH_ERROR("Cannot create disjoint union of directed and undirected graphs.", @@ -91,13 +90,13 @@ igraph_error_t igraph_disjoint_union(igraph_t *res, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); - for (igraph_integer_t i = 0; i < no_of_edges_left; i++) { + for (igraph_int_t i = 0; i < no_of_edges_left; i++) { from = IGRAPH_FROM(left, i); to = IGRAPH_TO(left, i); igraph_vector_int_push_back(&edges, from); /* reserved */ igraph_vector_int_push_back(&edges, to); /* reserved */ } - for (igraph_integer_t i = 0; i < no_of_edges_right; i++) { + for (igraph_int_t i = 0; i < no_of_edges_right; i++) { from = IGRAPH_FROM(right, i); to = IGRAPH_TO(right, i); igraph_vector_int_push_back(&edges, from + no_of_nodes_left); /* reserved */ @@ -150,18 +149,18 @@ igraph_error_t igraph_disjoint_union(igraph_t *res, */ igraph_error_t igraph_disjoint_union_many(igraph_t *res, const igraph_vector_ptr_t *graphs) { - igraph_integer_t no_of_graphs = igraph_vector_ptr_size(graphs); + igraph_int_t no_of_graphs = igraph_vector_ptr_size(graphs); igraph_bool_t directed = true; igraph_vector_int_t edges; - igraph_integer_t no_of_edges2 = 0; /* twice the edge count of the result */ - igraph_integer_t shift = 0; + igraph_int_t no_of_edges2 = 0; /* twice the edge count of the result */ + igraph_int_t shift = 0; igraph_t *graph; - igraph_integer_t from, to; + igraph_int_t from, to; if (no_of_graphs != 0) { graph = VECTOR(*graphs)[0]; directed = igraph_is_directed(graph); - for (igraph_integer_t i = 0; i < no_of_graphs; i++) { + for (igraph_int_t i = 0; i < no_of_graphs; i++) { graph = VECTOR(*graphs)[i]; IGRAPH_SAFE_ADD(no_of_edges2, 2*igraph_ecount(graph), &no_of_edges2); if (directed != igraph_is_directed(graph)) { @@ -174,11 +173,11 @@ igraph_error_t igraph_disjoint_union_many(igraph_t *res, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_int_reserve(&edges, no_of_edges2)); - for (igraph_integer_t i = 0; i < no_of_graphs; i++) { - igraph_integer_t ec; + for (igraph_int_t i = 0; i < no_of_graphs; i++) { + igraph_int_t ec; graph = VECTOR(*graphs)[i]; ec = igraph_ecount(graph); - for (igraph_integer_t j = 0; j < ec; j++) { + for (igraph_int_t j = 0; j < ec; j++) { from = IGRAPH_FROM(graph, j); to = IGRAPH_TO(graph, j); igraph_vector_int_push_back(&edges, from + shift); /* reserved */ diff --git a/src/vendor/cigraph/src/operators/intersection.c b/src/vendor/cigraph/src/operators/intersection.c index 006e390d73e..dc936ab750d 100644 --- a/src/vendor/cigraph/src/operators/intersection.c +++ b/src/vendor/cigraph/src/operators/intersection.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -123,16 +122,16 @@ igraph_error_t igraph_intersection_many( igraph_vector_int_list_t *edgemaps ) { - igraph_integer_t no_of_graphs = igraph_vector_ptr_size(graphs); - igraph_integer_t no_of_nodes = 0; + igraph_int_t no_of_graphs = igraph_vector_ptr_size(graphs); + igraph_int_t no_of_nodes = 0; igraph_bool_t directed = true; igraph_vector_int_t edges; igraph_vector_int_list_t edge_vects, order_vects; - igraph_integer_t i, j, tailfrom = no_of_graphs > 0 ? 0 : -1, tailto = -1; + igraph_int_t i, j, tailfrom = no_of_graphs > 0 ? 0 : -1, tailto = -1; igraph_vector_int_t no_edges; igraph_bool_t allne = no_of_graphs > 0; igraph_bool_t allsame = false; - igraph_integer_t idx = 0; + igraph_int_t idx = 0; /* Check directedness */ if (no_of_graphs != 0) { @@ -151,7 +150,7 @@ igraph_error_t igraph_intersection_many( /* Calculate number of nodes, query number of edges */ for (i = 0; i < no_of_graphs; i++) { - igraph_integer_t n = igraph_vcount(VECTOR(*graphs)[i]); + igraph_int_t n = igraph_vcount(VECTOR(*graphs)[i]); if (n > no_of_nodes) { no_of_nodes = n; } @@ -174,14 +173,14 @@ igraph_error_t igraph_intersection_many( /* Query and sort the edge lists */ for (i = 0; i < no_of_graphs; i++) { - igraph_integer_t k, j, n = VECTOR(no_edges)[i]; + igraph_int_t k, j, n = VECTOR(no_edges)[i]; igraph_vector_int_t *ev = igraph_vector_int_list_get_ptr(&edge_vects, i); igraph_vector_int_t *order = igraph_vector_int_list_get_ptr(&order_vects, i); IGRAPH_CHECK(igraph_get_edgelist(VECTOR(*graphs)[i], ev, /*bycol=*/ false)); if (!directed) { for (k = 0, j = 0; k < n; k++, j += 2) { if (VECTOR(*ev)[j] > VECTOR(*ev)[j + 1]) { - igraph_integer_t tmp = VECTOR(*ev)[j]; + igraph_int_t tmp = VECTOR(*ev)[j]; VECTOR(*ev)[j] = VECTOR(*ev)[j + 1]; VECTOR(*ev)[j + 1] = tmp; } @@ -207,9 +206,9 @@ igraph_error_t igraph_intersection_many( for (j = 0, tailfrom = IGRAPH_INTEGER_MAX, tailto = IGRAPH_INTEGER_MAX; j < no_of_graphs; j++) { igraph_vector_int_t *order = igraph_vector_int_list_get_ptr(&order_vects, j); igraph_vector_int_t *ev = igraph_vector_int_list_get_ptr(&edge_vects, j); - igraph_integer_t edge = igraph_vector_int_tail(order); - igraph_integer_t from = VECTOR(*ev)[2 * edge]; - igraph_integer_t to = VECTOR(*ev)[2 * edge + 1]; + igraph_int_t edge = igraph_vector_int_tail(order); + igraph_int_t from = VECTOR(*ev)[2 * edge]; + igraph_int_t to = VECTOR(*ev)[2 * edge + 1]; if (from < tailfrom || (from == tailfrom && to < tailto)) { tailfrom = from; tailto = to; } @@ -218,10 +217,10 @@ igraph_error_t igraph_intersection_many( /* OK, now remove all elements from the tail(s) that are bigger than the smallest tail element. */ for (j = 0, allsame = true; j < no_of_graphs; j++) { - igraph_integer_t from = -1, to = -1; + igraph_int_t from = -1, to = -1; igraph_vector_int_t *order = igraph_vector_int_list_get_ptr(&order_vects, j); while (true) { - igraph_integer_t edge = igraph_vector_int_tail(order); + igraph_int_t edge = igraph_vector_int_tail(order); igraph_vector_int_t *ev = igraph_vector_int_list_get_ptr(&edge_vects, j); from = VECTOR(*ev)[2 * edge]; to = VECTOR(*ev)[2 * edge + 1]; @@ -252,10 +251,10 @@ igraph_error_t igraph_intersection_many( if (allne) { for (j = 0; j < no_of_graphs; j++) { igraph_vector_int_t *order = igraph_vector_int_list_get_ptr(&order_vects, j); - igraph_integer_t edge = igraph_vector_int_tail(order); + igraph_int_t edge = igraph_vector_int_tail(order); igraph_vector_int_t *ev = igraph_vector_int_list_get_ptr(&edge_vects, j); - igraph_integer_t from = VECTOR(*ev)[2 * edge]; - igraph_integer_t to = VECTOR(*ev)[2 * edge + 1]; + igraph_int_t from = VECTOR(*ev)[2 * edge]; + igraph_int_t to = VECTOR(*ev)[2 * edge + 1]; if (from == tailfrom && to == tailto) { igraph_vector_int_pop_back(order); if (igraph_vector_int_empty(order)) { diff --git a/src/vendor/cigraph/src/operators/join.c b/src/vendor/cigraph/src/operators/join.c index 57bb2d99803..7570b753b9d 100644 --- a/src/vendor/cigraph/src/operators/join.c +++ b/src/vendor/cigraph/src/operators/join.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -26,8 +25,6 @@ * \function igraph_join * \brief Creates the join of two disjoint graphs. * - * \experimental - * * First the vertices of the second graph will be relabeled with new * vertex IDs to have two disjoint sets of vertex IDs, then the union * of the two graphs will be formed. Finally, the vertces from the @@ -67,13 +64,13 @@ igraph_error_t igraph_join(igraph_t *res, const igraph_t *left, const igraph_t *right) { - igraph_integer_t no_of_nodes_left = igraph_vcount(left); - igraph_integer_t no_of_nodes_right = igraph_vcount(right); - igraph_integer_t no_of_new_edges; + igraph_int_t no_of_nodes_left = igraph_vcount(left); + igraph_int_t no_of_nodes_right = igraph_vcount(right); + igraph_int_t no_of_new_edges; igraph_vector_int_t new_edges; igraph_bool_t directed_left = igraph_is_directed(left); - igraph_integer_t i; - igraph_integer_t j; + igraph_int_t i; + igraph_int_t j; if (directed_left != igraph_is_directed(right)) { IGRAPH_ERROR("Cannot create join of directed and undirected graphs.", diff --git a/src/vendor/cigraph/src/operators/misc_internal.c b/src/vendor/cigraph/src/operators/misc_internal.c index f57d88d35d0..f525afbeb9a 100644 --- a/src/vendor/cigraph/src/operators/misc_internal.c +++ b/src/vendor/cigraph/src/operators/misc_internal.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -29,17 +28,17 @@ int igraph_i_order_edgelist_cmp(void *edges, const void *e1, const void *e2) { igraph_vector_int_t *edgelist = edges; - igraph_integer_t edge1 = (*(const igraph_integer_t*) e1) * 2; - igraph_integer_t edge2 = (*(const igraph_integer_t*) e2) * 2; - igraph_integer_t from1 = VECTOR(*edgelist)[edge1]; - igraph_integer_t from2 = VECTOR(*edgelist)[edge2]; + igraph_int_t edge1 = (*(const igraph_int_t*) e1) * 2; + igraph_int_t edge2 = (*(const igraph_int_t*) e2) * 2; + igraph_int_t from1 = VECTOR(*edgelist)[edge1]; + igraph_int_t from2 = VECTOR(*edgelist)[edge2]; if (from1 < from2) { return -1; } else if (from1 > from2) { return 1; } else { - igraph_integer_t to1 = VECTOR(*edgelist)[edge1 + 1]; - igraph_integer_t to2 = VECTOR(*edgelist)[edge2 + 1]; + igraph_int_t to1 = VECTOR(*edgelist)[edge1 + 1]; + igraph_int_t to2 = VECTOR(*edgelist)[edge2 + 1]; if (to1 < to2) { return -1; } else if (to1 > to2) { @@ -54,17 +53,17 @@ igraph_error_t igraph_i_merge(igraph_t *res, igraph_i_merge_mode_t mode, const igraph_t *left, const igraph_t *right, igraph_vector_int_t *edge_map1, igraph_vector_int_t *edge_map2) { - igraph_integer_t no_of_nodes_left = igraph_vcount(left); - igraph_integer_t no_of_nodes_right = igraph_vcount(right); - igraph_integer_t no_of_nodes; - igraph_integer_t no_edges_left = igraph_ecount(left); - igraph_integer_t no_edges_right = igraph_ecount(right); + igraph_int_t no_of_nodes_left = igraph_vcount(left); + igraph_int_t no_of_nodes_right = igraph_vcount(right); + igraph_int_t no_of_nodes; + igraph_int_t no_edges_left = igraph_ecount(left); + igraph_int_t no_edges_right = igraph_ecount(right); igraph_bool_t directed = igraph_is_directed(left); igraph_vector_int_t edges; igraph_vector_int_t edges1, edges2; igraph_vector_int_t order1, order2; - igraph_integer_t i, j, eptr = 0; - igraph_integer_t idx1, idx2, edge1 = -1, edge2 = -1, from1 = -1, from2 = -1, to1 = -1, to2 = -1; + igraph_int_t i, j, eptr = 0; + igraph_int_t idx1, idx2, edge1 = -1, edge2 = -1, from1 = -1, from2 = -1, to1 = -1, to2 = -1; igraph_bool_t l; if (directed != igraph_is_directed(right)) { @@ -117,14 +116,14 @@ igraph_error_t igraph_i_merge(igraph_t *res, igraph_i_merge_mode_t mode, if (!directed) { for (i = 0, j = 0; i < no_edges_left; i++, j += 2) { if (VECTOR(edges1)[j] > VECTOR(edges1)[j + 1]) { - igraph_integer_t tmp = VECTOR(edges1)[j]; + igraph_int_t tmp = VECTOR(edges1)[j]; VECTOR(edges1)[j] = VECTOR(edges1)[j + 1]; VECTOR(edges1)[j + 1] = tmp; } } for (i = 0, j = 0; i < no_edges_right; i++, j += 2) { if (VECTOR(edges2)[j] > VECTOR(edges2)[j + 1]) { - igraph_integer_t tmp = VECTOR(edges2)[j]; + igraph_int_t tmp = VECTOR(edges2)[j]; VECTOR(edges2)[j] = VECTOR(edges2)[j + 1]; VECTOR(edges2)[j + 1] = tmp; } diff --git a/src/vendor/cigraph/src/operators/misc_internal.h b/src/vendor/cigraph/src/operators/misc_internal.h index 2dc7cc7b5ad..49d780f987b 100644 --- a/src/vendor/cigraph/src/operators/misc_internal.h +++ b/src/vendor/cigraph/src/operators/misc_internal.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2020 The igraph development team 334 Harvard street, Cambridge, MA 02139 USA @@ -30,7 +29,7 @@ #include "igraph_vector.h" #include "igraph_vector_ptr.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS typedef enum { IGRAPH_MERGE_MODE_UNION = 1, @@ -42,6 +41,6 @@ igraph_error_t igraph_i_merge(igraph_t *res, igraph_i_merge_mode_t mode, const igraph_t *left, const igraph_t *right, igraph_vector_int_t *edge_map1, igraph_vector_int_t *edge_map2); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/operators/permute.c b/src/vendor/cigraph/src/operators/permute.c index f84ba6bc663..a0f6fbb2fa6 100644 --- a/src/vendor/cigraph/src/operators/permute.c +++ b/src/vendor/cigraph/src/operators/permute.c @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2006-2020 The igraph development team + igraph library. + Copyright (C) 2006-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,17 +13,14 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_operators.h" +#include "igraph_isomorphism.h" #include "igraph_constructors.h" #include "igraph_interface.h" -#include "igraph_topology.h" #include "graph/attributes.h" @@ -41,13 +37,13 @@ * \return Error code. */ igraph_error_t igraph_invert_permutation(const igraph_vector_int_t *permutation, igraph_vector_int_t *inverse) { - const igraph_integer_t n = igraph_vector_int_size(permutation); + const igraph_int_t n = igraph_vector_int_size(permutation); IGRAPH_CHECK(igraph_vector_int_resize(inverse, n)); igraph_vector_int_fill(inverse, -1); - for (igraph_integer_t i=0; i < n; i++) { - igraph_integer_t j = VECTOR(*permutation)[i]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t j = VECTOR(*permutation)[i]; if (j < 0 || j >= n) { IGRAPH_ERROR("Invalid index in permutation vector.", IGRAPH_EINVAL); } @@ -73,8 +69,9 @@ igraph_error_t igraph_invert_permutation(const igraph_vector_int_t *permutation, * \param graph The input graph. * \param res Pointer to an uninitialized graph object. The new graph * is created here. - * \param permutation The permutation to apply. Vertex 0 is mapped to - * the first element of the vector, vertex 1 to the second, etc. + * \param permutation The permutation to apply. The i-th element of the + * vector specifies the index of the vertex in the original graph that + * will become vertex i in the new graph. * \return Error code. * * Time complexity: O(|V|+|E|), linear in terms of the number of @@ -83,11 +80,11 @@ igraph_error_t igraph_invert_permutation(const igraph_vector_int_t *permutation, igraph_error_t igraph_permute_vertices(const igraph_t *graph, igraph_t *res, const igraph_vector_int_t *permutation) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vector_int_t edges; igraph_vector_int_t index; - igraph_integer_t p; + igraph_int_t p; if (igraph_vector_int_size(permutation) != no_of_nodes) { IGRAPH_ERROR("Permute vertices: invalid permutation vector size.", IGRAPH_EINVAL); @@ -101,9 +98,9 @@ igraph_error_t igraph_permute_vertices(const igraph_t *graph, igraph_t *res, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges * 2); p = 0; - for (igraph_integer_t i = 0; i < no_of_edges; i++) { - VECTOR(edges)[p++] = VECTOR(*permutation)[ IGRAPH_FROM(graph, i) ]; - VECTOR(edges)[p++] = VECTOR(*permutation)[ IGRAPH_TO(graph, i) ]; + for (igraph_int_t i = 0; i < no_of_edges; i++) { + VECTOR(edges)[p++] = VECTOR(index)[ IGRAPH_FROM(graph, i) ]; + VECTOR(edges)[p++] = VECTOR(index)[ IGRAPH_TO(graph, i) ]; } IGRAPH_CHECK(igraph_create(res, &edges, no_of_nodes, igraph_is_directed(graph))); @@ -112,12 +109,11 @@ igraph_error_t igraph_permute_vertices(const igraph_t *graph, igraph_t *res, /* Attributes */ if (graph->attr) { igraph_vector_int_t vtypes; - IGRAPH_I_ATTRIBUTE_DESTROY(res); - IGRAPH_I_ATTRIBUTE_COPY(res, graph, /*graph=*/1, /*vertex=*/0, /*edge=*/1); + IGRAPH_CHECK(igraph_i_attribute_copy(res, graph, true, /* vertex= */ false, true)); IGRAPH_VECTOR_INT_INIT_FINALLY(&vtypes, 0); IGRAPH_CHECK(igraph_i_attribute_get_info(graph, 0, 0, 0, &vtypes, 0, 0)); if (igraph_vector_int_size(&vtypes) != 0) { - IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, res, &index)); + IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, res, permutation)); } igraph_vector_int_destroy(&vtypes); IGRAPH_FINALLY_CLEAN(1); diff --git a/src/vendor/cigraph/src/operators/products.c b/src/vendor/cigraph/src/operators/products.c index e05ae586dcc..a7dc109b8a0 100644 --- a/src/vendor/cigraph/src/operators/products.c +++ b/src/vendor/cigraph/src/operators/products.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2025 The igraph development team This program is free software; you can redistribute it and/or modify @@ -35,12 +35,12 @@ static igraph_error_t cartesian_product(igraph_t *res, IGRAPH_EINVAL); } - const igraph_integer_t vcount1 = igraph_vcount(g1); - const igraph_integer_t vcount2 = igraph_vcount(g2); - const igraph_integer_t ecount1 = igraph_ecount(g1); - const igraph_integer_t ecount2 = igraph_ecount(g2); - igraph_integer_t vcount; - igraph_integer_t ecount, ecount_double; + const igraph_int_t vcount1 = igraph_vcount(g1); + const igraph_int_t vcount2 = igraph_vcount(g2); + const igraph_int_t ecount1 = igraph_ecount(g1); + const igraph_int_t ecount2 = igraph_ecount(g2); + igraph_int_t vcount; + igraph_int_t ecount, ecount_double; igraph_vector_int_t edges; // New vertex count = vcount1 * vcount2 @@ -48,7 +48,7 @@ static igraph_error_t cartesian_product(igraph_t *res, { // New edge count = vcount1*ecount2 + vcount2*ecount1 - igraph_integer_t temp; + igraph_int_t temp; IGRAPH_SAFE_MULT(vcount1, ecount2, &ecount); IGRAPH_SAFE_MULT(vcount2, ecount1, &temp); IGRAPH_SAFE_ADD(ecount, temp, &ecount); @@ -60,29 +60,29 @@ static igraph_error_t cartesian_product(igraph_t *res, // Vertex ((i, j)) with i from g1, and j from g2 // will have new vertex id: i * vcount2 + j - igraph_integer_t edge_index = 0; + igraph_int_t edge_index = 0; // Edges from g1 - for (igraph_integer_t i = 0; i < ecount1; ++i) { - igraph_integer_t from = IGRAPH_FROM(g1, i); - igraph_integer_t to = IGRAPH_TO(g1, i); + for (igraph_int_t i = 0; i < ecount1; ++i) { + igraph_int_t from = IGRAPH_FROM(g1, i); + igraph_int_t to = IGRAPH_TO(g1, i); // For all edges (from, to) in g1, add edge from ((from, j)) to ((to, j)) // for all vertex j in g2 - for (igraph_integer_t j = 0; j < vcount2; ++j) { + for (igraph_int_t j = 0; j < vcount2; ++j) { VECTOR(edges)[edge_index++] = from * vcount2 + j; // ((from, j)) VECTOR(edges)[edge_index++] = to * vcount2 + j; // ((to, j)) } } // Edges from g2 - for (igraph_integer_t i = 0; i < ecount2; ++i) { - igraph_integer_t from = IGRAPH_FROM(g2, i); - igraph_integer_t to = IGRAPH_TO(g2, i); + for (igraph_int_t i = 0; i < ecount2; ++i) { + igraph_int_t from = IGRAPH_FROM(g2, i); + igraph_int_t to = IGRAPH_TO(g2, i); // For all edges (from, to) in g2, add edge from (j, from) to (j, to) // for all vertex j in g1 - for (igraph_integer_t j = 0; j < vcount1; ++j) { + for (igraph_int_t j = 0; j < vcount1; ++j) { VECTOR(edges)[edge_index++] = j * vcount2 + from; // ((j, from)) VECTOR(edges)[edge_index++] = j * vcount2 + to; // ((j, to)) } @@ -106,12 +106,12 @@ static igraph_error_t lexicographic_product(igraph_t *res, IGRAPH_EINVAL); } - const igraph_integer_t vcount1 = igraph_vcount(g1); - const igraph_integer_t vcount2 = igraph_vcount(g2); - const igraph_integer_t ecount1 = igraph_ecount(g1); - const igraph_integer_t ecount2 = igraph_ecount(g2); - igraph_integer_t vcount; - igraph_integer_t ecount, ecount_double; + const igraph_int_t vcount1 = igraph_vcount(g1); + const igraph_int_t vcount2 = igraph_vcount(g2); + const igraph_int_t ecount1 = igraph_ecount(g1); + const igraph_int_t ecount2 = igraph_ecount(g2); + igraph_int_t vcount; + igraph_int_t ecount, ecount_double; igraph_vector_int_t edges; // New vertex count = vcount1 * vcount2 @@ -119,7 +119,7 @@ static igraph_error_t lexicographic_product(igraph_t *res, { // New edge count = vcount1*ecount2 + (vcount2^2)*ecount1 - igraph_integer_t temp; + igraph_int_t temp; IGRAPH_SAFE_MULT(vcount1, ecount2, &ecount); IGRAPH_SAFE_MULT(vcount2, vcount2, &temp); IGRAPH_SAFE_MULT(temp, ecount1, &temp); @@ -132,29 +132,29 @@ static igraph_error_t lexicographic_product(igraph_t *res, // Vertex ((i, j)) with i from g1, and j from g2 // will have new vertex id: i * vcount2 + j - igraph_integer_t edge_index = 0; + igraph_int_t edge_index = 0; // edges of form u1=u2 and v1~v2 - for (igraph_integer_t i = 0; i < ecount2; ++i) { - igraph_integer_t from = IGRAPH_FROM(g2, i); - igraph_integer_t to = IGRAPH_TO(g2, i); + for (igraph_int_t i = 0; i < ecount2; ++i) { + igraph_int_t from = IGRAPH_FROM(g2, i); + igraph_int_t to = IGRAPH_TO(g2, i); // For all edges (from, to) in g2, add edge from (j, from) to (j, to) // for all vertex j in g1 - for (igraph_integer_t j = 0; j < vcount1; ++j) { + for (igraph_int_t j = 0; j < vcount1; ++j) { VECTOR(edges)[edge_index++] = j * vcount2 + from; // ((j, from)) VECTOR(edges)[edge_index++] = j * vcount2 + to; // ((j, to)) } } // edges of form u1~u2 - for (igraph_integer_t i = 0; i < ecount1; ++i) { - igraph_integer_t from1 = IGRAPH_FROM(g1, i); - igraph_integer_t to1 = IGRAPH_TO(g1, i); + for (igraph_int_t i = 0; i < ecount1; ++i) { + igraph_int_t from1 = IGRAPH_FROM(g1, i); + igraph_int_t to1 = IGRAPH_TO(g1, i); // each vertex pair irrespective of their connectivity - for (igraph_integer_t from2 = 0; from2 < vcount2; ++from2) { - for (igraph_integer_t to2 = 0; to2 < vcount2; ++to2) { + for (igraph_int_t from2 = 0; from2 < vcount2; ++from2) { + for (igraph_int_t to2 = 0; to2 < vcount2; ++to2) { // ((from1, from2)) to ((to1, to2)) VECTOR(edges)[edge_index++] = from1 * vcount2 + from2; // ((from1, from2)) VECTOR(edges)[edge_index++] = to1 * vcount2 + to2; // ((to1, to2)) @@ -180,12 +180,12 @@ static igraph_error_t strong_product(igraph_t *res, IGRAPH_EINVAL); } - const igraph_integer_t vcount1 = igraph_vcount(g1); - const igraph_integer_t vcount2 = igraph_vcount(g2); - const igraph_integer_t ecount1 = igraph_ecount(g1); - const igraph_integer_t ecount2 = igraph_ecount(g2); - igraph_integer_t vcount; - igraph_integer_t ecount, ecount_double; + const igraph_int_t vcount1 = igraph_vcount(g1); + const igraph_int_t vcount2 = igraph_vcount(g2); + const igraph_int_t ecount1 = igraph_ecount(g1); + const igraph_int_t ecount2 = igraph_ecount(g2); + igraph_int_t vcount; + igraph_int_t ecount, ecount_double; igraph_vector_int_t edges; // New vertex count = vcount1 * vcount2 @@ -194,7 +194,7 @@ static igraph_error_t strong_product(igraph_t *res, { // New edge count = vcount1*ecount2 + vcount2*ecount1 + 2*e1*e2 for undirected graph // = vcount1*ecount2 + vcount2*ecount1 + e1*e2 for directed graph - igraph_integer_t temp; + igraph_int_t temp; IGRAPH_SAFE_MULT(vcount1, ecount2, &ecount); IGRAPH_SAFE_MULT(vcount2, ecount1, &temp); IGRAPH_SAFE_ADD(ecount, temp, &ecount); @@ -209,18 +209,18 @@ static igraph_error_t strong_product(igraph_t *res, IGRAPH_SAFE_MULT(ecount, 2, &ecount_double); IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, ecount_double); - igraph_integer_t edge_index = 0; + igraph_int_t edge_index = 0; // Strong graph product contains all the edges from both cartesian and tensor product // Edges of type cartesian products: v1=v2 and u1~u2; v1~v2 and u1=u2 // v1=v2 and u1~u2 - for (igraph_integer_t i = 0; i < ecount1; ++i) { - igraph_integer_t from = IGRAPH_FROM(g1, i); - igraph_integer_t to = IGRAPH_TO(g1, i); + for (igraph_int_t i = 0; i < ecount1; ++i) { + igraph_int_t from = IGRAPH_FROM(g1, i); + igraph_int_t to = IGRAPH_TO(g1, i); // For all edges (from, to) in g1, add edge from ((from, j)) to ((to, j)) // for all vertex j in g2 - for (igraph_integer_t j = 0; j < vcount2; ++j) { + for (igraph_int_t j = 0; j < vcount2; ++j) { // SAFE MULT and SAFE ADD not needed as < vcount VECTOR(edges)[edge_index++] = from * vcount2 + j; // ((from, j)) VECTOR(edges)[edge_index++] = to * vcount2 + j; // ((to, j)) @@ -228,13 +228,13 @@ static igraph_error_t strong_product(igraph_t *res, } // v1~v2 and u1=u2 - for (igraph_integer_t i = 0; i < ecount2; ++i) { - igraph_integer_t from = IGRAPH_FROM(g2, i); - igraph_integer_t to = IGRAPH_TO(g2, i); + for (igraph_int_t i = 0; i < ecount2; ++i) { + igraph_int_t from = IGRAPH_FROM(g2, i); + igraph_int_t to = IGRAPH_TO(g2, i); // For all edges (from, to) in g2, add edge from (j, from) to (j, to) // for all vertex j in g1 - for (igraph_integer_t j = 0; j < vcount1; ++j) { + for (igraph_int_t j = 0; j < vcount1; ++j) { VECTOR(edges)[edge_index++] = j * vcount2 + from; // ((j, from)) VECTOR(edges)[edge_index++] = j * vcount2 + to; // ((j, to)) } @@ -242,13 +242,13 @@ static igraph_error_t strong_product(igraph_t *res, // Edges of type tensor product // u1 ~ u2 and v1 ~ v2 - for (igraph_integer_t i = 0; i < ecount1; ++i) { - igraph_integer_t from1 = IGRAPH_FROM(g1, i); - igraph_integer_t to1 = IGRAPH_TO(g1, i); + for (igraph_int_t i = 0; i < ecount1; ++i) { + igraph_int_t from1 = IGRAPH_FROM(g1, i); + igraph_int_t to1 = IGRAPH_TO(g1, i); - for (igraph_integer_t j = 0; j < ecount2; ++j) { - igraph_integer_t from2 = IGRAPH_FROM(g2, j); - igraph_integer_t to2 = IGRAPH_TO(g2, j); + for (igraph_int_t j = 0; j < ecount2; ++j) { + igraph_int_t from2 = IGRAPH_FROM(g2, j); + igraph_int_t to2 = IGRAPH_TO(g2, j); // Create edge between ((from1, from2)) to ((to1, to2)) VECTOR(edges)[edge_index++] = from1 * vcount2 + from2; // ((from1, from2)) @@ -281,12 +281,12 @@ static igraph_error_t tensor_product(igraph_t *res, IGRAPH_EINVAL); } - const igraph_integer_t vcount1 = igraph_vcount(g1); - const igraph_integer_t vcount2 = igraph_vcount(g2); - const igraph_integer_t ecount1 = igraph_ecount(g1); - const igraph_integer_t ecount2 = igraph_ecount(g2); - igraph_integer_t vcount; - igraph_integer_t ecount, ecount_double; + const igraph_int_t vcount1 = igraph_vcount(g1); + const igraph_int_t vcount2 = igraph_vcount(g2); + const igraph_int_t ecount1 = igraph_ecount(g1); + const igraph_int_t ecount2 = igraph_ecount(g2); + igraph_int_t vcount; + igraph_int_t ecount, ecount_double; igraph_vector_int_t edges; IGRAPH_SAFE_MULT(vcount1, vcount2, &vcount); @@ -302,15 +302,15 @@ static igraph_error_t tensor_product(igraph_t *res, // Vertex ((i, j)) with i from g1, and j from g2 // will have new vertex id: i * vcount2 + j - igraph_integer_t edge_index = 0; + igraph_int_t edge_index = 0; - for (igraph_integer_t i = 0; i < ecount1; ++i) { - igraph_integer_t from1 = IGRAPH_FROM(g1, i); - igraph_integer_t to1 = IGRAPH_TO(g1, i); + for (igraph_int_t i = 0; i < ecount1; ++i) { + igraph_int_t from1 = IGRAPH_FROM(g1, i); + igraph_int_t to1 = IGRAPH_TO(g1, i); - for (igraph_integer_t j = 0; j < ecount2; ++j) { - igraph_integer_t from2 = IGRAPH_FROM(g2, j); - igraph_integer_t to2 = IGRAPH_TO(g2, j); + for (igraph_int_t j = 0; j < ecount2; ++j) { + igraph_int_t from2 = IGRAPH_FROM(g2, j); + igraph_int_t to2 = IGRAPH_TO(g2, j); // Create edge between ((from1, from2)) to ((to1, to2)) VECTOR(edges)[edge_index++] = from1 * vcount2 + from2; // ((from1, from2)) @@ -345,8 +345,8 @@ static igraph_error_t modular_product(igraph_t *res, } igraph_bool_t is_simple1, is_simple2; - IGRAPH_CHECK(igraph_is_simple(g1, &is_simple1)); - IGRAPH_CHECK(igraph_is_simple(g2, &is_simple2)); + IGRAPH_CHECK(igraph_is_simple(g1, &is_simple1, IGRAPH_DIRECTED)); + IGRAPH_CHECK(igraph_is_simple(g2, &is_simple2, IGRAPH_DIRECTED)); if (!is_simple1 || !is_simple2) { IGRAPH_ERROR("Modular product requires simple graphs as input.", IGRAPH_EINVAL); @@ -585,7 +585,7 @@ igraph_error_t igraph_product(igraph_t *res, igraph_error_t igraph_rooted_product(igraph_t *res, const igraph_t *g1, const igraph_t *g2, - const igraph_integer_t root) { + igraph_int_t root) { const igraph_bool_t directed = igraph_is_directed(g1); @@ -594,17 +594,17 @@ igraph_error_t igraph_rooted_product(igraph_t *res, IGRAPH_EINVAL); } - const igraph_integer_t vcount1 = igraph_vcount(g1); - const igraph_integer_t vcount2 = igraph_vcount(g2); + const igraph_int_t vcount1 = igraph_vcount(g1); + const igraph_int_t vcount2 = igraph_vcount(g2); if (root < 0 || root >= vcount2) { // root must be in range [0, vcount2-1] IGRAPH_ERROR("The given root vertex is not present in the second graph.", IGRAPH_EINVVID); } - const igraph_integer_t ecount1 = igraph_ecount(g1); - const igraph_integer_t ecount2 = igraph_ecount(g2); - igraph_integer_t vcount; - igraph_integer_t ecount, ecount_double; + const igraph_int_t ecount1 = igraph_ecount(g1); + const igraph_int_t ecount2 = igraph_ecount(g2); + igraph_int_t vcount; + igraph_int_t ecount, ecount_double; igraph_vector_int_t edges; // New vertex count = vcount1 * vcount2 @@ -620,12 +620,12 @@ igraph_error_t igraph_rooted_product(igraph_t *res, // Vertex ((i, j)) with i from g1, and j from g2 // will have new vertex id: i * vcount2 + j - igraph_integer_t edge_index = 0; + igraph_int_t edge_index = 0; // Edges of form ((u, root)) - ((v, root)) - for (igraph_integer_t i = 0; i < ecount1; ++i) { - igraph_integer_t from = IGRAPH_FROM(g1, i); - igraph_integer_t to = IGRAPH_TO(g1, i); + for (igraph_int_t i = 0; i < ecount1; ++i) { + igraph_int_t from = IGRAPH_FROM(g1, i); + igraph_int_t to = IGRAPH_TO(g1, i); VECTOR(edges)[edge_index++] = from * vcount2 + root; // ((from, root)) VECTOR(edges)[edge_index++] = to * vcount2 + root; // ((to, root)) @@ -633,11 +633,11 @@ igraph_error_t igraph_rooted_product(igraph_t *res, // For all edges (from, to) in g2, add edge from ((j, from)) to ((j, to)) // for all vertex j in g1 - for (igraph_integer_t i = 0; i < ecount2; ++i) { - igraph_integer_t from = IGRAPH_FROM(g2, i); - igraph_integer_t to = IGRAPH_TO(g2, i); + for (igraph_int_t i = 0; i < ecount2; ++i) { + igraph_int_t from = IGRAPH_FROM(g2, i); + igraph_int_t to = IGRAPH_TO(g2, i); - for (igraph_integer_t j = 0; j < vcount1; ++j) { + for (igraph_int_t j = 0; j < vcount1; ++j) { VECTOR(edges)[edge_index++] = j * vcount2 + from; // ((j, from)) VECTOR(edges)[edge_index++] = j * vcount2 + to; // ((j, to)) } diff --git a/src/vendor/cigraph/src/operators/reverse.c b/src/vendor/cigraph/src/operators/reverse.c index da99dfadeae..1fd8e016188 100644 --- a/src/vendor/cigraph/src/operators/reverse.c +++ b/src/vendor/cigraph/src/operators/reverse.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -52,8 +52,8 @@ * O(|E|) where |E| is the number of edges in the graph. */ igraph_error_t igraph_reverse_edges(igraph_t *graph, const igraph_es_t eids) { - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t edges; igraph_eit_t eit; igraph_t new_graph; @@ -78,8 +78,8 @@ igraph_error_t igraph_reverse_edges(igraph_t *graph, const igraph_es_t eids) { IGRAPH_FINALLY(igraph_eit_destroy, &eit); for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t eid = IGRAPH_EIT_GET(eit); - igraph_integer_t tmp = VECTOR(edges)[2*eid]; + igraph_int_t eid = IGRAPH_EIT_GET(eit); + igraph_int_t tmp = VECTOR(edges)[2*eid]; VECTOR(edges)[2*eid] = VECTOR(edges)[2*eid + 1]; VECTOR(edges)[2*eid + 1] = tmp; } @@ -88,8 +88,7 @@ igraph_error_t igraph_reverse_edges(igraph_t *graph, const igraph_es_t eids) { IGRAPH_CHECK(igraph_create(&new_graph, &edges, no_of_nodes, IGRAPH_DIRECTED)); IGRAPH_FINALLY(igraph_destroy, &new_graph); - IGRAPH_I_ATTRIBUTE_DESTROY(&new_graph); - IGRAPH_I_ATTRIBUTE_COPY(&new_graph, graph, true, true, true); /* does IGRAPH_CHECK */ + IGRAPH_CHECK(igraph_i_attribute_copy(&new_graph, graph, true, true, true)); igraph_eit_destroy(&eit); igraph_vector_int_destroy(&edges); diff --git a/src/vendor/cigraph/src/operators/rewire.c b/src/vendor/cigraph/src/operators/rewire.c index 851da5cc7ac..f964f0457db 100644 --- a/src/vendor/cigraph/src/operators/rewire.c +++ b/src/vendor/cigraph/src/operators/rewire.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -32,21 +30,23 @@ #include "igraph_structural.h" #include "core/interruption.h" +#include "misc/graphicality.h" #include "operators/rewire_internal.h" +#include /* memset */ + /* Threshold that defines when to switch over to using adjacency lists during * rewiring */ #define REWIRE_ADJLIST_THRESHOLD 10 /* Not declared static so that the testsuite can use it, but not part of the public API. */ -igraph_error_t igraph_i_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode, igraph_bool_t use_adjlist) { - const igraph_integer_t no_of_edges = igraph_ecount(graph); +igraph_error_t igraph_i_rewire(igraph_t *graph, igraph_int_t n, igraph_bool_t loops, igraph_bool_t use_adjlist, igraph_rewiring_stats_t *stats) { + const igraph_int_t no_of_edges = igraph_ecount(graph); char message[256]; - igraph_integer_t a, b, c, d, dummy, num_swaps, num_successful_swaps; + igraph_int_t a, b, c, d, dummy, num_swaps, num_successful_swaps; igraph_vector_int_t eids; igraph_vector_int_t edgevec, alledges; const igraph_bool_t directed = igraph_is_directed(graph); - const igraph_bool_t loops = (mode & IGRAPH_REWIRING_SIMPLE_LOOPS); igraph_bool_t ok; igraph_es_t es; igraph_adjlist_t al; @@ -56,8 +56,6 @@ igraph_error_t igraph_i_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewir return IGRAPH_SUCCESS; } - RNG_BEGIN(); - IGRAPH_VECTOR_INT_INIT_FINALLY(&eids, 2); if (use_adjlist) { @@ -80,6 +78,7 @@ igraph_error_t igraph_i_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewir while (num_swaps < n) { IGRAPH_ALLOW_INTERRUPTION(); + if (num_swaps % 1000 == 0) { snprintf(message, sizeof(message), "Random rewiring (%.2f%% of the trials were successful)", @@ -87,110 +86,103 @@ igraph_error_t igraph_i_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewir IGRAPH_PROGRESS(message, (100.0 * num_swaps) / n, 0); } - switch (mode) { - case IGRAPH_REWIRING_SIMPLE: - case IGRAPH_REWIRING_SIMPLE_LOOPS: - ok = true; + ok = true; - /* Choose two edges randomly */ - VECTOR(eids)[0] = RNG_INTEGER(0, no_of_edges - 1); - do { - VECTOR(eids)[1] = RNG_INTEGER(0, no_of_edges - 1); - } while (VECTOR(eids)[0] == VECTOR(eids)[1]); + /* Choose two edges randomly */ + VECTOR(eids)[0] = RNG_INTEGER(0, no_of_edges - 1); + do { + VECTOR(eids)[1] = RNG_INTEGER(0, no_of_edges - 1); + } while (VECTOR(eids)[0] == VECTOR(eids)[1]); - /* Get the endpoints */ - if (use_adjlist) { - a = VECTOR(alledges)[VECTOR(eids)[0] * 2]; - b = VECTOR(alledges)[VECTOR(eids)[0] * 2 + 1]; - c = VECTOR(alledges)[VECTOR(eids)[1] * 2]; - d = VECTOR(alledges)[VECTOR(eids)[1] * 2 + 1]; - } else { - IGRAPH_CHECK(igraph_edge(graph, VECTOR(eids)[0], &a, &b)); - IGRAPH_CHECK(igraph_edge(graph, VECTOR(eids)[1], &c, &d)); - } + /* Get the endpoints */ + if (use_adjlist) { + a = VECTOR(alledges)[VECTOR(eids)[0] * 2]; + b = VECTOR(alledges)[VECTOR(eids)[0] * 2 + 1]; + c = VECTOR(alledges)[VECTOR(eids)[1] * 2]; + d = VECTOR(alledges)[VECTOR(eids)[1] * 2 + 1]; + } else { + IGRAPH_CHECK(igraph_edge(graph, VECTOR(eids)[0], &a, &b)); + IGRAPH_CHECK(igraph_edge(graph, VECTOR(eids)[1], &c, &d)); + } - /* For an undirected graph, we have two "variants" of each edge, i.e. - * a -- b and b -- a. Since some rewirings can be performed only when we - * "swap" the endpoints, we do it now with probability 0.5 */ - if (!directed && RNG_BOOL()) { - dummy = c; c = d; d = dummy; - if (use_adjlist) { - /* Flip the edge in the unordered edge-list, so the update later on - * hits the correct end. */ - VECTOR(alledges)[VECTOR(eids)[1] * 2] = c; - VECTOR(alledges)[VECTOR(eids)[1] * 2 + 1] = d; - } + /* For an undirected graph, we have two "variants" of each edge, i.e. + * a -- b and b -- a. Since some rewirings can be performed only when we + * "swap" the endpoints, we do it now with probability 0.5 */ + if (!directed && RNG_BOOL()) { + dummy = c; c = d; d = dummy; + if (use_adjlist) { + /* Flip the edge in the unordered edge-list, so the update later on + * hits the correct end. */ + VECTOR(alledges)[VECTOR(eids)[1] * 2] = c; + VECTOR(alledges)[VECTOR(eids)[1] * 2 + 1] = d; } + } - /* If we do not touch loops, check whether a == b or c == d and disallow - * the swap if needed */ - if (!loops && (a == b || c == d)) { + /* If we do not touch loops, check whether a == b or c == d and disallow + * the swap if needed */ + if (!loops && (a == b || c == d)) { + ok = false; + } else { + /* Check whether they are suitable for rewiring */ + if (a == c || b == d) { + /* Swapping would have no effect */ ok = false; } else { - /* Check whether they are suitable for rewiring */ - if (a == c || b == d) { - /* Swapping would have no effect */ - ok = false; - } else { - /* a != c && b != d */ - /* If a == d or b == c, the swap would generate at least one loop, so - * we disallow them unless we want to have loops */ - ok = loops || (a != d && b != c); - /* Also, if a == b and c == d and we allow loops, doing the swap - * would result in a multiple edge if the graph is undirected */ - ok = ok && (directed || a != b || c != d); - } + /* a != c && b != d */ + /* If a == d or b == c, the swap would generate at least one loop, so + * we disallow them unless we want to have loops */ + ok = loops || (a != d && b != c); + /* Also, if a == b and c == d and we allow loops, doing the swap + * would result in a multiple edge if the graph is undirected */ + ok = ok && (directed || a != b || c != d); } + } - /* All good so far. Now check for the existence of a --> d and c --> b to - * disallow the creation of multiple edges */ - if (ok) { - if (use_adjlist) { - if (igraph_adjlist_has_edge(&al, a, d, directed)) { - ok = false; - } - } else { - IGRAPH_CHECK(igraph_are_adjacent(graph, a, d, &ok)); - ok = !ok; + /* All good so far. Now check for the existence of a --> d and c --> b to + * disallow the creation of multiple edges */ + if (ok) { + if (use_adjlist) { + if (igraph_adjlist_has_edge(&al, a, d, directed)) { + ok = false; } + } else { + IGRAPH_CHECK(igraph_are_adjacent(graph, a, d, &ok)); + ok = !ok; } - if (ok) { - if (use_adjlist) { - if (igraph_adjlist_has_edge(&al, c, b, directed)) { - ok = false; - } - } else { - IGRAPH_CHECK(igraph_are_adjacent(graph, c, b, &ok)); - ok = !ok; + } + if (ok) { + if (use_adjlist) { + if (igraph_adjlist_has_edge(&al, c, b, directed)) { + ok = false; } + } else { + IGRAPH_CHECK(igraph_are_adjacent(graph, c, b, &ok)); + ok = !ok; } + } - /* If we are still okay, we can perform the rewiring */ - if (ok) { - /* printf("Deleting: %" IGRAPH_PRId " -> %" IGRAPH_PRId ", %" IGRAPH_PRId " -> %" IGRAPH_PRId "\n", - a, b, c, d); */ - if (use_adjlist) { - /* Replace entry in sorted adjlist: */ - IGRAPH_CHECK(igraph_adjlist_replace_edge(&al, a, b, d, directed)); - IGRAPH_CHECK(igraph_adjlist_replace_edge(&al, c, d, b, directed)); - /* Also replace in unsorted edgelist: */ - VECTOR(alledges)[VECTOR(eids)[0] * 2 + 1] = d; - VECTOR(alledges)[VECTOR(eids)[1] * 2 + 1] = b; - } else { - IGRAPH_CHECK(igraph_delete_edges(graph, es)); - VECTOR(edgevec)[0] = a; VECTOR(edgevec)[1] = d; - VECTOR(edgevec)[2] = c; VECTOR(edgevec)[3] = b; - /* printf("Adding: %" IGRAPH_PRId " -> %" IGRAPH_PRId ", %" IGRAPH_PRId " -> %" IGRAPH_PRId "\n", - a, d, c, b); */ - IGRAPH_CHECK(igraph_add_edges(graph, &edgevec, 0)); - } - num_successful_swaps++; + /* If we are still okay, we can perform the rewiring */ + if (ok) { + /* printf("Deleting: %" IGRAPH_PRId " -> %" IGRAPH_PRId ", %" IGRAPH_PRId " -> %" IGRAPH_PRId "\n", + a, b, c, d); */ + if (use_adjlist) { + /* Replace entry in sorted adjlist: */ + IGRAPH_CHECK(igraph_adjlist_replace_edge(&al, a, b, d, directed)); + IGRAPH_CHECK(igraph_adjlist_replace_edge(&al, c, d, b, directed)); + /* Also replace in unsorted edgelist: */ + VECTOR(alledges)[VECTOR(eids)[0] * 2 + 1] = d; + VECTOR(alledges)[VECTOR(eids)[1] * 2 + 1] = b; + } else { + IGRAPH_CHECK(igraph_delete_edges(graph, es)); + VECTOR(edgevec)[0] = a; VECTOR(edgevec)[1] = d; + VECTOR(edgevec)[2] = c; VECTOR(edgevec)[3] = b; + /* printf("Adding: %" IGRAPH_PRId " -> %" IGRAPH_PRId ", %" IGRAPH_PRId " -> %" IGRAPH_PRId "\n", + a, d, c, b); */ + IGRAPH_CHECK(igraph_add_edges(graph, &edgevec, 0)); } - break; - default: - RNG_END(); - IGRAPH_ERROR("Invalid rewiring mode.", IGRAPH_EINVAL); + num_successful_swaps++; } + num_swaps++; } @@ -212,7 +204,10 @@ igraph_error_t igraph_i_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewir igraph_vector_int_destroy(&eids); IGRAPH_FINALLY_CLEAN(use_adjlist ? 3 : 2); - RNG_END(); + if (stats) { + memset(stats, 0, sizeof(igraph_rewiring_stats_t)); + stats->successful_swaps = num_successful_swaps; + } return IGRAPH_SUCCESS; } @@ -237,16 +232,18 @@ igraph_error_t igraph_i_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewir * * \param graph The graph object to be rewired. * \param n Number of rewiring trials to perform. - * \param mode The rewiring algorithm to be used. It can be one of the following flags: - * \clist - * \cli IGRAPH_REWIRING_SIMPLE - * This method does not create or destroy self-loops, and does - * not create multi-edges. - * \cli IGRAPH_REWIRING_SIMPLE_LOOPS - * This method allows the creation or destruction of self-loops. - * Self-loops are created by switching edges that have a single - * common endpoint. - * \endclist + * \param allowed_edge_types The types of edges that rewiring may create in the graph. + * See \ref igraph_edge_type_sw_t for details. + * Currently, the following are implemented: + * \clist + * \cli IGRAPH_SIMPLE_SW + * simple graphs (i.e. no self-loops or multi-edges allowed). + * \cli IGRAPH_LOOPS_SW + * single self-loops are allowed, but not multi-edges. + * \endclist + * Multigraphs are not yet supported. + * \param stats Counts of the number of different operations + * performed by the algorithm are stored here. * * \return Error code: * \clist @@ -258,7 +255,13 @@ igraph_error_t igraph_i_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewir * * Time complexity: TODO. */ -igraph_error_t igraph_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode) { +igraph_error_t igraph_rewire(igraph_t *graph, igraph_int_t n, igraph_edge_type_sw_t allowed_edge_types, igraph_rewiring_stats_t *stats) { igraph_bool_t use_adjlist = n >= REWIRE_ADJLIST_THRESHOLD; - return igraph_i_rewire(graph, n, mode, use_adjlist); + + if ((allowed_edge_types & IGRAPH_I_MULTI_EDGES_SW) || + (allowed_edge_types & IGRAPH_I_MULTI_LOOPS_SW)) { + IGRAPH_ERROR("Rewiring multigraphs is not yet implemented.", IGRAPH_UNIMPLEMENTED); + } + + return igraph_i_rewire(graph, n, allowed_edge_types & IGRAPH_LOOPS_SW, use_adjlist, stats); } diff --git a/src/vendor/cigraph/src/operators/rewire_edges.c b/src/vendor/cigraph/src/operators/rewire_edges.c index 6c5b856bfe2..aa7a61b6575 100644 --- a/src/vendor/cigraph/src/operators/rewire_edges.c +++ b/src/vendor/cigraph/src/operators/rewire_edges.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -29,16 +27,17 @@ #include "igraph_random.h" #include "graph/attributes.h" +#include "misc/graphicality.h" static igraph_error_t igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_real_t prob, igraph_bool_t loops, igraph_vector_int_t *edges) { - igraph_integer_t no_verts = igraph_vcount(graph); - igraph_integer_t no_edges = igraph_ecount(graph); + igraph_int_t no_verts = igraph_vcount(graph); + igraph_int_t no_edges = igraph_ecount(graph); igraph_vector_int_t eorder, tmp; igraph_vector_int_t first, next, prev, marked; - igraph_integer_t i, to_rewire, last_other = -1; + igraph_int_t i, to_rewire, last_other = -1; /* Create our special graph representation */ @@ -63,9 +62,9 @@ static igraph_error_t igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_ } while (0) # define MARK_NEIGHBORS(vertex) do { \ - igraph_integer_t xxx_ =VECTOR(first)[(vertex)]; \ + igraph_int_t xxx_ =VECTOR(first)[(vertex)]; \ while (xxx_) { \ - igraph_integer_t o= VECTOR(*edges)[xxx_ % 2 ? xxx_ : xxx_-2]; \ + igraph_int_t o= VECTOR(*edges)[xxx_ % 2 ? xxx_ : xxx_-2]; \ VECTOR(marked)[o]=other+1; \ xxx_=VECTOR(next)[xxx_-1]; \ } \ @@ -81,14 +80,14 @@ static igraph_error_t igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_ IGRAPH_VECTOR_INT_INIT_FINALLY(&eorder, no_edges); IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, no_edges); for (i = 0; i < no_edges; i++) { - igraph_integer_t idx1 = 2 * i, idx2 = idx1 + 1; - igraph_integer_t from = VECTOR(*edges)[idx1]; - igraph_integer_t to = VECTOR(*edges)[idx2]; + igraph_int_t idx1 = 2 * i, idx2 = idx1 + 1; + igraph_int_t from = VECTOR(*edges)[idx1]; + igraph_int_t to = VECTOR(*edges)[idx2]; VECTOR(tmp)[i] = from; ADD_STUB(from, idx1); ADD_STUB(to, idx2); } - IGRAPH_CHECK(igraph_vector_int_order1(&tmp, &eorder, no_verts)); + IGRAPH_CHECK(igraph_i_vector_int_order(&tmp, &eorder, no_verts)); igraph_vector_int_destroy(&tmp); IGRAPH_FINALLY_CLEAN(1); @@ -97,13 +96,13 @@ static igraph_error_t igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_ /* Rewire the stubs, part I */ - to_rewire = (igraph_integer_t) RNG_GEOM(prob); + to_rewire = (igraph_int_t) RNG_GEOM(prob); while (to_rewire < no_edges) { - igraph_integer_t stub = 2 * VECTOR(eorder)[to_rewire] + 1; - igraph_integer_t v = VECTOR(*edges)[stub]; - igraph_integer_t ostub = stub - 1; - igraph_integer_t other = VECTOR(*edges)[ostub]; - igraph_integer_t pot; + igraph_int_t stub = 2 * VECTOR(eorder)[to_rewire] + 1; + igraph_int_t v = VECTOR(*edges)[stub]; + igraph_int_t ostub = stub - 1; + igraph_int_t other = VECTOR(*edges)[ostub]; + igraph_int_t pot; if (last_other != other) { MARK_NEIGHBORS(other); } @@ -135,7 +134,7 @@ static igraph_error_t igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_ for (i = 0; i < no_edges; i++) { VECTOR(tmp)[i] = VECTOR(*edges)[2 * i + 1]; } - IGRAPH_CHECK(igraph_vector_int_order1(&tmp, &eorder, no_verts)); + IGRAPH_CHECK(igraph_i_vector_int_order(&tmp, &eorder, no_verts)); igraph_vector_int_destroy(&tmp); IGRAPH_FINALLY_CLEAN(1); @@ -144,13 +143,13 @@ static igraph_error_t igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_ igraph_vector_int_null(&marked); last_other = -1; - to_rewire = (igraph_integer_t) RNG_GEOM(prob); + to_rewire = (igraph_int_t) RNG_GEOM(prob); while (to_rewire < no_edges) { - igraph_integer_t stub = (2 * VECTOR(eorder)[to_rewire]); - igraph_integer_t v = VECTOR(*edges)[stub]; - igraph_integer_t ostub = stub + 1; - igraph_integer_t other = VECTOR(*edges)[ostub]; - igraph_integer_t pot; + igraph_int_t stub = (2 * VECTOR(eorder)[to_rewire]); + igraph_int_t v = VECTOR(*edges)[stub]; + igraph_int_t ostub = stub + 1; + igraph_int_t other = VECTOR(*edges)[ostub]; + igraph_int_t pot; if (last_other != other) { MARK_NEIGHBORS(other); } @@ -205,10 +204,8 @@ static igraph_error_t igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_ * directed or undirected. * \param prob The rewiring probability a constant between zero and * one (inclusive). - * \param loops Boolean, whether loop edges are allowed in the new - * graph, or not. - * \param multiple Boolean, whether multiple edges are allowed in the - * new graph. + * \param allowed_edge_types Controls whether multi-edges and self-loops + * are allowed in the new graph. See \ref igraph_edge_type_sw_t. * \return Error code. * * \sa \ref igraph_watts_strogatz_game() uses this function for the @@ -217,14 +214,17 @@ static igraph_error_t igraph_i_rewire_edges_no_multiple(igraph_t *graph, igraph_ * Time complexity: O(|V|+|E|). */ igraph_error_t igraph_rewire_edges(igraph_t *graph, igraph_real_t prob, - igraph_bool_t loops, igraph_bool_t multiple) { + igraph_edge_type_sw_t allowed_edge_types) { igraph_t newgraph; - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t endpoints = no_of_edges * 2; - igraph_integer_t to_rewire; + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t endpoints = no_of_edges * 2; + igraph_int_t to_rewire; igraph_vector_int_t edges; + igraph_bool_t loops, multiple; + + IGRAPH_CHECK(igraph_i_edge_type_to_loops_multiple(allowed_edge_types, &loops, &multiple)); if (prob < 0 || prob > 1) { IGRAPH_ERROR("Rewiring probability should be between zero and one", @@ -238,8 +238,6 @@ igraph_error_t igraph_rewire_edges(igraph_t *graph, igraph_real_t prob, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, endpoints); - RNG_BEGIN(); - if (prob != 0 && no_of_edges > 0) { if (multiple) { /* If multiple edges are allowed, then there is an easy and fast @@ -252,9 +250,9 @@ igraph_error_t igraph_rewire_edges(igraph_t *graph, igraph_real_t prob, if (loops) { VECTOR(edges)[to_rewire] = RNG_INTEGER(0, no_of_nodes - 1); } else { - igraph_integer_t opos = to_rewire % 2 ? to_rewire - 1 : to_rewire + 1; - igraph_integer_t nei = VECTOR(edges)[opos]; - igraph_integer_t r = RNG_INTEGER(0, no_of_nodes - 2); + igraph_int_t opos = to_rewire % 2 ? to_rewire - 1 : to_rewire + 1; + igraph_int_t nei = VECTOR(edges)[opos]; + igraph_int_t r = RNG_INTEGER(0, no_of_nodes - 2); VECTOR(edges)[ to_rewire ] = (r != nei ? r : no_of_nodes - 1); } to_rewire += RNG_GEOM(prob) + 1; @@ -266,16 +264,13 @@ igraph_error_t igraph_rewire_edges(igraph_t *graph, igraph_real_t prob, } } - RNG_END(); - IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, igraph_is_directed(graph))); igraph_vector_int_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); IGRAPH_FINALLY(igraph_destroy, &newgraph); - IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); - IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1, 1, 1); + IGRAPH_CHECK(igraph_i_attribute_copy(&newgraph, graph, true, true, true)); IGRAPH_FINALLY_CLEAN(1); igraph_destroy(graph); *graph = newgraph; @@ -338,10 +333,10 @@ igraph_error_t igraph_rewire_directed_edges(igraph_t *graph, igraph_real_t prob, if (igraph_is_directed(graph) && mode != IGRAPH_ALL) { igraph_t newgraph; - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t to_rewire; - igraph_integer_t offset = 0; + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t to_rewire; + igraph_int_t offset = 0; igraph_vector_int_t edges; IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 2 * no_of_edges); @@ -359,36 +354,31 @@ igraph_error_t igraph_rewire_directed_edges(igraph_t *graph, igraph_real_t prob, IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); - RNG_BEGIN(); - to_rewire = RNG_GEOM(prob); while (to_rewire < no_of_edges) { if (loops) { VECTOR(edges)[2 * to_rewire + offset] = RNG_INTEGER(0, no_of_nodes - 1); } else { - igraph_integer_t nei = VECTOR(edges)[2 * to_rewire + (1 - offset)]; - igraph_integer_t r = RNG_INTEGER(0, no_of_nodes - 2); + igraph_int_t nei = VECTOR(edges)[2 * to_rewire + (1 - offset)]; + igraph_int_t r = RNG_INTEGER(0, no_of_nodes - 2); VECTOR(edges)[2 * to_rewire + offset] = (r != nei ? r : no_of_nodes - 1); } to_rewire += RNG_GEOM(prob) + 1; } - RNG_END(); - IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, igraph_is_directed(graph))); igraph_vector_int_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); IGRAPH_FINALLY(igraph_destroy, &newgraph); - IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); - IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1, 1, 1); + IGRAPH_CHECK(igraph_i_attribute_copy(&newgraph, graph, true, true, true)); IGRAPH_FINALLY_CLEAN(1); igraph_destroy(graph); *graph = newgraph; } else { - IGRAPH_CHECK(igraph_rewire_edges(graph, prob, loops, /* multiple = */ 1)); + IGRAPH_CHECK(igraph_rewire_edges(graph, prob, IGRAPH_MULTI_SW | (loops ? IGRAPH_LOOPS_SW : IGRAPH_SIMPLE_SW))); } return IGRAPH_SUCCESS; diff --git a/src/vendor/cigraph/src/operators/rewire_internal.h b/src/vendor/cigraph/src/operators/rewire_internal.h index b82b10eec95..145a79bdc26 100644 --- a/src/vendor/cigraph/src/operators/rewire_internal.h +++ b/src/vendor/cigraph/src/operators/rewire_internal.h @@ -2,14 +2,16 @@ #define IGRAPH_OPERATORS_REWIRE_INTERNAL_H #include "igraph_decls.h" -#include "igraph_interface.h" +#include "igraph_constants.h" +#include "igraph_datatype.h" +#include "igraph_error.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_rewire( - igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode, - igraph_bool_t use_adjlist); + igraph_t *graph, igraph_int_t n, igraph_bool_t loops, + igraph_bool_t use_adjlist, igraph_rewiring_stats_t *stats); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/operators/simplify.c b/src/vendor/cigraph/src/operators/simplify.c index ba6c98f9859..06257c862d2 100644 --- a/src/vendor/cigraph/src/operators/simplify.c +++ b/src/vendor/cigraph/src/operators/simplify.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -57,16 +56,16 @@ igraph_error_t igraph_simplify(igraph_t *graph, const igraph_attribute_combination_t *edge_comb) { igraph_vector_int_t edges; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t edge; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t edge; igraph_bool_t attr = edge_comb && igraph_has_attribute_table(); - igraph_integer_t from, to, pfrom = -1, pto = -2; + igraph_int_t from, to, pfrom = -1, pto = -2; igraph_t res; igraph_es_t es; igraph_eit_t eit; igraph_vector_int_t mergeinto; - igraph_integer_t actedge; + igraph_int_t actedge; /* if we already know there are no multi-edges, they don't need to be removed */ if (igraph_i_property_cache_has(graph, IGRAPH_PROP_HAS_MULTI) && @@ -172,8 +171,7 @@ igraph_error_t igraph_simplify(igraph_t *graph, IGRAPH_FINALLY(igraph_destroy, &res); - IGRAPH_I_ATTRIBUTE_DESTROY(&res); - IGRAPH_I_ATTRIBUTE_COPY(&res, graph, /*graph=*/ true, /*vertex=*/ true, /*edge=*/ false); + IGRAPH_CHECK(igraph_i_attribute_copy(&res, graph, true, true, /* edges= */ false)); if (attr) { igraph_fixed_vectorlist_t vl; diff --git a/src/vendor/cigraph/src/operators/subgraph.c b/src/vendor/cigraph/src/operators/subgraph.c index aede768480b..d164755ac7c 100644 --- a/src/vendor/cigraph/src/operators/subgraph.c +++ b/src/vendor/cigraph/src/operators/subgraph.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2006-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -25,7 +25,6 @@ #include "core/interruption.h" #include "core/set.h" #include "graph/attributes.h" -#include "graph/internal.h" #include "operators/subgraph.h" /** @@ -36,8 +35,8 @@ static igraph_error_t igraph_i_induced_subgraph_copy_and_delete( const igraph_t *graph, igraph_t *res, const igraph_vs_t vids, igraph_vector_int_t *map, igraph_vector_int_t *invmap) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_new_nodes_estimate; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_new_nodes_estimate; igraph_vector_int_t delete; igraph_bitset_t remain; igraph_vit_t vit; @@ -61,7 +60,7 @@ static igraph_error_t igraph_i_induced_subgraph_copy_and_delete( IGRAPH_BIT_SET(remain, IGRAPH_VIT_GET(vit)); } - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { IGRAPH_ALLOW_INTERRUPTION(); if (! IGRAPH_BIT_TEST(remain, i)) { @@ -74,7 +73,7 @@ static igraph_error_t igraph_i_induced_subgraph_copy_and_delete( IGRAPH_CHECK(igraph_copy(res, graph)); IGRAPH_FINALLY(igraph_destroy, res); - IGRAPH_CHECK(igraph_delete_vertices_idx(res, igraph_vss_vector(&delete), + IGRAPH_CHECK(igraph_delete_vertices_map(res, igraph_vss_vector(&delete), map, invmap)); igraph_vector_int_destroy(&delete); @@ -100,11 +99,11 @@ static igraph_error_t igraph_i_induced_subgraph_create_from_scratch( igraph_bool_t map_is_prepared) { const igraph_bool_t directed = igraph_is_directed(graph); - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_new_nodes = 0; - igraph_integer_t n; - igraph_integer_t to; - igraph_integer_t eid; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_new_nodes = 0; + igraph_int_t n; + igraph_int_t to; + igraph_int_t eid; igraph_vector_int_t vids_old2new, vids_new2old; igraph_vector_int_t eids_new2old; igraph_vector_int_t vids_vec; @@ -129,10 +128,11 @@ static igraph_error_t igraph_i_induced_subgraph_create_from_scratch( my_vids_old2new = map; if (!map_is_prepared) { IGRAPH_CHECK(igraph_vector_int_resize(map, no_of_nodes)); - igraph_vector_int_null(map); + igraph_vector_int_fill(map, -1); } } else { IGRAPH_VECTOR_INT_INIT_FINALLY(&vids_old2new, no_of_nodes); + igraph_vector_int_fill(&vids_old2new, -1); } IGRAPH_VECTOR_INT_INIT_FINALLY(&vids_vec, 0); @@ -153,49 +153,49 @@ static igraph_error_t igraph_i_induced_subgraph_create_from_scratch( igraph_vector_int_sort(&vids_vec); n = igraph_vector_int_size(&vids_vec); - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t vid = VECTOR(vids_vec)[i]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t vid = VECTOR(vids_vec)[i]; /* Cater for duplicate vertex IDs in the input vertex selector; we use * the first occurrence of each vertex ID and ignore the rest */ - if (VECTOR(*my_vids_old2new)[vid] == 0) { + if (VECTOR(*my_vids_old2new)[vid] < 0) { IGRAPH_CHECK(igraph_vector_int_push_back(my_vids_new2old, vid)); - no_of_new_nodes++; VECTOR(*my_vids_old2new)[vid] = no_of_new_nodes; + no_of_new_nodes++; } } igraph_vector_int_destroy(&vids_vec); IGRAPH_FINALLY_CLEAN(1); /* Create the new edge list */ - for (igraph_integer_t i = 0; i < no_of_new_nodes; i++) { - igraph_integer_t old_vid = VECTOR(*my_vids_new2old)[i]; - igraph_integer_t new_vid = i; + for (igraph_int_t i = 0; i < no_of_new_nodes; i++) { + igraph_int_t old_vid = VECTOR(*my_vids_new2old)[i]; + igraph_int_t new_vid = i; igraph_bool_t skip_loop_edge; - IGRAPH_CHECK(igraph_incident(graph, &nei_edges, old_vid, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(graph, &nei_edges, old_vid, IGRAPH_OUT, IGRAPH_LOOPS)); n = igraph_vector_int_size(&nei_edges); if (directed) { /* directed graph; this is easier */ - for (igraph_integer_t j = 0; j < n; j++) { + for (igraph_int_t j = 0; j < n; j++) { eid = VECTOR(nei_edges)[j]; to = VECTOR(*my_vids_old2new)[ IGRAPH_TO(graph, eid) ]; - if (!to) { + if (to < 0) { continue; } IGRAPH_CHECK(igraph_vector_int_push_back(&new_edges, new_vid)); - IGRAPH_CHECK(igraph_vector_int_push_back(&new_edges, to - 1)); + IGRAPH_CHECK(igraph_vector_int_push_back(&new_edges, to)); IGRAPH_CHECK(igraph_vector_int_push_back(&eids_new2old, eid)); } } else { /* undirected graph. We need to be careful with loop edges as each * loop edge will appear twice. We use a boolean flag to skip every * second loop edge */ - skip_loop_edge = 0; - for (igraph_integer_t j = 0; j < n; j++) { + skip_loop_edge = false; + for (igraph_int_t j = 0; j < n; j++) { eid = VECTOR(nei_edges)[j]; if (IGRAPH_FROM(graph, eid) != old_vid) { @@ -204,10 +204,9 @@ static igraph_error_t igraph_i_induced_subgraph_create_from_scratch( } to = VECTOR(*my_vids_old2new)[ IGRAPH_TO(graph, eid) ]; - if (!to) { + if (to < 0) { continue; } - to -= 1; if (new_vid == to) { /* this is a loop edge; check whether we need to skip it */ @@ -234,7 +233,6 @@ static igraph_error_t igraph_i_induced_subgraph_create_from_scratch( /* Create the new graph */ IGRAPH_CHECK(igraph_create(res, &new_edges, no_of_new_nodes, directed)); - IGRAPH_I_ATTRIBUTE_DESTROY(res); /* Now we can also get rid of the new_edges vector */ igraph_vector_int_destroy(&new_edges); @@ -245,8 +243,7 @@ static igraph_error_t igraph_i_induced_subgraph_create_from_scratch( IGRAPH_FINALLY(igraph_destroy, res); /* Copy the graph attributes */ - IGRAPH_CHECK(igraph_i_attribute_copy(res, graph, - /* ga = */ true, /* va = */ false, /* ea = */ false)); + IGRAPH_CHECK(igraph_i_attribute_copy(res, graph, true, /* vertex= */ false, /* edge= */ false)); /* Copy the vertex attributes */ IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, res, my_vids_new2old)); @@ -329,7 +326,7 @@ static igraph_error_t igraph_i_induced_subgraph_suggest_implementation( const igraph_t *graph, const igraph_vs_t vids, igraph_subgraph_implementation_t *result) { double ratio; - igraph_integer_t num_vs; + igraph_int_t num_vs; if (igraph_vs_is_all(&vids)) { ratio = 1.0; @@ -405,12 +402,12 @@ igraph_error_t igraph_i_induced_subgraph_map(const igraph_t *graph, igraph_t *re * two methods automatically based on the ratio of the number * of vertices in the new and the old graph. * \param map Returns a map of the vertices in \p graph to the vertices - * in \p res. A 0 indicates a vertex is not mapped. An \c i + 1 at + * in \p res. -1 indicates a vertex is not mapped. A value of \c i at * position \c j indicates the vertex \c j in \p graph is mapped * to vertex i in \p res. * \param invmap Returns a map of the vertices in \p res to the vertices - * in \p graph. An i at position \c j indicates the vertex \c i - * in \p graph is mapped to vertex j in \p res. + * in \p graph. A value of \c i at position \c j indicates that + * vertex \c i in \p graph is mapped to vertex \c j in \p res. * * \return Error code: * \c IGRAPH_ENOMEM, not enough memory for @@ -438,7 +435,7 @@ igraph_error_t igraph_induced_subgraph_map(const igraph_t *graph, igraph_t *res, /** * \function igraph_induced_subgraph_edges - * \brief The edges contained within an induced subgraph. + * \brief The edges contained within an induced sugraph. * * This function finds the IDs of those edges which connect vertices from * a given list, passed in the \p vids parameter. @@ -479,16 +476,16 @@ igraph_error_t igraph_induced_subgraph_edges(const igraph_t *graph, igraph_vs_t IGRAPH_VECTOR_INT_INIT_FINALLY(&incedges, 0); for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) { - igraph_integer_t v = IGRAPH_VIT_GET(vit); - IGRAPH_CHECK(igraph_i_incident(graph, &incedges, v, IGRAPH_ALL, IGRAPH_LOOPS_ONCE)); + igraph_int_t v = IGRAPH_VIT_GET(vit); + IGRAPH_CHECK(igraph_incident(graph, &incedges, v, IGRAPH_ALL, IGRAPH_LOOPS_ONCE)); - igraph_integer_t d = igraph_vector_int_size(&incedges); - for (igraph_integer_t i=0; i < d; i++) { - igraph_integer_t e = VECTOR(incedges)[i]; - igraph_integer_t u = IGRAPH_OTHER(graph, e, v); + igraph_int_t d = igraph_vector_int_size(&incedges); + for (igraph_int_t i=0; i < d; i++) { + igraph_int_t e = VECTOR(incedges)[i]; + igraph_int_t u = IGRAPH_OTHER(graph, e, v); /* The v <= u check avoids adding non-loop edges twice. * Loop edges only appear once due to the use of - * IGRAPH_LOOPS_ONCE in igraph_i_incident() */ + * IGRAPH_LOOPS_ONCE in igraph_incident() */ if (v <= u && igraph_set_contains(&vids_set, u)) { IGRAPH_CHECK(igraph_vector_int_push_back(edges, e)); } @@ -503,25 +500,12 @@ igraph_error_t igraph_induced_subgraph_edges(const igraph_t *graph, igraph_vs_t return IGRAPH_SUCCESS; } -/** - * \ingroup structural - * \function igraph_subgraph_edges - * \brief Creates a subgraph with the specified edges and their endpoints (deprecated alias). - * - * \deprecated-by igraph_subgraph_from_edges 0.10.3 - */ -igraph_error_t igraph_subgraph_edges( - const igraph_t *graph, igraph_t *res, const igraph_es_t eids, - igraph_bool_t delete_vertices -) { - return igraph_subgraph_from_edges(graph, res, eids, delete_vertices); -} - /** * \ingroup structural * \function igraph_subgraph_from_edges * \brief Creates a subgraph with the specified edges and their endpoints. * + * * This function collects the specified edges and their endpoints to a new * graph. As the edge IDs in a graph are always contiguous integers starting at * zero, the edge IDs in the extracted subgraph will be different from those @@ -554,9 +538,9 @@ igraph_error_t igraph_subgraph_from_edges( igraph_bool_t delete_vertices ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_edges_to_delete_estimate; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges_to_delete_estimate; igraph_vector_int_t delete = IGRAPH_VECTOR_NULL; igraph_bitset_t vremain, eremain; igraph_eit_t eit; @@ -579,8 +563,8 @@ igraph_error_t igraph_subgraph_from_edges( /* Collect the vertex and edge IDs that will remain */ for (IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t eid = IGRAPH_EIT_GET(eit); - igraph_integer_t from = IGRAPH_FROM(graph, eid), to = IGRAPH_TO(graph, eid); + igraph_int_t eid = IGRAPH_EIT_GET(eit); + igraph_int_t from = IGRAPH_FROM(graph, eid), to = IGRAPH_TO(graph, eid); IGRAPH_BIT_SET(eremain, eid); IGRAPH_BIT_SET(vremain, from); IGRAPH_BIT_SET(vremain, to); @@ -590,7 +574,7 @@ igraph_error_t igraph_subgraph_from_edges( IGRAPH_FINALLY_CLEAN(1); /* Collect the edge IDs to be deleted */ - for (igraph_integer_t i = 0; i < no_of_edges; i++) { + for (igraph_int_t i = 0; i < no_of_edges; i++) { IGRAPH_ALLOW_INTERRUPTION(); if (! IGRAPH_BIT_TEST(eremain, i)) { IGRAPH_CHECK(igraph_vector_int_push_back(&delete, i)); @@ -608,7 +592,7 @@ igraph_error_t igraph_subgraph_from_edges( if (delete_vertices) { /* Collect the vertex IDs to be deleted */ igraph_vector_int_clear(&delete); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { IGRAPH_ALLOW_INTERRUPTION(); if (! IGRAPH_BIT_TEST(vremain, i)) { IGRAPH_CHECK(igraph_vector_int_push_back(&delete, i)); diff --git a/src/vendor/cigraph/src/operators/subgraph.h b/src/vendor/cigraph/src/operators/subgraph.h index d293f7b2f9f..bc17c96fe6d 100644 --- a/src/vendor/cigraph/src/operators/subgraph.h +++ b/src/vendor/cigraph/src/operators/subgraph.h @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2003-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -29,7 +27,7 @@ #include "igraph_error.h" #include "igraph_iterators.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_induced_subgraph_map( const igraph_t *graph, igraph_t *res, const igraph_vs_t vids, @@ -37,6 +35,6 @@ IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_i_induced_subgraph_map( igraph_vector_int_t *invmap, igraph_bool_t map_is_prepared ); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/operators/union.c b/src/vendor/cigraph/src/operators/union.c index cfe9f414e6f..29392a2230e 100644 --- a/src/vendor/cigraph/src/operators/union.c +++ b/src/vendor/cigraph/src/operators/union.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2006-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -119,14 +118,14 @@ igraph_error_t igraph_union_many( igraph_vector_int_list_t *edgemaps ) { - igraph_integer_t no_of_graphs = igraph_vector_ptr_size(graphs); - igraph_integer_t no_of_nodes = 0; + igraph_int_t no_of_graphs = igraph_vector_ptr_size(graphs); + igraph_int_t no_of_nodes = 0; igraph_bool_t directed = true; igraph_vector_int_t edges; igraph_vector_int_list_t edge_vects, order_vects; igraph_vector_int_t no_edges; - igraph_integer_t i, j, tailfrom = no_of_graphs > 0 ? 0 : -1, tailto = -1; - igraph_integer_t idx = 0; + igraph_int_t i, j, tailfrom = no_of_graphs > 0 ? 0 : -1, tailto = -1; + igraph_int_t idx = 0; /* Check directedness */ if (no_of_graphs != 0) { @@ -146,7 +145,7 @@ igraph_error_t igraph_union_many( /* Calculate number of nodes, query number of edges */ for (i = 0; i < no_of_graphs; i++) { - igraph_integer_t n = igraph_vcount(VECTOR(*graphs)[i]); + igraph_int_t n = igraph_vcount(VECTOR(*graphs)[i]); if (n > no_of_nodes) { no_of_nodes = n; } @@ -167,14 +166,14 @@ igraph_error_t igraph_union_many( /* Query and sort the edge lists */ for (i = 0; i < no_of_graphs; i++) { - igraph_integer_t k, j, n = VECTOR(no_edges)[i]; + igraph_int_t k, j, n = VECTOR(no_edges)[i]; igraph_vector_int_t *ev = igraph_vector_int_list_get_ptr(&edge_vects, i); igraph_vector_int_t *order = igraph_vector_int_list_get_ptr(&order_vects, i); IGRAPH_CHECK(igraph_get_edgelist(VECTOR(*graphs)[i], ev, /*bycol=*/ false)); if (!directed) { for (k = 0, j = 0; k < n; k++, j += 2) { if (VECTOR(*ev)[j] > VECTOR(*ev)[j + 1]) { - igraph_integer_t tmp = VECTOR(*ev)[j]; + igraph_int_t tmp = VECTOR(*ev)[j]; VECTOR(*ev)[j] = VECTOR(*ev)[j + 1]; VECTOR(*ev)[j + 1] = tmp; } @@ -196,9 +195,9 @@ igraph_error_t igraph_union_many( igraph_vector_int_t *order = igraph_vector_int_list_get_ptr(&order_vects, j); if (!igraph_vector_int_empty(order)) { igraph_vector_int_t *ev = igraph_vector_int_list_get_ptr(&edge_vects, j); - igraph_integer_t edge = igraph_vector_int_tail(order); - igraph_integer_t from = VECTOR(*ev)[2 * edge]; - igraph_integer_t to = VECTOR(*ev)[2 * edge + 1]; + igraph_int_t edge = igraph_vector_int_tail(order); + igraph_int_t from = VECTOR(*ev)[2 * edge]; + igraph_int_t to = VECTOR(*ev)[2 * edge + 1]; if (from > tailfrom || (from == tailfrom && to > tailto)) { tailfrom = from; tailto = to; } @@ -217,9 +216,9 @@ igraph_error_t igraph_union_many( igraph_vector_int_t *order = igraph_vector_int_list_get_ptr(&order_vects, j); if (!igraph_vector_int_empty(order)) { igraph_vector_int_t *ev = igraph_vector_int_list_get_ptr(&edge_vects, j); - igraph_integer_t edge = igraph_vector_int_tail(order); - igraph_integer_t from = VECTOR(*ev)[2 * edge]; - igraph_integer_t to = VECTOR(*ev)[2 * edge + 1]; + igraph_int_t edge = igraph_vector_int_tail(order); + igraph_int_t from = VECTOR(*ev)[2 * edge]; + igraph_int_t to = VECTOR(*ev)[2 * edge + 1]; if (from == tailfrom && to == tailto) { igraph_vector_int_pop_back(order); if (edgemaps) { diff --git a/src/vendor/cigraph/src/paths/all_shortest_paths.c b/src/vendor/cigraph/src/paths/all_shortest_paths.c index 4cfa2196f10..1b53bdb7bf2 100644 --- a/src/vendor/cigraph/src/paths/all_shortest_paths.c +++ b/src/vendor/cigraph/src/paths/all_shortest_paths.c @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. - Copyright (C) 2005-2021 The igraph development team + igraph library. + Copyright (C) 2005-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_paths.h" @@ -28,6 +23,7 @@ #include "igraph_memory.h" #include "core/interruption.h" +#include "paths/paths_internal.h" #include /* memset */ @@ -94,16 +90,38 @@ * Time complexity: O(|V|+|E|) for most graphs, O(|V|^2) in the worst * case. */ +igraph_error_t igraph_get_all_shortest_paths( + const igraph_t *graph, + const igraph_vector_t *weights, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_vector_int_t *nrgeo, + igraph_int_t from, const igraph_vs_t to, + igraph_neimode_t mode) { + + if (weights == NULL) { + /* Unweighted version */ + return igraph_i_get_all_shortest_paths_unweighted( + graph, vertices, edges, nrgeo, from, to, mode + ); + } else { + /* Weighted version */ + return igraph_get_all_shortest_paths_dijkstra( + graph, vertices, edges, nrgeo, from, to, weights, mode + ); + } +} -igraph_error_t igraph_get_all_shortest_paths(const igraph_t *graph, - igraph_vector_int_list_t *vertices, - igraph_vector_int_list_t *edges, - igraph_vector_int_t *nrgeo, - igraph_integer_t from, const igraph_vs_t to, - igraph_neimode_t mode) { +igraph_error_t igraph_i_get_all_shortest_paths_unweighted( + const igraph_t *graph, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_vector_int_t *nrgeo, + igraph_int_t from, const igraph_vs_t to, + igraph_neimode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t *geodist; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t *geodist; igraph_vector_int_list_t paths; igraph_vector_int_list_t path_edge; igraph_dqueue_int_t q; @@ -112,8 +130,8 @@ igraph_error_t igraph_get_all_shortest_paths(const igraph_t *graph, igraph_vector_int_t neis; igraph_vector_int_t ptrlist; igraph_vector_int_t ptrhead; - igraph_integer_t n; - igraph_integer_t to_reach, reached = 0, maxdist = 0; + igraph_int_t n; + igraph_int_t to_reach, reached = 0, maxdist = 0; igraph_vit_t vit; @@ -149,7 +167,7 @@ igraph_error_t igraph_get_all_shortest_paths(const igraph_t *graph, * is in the target vertex sequence. Otherwise it is * one larger than the length of the shortest path from the * source */ - geodist = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + geodist = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(geodist, "Insufficient memory for calculating shortest paths."); IGRAPH_FINALLY(igraph_free, geodist); /* dequeue to store the BFS queue -- odd elements are the vertex indices, @@ -191,8 +209,8 @@ igraph_error_t igraph_get_all_shortest_paths(const igraph_t *graph, IGRAPH_CHECK(igraph_dqueue_int_push(&q, from)); IGRAPH_CHECK(igraph_dqueue_int_push(&q, 0)); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); IGRAPH_ALLOW_INTERRUPTION(); @@ -213,15 +231,15 @@ igraph_error_t igraph_get_all_shortest_paths(const igraph_t *graph, * using igraph_neighbors() due to branch mispredictions in IGRAPH_OTHER(), so we * use igraph_incident() only if the user needs the edge-paths */ if (edges) { - IGRAPH_CHECK(igraph_incident(graph, &neis, actnode, mode)); + IGRAPH_CHECK(igraph_incident(graph, &neis, actnode, mode, IGRAPH_LOOPS)); } else { - IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); } n = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t neighbor; - igraph_integer_t parentptr; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t neighbor; + igraph_int_t parentptr; if (edges) { /* user needs the edge-paths, so 'neis' contains edge IDs, we need to resolve @@ -297,8 +315,8 @@ igraph_error_t igraph_get_all_shortest_paths(const igraph_t *graph, igraph_vector_int_list_clear(edges); } - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t parentptr = VECTOR(ptrhead)[i]; + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t parentptr = VECTOR(ptrhead)[i]; IGRAPH_ALLOW_INTERRUPTION(); diff --git a/src/vendor/cigraph/src/paths/astar.c b/src/vendor/cigraph/src/paths/astar.c index c3d5f55c822..2913b7634cc 100644 --- a/src/vendor/cigraph/src/paths/astar.c +++ b/src/vendor/cigraph/src/paths/astar.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -28,7 +28,7 @@ #include "core/interruption.h" static igraph_error_t null_heuristic( - igraph_real_t *result, igraph_integer_t from, igraph_integer_t to, + igraph_real_t *result, igraph_int_t from, igraph_int_t to, void *extra ) { IGRAPH_UNUSED(from); @@ -44,8 +44,6 @@ static igraph_error_t null_heuristic( * \function igraph_get_shortest_path_astar * \brief A* gives the shortest path from one vertex to another, with heuristic. * - * \experimental - * * Calculates a shortest path from a single source vertex to a single * target, using the A* algorithm. A* tries to find a shortest path by * starting at \p from and moving to vertices that lie on a path with @@ -95,8 +93,8 @@ static igraph_error_t null_heuristic( igraph_error_t igraph_get_shortest_path_astar(const igraph_t *graph, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t from, - igraph_integer_t to, + igraph_int_t from, + igraph_int_t to, const igraph_vector_t *weights, igraph_neimode_t mode, igraph_astar_heuristic_func_t *heuristic, @@ -104,12 +102,12 @@ igraph_error_t igraph_get_shortest_path_astar(const igraph_t *graph, { igraph_real_t heur_res; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_2wheap_t Q; igraph_lazy_inclist_t inclist; igraph_vector_t dists; - igraph_integer_t *parent_eids; + igraph_int_t *parent_eids; if (from < 0 || from >= no_of_nodes) { IGRAPH_ERROR("Starting vertex out of range.", IGRAPH_EINVVID); @@ -150,7 +148,7 @@ igraph_error_t igraph_get_shortest_path_astar(const igraph_t *graph, /* parent_eids[v] is the 1 + the ID of v's inbound edge in the shortest path tree. * A value of 0 indicates unreachable vertices. */ - parent_eids = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + parent_eids = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(parent_eids, "Insufficient memory for shortest paths with A* algorithm."); IGRAPH_FINALLY(igraph_free, parent_eids); @@ -172,7 +170,7 @@ igraph_error_t igraph_get_shortest_path_astar(const igraph_t *graph, * in order to obtain smallest values first. The value taken off * the heap is ignored, we just want the index of 'u'. */ - igraph_integer_t u; + igraph_int_t u; igraph_2wheap_delete_max_index(&Q, &u); /* Reached the target vertex, the search can be stopped. */ @@ -187,10 +185,10 @@ igraph_error_t igraph_get_shortest_path_astar(const igraph_t *graph, igraph_vector_int_t *neis = igraph_lazy_inclist_get(&inclist, u); IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); - igraph_integer_t nlen = igraph_vector_int_size(neis); - for (igraph_integer_t i = 0; i < nlen; i++) { - igraph_integer_t edge = VECTOR(*neis)[i]; - igraph_integer_t v = IGRAPH_OTHER(graph, edge, u); + igraph_int_t nlen = igraph_vector_int_size(neis); + for (igraph_int_t i = 0; i < nlen; i++) { + igraph_int_t edge = VECTOR(*neis)[i]; + igraph_int_t v = IGRAPH_OTHER(graph, edge, u); igraph_real_t altdist; /* candidate from -> v distance */ if (weights) { igraph_real_t weight = VECTOR(*weights)[edge]; @@ -225,7 +223,7 @@ igraph_error_t igraph_get_shortest_path_astar(const igraph_t *graph, /* Reconstruct the shortest paths based on vertex and/or edge IDs */ if (vertices || edges) { - igraph_integer_t size, act, edge; + igraph_int_t size, act, edge; if (vertices) { igraph_vector_int_clear(vertices); diff --git a/src/vendor/cigraph/src/paths/bellman_ford.c b/src/vendor/cigraph/src/paths/bellman_ford.c index 0556c838aa5..3ff84e40049 100644 --- a/src/vendor/cigraph/src/paths/bellman_ford.c +++ b/src/vendor/cigraph/src/paths/bellman_ford.c @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. - Copyright (C) 2005-2021 The igraph development team + igraph library. + Copyright (C) 2005-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,6 +25,7 @@ #include "igraph_memory.h" #include "core/interruption.h" +#include "paths/paths_internal.h" /** * \function igraph_distances_bellman_ford @@ -61,30 +60,44 @@ * Time complexity: O(s*|E|*|V|), where |V| is the number of * vertices, |E| the number of edges and s the number of sources. * - * \sa \ref igraph_distances() for a faster unweighted version - * or \ref igraph_distances_dijkstra() if you do not have negative + * \sa \ref igraph_distances() for a non-algorithm-specific interface; + * \ref igraph_distances_dijkstra() if you do not have negative * edge weights. * * \example examples/simple/bellman_ford.c */ -igraph_error_t igraph_distances_bellman_ford(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights, - igraph_neimode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); +igraph_error_t igraph_distances_bellman_ford( + const igraph_t *graph, + igraph_matrix_t *res, + const igraph_vs_t from, + const igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode) { + + igraph_bool_t negative_weights; + IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights)); + return igraph_i_distances_bellman_ford(graph, res, from, to, weights, mode); +} + +igraph_error_t igraph_i_distances_bellman_ford( + const igraph_t *graph, + igraph_matrix_t *res, + const igraph_vs_t from, const igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode) { + + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_lazy_inclist_t inclist; - igraph_integer_t i; - igraph_integer_t no_of_from, no_of_to; + igraph_int_t i; + igraph_int_t no_of_from, no_of_to; igraph_dqueue_int_t Q; igraph_bitset_t clean_vertices; igraph_vector_int_t num_queued; igraph_vit_t fromvit, tovit; igraph_bool_t all_to; igraph_vector_t dist; - int counter = 0; + int iter = 0; /* - speedup: a vertex is marked clean if its distance from the source @@ -94,17 +107,9 @@ igraph_error_t igraph_distances_bellman_ford(const igraph_t *graph, be detected by checking whether a vertex has been queued at least n times. */ - if (!weights) { - return igraph_distances(graph, res, from, to, mode); - } - if (igraph_vector_size(weights) != no_of_edges) { - IGRAPH_ERRORF("Weight vector length (%" IGRAPH_PRId ") does not match number of edges (%" IGRAPH_PRId ").", - IGRAPH_EINVAL, - igraph_vector_size(weights), no_of_edges); - } - if (igraph_vector_is_any_nan(weights)) { - IGRAPH_ERROR("Weight vector must not contain NaN values.", IGRAPH_EINVAL); + if (!weights || no_of_edges == 0) { + return igraph_i_distances_unweighted_cutoff(graph, res, from, to, mode, -1); } IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit)); @@ -137,7 +142,7 @@ igraph_error_t igraph_distances_bellman_ford(const igraph_t *graph, for (IGRAPH_VIT_RESET(fromvit), i = 0; !IGRAPH_VIT_END(fromvit); IGRAPH_VIT_NEXT(fromvit), i++) { - igraph_integer_t source = IGRAPH_VIT_GET(fromvit); + igraph_int_t source = IGRAPH_VIT_GET(fromvit); igraph_vector_fill(&dist, IGRAPH_INFINITY); VECTOR(dist)[source] = 0; @@ -145,17 +150,14 @@ igraph_error_t igraph_distances_bellman_ford(const igraph_t *graph, igraph_vector_int_null(&num_queued); /* Fill the queue with vertices to be checked */ - for (igraph_integer_t j = 0; j < no_of_nodes; j++) { + for (igraph_int_t j = 0; j < no_of_nodes; j++) { IGRAPH_CHECK(igraph_dqueue_int_push(&Q, j)); } while (!igraph_dqueue_int_empty(&Q)) { - if (++counter >= 10000) { - counter = 0; - IGRAPH_ALLOW_INTERRUPTION(); - } + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 13); - igraph_integer_t j = igraph_dqueue_int_pop(&Q); + igraph_int_t j = igraph_dqueue_int_pop(&Q); IGRAPH_BIT_SET(clean_vertices, j); VECTOR(num_queued)[j] += 1; if (VECTOR(num_queued)[j] > no_of_nodes) { @@ -172,10 +174,10 @@ igraph_error_t igraph_distances_bellman_ford(const igraph_t *graph, igraph_vector_int_t *neis = igraph_lazy_inclist_get(&inclist, j); IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); - igraph_integer_t nlen = igraph_vector_int_size(neis); - for (igraph_integer_t k = 0; k < nlen; k++) { - igraph_integer_t nei = VECTOR(*neis)[k]; - igraph_integer_t target = IGRAPH_OTHER(graph, nei, j); + igraph_int_t nlen = igraph_vector_int_size(neis); + for (igraph_int_t k = 0; k < nlen; k++) { + igraph_int_t nei = VECTOR(*neis)[k]; + igraph_int_t target = IGRAPH_OTHER(graph, nei, j); igraph_real_t altdist = VECTOR(dist)[j] + VECTOR(*weights)[nei]; if (VECTOR(dist)[target] > altdist) { /* relax the edge */ @@ -190,12 +192,12 @@ igraph_error_t igraph_distances_bellman_ford(const igraph_t *graph, /* Copy it to the result */ if (all_to) { - igraph_matrix_set_row(res, &dist, i); + IGRAPH_CHECK(igraph_matrix_set_row(res, &dist, i)); } else { - igraph_integer_t j; + igraph_int_t j; for (IGRAPH_VIT_RESET(tovit), j = 0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit), j++) { - igraph_integer_t v = IGRAPH_VIT_GET(tovit); + igraph_int_t v = IGRAPH_VIT_GET(tovit); MATRIX(*res, i, j) = VECTOR(dist)[v]; } } @@ -219,20 +221,6 @@ igraph_error_t igraph_distances_bellman_ford(const igraph_t *graph, return IGRAPH_SUCCESS; } -/** - * \function igraph_shortest_paths_bellman_ford - * \brief Weighted shortest path lengths between vertices, allowing negative weights (deprecated). - * - * \deprecated-by igraph_distances_bellman_ford 0.10.0 - */ -igraph_error_t igraph_shortest_paths_bellman_ford(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights, - igraph_neimode_t mode) { - return igraph_distances_bellman_ford(graph, res, from, to, weights, mode); -} /** * \ingroup structural @@ -303,44 +291,54 @@ igraph_error_t igraph_shortest_paths_bellman_ford(const igraph_t *graph, * * \sa \ref igraph_distances_bellman_ford() to compute only shortest path * lengths, but not the paths themselves; \ref igraph_get_shortest_paths() for - * a faster unweighted version or \ref igraph_get_shortest_paths_dijkstra() - * if you do not have negative edge weights. + * a non-algorithm-specific interface. */ +igraph_error_t igraph_get_shortest_paths_bellman_ford( + const igraph_t *graph, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_int_t from, + igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode, + igraph_vector_int_t *parents, + igraph_vector_int_t *inbound_edges) { + + igraph_bool_t negative_weights; + IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights)); + return igraph_i_get_shortest_paths_bellman_ford(graph, vertices, edges, from, to, weights, mode, parents, inbound_edges); +} -igraph_error_t igraph_get_shortest_paths_bellman_ford(const igraph_t *graph, - igraph_vector_int_list_t *vertices, - igraph_vector_int_list_t *edges, - igraph_integer_t from, - igraph_vs_t to, - const igraph_vector_t *weights, - igraph_neimode_t mode, - igraph_vector_int_t *parents, - igraph_vector_int_t *inbound_edges) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t *parent_eids; +igraph_error_t igraph_i_get_shortest_paths_bellman_ford( + const igraph_t *graph, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_int_t from, + igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode, + igraph_vector_int_t *parents, + igraph_vector_int_t *inbound_edges) { + + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t *parent_eids; igraph_lazy_inclist_t inclist; - igraph_integer_t i, j, k; + igraph_int_t i, j, k; igraph_dqueue_int_t Q; igraph_bitset_t clean_vertices; igraph_vector_int_t num_queued; igraph_vit_t tovit; igraph_vector_t dist; - int counter = 0; + int iter = 0; if (!weights) { - return igraph_get_shortest_paths(graph, vertices, edges, from, to, mode, - parents, inbound_edges); + return igraph_i_get_shortest_paths_unweighted(graph, vertices, edges, from, to, mode, parents, inbound_edges); } if (from < 0 || from >= no_of_nodes) { IGRAPH_ERROR("Index of source vertex is out of range.", IGRAPH_EINVVID); } - if (igraph_vector_size(weights) != no_of_edges) { - IGRAPH_ERROR("Weight vector length must match number of edges.", IGRAPH_EINVAL); - } - IGRAPH_DQUEUE_INT_INIT_FINALLY(&Q, no_of_nodes); IGRAPH_BITSET_INIT_FINALLY(&clean_vertices, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&num_queued, no_of_nodes); @@ -357,7 +355,7 @@ igraph_error_t igraph_get_shortest_paths_bellman_ford(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_list_resize(edges, IGRAPH_VIT_SIZE(tovit))); } - parent_eids = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + parent_eids = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(parent_eids, "Insufficient memory for shortest paths with Bellman-Ford."); IGRAPH_FINALLY(igraph_free, parent_eids); @@ -372,10 +370,7 @@ igraph_error_t igraph_get_shortest_paths_bellman_ford(const igraph_t *graph, } while (!igraph_dqueue_int_empty(&Q)) { - if (++counter >= 10000) { - counter = 0; - IGRAPH_ALLOW_INTERRUPTION(); - } + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 13); j = igraph_dqueue_int_pop(&Q); IGRAPH_BIT_SET(clean_vertices, j); @@ -393,17 +388,13 @@ igraph_error_t igraph_get_shortest_paths_bellman_ford(const igraph_t *graph, igraph_vector_int_t *neis = igraph_lazy_inclist_get(&inclist, j); IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); - igraph_integer_t nlen = igraph_vector_int_size(neis); + igraph_int_t nlen = igraph_vector_int_size(neis); for (k = 0; k < nlen; k++) { - igraph_integer_t nei = VECTOR(*neis)[k]; - igraph_integer_t target = IGRAPH_OTHER(graph, nei, j); + igraph_int_t nei = VECTOR(*neis)[k]; + igraph_int_t target = IGRAPH_OTHER(graph, nei, j); igraph_real_t weight = VECTOR(*weights)[nei]; igraph_real_t altdist = VECTOR(dist)[j] + weight; - if (isnan(weight)) { - IGRAPH_ERROR("Weight vector must not contain NaN values.", IGRAPH_EINVAL); - } - /* infinite weights are handled correctly here; if an edge has * infinite weight, altdist will also be infinite so the condition * will never be true as if the edge was ignored */ @@ -456,8 +447,8 @@ igraph_error_t igraph_get_shortest_paths_bellman_ford(const igraph_t *graph, /* Reconstruct the shortest paths based on vertex and/or edge IDs */ if (vertices || edges) { for (IGRAPH_VIT_RESET(tovit), i = 0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit), i++) { - igraph_integer_t node = IGRAPH_VIT_GET(tovit); - igraph_integer_t size, act, edge; + igraph_int_t node = IGRAPH_VIT_GET(tovit); + igraph_int_t size, act, edge; igraph_vector_int_t *vvec = 0, *evec = 0; if (vertices) { vvec = igraph_vector_int_list_get_ptr(vertices, i); @@ -558,8 +549,8 @@ igraph_error_t igraph_get_shortest_paths_bellman_ford(const igraph_t *graph, igraph_error_t igraph_get_shortest_path_bellman_ford(const igraph_t *graph, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t from, - igraph_integer_t to, + igraph_int_t from, + igraph_int_t to, const igraph_vector_t *weights, igraph_neimode_t mode) { @@ -586,12 +577,12 @@ igraph_error_t igraph_get_shortest_path_bellman_ford(const igraph_t *graph, /* We use the constant time vector_swap() instead of the linear-time vector_update() to move the result to the output parameter. */ if (edges) { - IGRAPH_CHECK(igraph_vector_int_swap(edges, igraph_vector_int_list_get_ptr(&edges2, 0))); + igraph_vector_int_swap(edges, igraph_vector_int_list_get_ptr(&edges2, 0)); igraph_vector_int_list_destroy(&edges2); IGRAPH_FINALLY_CLEAN(1); } if (vertices) { - IGRAPH_CHECK(igraph_vector_int_swap(vertices, igraph_vector_int_list_get_ptr(&vertices2, 0))); + igraph_vector_int_swap(vertices, igraph_vector_int_list_get_ptr(&vertices2, 0)); igraph_vector_int_list_destroy(&vertices2); IGRAPH_FINALLY_CLEAN(1); } diff --git a/src/vendor/cigraph/src/paths/dijkstra.c b/src/vendor/cigraph/src/paths/dijkstra.c index 784fe33b4ca..a6960481021 100644 --- a/src/vendor/cigraph/src/paths/dijkstra.c +++ b/src/vendor/cigraph/src/paths/dijkstra.c @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. - Copyright (C) 2005-2021 The igraph development team + igraph library. + Copyright (C) 2005-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_paths.h" @@ -32,15 +27,44 @@ #include "core/indheap.h" #include "core/interruption.h" +#include "paths/paths_internal.h" #include /* memset */ +igraph_error_t igraph_i_validate_distance_weights( + const igraph_t *graph, + const igraph_vector_t *weights, + igraph_bool_t *negative_weights) { + + const igraph_int_t ecount = igraph_ecount(graph); + + *negative_weights = false; + + if (weights) { + if (igraph_vector_size(weights) != ecount) { + IGRAPH_ERRORF("Edge weight vector length (%" IGRAPH_PRId ") does not match number of edges (%" IGRAPH_PRId ").", + IGRAPH_EINVAL, + igraph_vector_size(weights), ecount); + } + + if (ecount > 0) { + igraph_real_t min = igraph_vector_min(weights); + if (min < 0) { + *negative_weights = true; + } + if (isnan(min)) { + IGRAPH_ERROR("Edge weights must not contain NaN values.", IGRAPH_EINVAL); + } + } + } + + return IGRAPH_SUCCESS; +} + /** * \function igraph_distances_dijkstra_cutoff * \brief Weighted shortest path lengths between vertices, with cutoff. * - * \experimental - * * This function is similar to \ref igraph_distances_dijkstra(), but * paths longer than \p cutoff will not be considered. * @@ -66,8 +90,8 @@ * for undirected graphs. * \param cutoff The maximal length of paths that will be considered. * When the distance of two vertices is greater than this value, - * it will be returned as \c IGRAPH_INFINITY. Negative cutoffs are - * treated as infinity. + * it will be returned as \c IGRAPH_INFINITY. Negative cutoffs and + * \ref IGRAPH_UNLIMITED are treated as infinity. * \return Error code. * * Time complexity: at most O(s |E| log|V| + |V|), where |V| is the number of @@ -80,7 +104,27 @@ * * \example examples/simple/distances.c */ -igraph_error_t igraph_distances_dijkstra_cutoff(const igraph_t *graph, +igraph_error_t igraph_distances_dijkstra_cutoff( + const igraph_t *graph, + igraph_matrix_t *res, + const igraph_vs_t from, + const igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode, + igraph_real_t cutoff) { + + igraph_bool_t negative_weights; + IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights)); + if (negative_weights) { + IGRAPH_ERRORF("Edge weights must not be negative when using Dijkstra's algorithm, got %g.", + IGRAPH_EINVAL, + igraph_vector_min(weights)); + } + return igraph_i_distances_dijkstra_cutoff(graph, res, from, to, weights, mode, cutoff); +} + + +igraph_error_t igraph_i_distances_dijkstra_cutoff(const igraph_t *graph, igraph_matrix_t *res, const igraph_vs_t from, const igraph_vs_t to, @@ -100,33 +144,17 @@ igraph_error_t igraph_distances_dijkstra_cutoff(const igraph_t *graph, maximum heap and we need a minimum heap. */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_2wheap_t Q; igraph_vit_t fromvit, tovit; - igraph_integer_t no_of_from, no_of_to; + igraph_int_t no_of_from, no_of_to; igraph_lazy_inclist_t inclist; - igraph_integer_t i, j; + igraph_int_t i, j; igraph_bool_t all_to; igraph_vector_int_t indexv; if (!weights) { - return igraph_distances_cutoff(graph, res, from, to, mode, cutoff); - } - - if (igraph_vector_size(weights) != no_of_edges) { - IGRAPH_ERRORF("Weight vector length (%" IGRAPH_PRId ") does not match number of edges (%" IGRAPH_PRId ").", - IGRAPH_EINVAL, - igraph_vector_size(weights), no_of_edges); - } - - if (no_of_edges > 0) { - igraph_real_t min = igraph_vector_min(weights); - if (min < 0) { - IGRAPH_ERRORF("Weights must not be negative, got %g.", IGRAPH_EINVAL, min); - } else if (isnan(min)) { - IGRAPH_ERROR("Weights must not contain NaN values.", IGRAPH_EINVAL); - } + return igraph_i_distances_unweighted_cutoff(graph, res, from, to, mode, cutoff); } IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit)); @@ -154,7 +182,7 @@ igraph_error_t igraph_distances_dijkstra_cutoff(const igraph_t *graph, * map a target vertex to its column in the distance matrix. The mapping * is constructed by the loop below */ for (i = 0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit)) { - igraph_integer_t v = IGRAPH_VIT_GET(tovit); + igraph_int_t v = IGRAPH_VIT_GET(tovit); if (VECTOR(indexv)[v]) { IGRAPH_ERROR("Target vertex list must not have any duplicates.", IGRAPH_EINVAL); @@ -170,8 +198,8 @@ igraph_error_t igraph_distances_dijkstra_cutoff(const igraph_t *graph, !IGRAPH_VIT_END(fromvit); IGRAPH_VIT_NEXT(fromvit), i++) { - igraph_integer_t reached = 0; - igraph_integer_t source = IGRAPH_VIT_GET(fromvit); + igraph_int_t reached = 0; + igraph_int_t source = IGRAPH_VIT_GET(fromvit); igraph_2wheap_clear(&Q); @@ -182,10 +210,10 @@ igraph_error_t igraph_distances_dijkstra_cutoff(const igraph_t *graph, igraph_2wheap_push_with_index(&Q, source, -0.0); while (!igraph_2wheap_empty(&Q)) { - igraph_integer_t minnei = igraph_2wheap_max_index(&Q); + igraph_int_t minnei = igraph_2wheap_max_index(&Q); igraph_real_t mindist = -igraph_2wheap_deactivate_max(&Q); igraph_vector_int_t *neis; - igraph_integer_t nlen; + igraph_int_t nlen; if (cutoff >= 0 && mindist > cutoff) { continue; @@ -209,7 +237,7 @@ igraph_error_t igraph_distances_dijkstra_cutoff(const igraph_t *graph, IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); nlen = igraph_vector_int_size(neis); for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*neis)[j]; + igraph_int_t edge = VECTOR(*neis)[j]; igraph_real_t weight = VECTOR(*weights)[edge]; /* Optimization: do not follow infinite-weight edges. */ @@ -217,7 +245,7 @@ igraph_error_t igraph_distances_dijkstra_cutoff(const igraph_t *graph, continue; } - igraph_integer_t tto = IGRAPH_OTHER(graph, edge, minnei); + igraph_int_t tto = IGRAPH_OTHER(graph, edge, minnei); igraph_real_t altdist = mindist + weight; if (! igraph_2wheap_has_elem(&Q, tto)) { @@ -284,36 +312,24 @@ igraph_error_t igraph_distances_dijkstra_cutoff(const igraph_t *graph, * Time complexity: O(s*|E|log|V|+|V|), where |V| is the number of * vertices, |E| the number of edges and s the number of sources. * - * \sa \ref igraph_distances() for a (slightly) faster unweighted - * version or \ref igraph_distances_bellman_ford() for a weighted + * \sa \ref igraph_distances() for a non-algorithm-specific interface + * or \ref igraph_distances_bellman_ford() for a weighted * variant that works in the presence of negative edge weights (but no * negative loops) * * \example examples/simple/distances.c */ -igraph_error_t igraph_distances_dijkstra(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights, - igraph_neimode_t mode) { +igraph_error_t igraph_distances_dijkstra( + const igraph_t *graph, + igraph_matrix_t *res, + const igraph_vs_t from, + const igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode) { + return igraph_distances_dijkstra_cutoff(graph, res, from, to, weights, mode, -1); } -/** - * \function igraph_shortest_paths_dijkstra - * \brief Weighted shortest path lengths between vertices (deprecated). - * - * \deprecated-by igraph_distances_dijkstra 0.10.0 - */ -igraph_error_t igraph_shortest_paths_dijkstra(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights, - igraph_neimode_t mode) { - return igraph_distances_dijkstra(graph, res, from, to, weights, mode); -} /** * \ingroup structural @@ -387,23 +403,43 @@ igraph_error_t igraph_shortest_paths_dijkstra(const igraph_t *graph, * vertices and |E| is the number of edges * * \sa \ref igraph_distances_dijkstra() if you only need the path lengths but - * not the paths themselves; \ref igraph_get_shortest_paths() if all edge - * weights are equal; \ref igraph_get_all_shortest_paths() to find all - * shortest paths between (source, target) pairs; - * \ref igraph_get_shortest_paths_bellman_ford() if some edge weights are - * negative. + * not the paths themselves; \ref igraph_get_all_shortest_paths_dijkstra() to + * find all shortest paths between (source, target) pairs; + * \ref igraph_get_shortest_paths() for a non-algorithm-specific interface. * * \example examples/simple/igraph_get_shortest_paths_dijkstra.c */ -igraph_error_t igraph_get_shortest_paths_dijkstra(const igraph_t *graph, - igraph_vector_int_list_t *vertices, - igraph_vector_int_list_t *edges, - igraph_integer_t from, - igraph_vs_t to, - const igraph_vector_t *weights, - igraph_neimode_t mode, - igraph_vector_int_t *parents, - igraph_vector_int_t *inbound_edges) { +igraph_error_t igraph_get_shortest_paths_dijkstra( + const igraph_t *graph, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_int_t from, + igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode, + igraph_vector_int_t *parents, + igraph_vector_int_t *inbound_edges) { + + igraph_bool_t negative_weights; + IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights)); + if (negative_weights) { + IGRAPH_ERRORF("Edge weights must not be negative when using Dijkstra's algorithm, got %g.", + IGRAPH_EINVAL, + igraph_vector_min(weights)); + } + return igraph_i_get_shortest_paths_dijkstra(graph, vertices, edges, from, to, weights, mode, parents, inbound_edges); +} + + +igraph_error_t igraph_i_get_shortest_paths_dijkstra(const igraph_t *graph, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_int_t from, + igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode, + igraph_vector_int_t *parents, + igraph_vector_int_t *inbound_edges) { /* Implementation details. This is the basic Dijkstra algorithm, with a binary heap. The heap is indexed, i.e. it stores not only the distances, but also which vertex they belong to. The other @@ -423,38 +459,23 @@ igraph_error_t igraph_get_shortest_paths_dijkstra(const igraph_t *graph, edge ID + 1 is stored, zero means unreachable vertices. */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vit_t vit; igraph_2wheap_t Q; igraph_lazy_inclist_t inclist; igraph_vector_t dists; - igraph_integer_t *parent_eids; + igraph_int_t *parent_eids; igraph_bool_t *is_target; - igraph_integer_t i, to_reach; + igraph_int_t i, to_reach; if (!weights) { - return igraph_get_shortest_paths(graph, vertices, edges, from, to, mode, - parents, inbound_edges); + return igraph_i_get_shortest_paths_unweighted(graph, vertices, edges, from, to, mode, parents, inbound_edges); } if (from < 0 || from >= no_of_nodes) { IGRAPH_ERROR("Index of source vertex is out of range.", IGRAPH_EINVVID); } - if (igraph_vector_size(weights) != no_of_edges) { - IGRAPH_ERROR("Weight vector length does not match number of edges.", IGRAPH_EINVAL); - } - if (no_of_edges > 0) { - igraph_real_t min = igraph_vector_min(weights); - if (min < 0) { - IGRAPH_ERRORF("Weights must not be negative, got %g.", IGRAPH_EINVAL, min); - } - else if (isnan(min)) { - IGRAPH_ERROR("Weights must not contain NaN values.", IGRAPH_EINVAL); - } - } - IGRAPH_CHECK(igraph_vit_create(graph, to, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); @@ -473,7 +494,7 @@ igraph_error_t igraph_get_shortest_paths_dijkstra(const igraph_t *graph, IGRAPH_VECTOR_INIT_FINALLY(&dists, no_of_nodes); igraph_vector_fill(&dists, -1.0); - parent_eids = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + parent_eids = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(parent_eids, "Insufficient memory for shortest paths with Dijkstra's algorithm."); IGRAPH_FINALLY(igraph_free, parent_eids); @@ -496,7 +517,7 @@ igraph_error_t igraph_get_shortest_paths_dijkstra(const igraph_t *graph, igraph_2wheap_push_with_index(&Q, from, 0); while (!igraph_2wheap_empty(&Q) && to_reach > 0) { - igraph_integer_t nlen, minnei = igraph_2wheap_max_index(&Q); + igraph_int_t nlen, minnei = igraph_2wheap_max_index(&Q); igraph_real_t mindist = -igraph_2wheap_delete_max(&Q); igraph_vector_int_t *neis; @@ -512,8 +533,8 @@ igraph_error_t igraph_get_shortest_paths_dijkstra(const igraph_t *graph, IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); nlen = igraph_vector_int_size(neis); for (i = 0; i < nlen; i++) { - igraph_integer_t edge = VECTOR(*neis)[i]; - igraph_integer_t tto = IGRAPH_OTHER(graph, edge, minnei); + igraph_int_t edge = VECTOR(*neis)[i]; + igraph_int_t tto = IGRAPH_OTHER(graph, edge, minnei); igraph_real_t altdist = mindist + VECTOR(*weights)[edge]; igraph_real_t curdist = VECTOR(dists)[tto]; if (curdist < 0) { @@ -570,8 +591,8 @@ igraph_error_t igraph_get_shortest_paths_dijkstra(const igraph_t *graph, /* Reconstruct the shortest paths based on vertex and/or edge IDs */ if (vertices || edges) { for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t node = IGRAPH_VIT_GET(vit); - igraph_integer_t size, act, edge; + igraph_int_t node = IGRAPH_VIT_GET(vit); + igraph_int_t size, act, edge; igraph_vector_int_t *vvec = 0, *evec = 0; if (vertices) { vvec = igraph_vector_int_list_get_ptr(vertices, i); @@ -668,8 +689,8 @@ igraph_error_t igraph_get_shortest_paths_dijkstra(const igraph_t *graph, igraph_error_t igraph_get_shortest_path_dijkstra(const igraph_t *graph, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t from, - igraph_integer_t to, + igraph_int_t from, + igraph_int_t to, const igraph_vector_t *weights, igraph_neimode_t mode) { @@ -696,12 +717,12 @@ igraph_error_t igraph_get_shortest_path_dijkstra(const igraph_t *graph, /* We use the constant time vector_swap() instead of the linear-time vector_update() to move the result to the output parameter. */ if (edges) { - IGRAPH_CHECK(igraph_vector_int_swap(edges, igraph_vector_int_list_get_ptr(&edges2, 0))); + igraph_vector_int_swap(edges, igraph_vector_int_list_get_ptr(&edges2, 0)); igraph_vector_int_list_destroy(&edges2); IGRAPH_FINALLY_CLEAN(1); } if (vertices) { - IGRAPH_CHECK(igraph_vector_int_swap(vertices, igraph_vector_int_list_get_ptr(&vertices2, 0))); + igraph_vector_int_swap(vertices, igraph_vector_int_list_get_ptr(&vertices2, 0)); igraph_vector_int_list_destroy(&vertices2); IGRAPH_FINALLY_CLEAN(1); } @@ -777,15 +798,14 @@ igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, igraph_vector_int_list_t *vertices, igraph_vector_int_list_t *edges, igraph_vector_int_t *nrgeo, - igraph_integer_t from, igraph_vs_t to, + igraph_int_t from, igraph_vs_t to, const igraph_vector_t *weights, igraph_neimode_t mode) { - /* Implementation details: see igraph_get_shortest_paths_dijkstra, - it's basically the same. - */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + /* Implementation details: see igraph_get_shortest_paths_dijkstra(), + * it's basically the same. */ + + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vit_t vit; igraph_2wheap_t Q; igraph_lazy_inclist_t inclist; @@ -793,36 +813,32 @@ igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, igraph_vector_int_t index; igraph_vector_int_t order; igraph_vector_ptr_t parents, parents_edge; + igraph_bool_t negative_weights; unsigned char *is_target; /* uses more than two discrete values, can't be 'bool' */ - igraph_integer_t i, n, to_reach; + igraph_int_t i, n, to_reach; igraph_bool_t free_vertices = false; int cmp_result; const double eps = IGRAPH_SHORTEST_PATH_EPSILON; if (!weights) { - return igraph_get_all_shortest_paths(graph, vertices, edges, nrgeo, from, to, mode); + return igraph_i_get_all_shortest_paths_unweighted(graph, vertices, edges, nrgeo, from, to, mode); } if (from < 0 || from >= no_of_nodes) { IGRAPH_ERROR("Index of source vertex is out of range.", IGRAPH_EINVVID); } + IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights)); + if (negative_weights) { + IGRAPH_ERRORF("Edge weights must not be negative when using Dijkstra's algorithm, got %g.", + IGRAPH_EINVAL, + igraph_vector_min(weights)); + } + if (vertices == NULL && nrgeo == NULL && edges == NULL) { return IGRAPH_SUCCESS; } - if (igraph_vector_size(weights) != no_of_edges) { - IGRAPH_ERROR("Weight vector length does not match number of edges.", IGRAPH_EINVAL); - } - if (no_of_edges > 0) { - igraph_real_t min = igraph_vector_min(weights); - if (min < 0) { - IGRAPH_ERRORF("Edge weights must not be negative, got %g.", IGRAPH_EINVAL, min); - } - else if (isnan(min)) { - IGRAPH_ERROR("Weights must not contain NaN values.", IGRAPH_EINVAL); - } - } /* parents stores a vector for each vertex, listing the parent vertices * of each vertex in the traversal. Right now we do not use an @@ -896,7 +912,7 @@ igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, igraph_2wheap_push_with_index(&Q, from, 0.0); while (!igraph_2wheap_empty(&Q) && to_reach > 0) { - igraph_integer_t nlen, minnei = igraph_2wheap_max_index(&Q); + igraph_int_t nlen, minnei = igraph_2wheap_max_index(&Q); igraph_real_t mindist = -igraph_2wheap_delete_max(&Q); igraph_vector_int_t *neis; @@ -915,8 +931,8 @@ igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); nlen = igraph_vector_int_size(neis); for (i = 0; i < nlen; i++) { - igraph_integer_t edge = VECTOR(*neis)[i]; - igraph_integer_t tto = IGRAPH_OTHER(graph, edge, minnei); + igraph_int_t edge = VECTOR(*neis)[i]; + igraph_int_t tto = IGRAPH_OTHER(graph, edge, minnei); igraph_real_t altdist = mindist + VECTOR(*weights)[edge]; igraph_real_t curdist = VECTOR(dists)[tto]; igraph_vector_int_t *parent_vec, *parent_edge_vec; @@ -993,7 +1009,7 @@ igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, VECTOR(*nrgeo)[from] = 1; n = igraph_vector_int_size(&order); for (i = 1; i < n; i++) { - igraph_integer_t node, j, k; + igraph_int_t node, j, k; igraph_vector_int_t *parent_vec; node = VECTOR(order)[i]; @@ -1010,7 +1026,7 @@ igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, igraph_vector_int_t *path, *parent_vec, *parent_edge_vec; igraph_vector_t *paths_index; igraph_stack_int_t stack; - igraph_integer_t j, node; + igraph_int_t j, node; /* a shortest path from the starting vertex to vertex i can be * obtained by calculating the shortest paths from the "parents" @@ -1046,7 +1062,7 @@ igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, while (!igraph_stack_int_empty(&stack)) { /* For each parent of node i, get its parents */ - igraph_integer_t el = igraph_stack_int_pop(&stack); + igraph_int_t el = igraph_stack_int_pop(&stack); parent_vec = (igraph_vector_int_t*) VECTOR(parents)[el]; i = igraph_vector_int_size(parent_vec); @@ -1103,7 +1119,7 @@ igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, VECTOR(*paths_index)[from] = 1; for (i = 1; i < n; i++) { - igraph_integer_t m, path_count; + igraph_int_t m, path_count; igraph_vector_int_t *parent_path, *parent_path_edge; node = VECTOR(order)[i]; @@ -1136,9 +1152,9 @@ igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, for (j = 0; j < m; j++) { /* for each parent, copy the shortest paths leading to that parent * and add the current vertex in the end */ - igraph_integer_t parent_node = VECTOR(*parent_vec)[j]; - igraph_integer_t parent_edge = VECTOR(*parent_edge_vec)[j]; - igraph_integer_t parent_path_idx = VECTOR(*paths_index)[parent_node] - 1; + igraph_int_t parent_node = VECTOR(*parent_vec)[j]; + igraph_int_t parent_edge = VECTOR(*parent_edge_vec)[j]; + igraph_int_t parent_path_idx = VECTOR(*paths_index)[parent_node] - 1; /* printf(" Considering parent: %ld\n", parent_node); printf(" Paths to parent start at index %ld in vertices\n", parent_path_idx); @@ -1174,7 +1190,7 @@ igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph, n = igraph_vector_int_list_size(vertices); i = 0; while (i < n) { - igraph_integer_t tmp; + igraph_int_t tmp; path = igraph_vector_int_list_get_ptr(vertices, i); tmp = igraph_vector_int_tail(path); if (is_target[tmp] == 1) { diff --git a/src/vendor/cigraph/src/paths/distances.c b/src/vendor/cigraph/src/paths/distances.c index 3b86fe87eac..106d7f94316 100644 --- a/src/vendor/cigraph/src/paths/distances.c +++ b/src/vendor/cigraph/src/paths/distances.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -36,19 +34,18 @@ * vid_ecc will then return the id of the vertex farthest from the one in * vids. If unconn == false and not all other vertices were reachable from * the single given vertex, -1 is returned in vid_ecc. */ -static igraph_error_t igraph_i_eccentricity(const igraph_t *graph, - igraph_vector_t *res, - igraph_vs_t vids, - igraph_lazy_adjlist_t *adjlist, - igraph_integer_t *vid_ecc, - igraph_bool_t unconn) { - - igraph_integer_t no_of_nodes = igraph_vcount(graph); +static igraph_error_t igraph_i_eccentricity_unweighted( + const igraph_t *graph, igraph_vector_t *res, igraph_vs_t vids, + igraph_lazy_adjlist_t *adjlist, igraph_int_t *vid_ecc, + igraph_bool_t unconn +) { + + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_dqueue_int_t q; igraph_vit_t vit; igraph_vector_int_t counted; - igraph_integer_t i, mark = 1; - igraph_integer_t min_degree = 0; + igraph_int_t i, mark = 1; + igraph_int_t min_degree = 0; IGRAPH_DQUEUE_INT_INIT_FINALLY(&q, 100); @@ -64,8 +61,8 @@ static igraph_error_t igraph_i_eccentricity(const igraph_t *graph, !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), mark++, i++) { - igraph_integer_t source; - igraph_integer_t nodes_reached = 1; + igraph_int_t source; + igraph_int_t nodes_reached = 1; source = IGRAPH_VIT_GET(vit); IGRAPH_CHECK(igraph_dqueue_int_push(&q, source)); IGRAPH_CHECK(igraph_dqueue_int_push(&q, 0)); @@ -74,16 +71,16 @@ static igraph_error_t igraph_i_eccentricity(const igraph_t *graph, IGRAPH_ALLOW_INTERRUPTION(); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t act = igraph_dqueue_int_pop(&q); - igraph_integer_t dist = igraph_dqueue_int_pop(&q); + igraph_int_t act = igraph_dqueue_int_pop(&q); + igraph_int_t dist = igraph_dqueue_int_pop(&q); igraph_vector_int_t *neis = igraph_lazy_adjlist_get(adjlist, act); - igraph_integer_t j, n; + igraph_int_t j, n; IGRAPH_CHECK_OOM(neis, "Failed to query neighbors."); n = igraph_vector_int_size(neis); for (j = 0; j < n; j++) { - igraph_integer_t nei = VECTOR(*neis)[j]; + igraph_int_t nei = VECTOR(*neis)[j]; if (VECTOR(counted)[nei] != mark) { VECTOR(counted)[nei] = mark; nodes_reached++; @@ -122,7 +119,7 @@ static igraph_error_t igraph_i_eccentricity(const igraph_t *graph, /** * This function finds the weighted eccentricity and returns it via \p ecc. - * It's used for igraph_pseudo_diameter_dijkstra() and igraph_eccentricity_dijkstra(). + * It's used for igraph_pseudo_diameter() and igraph_eccentricity(). * \p vid_ecc returns the vertex id of the ecc with the greatest * distance from \p vid_start. If two vertices have the same greatest distance, * the one with the lowest degree is chosen. @@ -130,20 +127,17 @@ static igraph_error_t igraph_i_eccentricity(const igraph_t *graph, * wil be set to infinity, and \p vid_ecc to -1; */ static igraph_error_t igraph_i_eccentricity_dijkstra( - const igraph_t *graph, - const igraph_vector_t *weights, - igraph_real_t *ecc, - igraph_integer_t vid_start, - igraph_integer_t *vid_ecc, - igraph_bool_t unconn, - igraph_lazy_inclist_t *inclist) { - - igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_t *graph, const igraph_vector_t *weights, igraph_real_t *ecc, + igraph_int_t vid_start, igraph_int_t *vid_ecc, igraph_bool_t unconn, + igraph_lazy_inclist_t *inclist +) { + + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_2wheap_t Q; igraph_vector_t vec_dist; - igraph_integer_t i; + igraph_int_t i; igraph_real_t degree_ecc, dist; - igraph_integer_t degree_i; + igraph_int_t degree_i; igraph_vector_int_t *neis; IGRAPH_VECTOR_INIT_FINALLY(&vec_dist, no_of_nodes); @@ -155,9 +149,9 @@ static igraph_error_t igraph_i_eccentricity_dijkstra( igraph_2wheap_push_with_index(&Q, vid_start, -1.0); while (!igraph_2wheap_empty(&Q)) { - igraph_integer_t minnei = igraph_2wheap_max_index(&Q); + igraph_int_t minnei = igraph_2wheap_max_index(&Q); igraph_real_t mindist = -igraph_2wheap_deactivate_max(&Q); - igraph_integer_t nlen; + igraph_int_t nlen; VECTOR(vec_dist)[minnei] = mindist - 1.0; @@ -166,8 +160,8 @@ static igraph_error_t igraph_i_eccentricity_dijkstra( IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); nlen = igraph_vector_int_size(neis); for (i = 0; i < nlen; i++) { - igraph_integer_t edge = VECTOR(*neis)[i]; - igraph_integer_t tto = IGRAPH_OTHER(graph, edge, minnei); + igraph_int_t edge = VECTOR(*neis)[i]; + igraph_int_t tto = IGRAPH_OTHER(graph, edge, minnei); igraph_real_t altdist = mindist + VECTOR(*weights)[edge]; igraph_bool_t active = igraph_2wheap_has_active(&Q, tto); igraph_bool_t has = igraph_2wheap_has_elem(&Q, tto); @@ -239,61 +233,11 @@ static igraph_error_t igraph_i_eccentricity_dijkstra( * components. Isolated vertices have eccentricity zero. * * \param graph The input graph, it can be directed or undirected. - * \param res Pointer to an initialized vector, the result is stored - * here. - * \param vids The vertices for which the eccentricity is calculated. - * \param mode What kind of paths to consider for the calculation: - * \c IGRAPH_OUT, paths that follow edge directions; - * \c IGRAPH_IN, paths that follow the opposite directions; and - * \c IGRAPH_ALL, paths that ignore edge directions. This argument - * is ignored for undirected graphs. - * \return Error code. - * - * Time complexity: O(|S| (|V|+|E|)), where |V| is the number of - * vertices, |E| is the number of edges and |S| is the number of - * vertices for which eccentricity is calculated. - * - * \sa \ref igraph_radius(). - * - * \example examples/simple/igraph_eccentricity.c - */ - -igraph_error_t igraph_eccentricity(const igraph_t *graph, - igraph_vector_t *res, - igraph_vs_t vids, - igraph_neimode_t mode) { - igraph_lazy_adjlist_t adjlist; - - IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, mode, - IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); - IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist); - - IGRAPH_CHECK(igraph_i_eccentricity(graph, res, vids, &adjlist, - /*vid_ecc*/ NULL, /*unconn*/ true)); - igraph_lazy_adjlist_destroy(&adjlist); - IGRAPH_FINALLY_CLEAN(1); - return IGRAPH_SUCCESS; -} - -/** - * \function igraph_eccentricity_dijkstra - * \brief Eccentricity of some vertices, using weighted edges. - * - * The eccentricity of a vertex is calculated by measuring the shortest - * distance from (or to) the vertex, to (or from) all vertices in the - * graph, and taking the maximum. - * - * - * This implementation ignores vertex pairs that are in different - * components. Isolated vertices have eccentricity zero. - * - * \param graph The input graph, it can be directed or undirected. * \param weights The edge weights. All edge weights must be * non-negative for Dijkstra's algorithm to work. Additionally, no * edge weight may be NaN. If either case does not hold, an error - * is returned. If this is a null pointer, then the unweighted - * version, \ref igraph_eccentricity() is called. Edges with positive - * infinite weights are ignored. + * is returned. Use a null pointer to calculate the unweighted + * eccentricities. Edges with positive infinite weights are ignored. * \param res Pointer to an initialized vector, the result is stored * here. * \param vids The vertices for which the eccentricity is calculated. @@ -307,21 +251,31 @@ igraph_error_t igraph_eccentricity(const igraph_t *graph, * Time complexity: O(|V| |E| log|V| + |V|), where |V| is the number of * vertices, |E| the number of edges. * + * \example examples/simple/igraph_eccentricity.c */ -igraph_error_t igraph_eccentricity_dijkstra(const igraph_t *graph, - const igraph_vector_t *weights, - igraph_vector_t *res, - igraph_vs_t vids, - igraph_neimode_t mode) { +igraph_error_t igraph_eccentricity( + const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_t *res, + igraph_vs_t vids, igraph_neimode_t mode +) { igraph_lazy_inclist_t inclist; igraph_vit_t vit; - igraph_integer_t dump; + igraph_int_t dump; igraph_real_t ecc; - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); if (weights == NULL) { - return igraph_eccentricity(graph, res, vids, mode); + igraph_lazy_adjlist_t adjlist; + + IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, mode, + IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); + IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist); + + IGRAPH_CHECK(igraph_i_eccentricity_unweighted(graph, res, vids, &adjlist, + /*vid_ecc*/ NULL, /*unconn*/ true)); + igraph_lazy_adjlist_destroy(&adjlist); + IGRAPH_FINALLY_CLEAN(1); + return IGRAPH_SUCCESS; } if (igraph_vector_size(weights) != no_of_edges) { @@ -346,10 +300,11 @@ igraph_error_t igraph_eccentricity_dijkstra(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_resize(res, 0)); IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); - for (IGRAPH_VIT_RESET(vit); - !IGRAPH_VIT_END(vit); - IGRAPH_VIT_NEXT(vit)) { - IGRAPH_CHECK(igraph_i_eccentricity_dijkstra(graph, weights, &ecc, IGRAPH_VIT_GET(vit), /*vid_ecc*/ &dump, /*unconn*/ true, &inclist)); + for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) { + IGRAPH_CHECK(igraph_i_eccentricity_dijkstra( + graph, weights, &ecc, IGRAPH_VIT_GET(vit), + /*vid_ecc*/ &dump, /*unconn*/ true, &inclist + )); IGRAPH_CHECK(igraph_vector_push_back(res, ecc)); } igraph_lazy_inclist_destroy(&inclist); @@ -359,57 +314,8 @@ igraph_error_t igraph_eccentricity_dijkstra(const igraph_t *graph, /** * \function igraph_radius - * \brief Radius of a graph. - * - * The radius of a graph is the defined as the minimum eccentricity of - * its vertices, see \ref igraph_eccentricity(). - * - * \param graph The input graph, it can be directed or undirected. - * \param radius Pointer to a real variable, the result is stored - * here. - * \param mode What kind of paths to consider for the calculation: - * \c IGRAPH_OUT, paths that follow edge directions; - * \c IGRAPH_IN, paths that follow the opposite directions; and - * \c IGRAPH_ALL, paths that ignore edge directions. This argument - * is ignored for undirected graphs. - * \return Error code. - * - * Time complexity: O(|V|(|V|+|E|)), where |V| is the number of - * vertices and |E| is the number of edges. - * - * \sa \ref igraph_radius_dijkstra() for the weighted version, - * \ref igraph_diameter() for the maximum eccentricity, - * \ref igraph_eccentricity() for the eccentricities of all vertices. - * - * \example examples/simple/igraph_radius.c - */ - -igraph_error_t igraph_radius(const igraph_t *graph, igraph_real_t *radius, - igraph_neimode_t mode) { - - igraph_integer_t no_of_nodes = igraph_vcount(graph); - - if (no_of_nodes == 0) { - *radius = IGRAPH_NAN; - } else { - igraph_vector_t ecc; - IGRAPH_VECTOR_INIT_FINALLY(&ecc, igraph_vcount(graph)); - IGRAPH_CHECK(igraph_eccentricity(graph, &ecc, igraph_vss_all(), - mode)); - *radius = igraph_vector_min(&ecc); - igraph_vector_destroy(&ecc); - IGRAPH_FINALLY_CLEAN(1); - } - - return IGRAPH_SUCCESS; -} - -/** - * \function igraph_radius_dijkstra * \brief Radius of a graph, using weighted edges. * - * \experimental - * * The radius of a graph is the defined as the minimum eccentricity of * its vertices, see \ref igraph_eccentricity(). * @@ -432,27 +338,22 @@ igraph_error_t igraph_radius(const igraph_t *graph, igraph_real_t *radius, * Time complexity: O(|V| |E| log|V| + |V|), where |V| is the number of * vertices, |E| the number of edges. * - * \sa \ref igraph_radius() for the unweighted version, - * \ref igraph_diameter_dijkstra() for the maximum weighted eccentricity, - * \ref igraph_eccentricity_dijkstra() for weighted eccentricities of - * all vertices. + * \sa \ref igraph_diameter() for the maximum eccentricity, + * \ref igraph_eccentricity() for eccentricities of all vertices. */ -igraph_error_t igraph_radius_dijkstra(const igraph_t *graph, const igraph_vector_t *weights, - igraph_real_t *radius, igraph_neimode_t mode) { - - igraph_integer_t no_of_nodes = igraph_vcount(graph); - - if (weights == NULL) { - return igraph_radius(graph, radius, mode); - } +igraph_error_t igraph_radius( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_real_t *radius, igraph_neimode_t mode +) { + igraph_int_t no_of_nodes = igraph_vcount(graph); if (no_of_nodes == 0) { *radius = IGRAPH_NAN; } else { igraph_vector_t ecc; IGRAPH_VECTOR_INIT_FINALLY(&ecc, igraph_vcount(graph)); - IGRAPH_CHECK(igraph_eccentricity_dijkstra(graph, weights, &ecc, igraph_vss_all(), mode)); + IGRAPH_CHECK(igraph_eccentricity(graph, weights, &ecc, igraph_vss_all(), mode)); *radius = igraph_vector_min(&ecc); igraph_vector_destroy(&ecc); IGRAPH_FINALLY_CLEAN(1); @@ -461,60 +362,17 @@ igraph_error_t igraph_radius_dijkstra(const igraph_t *graph, const igraph_vector return IGRAPH_SUCCESS; } -/** - * \function igraph_pseudo_diameter - * \brief Approximation and lower bound of diameter. - * - * This algorithm finds a pseudo-peripheral vertex and returns its - * eccentricity. This value can be used as an approximation - * and lower bound of the diameter of a graph. - * - * - * A pseudo-peripheral vertex is a vertex v, such that for every - * vertex u which is as far away from v as possible, v is also as - * far away from u as possible. The process of finding one depends - * on where the search starts, and for a disconnected graph the - * maximum diameter found will be that of the component \p vid_start - * is in. - * - * \param graph The input graph, if it is directed, its edge directions - * are ignored. - * \param diameter Pointer to a real variable, the result is stored - * here. - * \param vid_start Id of the starting vertex. If this is negative, a - * random starting vertex is chosen. - * \param from Pointer to an integer, if not \c NULL it will be set to the - * source vertex of the diameter path. If \p unconn is \c false, and - * a disconnected graph is detected, this is set to -1. - * \param to Pointer to an integer, if not \c NULL it will be set to the - * target vertex of the diameter path. If \p unconn is \c false, and - * a disconnected graph is detected, this is set to -1. - * \param directed Boolean, whether to consider directed - * paths. Ignored for undirected graphs. - * \param unconn What to do if the graph is not connected. If - * \c true the longest geodesic within a component - * will be returned, otherwise \c IGRAPH_INFINITY is returned. - * \return Error code. - * - * Time complexity: O(|V| |E|)), where |V| is the number of - * vertices and |E| is the number of edges. - * - * \sa \ref igraph_eccentricity(), \ref igraph_diameter(). - * - */ -igraph_error_t igraph_pseudo_diameter(const igraph_t *graph, - igraph_real_t *diameter, - igraph_integer_t vid_start, - igraph_integer_t *from, - igraph_integer_t *to, - igraph_bool_t directed, - igraph_bool_t unconn) { - - igraph_integer_t no_of_nodes = igraph_vcount(graph); +static igraph_error_t igraph_i_pseudo_diameter_unweighted( + const igraph_t *graph, igraph_real_t *diameter, igraph_int_t vid_start, + igraph_int_t *from, igraph_int_t *to, + igraph_bool_t directed, igraph_bool_t unconn +) { + + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_real_t ecc_v; igraph_real_t ecc_u; - igraph_integer_t vid_ecc; - igraph_integer_t ito, ifrom; + igraph_int_t vid_ecc; + igraph_int_t ito, ifrom; igraph_bool_t inf = false; if (vid_start >= no_of_nodes) { @@ -536,9 +394,7 @@ igraph_error_t igraph_pseudo_diameter(const igraph_t *graph, } if (vid_start < 0) { - RNG_BEGIN(); vid_start = RNG_INTEGER(0, no_of_nodes - 1); - RNG_END(); } if (!igraph_is_directed(graph) || !directed) { @@ -551,8 +407,9 @@ igraph_error_t igraph_pseudo_diameter(const igraph_t *graph, ifrom = vid_start; IGRAPH_VECTOR_INIT_FINALLY(&ecc_vec, no_of_nodes); - IGRAPH_CHECK(igraph_i_eccentricity(graph, &ecc_vec, igraph_vss_1(vid_start), - &adjlist, &vid_ecc, unconn)); + IGRAPH_CHECK(igraph_i_eccentricity_unweighted( + graph, &ecc_vec, igraph_vss_1(vid_start), &adjlist, &vid_ecc, unconn + )); ecc_u = VECTOR(ecc_vec)[0]; if (!unconn && vid_ecc == -1) { @@ -563,8 +420,9 @@ igraph_error_t igraph_pseudo_diameter(const igraph_t *graph, ito = vid_ecc; - IGRAPH_CHECK(igraph_i_eccentricity(graph, &ecc_vec, igraph_vss_1(vid_ecc), - &adjlist, &vid_ecc, true)); + IGRAPH_CHECK(igraph_i_eccentricity_unweighted( + graph, &ecc_vec, igraph_vss_1(vid_ecc), &adjlist, &vid_ecc, true + )); ecc_v = VECTOR(ecc_vec)[0]; @@ -582,9 +440,9 @@ igraph_error_t igraph_pseudo_diameter(const igraph_t *graph, } else { igraph_vector_t ecc_out; igraph_vector_t ecc_in; - igraph_integer_t vid_ecc_in; - igraph_integer_t vid_ecc_out; - igraph_integer_t vid_end; + igraph_int_t vid_ecc_in; + igraph_int_t vid_ecc_out; + igraph_int_t vid_end; igraph_bool_t direction; igraph_lazy_adjlist_t adjlist_in; igraph_lazy_adjlist_t adjlist_out; @@ -599,10 +457,14 @@ igraph_error_t igraph_pseudo_diameter(const igraph_t *graph, IGRAPH_VECTOR_INIT_FINALLY(&ecc_in, igraph_vcount(graph)); IGRAPH_VECTOR_INIT_FINALLY(&ecc_out, igraph_vcount(graph)); - IGRAPH_CHECK(igraph_i_eccentricity(graph, &ecc_out, igraph_vss_1(vid_start), - &adjlist_out, &vid_ecc_out, unconn)); - IGRAPH_CHECK(igraph_i_eccentricity(graph, &ecc_in, igraph_vss_1(vid_start), - &adjlist_in, &vid_ecc_in, unconn)); + IGRAPH_CHECK(igraph_i_eccentricity_unweighted( + graph, &ecc_out, igraph_vss_1(vid_start), &adjlist_out, + &vid_ecc_out, unconn + )); + IGRAPH_CHECK(igraph_i_eccentricity_unweighted( + graph, &ecc_in, igraph_vss_1(vid_start), &adjlist_in, + &vid_ecc_in, unconn + )); /* A directed graph is strongly connected iff all vertices are reachable * from vid_start both when moving along or moving opposite the edge directions. */ @@ -625,10 +487,14 @@ igraph_error_t igraph_pseudo_diameter(const igraph_t *graph, /* TODO: In the undirected case, we break ties between vertices at the * same distance based on their degree. In te directed case, should we * use in-, out- or total degree? */ - IGRAPH_CHECK(igraph_i_eccentricity(graph, &ecc_out, igraph_vss_1(vid_ecc), - &adjlist_out, &vid_ecc_out, true)); - IGRAPH_CHECK(igraph_i_eccentricity(graph, &ecc_in, igraph_vss_1(vid_ecc), - &adjlist_in, &vid_ecc_in, true)); + IGRAPH_CHECK(igraph_i_eccentricity_unweighted( + graph, &ecc_out, igraph_vss_1(vid_ecc), &adjlist_out, + &vid_ecc_out, true + )); + IGRAPH_CHECK(igraph_i_eccentricity_unweighted( + graph, &ecc_in, igraph_vss_1(vid_ecc), &adjlist_in, + &vid_ecc_in, true + )); if (VECTOR(ecc_out)[0] > VECTOR(ecc_in)[0]) { vid_ecc = vid_ecc_out; @@ -690,76 +556,26 @@ igraph_error_t igraph_pseudo_diameter(const igraph_t *graph, } -/** - * \function igraph_pseudo_diameter_dijkstra - * \brief Approximation and lower bound of the diameter of a weighted graph. - * - * This algorithm finds a pseudo-peripheral vertex and returns its - * weighted eccentricity. This value can be used as an approximation - * and lower bound of the diameter of a graph. - * - * - * A pseudo-peripheral vertex is a vertex v, such that for every - * vertex u which is as far away from v as possible, v is also as - * far away from u as possible. The process of finding one depends - * on where the search starts, and for a disconnected graph the - * maximum diameter found will be that of the component \p vid_start - * is in. - * - * - * If the graph has no vertices, \c IGRAPH_NAN is returned. - * - * \param graph The input graph, can be directed or undirected. - * \param weights The edge weights of the graph. Can be \c NULL for an - * unweighted graph. All weights should be non-negative. Edges with - * positive infinite weights are ignored. - * \param diameter This will contain the weighted pseudo-diameter. - * \param vid_start Id of the starting vertex. If this is negative, a - * random starting vertex is chosen. - * \param from If not \c NULL this will be set to the - * source vertex of the diameter path. If the graph has no diameter path, - * it will be set to -1. - * \param to If not \c NULL this will be set to the - * target vertex of the diameter path. If the graph has no diameter path, - * it will be set to -1. - * \param directed Boolean, whether to consider directed - * paths. Ignored for undirected graphs. - * \param unconn What to do if the graph is not connected. If - * \c true the longest geodesic within a component - * will be returned, otherwise \c IGRAPH_INFINITY is - * returned. - * \return Error code. - * - * Time complexity: O(|V| |E| log|E|), |V| is the number of vertices, - * |E| is the number of edges. - * - * \sa \ref igraph_diameter_dijkstra() - */ -igraph_error_t igraph_pseudo_diameter_dijkstra(const igraph_t *graph, - const igraph_vector_t *weights, - igraph_real_t *diameter, - igraph_integer_t vid_start, - igraph_integer_t *from, - igraph_integer_t *to, - igraph_bool_t directed, - igraph_bool_t unconn) { - - - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); +static igraph_error_t igraph_i_pseudo_diameter_dijkstra( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_real_t *diameter, igraph_int_t vid_start, + igraph_int_t *from, igraph_int_t *to, + igraph_bool_t directed, igraph_bool_t unconn +) { + + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_real_t ecc_v; igraph_real_t ecc_u; - igraph_integer_t vid_ecc; - igraph_integer_t ito, ifrom; + igraph_int_t vid_ecc; + igraph_int_t ito, ifrom; igraph_bool_t inf = false; if (vid_start >= no_of_nodes) { IGRAPH_ERROR("Starting vertex ID for pseudo-diameter out of range.", IGRAPH_EINVAL); } - if (!weights) { - return igraph_pseudo_diameter(graph, diameter, vid_start, from, to, directed, unconn); - } + IGRAPH_ASSERT(weights != 0); if (igraph_vector_size(weights) != no_of_edges) { IGRAPH_ERRORF("Weight vector length (%" IGRAPH_PRId ") does not match number of edges (%" IGRAPH_PRId ").", @@ -791,9 +607,7 @@ igraph_error_t igraph_pseudo_diameter_dijkstra(const igraph_t *graph, } if (vid_start < 0) { - RNG_BEGIN(); vid_start = RNG_INTEGER(0, no_of_nodes - 1); - RNG_END(); } if (!igraph_is_directed(graph) || !directed) { @@ -827,9 +641,9 @@ igraph_error_t igraph_pseudo_diameter_dijkstra(const igraph_t *graph, } else { igraph_real_t ecc_out; igraph_real_t ecc_in; - igraph_integer_t vid_ecc_in; - igraph_integer_t vid_ecc_out; - igraph_integer_t vid_end; + igraph_int_t vid_ecc_in; + igraph_int_t vid_ecc_out; + igraph_int_t vid_end; igraph_bool_t direction; igraph_lazy_inclist_t inclist_out; igraph_lazy_inclist_t inclist_in; @@ -924,81 +738,84 @@ igraph_error_t igraph_pseudo_diameter_dijkstra(const igraph_t *graph, } /** - * \function igraph_graph_center - * \brief Central vertices of a graph. + * \function igraph_pseudo_diameter + * \brief Approximation and lower bound of the diameter of a graph. * - * The central vertices of a graph are calculated by finding the vertices - * with the minimum eccentricity. This concept is typically applied to - * (strongly) connected graphs. In disconnected graphs, the smallest - * eccentricity is taken across all components. + * This algorithm finds a pseudo-peripheral vertex and returns its + * eccentricity. This value can be used as an approximation + * and lower bound of the diameter of a graph. * - * \param graph The input graph, it can be directed or undirected. - * \param res Pointer to an initialized vector, the result is stored - * here. - * \param mode What kind of paths to consider for the calculation: - * \c IGRAPH_OUT, paths that follow edge directions; - * \c IGRAPH_IN, paths that follow the opposite directions; and - * \c IGRAPH_ALL, paths that ignore edge directions. This argument - * is ignored for undirected graphs. - * \return Error code. + * + * A pseudo-peripheral vertex is a vertex v, such that for every + * vertex u which is as far away from v as possible, v is also as + * far away from u as possible. The process of finding one depends + * on where the search starts, and for a disconnected graph the + * maximum diameter found will be that of the component \p vid_start + * is in. * - * Time complexity: O(|V| (|V|+|E|)), where |V| is the number of - * vertices and |E| is the number of edges. + * + * If the graph has no vertices, \c IGRAPH_NAN is returned. + * + * \param graph The input graph, can be directed or undirected. + * \param weights The edge weights of the graph. Can be \c NULL for an + * unweighted graph. All weights should be non-negative. Edges with + * positive infinite weights are ignored. + * \param diameter This will contain the pseudo-diameter. + * \param vid_start Id of the starting vertex. If this is negative, a + * random starting vertex is chosen. + * \param from If not \c NULL this will be set to the + * source vertex of the diameter path. If the graph has no diameter path, + * it will be set to -1. + * \param to If not \c NULL this will be set to the + * target vertex of the diameter path. If the graph has no diameter path, + * it will be set to -1. + * \param directed Boolean, whether to consider directed + * paths. Ignored for undirected graphs. + * \param unconn What to do if the graph is not connected. If + * \c true the longest geodesic within a component + * will be returned, otherwise \c IGRAPH_INFINITY is + * returned. + * \return Error code. * - * \sa \ref igraph_graph_center_dijkstra(), - * \ref igraph_eccentricity(), \ref igraph_radius() + * Time complexity: O(|V| |E| log|E|), |V| is the number of vertices, + * |E| is the number of edges. * + * \sa \ref igraph_diameter() */ -igraph_error_t igraph_graph_center( - const igraph_t *graph, igraph_vector_int_t *res, igraph_neimode_t mode +igraph_error_t igraph_pseudo_diameter( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_real_t *diameter, igraph_int_t vid_start, + igraph_int_t *from, igraph_int_t *to, + igraph_bool_t directed, igraph_bool_t unconn ) { - - igraph_vector_t ecc; - - igraph_vector_int_clear(res); - if (igraph_vcount(graph) == 0) { - return IGRAPH_SUCCESS; - } - - IGRAPH_VECTOR_INIT_FINALLY(&ecc, 0); - IGRAPH_CHECK(igraph_eccentricity(graph, &ecc, igraph_vss_all(), mode)); - - /* igraph_eccentricity() does not return infinity or NaN, and the null graph - * case was handled above, therefore calling vector_min() is safe. */ - igraph_real_t min_eccentricity = igraph_vector_min(&ecc); - igraph_integer_t n = igraph_vector_size(&ecc); - for (igraph_integer_t i = 0; i < n; i++) { - if (VECTOR(ecc)[i] == min_eccentricity) { - IGRAPH_CHECK(igraph_vector_int_push_back(res, i)); - } + if (weights) { + return igraph_i_pseudo_diameter_dijkstra( + graph, weights, diameter, vid_start, from, to, directed, unconn + ); + } else { + return igraph_i_pseudo_diameter_unweighted( + graph, diameter, vid_start, from, to, directed, unconn + ); } - - igraph_vector_destroy(&ecc); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; } /** - * \function igraph_graph_center_dijkstra - * \brief Central vertices of a graph, using weighted edges. + * \function igraph_graph_center + * \brief Central vertices of a graph. * * \experimental * * The central vertices of a graph are calculated by finding the vertices - * with the minimum eccentricity. This function takes edge weights into - * account and uses Dijkstra's algorithm for the shortest path calculation. - * The concept of the graph center is typically applied to - * (strongly) connected graphs. In disconnected graphs, the smallest + * with the minimum eccentricity. The concept of the graph center is typically + * applied to (strongly) connected graphs. In disconnected graphs, the smallest * eccentricity is taken across all components. * * \param graph The input graph, it can be directed or undirected. * \param weights The edge weights. All edge weights must be * non-negative for Dijkstra's algorithm to work. Additionally, no * edge weight may be NaN. If either case does not hold, an error - * is returned. If this is a null pointer, then the unweighted - * version, \ref igraph_graph_center() is called. Edges with positive - * infinite weights are ignored. + * is returned. Pass a null pointer here if all edges have equal weight. + * Edges with positive infinite weights are ignored. * \param res Pointer to an initialized vector, the result is stored * here. * \param mode What kind of paths to consider for the calculation: @@ -1011,34 +828,30 @@ igraph_error_t igraph_graph_center( * Time complexity: O(|V| |E| log|V| + |V|), where |V| is the number of * vertices, |E| the number of edges. * - * \sa \ref igraph_graph_center(), - * \ref igraph_eccentricity_dijkstra(), \ref igraph_radius_dijkstra() + * \sa \ref igraph_graph_center(), \ref igraph_eccentricity(), \ref igraph_radius() * */ -igraph_error_t igraph_graph_center_dijkstra( - const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_int_t *res, igraph_neimode_t mode +igraph_error_t igraph_graph_center( + const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_int_t *res, + igraph_neimode_t mode ) { igraph_vector_t ecc; const igraph_real_t eps = IGRAPH_SHORTEST_PATH_EPSILON; - if (weights == NULL) { - return igraph_graph_center(graph, res, mode); - } - igraph_vector_int_clear(res); if (igraph_vcount(graph) == 0) { return IGRAPH_SUCCESS; } IGRAPH_VECTOR_INIT_FINALLY(&ecc, 0); - IGRAPH_CHECK(igraph_eccentricity_dijkstra(graph, weights, &ecc, igraph_vss_all(), mode)); + IGRAPH_CHECK(igraph_eccentricity(graph, weights, &ecc, igraph_vss_all(), mode)); - /* igraph_eccentricity_dijkstra() does not return infinity or NaN, and the null graph + /* igraph_eccentricity() does not return infinity or NaN, and the null graph * case was handled above, therefore calling vector_min() is safe. */ igraph_real_t min_eccentricity = igraph_vector_min(&ecc); - igraph_integer_t n = igraph_vector_size(&ecc); - for (igraph_integer_t i = 0; i < n; i++) { + igraph_int_t n = igraph_vector_size(&ecc); + for (igraph_int_t i = 0; i < n; i++) { if (igraph_cmp_epsilon(VECTOR(ecc)[i], min_eccentricity, eps) == 0) { IGRAPH_CHECK(igraph_vector_int_push_back(res, i)); } diff --git a/src/vendor/cigraph/src/paths/eulerian.c b/src/vendor/cigraph/src/paths/eulerian.c index 11cf63fd762..77acd2be61c 100644 --- a/src/vendor/cigraph/src/paths/eulerian.c +++ b/src/vendor/cigraph/src/paths/eulerian.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -42,18 +40,18 @@ has_path is set to 1 if a path exists, 0 otherwise has_cycle is set to 1 if a cycle exists, 0 otherwise */ static igraph_error_t igraph_i_is_eulerian_undirected( - const igraph_t *graph, igraph_bool_t *has_path, igraph_bool_t *has_cycle, igraph_integer_t *start_of_path) { - igraph_integer_t odd; + const igraph_t *graph, igraph_bool_t *has_path, igraph_bool_t *has_cycle, igraph_int_t *start_of_path) { + igraph_int_t odd; igraph_vector_int_t degree; igraph_vector_int_t csize; /* boolean vector to mark singletons: */ igraph_vector_int_t nonsingleton; - igraph_integer_t i, n, vsize; - igraph_integer_t cluster_count; + igraph_int_t i, n, vsize; + igraph_int_t cluster_count; /* number of self-looping singletons: */ - igraph_integer_t es; + igraph_int_t es; /* will be set to 1 if there are non-isolated vertices, otherwise 0: */ - igraph_integer_t ens; + igraph_int_t ens; n = igraph_vcount(graph); @@ -105,7 +103,7 @@ static igraph_error_t igraph_i_is_eulerian_undirected( es = 0; ens = 0; for (i = 0; i < n; i++) { - igraph_integer_t deg = VECTOR(degree)[i]; + igraph_int_t deg = VECTOR(degree)[i]; /* Eulerian is about edges, so skip free vertices */ if (deg == 0) continue; @@ -165,18 +163,18 @@ static igraph_error_t igraph_i_is_eulerian_undirected( static igraph_error_t igraph_i_is_eulerian_directed( - const igraph_t *graph, igraph_bool_t *has_path, igraph_bool_t *has_cycle, igraph_integer_t *start_of_path) { - igraph_integer_t incoming_excess, outgoing_excess, n; - igraph_integer_t i, vsize; - igraph_integer_t cluster_count; + const igraph_t *graph, igraph_bool_t *has_path, igraph_bool_t *has_cycle, igraph_int_t *start_of_path) { + igraph_int_t incoming_excess, outgoing_excess, n; + igraph_int_t i, vsize; + igraph_int_t cluster_count; igraph_vector_int_t out_degree, in_degree; igraph_vector_int_t csize; /* boolean vector to mark singletons: */ igraph_vector_int_t nonsingleton; /* number of self-looping singletons: */ - igraph_integer_t es; + igraph_int_t es; /* will be set to 1 if there are non-isolated vertices, otherwise 0: */ - igraph_integer_t ens; + igraph_int_t ens; n = igraph_vcount(graph); @@ -233,8 +231,8 @@ static igraph_error_t igraph_i_is_eulerian_directed( ens = 0; *start_of_path = -1; for (i = 0; i < n; i++) { - igraph_integer_t degin = VECTOR(in_degree)[i]; - igraph_integer_t degout = VECTOR(out_degree)[i]; + igraph_int_t degin = VECTOR(in_degree)[i]; + igraph_int_t degout = VECTOR(out_degree)[i]; /* Eulerian is about edges, so skip free vertices */ if (degin + degout == 0) continue; @@ -333,7 +331,7 @@ static igraph_error_t igraph_i_is_eulerian_directed( */ igraph_error_t igraph_is_eulerian(const igraph_t *graph, igraph_bool_t *has_path, igraph_bool_t *has_cycle) { - igraph_integer_t start_of_path = 0; + igraph_int_t start_of_path = 0; if (igraph_is_directed(graph)) { IGRAPH_CHECK(igraph_i_is_eulerian_directed(graph, has_path, has_cycle, &start_of_path)); @@ -346,10 +344,10 @@ igraph_error_t igraph_is_eulerian(const igraph_t *graph, igraph_bool_t *has_path static igraph_error_t igraph_i_eulerian_path_undirected( const igraph_t *graph, igraph_vector_int_t *edge_res, igraph_vector_int_t *vertex_res, - igraph_integer_t start_of_path) { + igraph_int_t start_of_path) { - igraph_integer_t curr; - igraph_integer_t n, m; + igraph_int_t curr; + igraph_int_t n, m; igraph_inclist_t il; igraph_stack_int_t path, tracker, edge_tracker, edge_path; igraph_bitset_t visited_list; @@ -390,8 +388,8 @@ static igraph_error_t igraph_i_eulerian_path_undirected( if (VECTOR(degree)[curr] != 0) { igraph_vector_int_t *incedges; - igraph_integer_t nc, edge = -1; - igraph_integer_t j, next; + igraph_int_t nc, edge = -1; + igraph_int_t j, next; IGRAPH_CHECK(igraph_stack_int_push(&tracker, curr)); incedges = igraph_inclist_get(&il, curr); @@ -416,7 +414,7 @@ static igraph_error_t igraph_i_eulerian_path_undirected( curr = next; } else { /* back track to find remaining circuit */ - igraph_integer_t curr_e; + igraph_int_t curr_e; IGRAPH_CHECK(igraph_stack_int_push(&path, curr)); curr = igraph_stack_int_pop(&tracker); if (!igraph_stack_int_empty(&edge_tracker)) { @@ -454,10 +452,10 @@ static igraph_error_t igraph_i_eulerian_path_undirected( /* solution adapted from https://www.geeksforgeeks.org/hierholzers-algorithm-directed-graph/ */ static igraph_error_t igraph_i_eulerian_path_directed( const igraph_t *graph, igraph_vector_int_t *edge_res, igraph_vector_int_t *vertex_res, - igraph_integer_t start_of_path) { + igraph_int_t start_of_path) { - igraph_integer_t curr; - igraph_integer_t n, m; + igraph_int_t curr; + igraph_int_t n, m; igraph_inclist_t il; igraph_stack_int_t path, tracker, edge_tracker, edge_path; igraph_bitset_t visited_list; @@ -498,8 +496,8 @@ static igraph_error_t igraph_i_eulerian_path_directed( if (VECTOR(remaining_out_edges)[curr] != 0) { igraph_vector_int_t *incedges; - igraph_integer_t nc, edge = -1; - igraph_integer_t j, next; + igraph_int_t nc, edge = -1; + igraph_int_t j, next; IGRAPH_CHECK(igraph_stack_int_push(&tracker, curr)); incedges = igraph_inclist_get(&il, curr); @@ -523,7 +521,7 @@ static igraph_error_t igraph_i_eulerian_path_directed( curr = next; } else { /* back track to find remaining circuit */ - igraph_integer_t curr_e; + igraph_int_t curr_e; IGRAPH_CHECK(igraph_stack_int_push(&path, curr)); curr = igraph_stack_int_pop(&tracker); if (!igraph_stack_int_empty(&edge_tracker)) { @@ -598,7 +596,7 @@ igraph_error_t igraph_eulerian_cycle( igraph_bool_t has_cycle; igraph_bool_t has_path; - igraph_integer_t start_of_path = 0; + igraph_int_t start_of_path = 0; if (igraph_is_directed(graph)) { IGRAPH_CHECK(igraph_i_is_eulerian_directed(graph, &has_path, &has_cycle, &start_of_path)); @@ -660,7 +658,7 @@ igraph_error_t igraph_eulerian_path( igraph_bool_t has_cycle; igraph_bool_t has_path; - igraph_integer_t start_of_path = 0; + igraph_int_t start_of_path = 0; if (igraph_is_directed(graph)) { IGRAPH_CHECK(igraph_i_is_eulerian_directed(graph, &has_path, &has_cycle, &start_of_path)); diff --git a/src/vendor/cigraph/src/paths/floyd_warshall.c b/src/vendor/cigraph/src/paths/floyd_warshall.c index 9fe0083d3d0..5cb7b7341d6 100644 --- a/src/vendor/cigraph/src/paths/floyd_warshall.c +++ b/src/vendor/cigraph/src/paths/floyd_warshall.c @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2022-2023 The igraph development team + igraph library. + Copyright (C) 2022-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,23 +22,24 @@ #include "core/interruption.h" #include "internal/utils.h" +#include "paths/paths_internal.h" static igraph_error_t distances_floyd_warshall_original(igraph_matrix_t *res) { - igraph_integer_t no_of_nodes = igraph_matrix_nrow(res); + igraph_int_t no_of_nodes = igraph_matrix_nrow(res); - for (igraph_integer_t k = 0; k < no_of_nodes; k++) { + for (igraph_int_t k = 0; k < no_of_nodes; k++) { IGRAPH_ALLOW_INTERRUPTION(); /* Iteration order matters for performance! * First j, then i, because matrices are stored as column-major. */ - for (igraph_integer_t j = 0; j < no_of_nodes; j++) { + for (igraph_int_t j = 0; j < no_of_nodes; j++) { igraph_real_t dkj = MATRIX(*res, k, j); if (dkj == IGRAPH_INFINITY) { continue; } - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { igraph_real_t di = MATRIX(*res, i, k) + dkj; igraph_real_t dd = MATRIX(*res, i, j); if (di < dd) { @@ -64,7 +65,7 @@ static igraph_error_t distances_floyd_warshall_tree(igraph_matrix_t *res) { * This makes it easier to iterate through matrices in column-major order, * i.e. storage order, thus increasing performance. */ - igraph_integer_t no_of_nodes = igraph_matrix_nrow(res); + igraph_int_t no_of_nodes = igraph_matrix_nrow(res); /* successors[v][u] is the second vertex on the shortest path from v to u, i.e. the parent of v in the IN_u tree. */ @@ -99,28 +100,28 @@ static igraph_error_t distances_floyd_warshall_tree(igraph_matrix_t *res) { igraph_stack_int_t stack; IGRAPH_STACK_INT_INIT_FINALLY(&stack, no_of_nodes); - for (igraph_integer_t u = 0; u < no_of_nodes; u++) { - for (igraph_integer_t v = 0; v < no_of_nodes; v++) { + for (igraph_int_t u = 0; u < no_of_nodes; u++) { + for (igraph_int_t v = 0; v < no_of_nodes; v++) { MATRIX(successors, v, u) = u; } } - for (igraph_integer_t k = 0; k < no_of_nodes; k++) { + for (igraph_int_t k = 0; k < no_of_nodes; k++) { IGRAPH_ALLOW_INTERRUPTION(); /* Count the children of each node in the shortest path tree, assuming that at this point all elements of no_of_children[] are zeros. */ - for (igraph_integer_t v = 0; v < no_of_nodes; v++) { + for (igraph_int_t v = 0; v < no_of_nodes; v++) { if (v == k) continue; - igraph_integer_t parent = MATRIX(successors, v, k); + igraph_int_t parent = MATRIX(successors, v, k); VECTOR(no_of_children)[parent]++; } /* Note: we do not use igraph_vector_int_cumsum() here as that function produces an output vector of the same length as the input vector. Here we need an output one longer, with a 0 being prepended to what vector_cumsum() would produce. */ - igraph_integer_t cumsum = 0; - for (igraph_integer_t v = 0; v < no_of_nodes; v++) { + igraph_int_t cumsum = 0; + for (igraph_int_t v = 0; v < no_of_nodes; v++) { VECTOR(children_start)[v] = cumsum; cumsum += VECTOR(no_of_children)[v]; } @@ -131,25 +132,25 @@ static igraph_error_t distances_floyd_warshall_tree(igraph_matrix_t *res) { vector as re-used as an index of where to insert child node indices. At the end of the calculation, all elements of no_of_children[] will be zeros, making this vector ready for the next iteration of the outer loop. */ - for (igraph_integer_t v = 0; v < no_of_nodes; v++) { + for (igraph_int_t v = 0; v < no_of_nodes; v++) { if (v == k) continue; - igraph_integer_t parent = MATRIX(successors, v, k); + igraph_int_t parent = MATRIX(successors, v, k); VECTOR(no_of_children)[parent]--; VECTOR(children)[ VECTOR(children_start)[parent] + VECTOR(no_of_children)[parent] ] = v; } /* constructing dfs-traversal and dfs-skip arrays for the IN_k tree */ IGRAPH_CHECK(igraph_stack_int_push(&stack, k)); - igraph_integer_t counter = 0; + igraph_int_t counter = 0; while (!igraph_stack_int_empty(&stack)) { - igraph_integer_t parent = igraph_stack_int_pop(&stack); + igraph_int_t parent = igraph_stack_int_pop(&stack); if (parent >= 0) { VECTOR(dfs_traversal)[counter] = parent; counter++; /* a negative marker -parent - 1 that is popped right after all the descendants of the parent were processed */ IGRAPH_CHECK(igraph_stack_int_push(&stack, -parent - 1)); - for (igraph_integer_t l = VECTOR(children_start)[parent]; l < VECTOR(children_start)[parent + 1]; l++) { + for (igraph_int_t l = VECTOR(children_start)[parent]; l < VECTOR(children_start)[parent + 1]; l++) { IGRAPH_CHECK(igraph_stack_int_push(&stack, VECTOR(children)[l])); } } else { @@ -158,14 +159,14 @@ static igraph_error_t distances_floyd_warshall_tree(igraph_matrix_t *res) { } /* main inner loop */ - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { igraph_real_t dki = MATRIX(*res, k, i); if (dki == IGRAPH_INFINITY || i == k) { continue; } - igraph_integer_t counter = 1; + igraph_int_t counter = 1; while (counter < no_of_nodes) { - igraph_integer_t j = VECTOR(dfs_traversal)[counter]; + igraph_int_t j = VECTOR(dfs_traversal)[counter]; igraph_real_t di = MATRIX(*res, j, k) + dki; igraph_real_t dd = MATRIX(*res, j, i); if (di < dd) { @@ -199,8 +200,6 @@ static igraph_error_t distances_floyd_warshall_tree(igraph_matrix_t *res) { * \function igraph_distances_floyd_warshall * \brief Weighted all-pairs shortest path lengths with the Floyd-Warshall algorithm. * - * \experimental - * * The Floyd-Warshall algorithm computes weighted shortest path lengths between * all pairs of vertices at the same time. It is useful with very dense weighted graphs, * as its running time is primarily determined by the vertex count, and is not sensitive @@ -274,13 +273,20 @@ igraph_error_t igraph_distances_floyd_warshall( const igraph_vector_t *weights, igraph_neimode_t mode, const igraph_floyd_warshall_algorithm_t method) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_bool_t in = false, out = false; + igraph_bool_t negative_weights; + IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights)); + return igraph_i_distances_floyd_warshall(graph, res, from, to, weights, mode, method); +} - if (weights && igraph_vector_size(weights) != no_of_edges) { - IGRAPH_ERROR("Invalid weight vector length.", IGRAPH_EINVAL); - } +igraph_error_t igraph_i_distances_floyd_warshall( + const igraph_t *graph, igraph_matrix_t *res, + igraph_vs_t from, igraph_vs_t to, + const igraph_vector_t *weights, igraph_neimode_t mode, + const igraph_floyd_warshall_algorithm_t method) { + + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_bool_t in = false, out = false; if (! igraph_is_directed(graph)) { mode = IGRAPH_ALL; @@ -300,20 +306,16 @@ igraph_error_t igraph_distances_floyd_warshall( IGRAPH_ERROR("Invalid mode for Floyd-Warshall shortest path calculation.", IGRAPH_EINVMODE); } - if (weights && igraph_vector_is_any_nan(weights)) { - IGRAPH_ERROR("Weight vector must not contain NaN values.", IGRAPH_EINVAL); - } - IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, no_of_nodes)); igraph_matrix_fill(res, IGRAPH_INFINITY); - for (igraph_integer_t v = 0; v < no_of_nodes; v++) { + for (igraph_int_t v = 0; v < no_of_nodes; v++) { MATRIX(*res, v, v) = 0; } - for (igraph_integer_t e = 0; e < no_of_edges; e++) { - igraph_integer_t from = IGRAPH_FROM(graph, e); - igraph_integer_t to = IGRAPH_TO(graph, e); + for (igraph_int_t e = 0; e < no_of_edges; e++) { + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); igraph_real_t w = weights ? VECTOR(*weights)[e] : 1; if (w < 0) { diff --git a/src/vendor/cigraph/src/paths/histogram.c b/src/vendor/cigraph/src/paths/histogram.c index d9bd65b5d50..02bd706c4f9 100644 --- a/src/vendor/cigraph/src/paths/histogram.c +++ b/src/vendor/cigraph/src/paths/histogram.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2005-2024 The igraph development team This program is free software; you can redistribute it and/or modify @@ -54,14 +54,14 @@ igraph_error_t igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *res, igraph_real_t *unconnected, igraph_bool_t directed) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t already_added; - igraph_integer_t nodes_reached; + igraph_int_t nodes_reached; igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; igraph_vector_int_t *neis; igraph_adjlist_t allneis; igraph_real_t unconn = 0; - igraph_integer_t ressize; + igraph_int_t ressize; if (! igraph_is_directed(graph)) { directed = false; @@ -78,7 +78,7 @@ igraph_error_t igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *r igraph_vector_clear(res); ressize = 0; - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { nodes_reached = 1; /* itself */ IGRAPH_CHECK(igraph_dqueue_int_push(&q, i)); IGRAPH_CHECK(igraph_dqueue_int_push(&q, 0)); @@ -89,13 +89,13 @@ igraph_error_t igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *r IGRAPH_ALLOW_INTERRUPTION(); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); neis = igraph_adjlist_get(&allneis, actnode); - const igraph_integer_t n = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t neighbor = VECTOR(*neis)[j]; + const igraph_int_t n = igraph_vector_int_size(neis); + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t neighbor = VECTOR(*neis)[j]; if (VECTOR(already_added)[neighbor] == i + 1) { continue; } @@ -122,7 +122,7 @@ igraph_error_t igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *r /* count every pair only once for an undirected graph */ if (!directed) { - for (igraph_integer_t i = 0; i < ressize; i++) { + for (igraph_int_t i = 0; i < ressize; i++) { VECTOR(*res)[i] /= 2; } unconn /= 2; diff --git a/src/vendor/cigraph/src/paths/johnson.c b/src/vendor/cigraph/src/paths/johnson.c index fdd09ffc8a0..75e614f3fe2 100644 --- a/src/vendor/cigraph/src/paths/johnson.c +++ b/src/vendor/cigraph/src/paths/johnson.c @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. - Copyright (C) 2005-2021 The igraph development team + igraph library. + Copyright (C) 2005-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_paths.h" @@ -27,6 +22,9 @@ #include "igraph_interface.h" #include "math/safe_intop.h" +#include "paths/paths_internal.h" + + /** * \function igraph_distances_johnson * \brief Weighted shortest path lengths between vertices, using Johnson's algorithm. @@ -66,7 +64,12 @@ * vertex twice or more. * \param weights Optional edge weights. If it is a null-pointer, then * the unweighted breadth-first search based \ref igraph_distances() will - * be called. Edges with positive infinite weights are ignored. + * be called. Edges with positive infinite weights are ignored. + * \param mode For directed graphs; whether to follow paths along edge + * directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or + * ignore edge directions completely (\c IGRAPH_ALL). It is ignored + * for undirected graphs. \c IGRAPH_ALL should not be used with + * negative weights. * \return Error code. * * Time complexity: O(s|V|log|V|+|V||E|), |V| and |E| are the number @@ -77,53 +80,50 @@ * edge weights, \ref igraph_distances_bellman_ford() if you only * need to calculate shortest paths from a couple of sources. */ -igraph_error_t igraph_distances_johnson(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights) { - - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); +igraph_error_t igraph_distances_johnson( + const igraph_t *graph, + igraph_matrix_t *res, + igraph_vs_t from, igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode) { + + igraph_bool_t negative_weights; + IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights)); + if (!negative_weights) { + /* If no negative weights, then we can run Dijkstra's algorithm directly, without + * needing to go through Johnson's procedure to eliminate negative weights. */ + return igraph_i_distances_dijkstra_cutoff(graph, res, from, to, weights, mode, -1); + } else { + return igraph_i_distances_johnson(graph, res, from, to, weights, mode); + } +} + +igraph_error_t igraph_i_distances_johnson( + const igraph_t *graph, + igraph_matrix_t *res, + igraph_vs_t from, igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode) { + + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_t newgraph; igraph_vector_int_t edges; igraph_vector_t newweights; igraph_matrix_t bfres; - igraph_integer_t i, ptr; - igraph_integer_t nr, nc; + igraph_int_t i, ptr; + igraph_int_t nr, nc; igraph_vit_t fromvit; - igraph_integer_t no_edges_reserved; - - /* If no weights, then we can just run the unweighted version */ - if (!weights) { - return igraph_distances(graph, res, from, to, IGRAPH_OUT); - } - - if (igraph_vector_size(weights) != no_of_edges) { - IGRAPH_ERRORF("Weight vector length (%" IGRAPH_PRId ") does not match number of edges (%" IGRAPH_PRId ").", - IGRAPH_EINVAL, - igraph_vector_size(weights), no_of_edges); - } - - /* If no edges, then we can just run the unweighted version */ - if (no_of_edges == 0) { - return igraph_distances(graph, res, from, to, IGRAPH_OUT); - } + igraph_int_t no_edges_reserved; - /* If no negative weights, then we can run Dijkstra's algorithm */ - { - igraph_real_t min_weight = igraph_vector_min(weights); - if (isnan(min_weight)) { - IGRAPH_ERROR("Weight vector must not contain NaN values.", IGRAPH_EINVAL); - } - if (min_weight >= 0) { - return igraph_distances_dijkstra(graph, res, from, to, weights, IGRAPH_OUT); - } + /* If no weights or no edges, then we can just run the unweighted version */ + if (!weights || no_of_edges == 0) { + return igraph_i_distances_unweighted_cutoff(graph, res, from, to, mode, -1); } - if (!igraph_is_directed(graph)) { - IGRAPH_ERROR("Johnson's shortest path: undirected graph and negative weight.", - IGRAPH_EINVAL); + if (!igraph_is_directed(graph) || mode == IGRAPH_ALL) { + IGRAPH_ERROR("Undirected graph with negative weight.", + IGRAPH_ENEGCYCLE); } /* ------------------------------------------------------------ */ @@ -142,9 +142,16 @@ igraph_error_t igraph_distances_johnson(const igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_edges_reserved); igraph_get_edgelist(graph, &edges, /*bycol=*/ 0); /* reserved */ igraph_vector_int_resize(&edges, no_edges_reserved); /* reserved */ - for (i = 0, ptr = no_of_edges * 2; i < no_of_nodes; i++) { - VECTOR(edges)[ptr++] = no_of_nodes; - VECTOR(edges)[ptr++] = i; + if (mode == IGRAPH_OUT) { + for (i = 0, ptr = no_of_edges * 2; i < no_of_nodes; i++) { + VECTOR(edges)[ptr++] = no_of_nodes; + VECTOR(edges)[ptr++] = i; + } + } else { + for (i = 0, ptr = no_of_edges * 2; i < no_of_nodes; i++) { + VECTOR(edges)[ptr++] = i; + VECTOR(edges)[ptr++] = no_of_nodes; + } } IGRAPH_CHECK(igraph_add_edges(&newgraph, &edges, 0)); igraph_vector_int_destroy(&edges); @@ -160,9 +167,10 @@ igraph_error_t igraph_distances_johnson(const igraph_t *graph, /* Run Bellman-Ford algorithm on the new graph, starting from the new vertex. */ - IGRAPH_CHECK(igraph_distances_bellman_ford(&newgraph, &bfres, - igraph_vss_1(no_of_nodes), - igraph_vss_all(), &newweights, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_i_distances_bellman_ford( + &newgraph, &bfres, + igraph_vss_1(no_of_nodes), igraph_vss_all(), + &newweights, mode)); igraph_destroy(&newgraph); IGRAPH_FINALLY_CLEAN(1); @@ -173,9 +181,13 @@ igraph_error_t igraph_distances_johnson(const igraph_t *graph, igraph_vector_resize(&newweights, no_of_edges); /* reserved */ for (i = 0; i < no_of_edges; i++) { - igraph_integer_t ffrom = IGRAPH_FROM(graph, i); - igraph_integer_t tto = IGRAPH_TO(graph, i); - VECTOR(newweights)[i] += MATRIX(bfres, 0, ffrom) - MATRIX(bfres, 0, tto); + igraph_int_t ffrom = IGRAPH_FROM(graph, i); + igraph_int_t tto = IGRAPH_TO(graph, i); + if (mode == IGRAPH_OUT) { + VECTOR(newweights)[i] += MATRIX(bfres, 0, ffrom) - MATRIX(bfres, 0, tto); + } else { + VECTOR(newweights)[i] += MATRIX(bfres, 0, tto) - MATRIX(bfres, 0, ffrom); + } /* If a weight becomes slightly negative due to roundoff errors, snap it to exact zero. */ @@ -183,9 +195,11 @@ igraph_error_t igraph_distances_johnson(const igraph_t *graph, } /* Run Dijkstra's algorithm on the new weights */ - IGRAPH_CHECK(igraph_distances_dijkstra(graph, res, from, - to, &newweights, - IGRAPH_OUT)); + IGRAPH_CHECK(igraph_i_distances_dijkstra_cutoff( + graph, res, + from, to, + &newweights, + mode, -1)); igraph_vector_destroy(&newweights); IGRAPH_FINALLY_CLEAN(1); @@ -198,22 +212,34 @@ igraph_error_t igraph_distances_johnson(const igraph_t *graph, IGRAPH_FINALLY(igraph_vit_destroy, &fromvit); for (i = 0; i < nr; i++, IGRAPH_VIT_NEXT(fromvit)) { - igraph_integer_t v1 = IGRAPH_VIT_GET(fromvit); + igraph_int_t v1 = IGRAPH_VIT_GET(fromvit); if (igraph_vs_is_all(&to)) { - igraph_integer_t v2; + igraph_int_t v2; for (v2 = 0; v2 < nc; v2++) { - igraph_real_t sub = MATRIX(bfres, 0, v1) - MATRIX(bfres, 0, v2); - MATRIX(*res, i, v2) -= sub; + igraph_real_t sub; + if (mode == IGRAPH_OUT) { + sub = MATRIX(bfres, 0, v1) - MATRIX(bfres, 0, v2); + MATRIX(*res, i, v2) -= sub; + } else { + sub = MATRIX(bfres, 0, v2) - MATRIX(bfres, 0, v1); + MATRIX(*res, v2, i) -= sub; + } } } else { - igraph_integer_t j; + igraph_int_t j; igraph_vit_t tovit; IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit)); IGRAPH_FINALLY(igraph_vit_destroy, &tovit); for (j = 0, IGRAPH_VIT_RESET(tovit); j < nc; j++, IGRAPH_VIT_NEXT(tovit)) { - igraph_integer_t v2 = IGRAPH_VIT_GET(tovit); - igraph_real_t sub = MATRIX(bfres, 0, v1) - MATRIX(bfres, 0, v2); - MATRIX(*res, i, j) -= sub; + igraph_real_t sub; + igraph_int_t v2 = IGRAPH_VIT_GET(tovit); + if (mode == IGRAPH_OUT) { + sub = MATRIX(bfres, 0, v1) - MATRIX(bfres, 0, v2); + MATRIX(*res, i, j) -= sub; + } else { + sub = MATRIX(bfres, 0, v2) - MATRIX(bfres, 0, v1); + MATRIX(*res, j, i) -= sub; + } } igraph_vit_destroy(&tovit); IGRAPH_FINALLY_CLEAN(1); @@ -226,17 +252,3 @@ igraph_error_t igraph_distances_johnson(const igraph_t *graph, return IGRAPH_SUCCESS; } - -/** - * \function igraph_shortest_paths_johnson - * \brief Weighted shortest path lengths between vertices, using Johnson's algorithm (deprecated). - * - * \deprecated-by igraph_distances_johnson 0.10.0 - */ -igraph_error_t igraph_shortest_paths_johnson(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - const igraph_vector_t *weights) { - return igraph_distances_johnson(graph, res, from, to, weights); -} diff --git a/src/vendor/cigraph/src/paths/paths_internal.h b/src/vendor/cigraph/src/paths/paths_internal.h new file mode 100644 index 00000000000..477ef03bf7e --- /dev/null +++ b/src/vendor/cigraph/src/paths/paths_internal.h @@ -0,0 +1,119 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef IGRAPH_PATHS_INTERNAL_H +#define IGRAPH_PATHS_INTERNAL_H + +#include "igraph_decls.h" +#include "igraph_paths.h" + +IGRAPH_BEGIN_C_DECLS + +/* Helper functions for validating input to shortest path functions. */ + +igraph_error_t igraph_i_validate_distance_weights( + const igraph_t *graph, + const igraph_vector_t *weights, + igraph_bool_t *negative_weights); + + +/* The following shortest path functions skip most input validation, + * and are meant for internal use in context where the validation + * has already been done. */ + +/* Distances */ + +igraph_error_t igraph_i_distances_unweighted_cutoff( + const igraph_t *graph, + igraph_matrix_t *res, + igraph_vs_t from, igraph_vs_t to, + igraph_neimode_t mode, + igraph_real_t cutoff); + +igraph_error_t igraph_i_distances_dijkstra_cutoff( + const igraph_t *graph, + igraph_matrix_t *res, + igraph_vs_t from, igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode, + igraph_real_t cutoff); + +igraph_error_t igraph_i_distances_bellman_ford( + const igraph_t *graph, + igraph_matrix_t *res, + igraph_vs_t from, igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode); + +igraph_error_t igraph_i_distances_johnson( + const igraph_t *graph, + igraph_matrix_t *res, + igraph_vs_t from, igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode); + +igraph_error_t igraph_i_distances_floyd_warshall( + const igraph_t *graph, + igraph_matrix_t *res, + igraph_vs_t from, igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode, + igraph_floyd_warshall_algorithm_t method); + +/* Get shortest paths */ + +igraph_error_t igraph_i_get_shortest_paths_unweighted( + const igraph_t *graph, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_int_t from, igraph_vs_t to, + igraph_neimode_t mode, + igraph_vector_int_t *parents, + igraph_vector_int_t *inbound_edges); + +igraph_error_t igraph_i_get_shortest_paths_dijkstra( + const igraph_t *graph, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_int_t from, igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode, + igraph_vector_int_t *parents, + igraph_vector_int_t *inbound_edges); + +igraph_error_t igraph_i_get_shortest_paths_bellman_ford( + const igraph_t *graph, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_int_t from, igraph_vs_t to, + const igraph_vector_t *weights, + igraph_neimode_t mode, + igraph_vector_int_t *parents, + igraph_vector_int_t *inbound_edges); + +igraph_error_t igraph_i_get_all_shortest_paths_unweighted( + const igraph_t *graph, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_vector_int_t *nrgeo, + igraph_int_t from, igraph_vs_t to, + igraph_neimode_t mode); + +IGRAPH_END_C_DECLS + +#endif /* IGRAPH_PATHS_INTERNAL_H */ diff --git a/src/vendor/cigraph/src/paths/random_walk.c b/src/vendor/cigraph/src/paths/random_walk.c index 40d9938a1f8..fde30bfc515 100644 --- a/src/vendor/cigraph/src/paths/random_walk.c +++ b/src/vendor/cigraph/src/paths/random_walk.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2014 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -42,11 +41,11 @@ */ static igraph_error_t igraph_i_random_walk_adjlist(const igraph_t *graph, igraph_vector_int_t *vertices, - igraph_integer_t start, + igraph_int_t start, igraph_neimode_t mode, - igraph_integer_t steps, + igraph_int_t steps, igraph_random_walk_stuck_t stuck) { - igraph_integer_t i; + igraph_int_t i; igraph_lazy_adjlist_t adj; if (vertices == NULL) { @@ -59,12 +58,10 @@ static igraph_error_t igraph_i_random_walk_adjlist(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_resize(vertices, steps + 1)); - RNG_BEGIN(); - VECTOR(*vertices)[0] = start; for (i = 1; i <= steps; i++) { igraph_vector_int_t *neis; - igraph_integer_t nn; + igraph_int_t nn; neis = igraph_lazy_adjlist_get(&adj, start); IGRAPH_CHECK_OOM(neis, "Failed to query neighbors."); @@ -83,8 +80,6 @@ static igraph_error_t igraph_i_random_walk_adjlist(const igraph_t *graph, IGRAPH_ALLOW_INTERRUPTION(); } - RNG_END(); - igraph_lazy_adjlist_destroy(&adj); IGRAPH_FINALLY_CLEAN(1); @@ -122,13 +117,13 @@ static igraph_error_t igraph_i_random_walk_inclist( const igraph_vector_t *weights, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t start, + igraph_int_t start, igraph_neimode_t mode, - igraph_integer_t steps, + igraph_int_t steps, igraph_random_walk_stuck_t stuck) { - igraph_integer_t vc = igraph_vcount(graph); - igraph_integer_t i, next; + igraph_int_t vc = igraph_vcount(graph); + igraph_int_t i, next; igraph_vector_t weight_temp; igraph_lazy_inclist_t il; igraph_vector_ptr_t cdfs; /* cumulative distribution vectors for each node, used for weighted choice */ @@ -155,13 +150,11 @@ static igraph_error_t igraph_i_random_walk_inclist( VECTOR(cdfs)[i] = NULL; } - RNG_BEGIN(); - if (vertices) { VECTOR(*vertices)[0] = start; } for (i = 0; i < steps; ++i) { - igraph_integer_t degree, edge, idx; + igraph_int_t degree, edge, idx; igraph_vector_int_t *inc_edges = igraph_lazy_inclist_get(&il, start); IGRAPH_CHECK_OOM(inc_edges, "Failed to query incident edges."); @@ -189,7 +182,7 @@ static igraph_error_t igraph_i_random_walk_inclist( /* compute out-edge cdf for this node if not already done */ if (IGRAPH_UNLIKELY(! *cd)) { - igraph_integer_t j; + igraph_int_t j; *cd = IGRAPH_CALLOC(1, igraph_vector_t); IGRAPH_CHECK_OOM(*cd, "Insufficient memory for random walk."); @@ -237,8 +230,6 @@ static igraph_error_t igraph_i_random_walk_inclist( IGRAPH_ALLOW_INTERRUPTION(); } - RNG_END(); - igraph_vector_ptr_destroy_all(&cdfs); igraph_vector_destroy(&weight_temp); igraph_lazy_inclist_destroy(&il); @@ -298,13 +289,13 @@ igraph_error_t igraph_random_walk(const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t start, + igraph_int_t start, igraph_neimode_t mode, - igraph_integer_t steps, + igraph_int_t steps, igraph_random_walk_stuck_t stuck) { - igraph_integer_t vc = igraph_vcount(graph); - igraph_integer_t ec = igraph_ecount(graph); + igraph_int_t vc = igraph_vcount(graph); + igraph_int_t ec = igraph_ecount(graph); if (!(mode == IGRAPH_ALL || mode == IGRAPH_IN || mode == IGRAPH_OUT)) { IGRAPH_ERROR("Invalid mode parameter.", IGRAPH_EINVMODE); @@ -347,50 +338,3 @@ igraph_error_t igraph_random_walk(const igraph_t *graph, start, mode, steps, stuck); } } - - -/** - * \function igraph_random_edge_walk - * \brief Performs a random walk on a graph and returns the traversed edges. - * - * Performs a random walk with a given length on a graph, from the given - * start vertex. Edge directions are (potentially) considered, depending on - * the \p mode argument. - * - * \param graph The input graph, it can be directed or undirected. - * Multiple edges are respected, so are loop edges. - * \param weights A vector of non-negative edge weights. It is assumed - * that at least one strictly positive weight is found among the - * outgoing edges of each vertex. Additionally, no edge weight may - * be NaN. If either case does not hold, an error is returned. If it - * is a NULL pointer, all edges are considered to have equal weight. - * \param edgewalk An initialized vector; the indices of traversed - * edges are stored here. It will be resized as needed. - * \param start The start vertex for the walk. - * \param steps The number of steps to take. If the random walk gets - * stuck, then the \p stuck argument specifies what happens. - * \param mode How to walk along the edges in directed graphs. - * \c IGRAPH_OUT means following edge directions, \c IGRAPH_IN means - * going opposite the edge directions, \c IGRAPH_ALL means ignoring - * edge directions. This argument is ignored for undirected graphs. - * \param stuck What to do if the random walk gets stuck. - * \c IGRAPH_RANDOM_WALK_STUCK_RETURN means that the function returns - * with a shorter walk; \c IGRAPH_RANDOM_WALK_STUCK_ERROR means - * that an \c IGRAPH_ERWSTUCK error is reported. In both cases, - * \p edgewalk is truncated to contain the actual interrupted walk. - * - * \return Error code. - * - * \deprecated-by igraph_random_walk 0.10.0 - */ -igraph_error_t igraph_random_edge_walk( - const igraph_t *graph, - const igraph_vector_t *weights, - igraph_vector_int_t *edgewalk, - igraph_integer_t start, igraph_neimode_t mode, - igraph_integer_t steps, - igraph_random_walk_stuck_t stuck) { - - return igraph_random_walk(graph, weights, NULL, edgewalk, - start, mode, steps, stuck); -} diff --git a/src/vendor/cigraph/src/paths/shortest_paths.c b/src/vendor/cigraph/src/paths/shortest_paths.c index 315236d8dd9..a443c0097a8 100644 --- a/src/vendor/cigraph/src/paths/shortest_paths.c +++ b/src/vendor/cigraph/src/paths/shortest_paths.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2020 The igraph development team This program is free software; you can redistribute it and/or modify @@ -45,15 +43,15 @@ static igraph_error_t igraph_i_average_path_length_unweighted( const igraph_bool_t invert, /* average inverse distances instead of distances */ const igraph_bool_t unconn /* average over connected pairs instead of all pairs */) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); /* The number of ordered vertex pairs. * While the conditional below is not mathematically necessary, it prevents * returning -0.0 where 0.0 would be expected. */ const igraph_real_t no_of_pairs = no_of_nodes > 0 ? no_of_nodes * (no_of_nodes - 1.0) : 0.0; - igraph_integer_t n; - igraph_integer_t *already_added; + igraph_int_t n; + igraph_int_t *already_added; igraph_real_t no_of_conn_pairs = 0.0; /* no. of ordered pairs between which there is a path */ @@ -62,7 +60,7 @@ static igraph_error_t igraph_i_average_path_length_unweighted( igraph_adjlist_t allneis; *res = 0; - already_added = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + already_added = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(already_added, "Insufficient memory for average path length."); IGRAPH_FINALLY(igraph_free, already_added); @@ -75,7 +73,7 @@ static igraph_error_t igraph_i_average_path_length_unweighted( )); IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis); - for (igraph_integer_t source = 0; source < no_of_nodes; source++) { + for (igraph_int_t source = 0; source < no_of_nodes; source++) { IGRAPH_CHECK(igraph_dqueue_int_push(&q, source)); IGRAPH_CHECK(igraph_dqueue_int_push(&q, 0)); already_added[source] = source + 1; @@ -83,13 +81,13 @@ static igraph_error_t igraph_i_average_path_length_unweighted( IGRAPH_ALLOW_INTERRUPTION(); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); neis = igraph_adjlist_get(&allneis, actnode); n = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t neighbor = VECTOR(*neis)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t neighbor = VECTOR(*neis)[j]; if (already_added[neighbor] == source + 1) { continue; } @@ -142,15 +140,15 @@ static igraph_error_t igraph_i_average_path_length_unweighted( } -/* Computes the average of pairwise distances (used for igraph_average_path_length_dijkstra), - * or of inverse pairwise distances (used for igraph_global_efficiency), in an unweighted graph. +/* Computes the average of pairwise distances (used for igraph_average_path_length), + * or of inverse pairwise distances (used for igraph_global_efficiency), in a weighted graph. * Uses Dijkstra's algorithm, therefore all weights must be non-negative. */ static igraph_error_t igraph_i_average_path_length_dijkstra( const igraph_t *graph, + const igraph_vector_t *weights, igraph_real_t *res, igraph_real_t *unconnected_pairs, - const igraph_vector_t *weights, const igraph_bool_t directed, const igraph_bool_t invert, /* average inverse distances instead of distances */ const igraph_bool_t unconn /* average over connected pairs instead of all pairs */) @@ -171,16 +169,14 @@ static igraph_error_t igraph_i_average_path_length_dijkstra( and we want to spare that. -1 will denote infinity instead. */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_2wheap_t Q; igraph_lazy_inclist_t inclist; igraph_real_t no_of_pairs; igraph_real_t no_of_conn_pairs = 0.0; /* no. of ordered pairs between which there is a path */ - if (!weights) { - return igraph_i_average_path_length_unweighted(graph, res, unconnected_pairs, directed, invert, unconn); - } + IGRAPH_ASSERT(weights != 0); if (igraph_vector_size(weights) != no_of_edges) { IGRAPH_ERRORF("Weight vector length (%" IGRAPH_PRId ") does not match the number of edges (%" IGRAPH_PRId ").", @@ -212,7 +208,7 @@ static igraph_error_t igraph_i_average_path_length_dijkstra( *res = 0.0; - for (igraph_integer_t source = 0; source < no_of_nodes; ++source) { + for (igraph_int_t source = 0; source < no_of_nodes; ++source) { IGRAPH_ALLOW_INTERRUPTION(); @@ -220,10 +216,10 @@ static igraph_error_t igraph_i_average_path_length_dijkstra( igraph_2wheap_push_with_index(&Q, source, -1.0); while (!igraph_2wheap_empty(&Q)) { - igraph_integer_t minnei = igraph_2wheap_max_index(&Q); + igraph_int_t minnei = igraph_2wheap_max_index(&Q); igraph_real_t mindist = -igraph_2wheap_deactivate_max(&Q); igraph_vector_int_t *neis; - igraph_integer_t nlen; + igraph_int_t nlen; if (minnei != source) { if (invert) { @@ -238,9 +234,9 @@ static igraph_error_t igraph_i_average_path_length_dijkstra( neis = igraph_lazy_inclist_get(&inclist, minnei); IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); nlen = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*neis)[j]; - igraph_integer_t tto = IGRAPH_OTHER(graph, edge, minnei); + for (igraph_int_t j = 0; j < nlen; j++) { + igraph_int_t edge = VECTOR(*neis)[j]; + igraph_int_t tto = IGRAPH_OTHER(graph, edge, minnei); igraph_real_t altdist = mindist + VECTOR(*weights)[edge]; igraph_bool_t active = igraph_2wheap_has_active(&Q, tto); igraph_bool_t has = igraph_2wheap_has_elem(&Q, tto); @@ -292,45 +288,7 @@ static igraph_error_t igraph_i_average_path_length_dijkstra( /** * \ingroup structural * \function igraph_average_path_length - * \brief The average unweighted shortest path length between all vertex pairs. - * - * If no vertex pairs can be included in the calculation, for example because - * the graph has fewer than two vertices, or if the graph has no edges and - * \p unconn is set to \c true, NaN is returned. - * - * \param graph The graph object. - * \param res Pointer to a real number, this will contain the result. - * \param unconn_pairs Pointer to a real number. If not a null pointer, the - * number of ordered vertex pairs where the second vertex is unreachable - * from the first one will be stored here. - * \param directed Boolean, whether to consider directed - * paths. Ignored for undirected graphs. - * \param unconn What to do if the graph is not connected. If - * \c true, only those vertex pairs will be included in the calculation - * between which there is a path. If \c false, \c IGRAPH_INFINITY is returned - * for disconnected graphs. - * \return Error code: - * \c IGRAPH_ENOMEM, not enough memory for data structures - * - * Time complexity: O(|V| |E|), the number of vertices times the number of edges. - * - * \sa \ref igraph_average_path_length_dijkstra() for the weighted version. - * - * \example examples/simple/igraph_average_path_length.c - */ - -igraph_error_t igraph_average_path_length(const igraph_t *graph, - igraph_real_t *res, igraph_real_t *unconn_pairs, - igraph_bool_t directed, igraph_bool_t unconn) -{ - return igraph_i_average_path_length_unweighted(graph, res, unconn_pairs, directed, /* invert= */ 0, unconn); -} - - -/** - * \ingroup structural - * \function igraph_average_path_length_dijkstra - * \brief The average weighted shortest path length between all vertex pairs. + * \brief The average shortest path length between all vertex pairs. * * If no vertex pairs can be included in the calculation, for example because the graph * has fewer than two vertices, or if the graph has no edges and \c unconn is set to \c true, @@ -340,16 +298,15 @@ igraph_error_t igraph_average_path_length(const igraph_t *graph, * All distinct ordered vertex pairs are taken into account. * * \param graph The graph object. + * \param weights The edge weights. All edge weights must be + * non-negative for Dijkstra's algorithm to work. Additionally, no + * edge weight may be NaN. If either case does not hold, an error + * is returned. Passa a null pointer here if the graph is unweighted. + * Edges with positive infinite weight are ignored. * \param res Pointer to a real number, this will contain the result. * \param unconn_pairs Pointer to a real number. If not a null pointer, the number of * ordered vertex pairs where the second vertex is unreachable from the first one * will be stored here. - * \param weights The edge weights. All edge weights must be - * non-negative for Dijkstra's algorithm to work. Additionally, no - * edge weight may be NaN. If either case does not hold, an error - * is returned. If this is a null pointer, then the unweighted - * version, \ref igraph_average_path_length() is called. Edges with positive - * infinite weight are ignored. * \param directed Boolean, whether to consider directed paths. * Ignored for undirected graphs. * \param unconn If \c true, only those pairs are considered for the calculation @@ -366,17 +323,22 @@ igraph_error_t igraph_average_path_length(const igraph_t *graph, * Time complexity: O(|V| |E| log|E| + |V|), where |V| is the number of * vertices and |E| is the number of edges. * - * \sa \ref igraph_average_path_length() for a slightly faster unweighted version. - * * \example examples/simple/igraph_grg_game.c */ -igraph_error_t igraph_average_path_length_dijkstra(const igraph_t *graph, - igraph_real_t *res, igraph_real_t *unconn_pairs, - const igraph_vector_t *weights, - igraph_bool_t directed, igraph_bool_t unconn) -{ - return igraph_i_average_path_length_dijkstra(graph, res, unconn_pairs, weights, directed, /* invert= */ false, unconn); +igraph_error_t igraph_average_path_length( + const igraph_t *graph, const igraph_vector_t *weights, igraph_real_t *res, + igraph_real_t *unconn_pairs, igraph_bool_t directed, igraph_bool_t unconn +) { + if (weights) { + return igraph_i_average_path_length_dijkstra( + graph, weights, res, unconn_pairs, directed, /* invert= */ false, unconn + ); + } else { + return igraph_i_average_path_length_unweighted( + graph, res, unconn_pairs, directed, /* invert = */ false, unconn + ); + } } @@ -402,7 +364,6 @@ igraph_error_t igraph_average_path_length_dijkstra(const igraph_t *graph, * https://dx.doi.org/10.1103/PhysRevLett.87.198701 * * \param graph The graph object. - * \param res Pointer to a real number, this will contain the result. * \param weights The edge weights. All edge weights must be * non-negative for Dijkstra's algorithm to work. Additionally, no * edge weight may be NaN. If either case does not hold, an error @@ -410,6 +371,7 @@ igraph_error_t igraph_average_path_length_dijkstra(const igraph_t *graph, * version, \ref igraph_average_path_length() is used in calculating * the global efficiency. Edges with positive infinite weights are * ignored. + * \param res Pointer to a real number, this will contain the result. * \param directed Boolean, whether to consider directed paths. * Ignored for undirected graphs. * \return Error code: @@ -427,11 +389,19 @@ igraph_error_t igraph_average_path_length_dijkstra(const igraph_t *graph, * \sa \ref igraph_local_efficiency(), \ref igraph_average_local_efficiency() */ -igraph_error_t igraph_global_efficiency(const igraph_t *graph, igraph_real_t *res, - const igraph_vector_t *weights, - igraph_bool_t directed) -{ - return igraph_i_average_path_length_dijkstra(graph, res, NULL, weights, directed, /* invert= */ true, /* unconn= */ false); +igraph_error_t igraph_global_efficiency( + const igraph_t *graph, const igraph_vector_t *weights, + igraph_real_t *res, igraph_bool_t directed +) { + if (weights) { + return igraph_i_average_path_length_dijkstra( + graph, weights, res, NULL, directed, /* invert= */ true, /* unconn= */ false + ); + } else { + return igraph_i_average_path_length_unweighted( + graph, res, NULL, directed, /* invert= */ true, /* unconn= */ false + ); + } } @@ -443,17 +413,17 @@ static igraph_error_t igraph_i_local_efficiency_unweighted( const igraph_t *graph, const igraph_adjlist_t *adjlist, igraph_dqueue_int_t *q, - igraph_integer_t *already_counted, + igraph_int_t *already_counted, igraph_vector_int_t *vertex_neis, igraph_vector_char_t *nei_mask, igraph_real_t *res, - igraph_integer_t vertex, + igraph_int_t vertex, igraph_neimode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t vertex_neis_size; - igraph_integer_t neighbor_count; /* unlike 'vertex_neis_size', 'neighbor_count' does not count self-loops and multi-edges */ + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t vertex_neis_size; + igraph_int_t neighbor_count; /* unlike 'vertex_neis_size', 'neighbor_count' does not count self-loops and multi-edges */ igraph_dqueue_int_clear(q); @@ -462,13 +432,13 @@ static igraph_error_t igraph_i_local_efficiency_unweighted( * from, plus 1 */ memset(already_counted, 0, no_of_nodes * sizeof(already_counted[0])); - IGRAPH_CHECK(igraph_neighbors(graph, vertex_neis, vertex, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, vertex_neis, vertex, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); vertex_neis_size = igraph_vector_int_size(vertex_neis); igraph_vector_char_null(nei_mask); neighbor_count = 0; - for (igraph_integer_t i=0; i < vertex_neis_size; ++i) { - igraph_integer_t v = VECTOR(*vertex_neis)[i]; + for (igraph_int_t i=0; i < vertex_neis_size; ++i) { + igraph_int_t v = VECTOR(*vertex_neis)[i]; if (v != vertex && ! VECTOR(*nei_mask)[v]) { VECTOR(*nei_mask)[v] = 1; /* mark as unprocessed neighbour */ neighbor_count++; @@ -482,9 +452,9 @@ static igraph_error_t igraph_i_local_efficiency_unweighted( return IGRAPH_SUCCESS; } - for (igraph_integer_t i=0; i < vertex_neis_size; ++i) { - igraph_integer_t source = VECTOR(*vertex_neis)[i]; - igraph_integer_t reached = 0; + for (igraph_int_t i=0; i < vertex_neis_size; ++i) { + igraph_int_t source = VECTOR(*vertex_neis)[i]; + igraph_int_t reached = 0; IGRAPH_ALLOW_INTERRUPTION(); @@ -502,9 +472,9 @@ static igraph_error_t igraph_i_local_efficiency_unweighted( while (!igraph_dqueue_int_empty(q)) { igraph_vector_int_t *act_neis; - igraph_integer_t act_neis_size; - igraph_integer_t act = igraph_dqueue_int_pop(q); - igraph_integer_t actdist = igraph_dqueue_int_pop(q); + igraph_int_t act_neis_size; + igraph_int_t act = igraph_dqueue_int_pop(q); + igraph_int_t actdist = igraph_dqueue_int_pop(q); if (act != source && VECTOR(*nei_mask)[act]) { *res += 1.0 / actdist; @@ -517,8 +487,8 @@ static igraph_error_t igraph_i_local_efficiency_unweighted( act_neis = igraph_adjlist_get(adjlist, act); act_neis_size = igraph_vector_int_size(act_neis); - for (igraph_integer_t j = 0; j < act_neis_size; j++) { - igraph_integer_t neighbor = VECTOR(*act_neis)[j]; + for (igraph_int_t j = 0; j < act_neis_size; j++) { + igraph_int_t neighbor = VECTOR(*act_neis)[j]; if (neighbor == vertex || already_counted[neighbor] == i + 1) continue; @@ -542,7 +512,7 @@ static igraph_error_t igraph_i_local_efficiency_dijkstra( igraph_vector_int_t *vertex_neis, igraph_vector_char_t *nei_mask, /* true if the corresponding node is a neighbour of 'vertex' */ igraph_real_t *res, - igraph_integer_t vertex, + igraph_int_t vertex, igraph_neimode_t mode, const igraph_vector_t *weights) { @@ -562,16 +532,16 @@ static igraph_error_t igraph_i_local_efficiency_dijkstra( and we want to spare that. -1 will denote infinity instead. */ - igraph_integer_t vertex_neis_size; - igraph_integer_t neighbor_count; /* unlike 'inc_edges_size', 'neighbor_count' does not count self-loops or multi-edges */ + igraph_int_t vertex_neis_size; + igraph_int_t neighbor_count; /* unlike 'inc_edges_size', 'neighbor_count' does not count self-loops or multi-edges */ - IGRAPH_CHECK(igraph_neighbors(graph, vertex_neis, vertex, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, vertex_neis, vertex, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); vertex_neis_size = igraph_vector_int_size(vertex_neis); igraph_vector_char_null(nei_mask); neighbor_count = 0; - for (igraph_integer_t i=0; i < vertex_neis_size; ++i) { - igraph_integer_t v = VECTOR(*vertex_neis)[i]; + for (igraph_int_t i=0; i < vertex_neis_size; ++i) { + igraph_int_t v = VECTOR(*vertex_neis)[i]; if (v != vertex && ! VECTOR(*nei_mask)[v]) { VECTOR(*nei_mask)[v] = 1; /* mark as unprocessed neighbour */ neighbor_count++; @@ -585,9 +555,9 @@ static igraph_error_t igraph_i_local_efficiency_dijkstra( return IGRAPH_SUCCESS; } - for (igraph_integer_t i=0; i < vertex_neis_size; ++i) { - igraph_integer_t source = VECTOR(*vertex_neis)[i]; - igraph_integer_t reached = 0; + for (igraph_int_t i=0; i < vertex_neis_size; ++i) { + igraph_int_t source = VECTOR(*vertex_neis)[i]; + igraph_int_t reached = 0; IGRAPH_ALLOW_INTERRUPTION(); @@ -603,10 +573,10 @@ static igraph_error_t igraph_i_local_efficiency_dijkstra( igraph_2wheap_push_with_index(Q, source, -1.0); while (!igraph_2wheap_empty(Q)) { - igraph_integer_t minnei = igraph_2wheap_max_index(Q); + igraph_int_t minnei = igraph_2wheap_max_index(Q); igraph_real_t mindist = -igraph_2wheap_deactivate_max(Q); igraph_vector_int_t *neis; - igraph_integer_t nlen; + igraph_int_t nlen; if (minnei != source && VECTOR(*nei_mask)[minnei]) { *res += 1.0/(mindist - 1.0); @@ -621,11 +591,11 @@ static igraph_error_t igraph_i_local_efficiency_dijkstra( neis = igraph_lazy_inclist_get(inclist, minnei); IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); nlen = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < nlen; j++) { + for (igraph_int_t j = 0; j < nlen; j++) { igraph_real_t altdist, curdist; igraph_bool_t active, has; - igraph_integer_t edge = VECTOR(*neis)[j]; - igraph_integer_t tto = IGRAPH_OTHER(graph, edge, minnei); + igraph_int_t edge = VECTOR(*neis)[j]; + igraph_int_t tto = IGRAPH_OTHER(graph, edge, minnei); if (tto == vertex) { continue; @@ -679,14 +649,14 @@ static igraph_error_t igraph_i_local_efficiency_dijkstra( * http://dx.doi.org/10.1103/PhysRevE.71.036122 * * \param graph The graph object. - * \param res Pointer to an initialized vector, this will contain the result. - * \param vids The vertices around which the local efficiency will be calculated. * \param weights The edge weights. All edge weights must be * non-negative. Additionally, no edge weight may be NaN. If either * case does not hold, an error is returned. If this is a null * pointer, then the unweighted version, * \ref igraph_average_path_length() is called. Edges with positive * infinite weights are ignored. + * \param res Pointer to an initialized vector, this will contain the result. + * \param vids The vertices around which the local efficiency will be calculated. * \param directed Boolean, whether to consider directed paths. * Ignored for undirected graphs. * \param mode How to determine the local neighborhood of each vertex @@ -715,18 +685,17 @@ static igraph_error_t igraph_i_local_efficiency_dijkstra( * */ -igraph_error_t igraph_local_efficiency(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, - const igraph_vector_t *weights, - igraph_bool_t directed, igraph_neimode_t mode) -{ - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t nodes_to_calc; /* no. of vertices includes in computation */ +igraph_error_t igraph_local_efficiency( + const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_t *res, + const igraph_vs_t vids, igraph_bool_t directed, igraph_neimode_t mode +) { + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t nodes_to_calc; /* no. of vertices includes in computation */ igraph_vit_t vit; igraph_vector_int_t vertex_neis; igraph_vector_char_t nei_mask; - igraph_integer_t i; + igraph_int_t i; /* 'nei_mask' is a vector indexed by vertices. The meaning of its values is as follows: * 0: not a neighbour of 'vertex' @@ -749,11 +718,11 @@ igraph_error_t igraph_local_efficiency(const igraph_t *graph, igraph_vector_t *r if (! weights) /* unweighted case */ { - igraph_integer_t *already_counted; + igraph_int_t *already_counted; igraph_adjlist_t adjlist; igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; - already_counted = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + already_counted = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(already_counted, "Insufficient memory for local efficiency calculation."); IGRAPH_FINALLY(igraph_free, already_counted); @@ -838,10 +807,10 @@ igraph_error_t igraph_local_efficiency(const igraph_t *graph, igraph_vector_t *r * For the null graph, zero is returned by convention. * * \param graph The graph object. - * \param res Pointer to a real number, this will contain the result. * \param weights The edge weights. They must be all non-negative. * If a null pointer is given, all weights are assumed to be 1. Edges * with positive infinite weight are ignored. + * \param res Pointer to a real number, this will contain the result. * \param directed Boolean, whether to consider directed paths. * Ignored for undirected graphs. * \param mode How to determine the local neighborhood of each vertex @@ -870,11 +839,11 @@ igraph_error_t igraph_local_efficiency(const igraph_t *graph, igraph_vector_t *r * */ -igraph_error_t igraph_average_local_efficiency(const igraph_t *graph, igraph_real_t *res, - const igraph_vector_t *weights, - igraph_bool_t directed, igraph_neimode_t mode) -{ - igraph_integer_t no_of_nodes = igraph_vcount(graph); +igraph_error_t igraph_average_local_efficiency( + const igraph_t *graph, const igraph_vector_t *weights, igraph_real_t *res, + igraph_bool_t directed, igraph_neimode_t mode +) { + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_t local_eff; /* If there are fewer than 3 vertices, no vertex has more than one neighbour, thus all @@ -886,7 +855,7 @@ igraph_error_t igraph_average_local_efficiency(const igraph_t *graph, igraph_rea IGRAPH_VECTOR_INIT_FINALLY(&local_eff, no_of_nodes); - IGRAPH_CHECK(igraph_local_efficiency(graph, &local_eff, igraph_vss_all(), weights, directed, mode)); + IGRAPH_CHECK(igraph_local_efficiency(graph, weights, &local_eff, igraph_vss_all(),directed, mode)); *res = igraph_vector_sum(&local_eff); *res /= no_of_nodes; @@ -941,24 +910,24 @@ igraph_error_t igraph_average_local_efficiency(const igraph_t *graph, igraph_rea * Time complexity: O(|V||E|), the * number of vertices times the number of edges. * - * \sa \ref igraph_diameter_dijkstra() for the weighted version, - * \ref igraph_radius() for the minimum eccentricity. + * \sa \ref igraph_radius() for the minimum eccentricity. * * \example examples/simple/igraph_diameter.c */ -igraph_error_t igraph_diameter(const igraph_t *graph, igraph_real_t *res, - igraph_integer_t *from, igraph_integer_t *to, - igraph_vector_int_t *vertex_path, igraph_vector_int_t *edge_path, - igraph_bool_t directed, igraph_bool_t unconn) { +static igraph_error_t igraph_i_diameter_unweighted( + const igraph_t *graph, igraph_real_t *res, igraph_int_t *from, + igraph_int_t *to, igraph_vector_int_t *vertex_path, + igraph_vector_int_t *edge_path, igraph_bool_t directed, igraph_bool_t unconn +) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t n; - igraph_integer_t *already_added; - igraph_integer_t nodes_reached; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t n; + igraph_int_t *already_added; + igraph_int_t nodes_reached; /* from/to are initialized to 0 because in a singleton graph, or in an edgeless graph * with unconn = true, the diameter path will be considered to consist of vertex 0 only. */ - igraph_integer_t ifrom = 0, ito = 0; + igraph_int_t ifrom = 0, ito = 0; igraph_real_t ires = 0; igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; @@ -992,7 +961,7 @@ igraph_error_t igraph_diameter(const igraph_t *graph, igraph_real_t *res, } else { dirmode = IGRAPH_ALL; } - already_added = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + already_added = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(already_added, "Insufficient memory for diameter calculation."); IGRAPH_FINALLY(igraph_free, already_added); @@ -1001,7 +970,7 @@ igraph_error_t igraph_diameter(const igraph_t *graph, igraph_real_t *res, IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, dirmode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { nodes_reached = 1; IGRAPH_CHECK(igraph_dqueue_int_push(&q, i)); IGRAPH_CHECK(igraph_dqueue_int_push(&q, 0)); @@ -1012,8 +981,8 @@ igraph_error_t igraph_diameter(const igraph_t *graph, igraph_real_t *res, IGRAPH_ALLOW_INTERRUPTION(); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); if (actdist > ires) { ires = actdist; ifrom = i; @@ -1022,8 +991,8 @@ igraph_error_t igraph_diameter(const igraph_t *graph, igraph_real_t *res, neis = igraph_adjlist_get(&allneis, actnode); n = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t neighbor = VECTOR(*neis)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t neighbor = VECTOR(*neis)[j]; if (already_added[neighbor] == i + 1) { continue; } @@ -1064,7 +1033,7 @@ igraph_error_t igraph_diameter(const igraph_t *graph, igraph_real_t *res, igraph_vector_int_clear(edge_path); } } else { - IGRAPH_CHECK(igraph_get_shortest_path(graph, vertex_path, edge_path, + IGRAPH_CHECK(igraph_get_shortest_path(graph, NULL, vertex_path, edge_path, ifrom, ito, dirmode)); } } @@ -1078,61 +1047,11 @@ igraph_error_t igraph_diameter(const igraph_t *graph, igraph_real_t *res, return IGRAPH_SUCCESS; } -/** - * \function igraph_diameter_dijkstra - * \brief Calculates the weighted diameter of a graph using Dijkstra's algorithm. - * - * This function computes the weighted diameter of a graph, defined as the longest - * weighted shortest path, or the maximum weighted eccentricity of the graph's - * vertices. A corresponding shortest path, as well as its endpoints, - * can also be optionally computed. - * - * - * If the graph has no vertices, \c IGRAPH_NAN is returned. - * - * \param graph The input graph, can be directed or undirected. - * \param weights The edge weights of the graph. Can be \c NULL for an - * unweighted graph. Edges with positive infinite weight are ignored. - * \param res Pointer to a real number, if not \c NULL then it will contain - * the diameter (the actual distance). - * \param from Pointer to an integer, if not \c NULL it will be set to the - * source vertex of the diameter path. If the graph has no diameter path, - * it will be set to -1. - * \param to Pointer to an integer, if not \c NULL it will be set to the - * target vertex of the diameter path. If the graph has no diameter path, - * it will be set to -1. - * \param vertex_path Pointer to an initialized vector. If not \c NULL the actual - * longest geodesic path in terms of vertices will be stored here. The vector will be - * resized as needed. - * \param edge_path Pointer to an initialized vector. If not \c NULL the actual - * longest geodesic path in terms of edges will be stored here. The vector will be - * resized as needed. - * \param directed Boolean, whether to consider directed - * paths. Ignored for undirected graphs. - * \param unconn What to do if the graph is not connected. If - * \c true the longest geodesic within a component - * will be returned, otherwise \c IGRAPH_INFINITY is - * returned. - * \return Error code. - * - * Time complexity: O(|V||E|*log|E|), |V| is the number of vertices, - * |E| is the number of edges. - * - * \sa \ref igraph_diameter() for the unweighted version, - * \ref igraph_radius_dijkstra() for the minimum weighted eccentricity. - */ - - -igraph_error_t igraph_diameter_dijkstra(const igraph_t *graph, - const igraph_vector_t *weights, - igraph_real_t *res, - igraph_integer_t *from, - igraph_integer_t *to, - igraph_vector_int_t *vertex_path, - igraph_vector_int_t *edge_path, - igraph_bool_t directed, - igraph_bool_t unconn) { - +static igraph_error_t igraph_i_diameter_dijkstra( + const igraph_t *graph, const igraph_vector_t *weights, igraph_real_t *res, + igraph_int_t *from, igraph_int_t *to, igraph_vector_int_t *vertex_path, + igraph_vector_int_t *edge_path, igraph_bool_t directed, igraph_bool_t unconn +) { /* Implementation details. This is the basic Dijkstra algorithm, with a binary heap. The heap is indexed, i.e. it stores not only the distances, but also which vertex they belong to. @@ -1148,8 +1067,8 @@ igraph_error_t igraph_diameter_dijkstra(const igraph_t *graph, infinity instead. */ - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); igraph_2wheap_t Q; igraph_inclist_t inclist; @@ -1157,9 +1076,9 @@ igraph_error_t igraph_diameter_dijkstra(const igraph_t *graph, /* from/to are initialized to 0 because in a singleton graph, or in an edgeless graph * with unconn = true, the diameter path will be considered to consist of vertex 0 only. */ - igraph_integer_t ifrom = 0, ito = 0; + igraph_int_t ifrom = 0, ito = 0; igraph_real_t ires = 0; - igraph_integer_t nodes_reached = 0; + igraph_int_t nodes_reached = 0; /* See https://github.com/igraph/igraph/issues/1538#issuecomment-724071857 * for why we return NaN for the null graph. */ @@ -1182,16 +1101,9 @@ igraph_error_t igraph_diameter_dijkstra(const igraph_t *graph, return IGRAPH_SUCCESS; } - if (!weights) { - igraph_real_t diameter; - IGRAPH_CHECK(igraph_diameter(graph, &diameter, from, to, vertex_path, edge_path, directed, unconn)); - if (res) { - *res = diameter; - } - return IGRAPH_SUCCESS; - } + IGRAPH_ASSERT(weights != 0); - if (weights && igraph_vector_size(weights) != no_of_edges) { + if (igraph_vector_size(weights) != no_of_edges) { IGRAPH_ERRORF("Weight vector length (%" IGRAPH_PRId ") not equal to number of edges (%" IGRAPH_PRId ").", IGRAPH_EINVAL, igraph_vector_size(weights), no_of_edges); } @@ -1211,7 +1123,7 @@ igraph_error_t igraph_diameter_dijkstra(const igraph_t *graph, IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, dirmode, IGRAPH_LOOPS)); IGRAPH_FINALLY(igraph_inclist_destroy, &inclist); - for (igraph_integer_t source = 0; source < no_of_nodes; source++) { + for (igraph_int_t source = 0; source < no_of_nodes; source++) { IGRAPH_PROGRESS("Weighted diameter: ", source * 100.0 / no_of_nodes, NULL); IGRAPH_ALLOW_INTERRUPTION(); @@ -1222,10 +1134,10 @@ igraph_error_t igraph_diameter_dijkstra(const igraph_t *graph, nodes_reached = 0.0; while (!igraph_2wheap_empty(&Q)) { - igraph_integer_t minnei = igraph_2wheap_max_index(&Q); + igraph_int_t minnei = igraph_2wheap_max_index(&Q); igraph_real_t mindist = -igraph_2wheap_deactivate_max(&Q); igraph_vector_int_t *neis; - igraph_integer_t nlen; + igraph_int_t nlen; if (mindist > ires) { ires = mindist; ifrom = source; ito = minnei; @@ -1235,9 +1147,9 @@ igraph_error_t igraph_diameter_dijkstra(const igraph_t *graph, /* Now check all neighbors of 'minnei' for a shorter path */ neis = igraph_inclist_get(&inclist, minnei); nlen = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*neis)[j]; - igraph_integer_t tto = IGRAPH_OTHER(graph, edge, minnei); + for (igraph_int_t j = 0; j < nlen; j++) { + igraph_int_t edge = VECTOR(*neis)[j]; + igraph_int_t tto = IGRAPH_OTHER(graph, edge, minnei); igraph_real_t altdist = mindist + VECTOR(*weights)[edge]; igraph_bool_t active = igraph_2wheap_has_active(&Q, tto); igraph_bool_t has = igraph_2wheap_has_elem(&Q, tto); @@ -1296,9 +1208,72 @@ igraph_error_t igraph_diameter_dijkstra(const igraph_t *graph, weights, dirmode)); } } + return IGRAPH_SUCCESS; } +/** + * \function igraph_diameter + * \brief Calculates the weighted diameter of a graph using Dijkstra's algorithm. + * + * This function computes the weighted diameter of a graph, defined as the longest + * weighted shortest path, or the maximum weighted eccentricity of the graph's + * vertices. A corresponding shortest path, as well as its endpoints, + * can also be optionally computed. + * + * + * If the graph has no vertices, \c IGRAPH_NAN is returned. + * + * \param graph The input graph, can be directed or undirected. + * \param weights The edge weights of the graph. Can be \c NULL for an + * unweighted graph. Edges with positive infinite weight are ignored. + * \param res Pointer to a real number, if not \c NULL then it will contain + * the diameter (the actual distance). + * \param from Pointer to an integer, if not \c NULL it will be set to the + * source vertex of the diameter path. If the graph has no diameter path, + * it will be set to -1. + * \param to Pointer to an integer, if not \c NULL it will be set to the + * target vertex of the diameter path. If the graph has no diameter path, + * it will be set to -1. + * \param vertex_path Pointer to an initialized vector. If not \c NULL the actual + * longest geodesic path in terms of vertices will be stored here. The vector will be + * resized as needed. + * \param edge_path Pointer to an initialized vector. If not \c NULL the actual + * longest geodesic path in terms of edges will be stored here. The vector will be + * resized as needed. + * \param directed Boolean, whether to consider directed + * paths. Ignored for undirected graphs. + * \param unconn What to do if the graph is not connected. If + * \c true the longest geodesic within a component + * will be returned, otherwise \c IGRAPH_INFINITY is + * returned. + * \return Error code. + * + * Time complexity: O(|V||E|*log|E|), |V| is the number of vertices, + * |E| is the number of edges. + * + * \sa \ref igraph_radius() for the minimum eccentricity. + * + * \example examples/simple/igraph_diameter.c + */ +igraph_error_t igraph_diameter( + const igraph_t *graph, const igraph_vector_t *weights, igraph_real_t *res, + igraph_int_t *from, igraph_int_t *to, igraph_vector_int_t *vertex_path, + igraph_vector_int_t *edge_path, igraph_bool_t directed, igraph_bool_t unconn +) { + if (weights) { + return igraph_i_diameter_dijkstra( + graph, weights, res, from, to, vertex_path, edge_path, + directed, unconn + ); + } else { + return igraph_i_diameter_unweighted( + graph, res, from, to, vertex_path, edge_path, + directed, unconn + ); + } +} + /** * Temporarily removes all edges incident on the vertex with the given ID from * the graph by setting the weights of these edges to infinity. @@ -1313,14 +1288,14 @@ igraph_error_t igraph_diameter_dijkstra(const igraph_t *graph, */ static igraph_error_t igraph_i_semidelete_vertex( const igraph_t *graph, igraph_vector_t *weights, - igraph_integer_t vid, igraph_vector_int_t *edges_removed, + igraph_int_t vid, igraph_vector_int_t *edges_removed, igraph_vector_int_t *eids ) { - IGRAPH_CHECK(igraph_incident(graph, eids, vid, IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(graph, eids, vid, IGRAPH_ALL, IGRAPH_LOOPS)); - const igraph_integer_t n = igraph_vector_int_size(eids); - for (igraph_integer_t j = 0; j < n; j++) { - const igraph_integer_t eid = VECTOR(*eids)[j]; + const igraph_int_t n = igraph_vector_int_size(eids); + for (igraph_int_t j = 0; j < n; j++) { + const igraph_int_t eid = VECTOR(*eids)[j]; IGRAPH_CHECK(igraph_vector_int_push_back(edges_removed, eid)); VECTOR(*weights)[eid] = IGRAPH_INFINITY; } @@ -1331,9 +1306,9 @@ static igraph_error_t igraph_i_semidelete_vertex( static igraph_bool_t igraph_i_has_edge_with_infinite_weight( const igraph_vector_int_t* path, const igraph_vector_t* weights ) { - const igraph_integer_t n = weights ? igraph_vector_int_size(path) : 0; - for (igraph_integer_t i = 0; i < n; i++) { - const igraph_integer_t edge = VECTOR(*path)[i]; + const igraph_int_t n = weights ? igraph_vector_int_size(path) : 0; + for (igraph_int_t i = 0; i < n; i++) { + const igraph_int_t edge = VECTOR(*path)[i]; if (!isfinite(VECTOR(*weights)[edge])) { return true; } @@ -1345,13 +1320,13 @@ static igraph_bool_t igraph_i_has_edge_with_infinite_weight( static igraph_real_t igraph_i_get_total_weight_of_path( igraph_vector_int_t* path, const igraph_vector_t* weights ) { - const igraph_integer_t n = igraph_vector_int_size(path); + const igraph_int_t n = igraph_vector_int_size(path); igraph_real_t result; if (weights) { result = 0; - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t edge = VECTOR(*path)[i]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t edge = VECTOR(*path)[i]; result += VECTOR(*weights)[edge]; } } else { @@ -1428,22 +1403,22 @@ igraph_error_t igraph_get_k_shortest_paths( const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_int_list_t *vertex_paths, igraph_vector_int_list_t *edge_paths, - igraph_integer_t k, igraph_integer_t from, igraph_integer_t to, + igraph_int_t k, igraph_int_t from, igraph_int_t to, igraph_neimode_t mode ) { igraph_vector_int_list_t paths_pot; /* potential shortest paths */ - igraph_integer_t vertex_spur; + igraph_int_t vertex_spur; igraph_vector_int_t path_spur, path_root, path_total, path_shortest; - igraph_integer_t nr_edges_root, i_path_current, i_path, edge_path_root, vertex_root_del; - igraph_integer_t n; + igraph_int_t nr_edges_root, i_path_current, i_path, edge_path_root, vertex_root_del; + igraph_int_t n; igraph_vector_t current_weights; igraph_vector_int_t edges_removed; - const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t infinite_path, already_in_potential_paths; igraph_vector_int_t *path_0; igraph_vector_int_t eids; igraph_real_t path_weight, shortest_path_weight; - igraph_integer_t edge_paths_owned = 0; + igraph_int_t edge_paths_owned = 0; if (!igraph_is_directed(graph) && (mode == IGRAPH_IN || mode == IGRAPH_OUT)) { mode = IGRAPH_ALL; @@ -1510,7 +1485,7 @@ igraph_error_t igraph_get_k_shortest_paths( for (i_path_current = 1; i_path_current < k; i_path_current++) { igraph_vector_int_t *path_previous = igraph_vector_int_list_tail_ptr(edge_paths); - igraph_integer_t path_previous_length = igraph_vector_int_size(path_previous); + igraph_int_t path_previous_length = igraph_vector_int_size(path_previous); for (nr_edges_root = 0; nr_edges_root < path_previous_length; nr_edges_root++) { /* Determine spur node. */ if (mode == IGRAPH_OUT) { @@ -1518,13 +1493,13 @@ igraph_error_t igraph_get_k_shortest_paths( } else if (mode == IGRAPH_IN) { vertex_spur = IGRAPH_TO(graph, VECTOR(*path_previous)[nr_edges_root]); } else { - igraph_integer_t eid = VECTOR(*path_previous)[nr_edges_root]; - igraph_integer_t vertex_spur_1 = IGRAPH_FROM(graph, eid); - igraph_integer_t vertex_spur_2 = IGRAPH_TO(graph, eid); - igraph_integer_t vertex_spur_3; - igraph_integer_t vertex_spur_4; + igraph_int_t eid = VECTOR(*path_previous)[nr_edges_root]; + igraph_int_t vertex_spur_1 = IGRAPH_FROM(graph, eid); + igraph_int_t vertex_spur_2 = IGRAPH_TO(graph, eid); + igraph_int_t vertex_spur_3; + igraph_int_t vertex_spur_4; if (nr_edges_root < path_previous_length-1) { - igraph_integer_t eid_next = VECTOR(*path_previous)[nr_edges_root + 1]; + igraph_int_t eid_next = VECTOR(*path_previous)[nr_edges_root + 1]; vertex_spur_3 = IGRAPH_FROM(graph, eid_next); vertex_spur_4 = IGRAPH_TO(graph, eid_next); } else { @@ -1539,7 +1514,7 @@ igraph_error_t igraph_get_k_shortest_paths( /* Determine root path. */ IGRAPH_CHECK(igraph_vector_int_resize(&path_root, nr_edges_root)); - for (igraph_integer_t i = 0; i < nr_edges_root; i++) { + for (igraph_int_t i = 0; i < nr_edges_root; i++) { VECTOR(path_root)[i] = VECTOR(*path_previous)[i]; } @@ -1547,7 +1522,7 @@ igraph_error_t igraph_get_k_shortest_paths( for (i_path = 0; i_path < i_path_current; i_path++) { igraph_vector_int_t *path_check = igraph_vector_int_list_get_ptr(edge_paths, i_path); igraph_bool_t equal = true; - for (igraph_integer_t i = 0; i < nr_edges_root; i++) { + for (igraph_int_t i = 0; i < nr_edges_root; i++) { if (VECTOR(path_root)[i] != VECTOR(*path_check)[i]) { equal = false; break; @@ -1568,12 +1543,12 @@ igraph_error_t igraph_get_k_shortest_paths( } else if (mode == IGRAPH_IN) { vertex_root_del = IGRAPH_TO(graph, VECTOR(path_root)[edge_path_root]); } else { - igraph_integer_t eid = VECTOR(*path_previous)[edge_path_root]; - igraph_integer_t eid_next = VECTOR(*path_previous)[edge_path_root + 1]; - igraph_integer_t vertex_root_del_1 = IGRAPH_FROM(graph, eid); - igraph_integer_t vertex_root_del_2 = IGRAPH_TO(graph, eid); - igraph_integer_t vertex_root_del_3 = IGRAPH_FROM(graph, eid_next); - igraph_integer_t vertex_root_del_4 = IGRAPH_TO(graph, eid_next); + igraph_int_t eid = VECTOR(*path_previous)[edge_path_root]; + igraph_int_t eid_next = VECTOR(*path_previous)[edge_path_root + 1]; + igraph_int_t vertex_root_del_1 = IGRAPH_FROM(graph, eid); + igraph_int_t vertex_root_del_2 = IGRAPH_TO(graph, eid); + igraph_int_t vertex_root_del_3 = IGRAPH_FROM(graph, eid_next); + igraph_int_t vertex_root_del_4 = IGRAPH_TO(graph, eid_next); if (vertex_root_del_1 == vertex_root_del_3 || vertex_root_del_1 == vertex_root_del_4) { vertex_root_del = vertex_root_del_2; } else { @@ -1604,7 +1579,7 @@ igraph_error_t igraph_get_k_shortest_paths( already_in_potential_paths = false; n = igraph_vector_int_list_size(&paths_pot); - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { if (igraph_vector_int_all_e(&path_total, igraph_vector_int_list_get_ptr(&paths_pot, i))) { already_in_potential_paths = true; break; @@ -1618,7 +1593,7 @@ igraph_error_t igraph_get_k_shortest_paths( /* Cleanup */ n = igraph_vector_int_size(&edges_removed); - for (igraph_integer_t i = 0; i < n; i++) { + for (igraph_int_t i = 0; i < n; i++) { VECTOR(current_weights)[VECTOR(edges_removed)[i]] = weights ? VECTOR(*weights)[VECTOR(edges_removed)[i]] : 1; } @@ -1635,7 +1610,7 @@ igraph_error_t igraph_get_k_shortest_paths( igraph_vector_int_list_get_ptr(&paths_pot, 0), weights ); i_path = 0; - for (igraph_integer_t i = 1; i < n; i++) { + for (igraph_int_t i = 1; i < n; i++) { path_weight = igraph_i_get_total_weight_of_path( igraph_vector_int_list_get_ptr(&paths_pot, i), weights ); @@ -1659,10 +1634,10 @@ igraph_error_t igraph_get_k_shortest_paths( IGRAPH_FINALLY_CLEAN(7); if (vertex_paths) { - const igraph_integer_t no_of_edge_paths = igraph_vector_int_list_size(edge_paths); + const igraph_int_t no_of_edge_paths = igraph_vector_int_list_size(edge_paths); IGRAPH_CHECK(igraph_vector_int_list_resize(vertex_paths, no_of_edge_paths)); - for (igraph_integer_t i = 0; i < no_of_edge_paths; i++) { + for (igraph_int_t i = 0; i < no_of_edge_paths; i++) { igraph_vector_int_t* edge_path = igraph_vector_int_list_get_ptr(edge_paths, i); igraph_vector_int_t* vertex_path = igraph_vector_int_list_get_ptr(vertex_paths, i); IGRAPH_CHECK(igraph_vertex_path_from_edge_path(graph, from, edge_path, vertex_path, mode)); diff --git a/src/vendor/cigraph/src/paths/simple_paths.c b/src/vendor/cigraph/src/paths/simple_paths.c index 13837750a2a..630689a0227 100644 --- a/src/vendor/cigraph/src/paths/simple_paths.c +++ b/src/vendor/cigraph/src/paths/simple_paths.c @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2014-2022 The igraph development team + igraph library. + Copyright (C) 2014-2024 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,9 +19,11 @@ #include "igraph_paths.h" +#include "igraph_adjlist.h" +#include "igraph_bitset.h" #include "igraph_interface.h" #include "igraph_iterators.h" -#include "igraph_adjlist.h" +#include "igraph_vector_list.h" #include "core/interruption.h" @@ -29,27 +31,39 @@ * \function igraph_get_all_simple_paths * \brief List all simple paths from one source. * - * A path is simple if its vertices are unique, i.e. no vertex - * is visited more than once. + * A path is simple if its vertices are unique, i.e. no vertex is visited more + * than once. This function returns paths in terms of their vertices and + * ignores multi-edges. * * - * Note that potentially there are exponentially many - * paths between two vertices of a graph, and you may - * run out of memory when using this function when the - * graph has many cycles. Consider using the \p cutoff - * parameter when you do not need long paths. + * Note that potentially there are exponentially many paths between two + * vertices of a graph, and you may run out of memory when using this function + * when the graph has many cycles. Consider using the \p minlen and \p maxlen + * parameters to restrict the paths that are returned. * * \param graph The input graph. - * \param res Initialized integer vector. The paths are - * returned here in terms of their vertices, separated - * by -1 markers. The paths are included in arbitrary - * order, as they are found. + * \param res Initialized integer vector list. The paths are returned here in + * terms of their vertices. The paths are included in arbitrary order, as + * they are found. * \param from The start vertex. * \param to The target vertices. - * \param cutoff Maximum length of path that is considered. If - * negative, paths of all lengths are considered. - * \param mode The type of the paths to consider, it is ignored - * for undirected graphs. + * \param mode The type of paths to be used for the calculation in directed + * graphs. Possible values: + * \clist + * \cli IGRAPH_OUT + * outgoing paths are calculated. + * \cli IGRAPH_IN + * incoming paths are calculated. + * \cli IGRAPH_ALL + * the directed graph is considered as an undirected one for + * the computation. + * \endclist + * \param minlen Minimum length of paths that is considered. If negative + * or \ref IGRAPH_UNLIMITED, no lower bound is used on the path lengths. + * \param maxlen Maximum length of paths that is considered. If negative + * or \ref IGRAPH_UNLIMITED, no upper bound is used on the path lengths. + * \param max_results At most this many paths will be recorded. If + * negative, or \ref IGRAPH_UNLIMITED, no limit is applied. * \return Error code. * * \sa \ref igraph_get_k_shortest_paths() @@ -58,75 +72,79 @@ * vertices. */ -igraph_error_t igraph_get_all_simple_paths(const igraph_t *graph, - igraph_vector_int_t *res, - igraph_integer_t from, - const igraph_vs_t to, - igraph_integer_t cutoff, - igraph_neimode_t mode) { +igraph_error_t igraph_get_all_simple_paths( + const igraph_t *graph, + igraph_vector_int_list_t *res, + igraph_int_t from, const igraph_vs_t to, + igraph_neimode_t mode, + igraph_int_t minlen, igraph_int_t maxlen, + igraph_int_t max_results) { - igraph_integer_t no_nodes = igraph_vcount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_bool_t toall = igraph_vs_is_all(&to); igraph_vit_t vit; - igraph_bool_t toall = igraph_vs_is_all(&to); igraph_lazy_adjlist_t adjlist; igraph_vector_int_t stack, dist; /* used as a stack, but represented as a vector, - in order to be appendable to other vectors */ - igraph_vector_bool_t markto, added; + in order to be appendable the result vector list */ + igraph_bitset_t markto, added; igraph_vector_int_t nptr; int iter = 0; - if (from < 0 || from >= no_nodes) { + if (from < 0 || from >= vcount) { IGRAPH_ERROR("Index of source vertex is out of range.", IGRAPH_EINVVID); } + igraph_vector_int_list_clear(res); + + if (max_results == 0) { + return IGRAPH_SUCCESS; + } + if (!toall) { - IGRAPH_VECTOR_BOOL_INIT_FINALLY(&markto, no_nodes); + IGRAPH_BITSET_INIT_FINALLY(&markto, vcount); IGRAPH_CHECK(igraph_vit_create(graph, to, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); for (; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) { - VECTOR(markto)[ IGRAPH_VIT_GET(vit) ] = true; + IGRAPH_BIT_SET(markto, IGRAPH_VIT_GET(vit)); } igraph_vit_destroy(&vit); IGRAPH_FINALLY_CLEAN(1); } - IGRAPH_VECTOR_BOOL_INIT_FINALLY(&added, no_nodes); + IGRAPH_BITSET_INIT_FINALLY(&added, vcount); IGRAPH_VECTOR_INT_INIT_FINALLY(&stack, 100); IGRAPH_VECTOR_INT_INIT_FINALLY(&dist, 100); IGRAPH_CHECK(igraph_lazy_adjlist_init( graph, &adjlist, mode, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE )); IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist); - IGRAPH_VECTOR_INT_INIT_FINALLY(&nptr, no_nodes); - - igraph_vector_int_clear(res); + IGRAPH_VECTOR_INT_INIT_FINALLY(&nptr, vcount); igraph_vector_int_clear(&stack); igraph_vector_int_clear(&dist); - igraph_vector_int_push_back(&stack, from); - igraph_vector_int_push_back(&dist, 0); - VECTOR(added)[from] = true; + igraph_vector_int_push_back(&stack, from); /* reserved enough for initial push */ + igraph_vector_int_push_back(&dist, 0); /* reserved enough for initial push */ + IGRAPH_BIT_SET(added, from); while (!igraph_vector_int_empty(&stack)) { - igraph_integer_t act = igraph_vector_int_tail(&stack); - igraph_integer_t curdist = igraph_vector_int_tail(&dist); - igraph_vector_int_t *neis = igraph_lazy_adjlist_get(&adjlist, act); - igraph_integer_t n; - igraph_integer_t *ptr = igraph_vector_int_get_ptr(&nptr, act); - igraph_bool_t any; - igraph_bool_t within_dist; - igraph_integer_t nei; + const igraph_int_t act = igraph_vector_int_tail(&stack); + const igraph_int_t curdist = igraph_vector_int_tail(&dist); + const igraph_vector_int_t *neis = igraph_lazy_adjlist_get(&adjlist, act); IGRAPH_CHECK_OOM(neis, "Failed to query neighbors."); - n = igraph_vector_int_size(neis); + const igraph_int_t n = igraph_vector_int_size(neis); + igraph_int_t *ptr = igraph_vector_int_get_ptr(&nptr, act); + igraph_bool_t any; + igraph_bool_t within_dist; + igraph_int_t nei; - within_dist = (curdist < cutoff || cutoff < 0); + within_dist = (curdist < maxlen || maxlen < 0); if (within_dist) { /* Search for a neighbor that was not yet visited */ any = false; while (!any && (*ptr) < n) { nei = VECTOR(*neis)[(*ptr)]; - any = !VECTOR(added)[nei]; + any = !IGRAPH_BIT_TEST(added, nei); (*ptr) ++; } } @@ -134,17 +152,21 @@ igraph_error_t igraph_get_all_simple_paths(const igraph_t *graph, /* There is such a neighbor, add it */ IGRAPH_CHECK(igraph_vector_int_push_back(&stack, nei)); IGRAPH_CHECK(igraph_vector_int_push_back(&dist, curdist + 1)); - VECTOR(added)[nei] = true; + IGRAPH_BIT_SET(added, nei); /* Add to results */ - if (toall || VECTOR(markto)[nei]) { - IGRAPH_CHECK(igraph_vector_int_append(res, &stack)); - IGRAPH_CHECK(igraph_vector_int_push_back(res, -1)); + if (toall || IGRAPH_BIT_TEST(markto, nei)) { + if (curdist + 1 >= minlen) { + IGRAPH_CHECK(igraph_vector_int_list_push_back_copy(res, &stack)); + if (max_results >= 0 && igraph_vector_int_list_size(res) == max_results) { + break; + } + } } } else { /* There is no such neighbor, finished with the subtree */ - igraph_integer_t up = igraph_vector_int_pop_back(&stack); + igraph_int_t up = igraph_vector_int_pop_back(&stack); igraph_vector_int_pop_back(&dist); - VECTOR(added)[up] = false; + IGRAPH_BIT_CLEAR(added, up); VECTOR(nptr)[up] = 0; } @@ -155,11 +177,11 @@ igraph_error_t igraph_get_all_simple_paths(const igraph_t *graph, igraph_lazy_adjlist_destroy(&adjlist); igraph_vector_int_destroy(&dist); igraph_vector_int_destroy(&stack); - igraph_vector_bool_destroy(&added); + igraph_bitset_destroy(&added); IGRAPH_FINALLY_CLEAN(5); if (!toall) { - igraph_vector_bool_destroy(&markto); + igraph_bitset_destroy(&markto); IGRAPH_FINALLY_CLEAN(1); } diff --git a/src/vendor/cigraph/src/paths/sparsifier.c b/src/vendor/cigraph/src/paths/sparsifier.c index fe0c23cd551..1d9a1405c31 100644 --- a/src/vendor/cigraph/src/paths/sparsifier.c +++ b/src/vendor/cigraph/src/paths/sparsifier.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -49,31 +49,31 @@ * one is O(|V|), while igraph_i_clean_lightest_edge_vector() is O(d) where d * is the degree of the vertex. */ -static igraph_error_t igraph_i_collect_lightest_edges_to_clusters( +static igraph_error_t collect_lightest_edges_to_clusters( const igraph_adjlist_t *adjlist, const igraph_inclist_t *inclist, const igraph_vector_t *weights, const igraph_vector_int_t *clustering, const igraph_bitset_t *is_cluster_sampled, - igraph_integer_t v, + igraph_int_t v, igraph_vector_int_t *lightest_eid, igraph_vector_t *lightest_weight, igraph_vector_int_t *dirty_vids, - igraph_integer_t *nearest_neighboring_sampled_cluster + igraph_int_t *nearest_neighboring_sampled_cluster ) { // This internal function gets the residual graph, the clustering, the sampled clustering and - // the vector and return the lightest edge to each neighboring cluster and the index of the lightest + // the vector and returns the lightest edge to each neighboring cluster and the index of the lightest // sampled cluster (if any) igraph_real_t lightest_weight_to_sampled = IGRAPH_INFINITY; - igraph_vector_int_t* adjacent_nodes = igraph_adjlist_get(adjlist, v); - igraph_vector_int_t* incident_edges = igraph_inclist_get(inclist, v); - igraph_integer_t i, nlen = igraph_vector_int_size(incident_edges); - - for (i = 0; i < nlen; i++) { - igraph_integer_t neighbor_node = VECTOR(*adjacent_nodes)[i]; - igraph_integer_t edge = VECTOR(*incident_edges)[i]; - igraph_integer_t neighbor_cluster = VECTOR(*clustering)[neighbor_node]; + const igraph_vector_int_t *adjacent_nodes = igraph_adjlist_get(adjlist, v); + const igraph_vector_int_t *incident_edges = igraph_inclist_get(inclist, v); + const igraph_int_t nlen = igraph_vector_int_size(incident_edges); + + for (igraph_int_t i = 0; i < nlen; i++) { + igraph_int_t neighbor_node = VECTOR(*adjacent_nodes)[i]; + igraph_int_t edge = VECTOR(*incident_edges)[i]; + igraph_int_t neighbor_cluster = VECTOR(*clustering)[neighbor_node]; igraph_real_t weight = weights ? VECTOR(*weights)[edge] : 1; // If the weight of the edge being considered is smaller than the weight @@ -100,14 +100,14 @@ static igraph_error_t igraph_i_collect_lightest_edges_to_clusters( return IGRAPH_SUCCESS; } -static void igraph_i_clear_lightest_edges_to_clusters( +static void clear_lightest_edges_to_clusters( igraph_vector_int_t *dirty_vids, igraph_vector_int_t *lightest_eid, igraph_vector_t *lightest_weight ) { - igraph_integer_t i, n = igraph_vector_int_size(dirty_vids); - for (i = 0; i < n; i++) { - igraph_integer_t vid = VECTOR(*dirty_vids)[i]; + const igraph_int_t n = igraph_vector_int_size(dirty_vids); + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t vid = VECTOR(*dirty_vids)[i]; VECTOR(*lightest_weight)[vid] = IGRAPH_INFINITY; VECTOR(*lightest_eid)[vid] = -1; } @@ -143,12 +143,7 @@ static void igraph_i_clear_lightest_edges_to_clusters( * graph object. * \param stretch The stretch factor \c t of the spanner. * \param weights The edge weights or \c NULL. - * - * \return Error code: - * \clist - * \cli IGRAPH_ENOMEM - * not enough memory for temporary data. - * \endclist + * \return Error code. * * Time complexity: The algorithm is a randomized Las Vegas algorithm. The expected * running time is O(km) where k is the value mentioned above and m is the number @@ -157,9 +152,9 @@ static void igraph_i_clear_lightest_edges_to_clusters( igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanner, igraph_real_t stretch, const igraph_vector_t *weights) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - const igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t i, j, v, nlen, neighbor, cluster; + const igraph_int_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t nlen, neighbor, cluster; igraph_real_t sample_prob, k = (stretch + 1) / 2, weight, lightest_sampled_weight; igraph_vector_int_t clustering, lightest_eid; igraph_vector_t lightest_weight; @@ -171,8 +166,8 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne igraph_vector_int_t *incident_edges; igraph_adjlist_t adjlist; igraph_inclist_t inclist; - igraph_integer_t edge; - igraph_integer_t index; + igraph_int_t edge; + igraph_int_t index; if (spanner == NULL) { return IGRAPH_SUCCESS; @@ -220,14 +215,14 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne // A mapping vector which indicates the neighboring edge with the smallest // weight for each cluster central, for a single vertex of interest. - // Preconditions needed by igraph_i_collect_lightest_edges_to_clusters() + // Preconditions needed by collect_lightest_edges_to_clusters() // are enforced here. IGRAPH_VECTOR_INT_INIT_FINALLY(&lightest_eid, no_of_nodes); igraph_vector_int_fill(&lightest_eid, -1); // A mapping vector which indicated the minimum weight to each neighboring // cluster, for a single vertex of interest. - // Preconditions needed by igraph_i_collect_lightest_edges_to_clusters() + // Preconditions needed by collect_lightest_edges_to_clusters() // are enforced here. IGRAPH_VECTOR_INIT_FINALLY(&lightest_weight, no_of_nodes); igraph_vector_fill(&lightest_weight, IGRAPH_INFINITY); @@ -239,37 +234,35 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne IGRAPH_BITSET_INIT_FINALLY(&is_cluster_sampled, no_of_nodes); IGRAPH_BITSET_INIT_FINALLY(&is_edge_in_spanner, no_of_edges); - // Temporary vector used by igraph_i_collect_lightest_edges_to_clusters() + // Temporary vector used by collect_lightest_edges_to_clusters() // to keep track of the nodes that it has written to IGRAPH_VECTOR_INT_INIT_FINALLY(&dirty_vids, 0); - sample_prob = pow(no_of_nodes, -1 / k); + sample_prob = pow((igraph_real_t) no_of_nodes, -1 / k); #define ADD_EDGE_TO_SPANNER \ - if (!IGRAPH_BIT_TEST(is_edge_in_spanner, edge)) { \ + do { if (!IGRAPH_BIT_TEST(is_edge_in_spanner, edge)) { \ IGRAPH_BIT_SET(is_edge_in_spanner, edge); \ IGRAPH_CHECK(igraph_vector_int_push_back(spanner, edge)); \ - } + } } while (0) igraph_vector_fill(&lightest_weight, IGRAPH_INFINITY); - for (i = 0; i < k - 1; i++) { + for (igraph_int_t i = 0; i < k - 1; i++) { IGRAPH_ALLOW_INTERRUPTION(); igraph_vector_int_fill(&new_clustering, -1); igraph_bitset_null(&is_cluster_sampled); // Step 1: sample cluster centers - RNG_BEGIN(); - for (j = 0; j < no_of_nodes; j++) { + for (igraph_int_t j = 0; j < no_of_nodes; j++) { if (VECTOR(clustering)[j] == j && RNG_UNIF01() < sample_prob) { IGRAPH_BIT_SET(is_cluster_sampled, j); } } - RNG_END(); // Step 2 and 3 - for (v = 0; v < no_of_nodes; v++) { + for (igraph_int_t v = 0; v < no_of_nodes; v++) { // If v is inside a cluster and the cluster of v is sampled, then continue cluster = VECTOR(clustering)[v]; if (cluster != -1 && IGRAPH_BIT_TEST(is_cluster_sampled, cluster)) { @@ -279,18 +272,18 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne // Step 2: find the lightest edge that connects vertex v to its // neighboring sampled clusters - igraph_integer_t nearest_neighboring_sampled_cluster = -1; - IGRAPH_CHECK(igraph_i_collect_lightest_edges_to_clusters( - &adjlist, - &inclist, - weights, - &clustering, - &is_cluster_sampled, - v, - &lightest_eid, - &lightest_weight, - &dirty_vids, - &nearest_neighboring_sampled_cluster + igraph_int_t nearest_neighboring_sampled_cluster = -1; + IGRAPH_CHECK(collect_lightest_edges_to_clusters( + &adjlist, + &inclist, + weights, + &clustering, + &is_cluster_sampled, + v, + &lightest_eid, + &lightest_weight, + &dirty_vids, + &nearest_neighboring_sampled_cluster )); // Step 3: add edges to spanner @@ -300,7 +293,7 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne // Add lightest edge which connects vertex v to each neighboring // cluster (none of which are sampled) - for (j = 0; j < no_of_nodes; j++) { + for (igraph_int_t j = 0; j < no_of_nodes; j++) { edge = VECTOR(lightest_eid)[j]; if (edge != -1) { ADD_EDGE_TO_SPANNER; @@ -313,7 +306,7 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne adjacent_vertices = igraph_adjlist_get(&adjlist, v); incident_edges = igraph_inclist_get(&inclist, v); nlen = igraph_vector_int_size(incident_edges); - for (j = 0; j < nlen; j++) { + for (igraph_int_t j = 0; j < nlen; j++) { neighbor = VECTOR(*adjacent_vertices)[j]; if (neighbor == v) { /* should not happen as we did not ask for loop edges in @@ -348,7 +341,7 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne VECTOR(new_clustering)[v] = nearest_neighboring_sampled_cluster; // Add to the spanner light edges with weight less than 'lightest_sampled_weight' - for (j = 0; j < no_of_nodes; j++) { + for (igraph_int_t j = 0; j < no_of_nodes; j++) { if (VECTOR(lightest_weight)[j] < lightest_sampled_weight) { edge = VECTOR(lightest_eid)[j]; ADD_EDGE_TO_SPANNER; @@ -359,7 +352,7 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne adjacent_vertices = igraph_adjlist_get(&adjlist, v); incident_edges = igraph_inclist_get(&inclist, v); nlen = igraph_vector_int_size(incident_edges); - for (j = 0; j < nlen; j++) { + for (igraph_int_t j = 0; j < nlen; j++) { neighbor = VECTOR(*adjacent_vertices)[j]; if (neighbor == v) { /* should not happen as we did not ask for loop edges in @@ -388,10 +381,10 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne } } - // We don't need lightest_eids and lightest_weights any more so + // We don't need lightest_eids and lightest_weights anymore so // clear them in O(d) time - igraph_i_clear_lightest_edges_to_clusters( - &dirty_vids, &lightest_eid, &lightest_weight + clear_lightest_edges_to_clusters( + &dirty_vids, &lightest_eid, &lightest_weight ); } @@ -399,11 +392,11 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne igraph_vector_int_update(&clustering, &new_clustering); /* reserved */ // Remove intra-cluster edges - for (v = 0; v < no_of_nodes; v++) { + for (igraph_int_t v = 0; v < no_of_nodes; v++) { adjacent_vertices = igraph_adjlist_get(&adjlist, v); incident_edges = igraph_inclist_get(&inclist, v); nlen = igraph_vector_int_size(incident_edges); - for (j = 0; j < nlen; j++) { + for (igraph_int_t j = 0; j < nlen; j++) { neighbor = VECTOR(*adjacent_vertices)[j]; edge = VECTOR(*incident_edges)[j]; @@ -422,27 +415,27 @@ igraph_error_t igraph_spanner(const igraph_t *graph, igraph_vector_int_t *spanne } // Phase 2: vertex_clustering joining - for (v = 0; v < no_of_nodes; v++) { + for (igraph_int_t v = 0; v < no_of_nodes; v++) { if (VECTOR(clustering)[v] != -1) { - IGRAPH_CHECK(igraph_i_collect_lightest_edges_to_clusters( - &adjlist, - &inclist, - weights, - &clustering, - /* is_cluster_sampled = */ NULL, - v, - &lightest_eid, - &lightest_weight, - &dirty_vids, - NULL + IGRAPH_CHECK(collect_lightest_edges_to_clusters( + &adjlist, + &inclist, + weights, + &clustering, + /* is_cluster_sampled = */ NULL, + v, + &lightest_eid, + &lightest_weight, + &dirty_vids, + NULL )); - for (j = 0; j < no_of_nodes; j++) { + for (igraph_int_t j = 0; j < no_of_nodes; j++) { edge = VECTOR(lightest_eid)[j]; if (edge != -1) { ADD_EDGE_TO_SPANNER; } } - igraph_i_clear_lightest_edges_to_clusters(&dirty_vids, &lightest_eid, &lightest_weight); + clear_lightest_edges_to_clusters(&dirty_vids, &lightest_eid, &lightest_weight); } } diff --git a/src/vendor/cigraph/src/paths/unweighted.c b/src/vendor/cigraph/src/paths/unweighted.c index 2bf3affafe7..ad691c0022b 100644 --- a/src/vendor/cigraph/src/paths/unweighted.c +++ b/src/vendor/cigraph/src/paths/unweighted.c @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. - Copyright (C) 2005-2021 The igraph development team + igraph library. + Copyright (C) 2005-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,18 +24,19 @@ #include "igraph_memory.h" #include "core/interruption.h" +#include "paths/paths_internal.h" /** * \ingroup structural * \function igraph_distances_cutoff * \brief Length of the shortest paths between vertices, with cutoff. * - * \experimental - * * This function is similar to \ref igraph_distances(), but * paths longer than \p cutoff will not be considered. * * \param graph The graph object. + * \param weights Optional edge weights. If \c NULL, the graph is considered + * unweighted, i.e. all edge weights are equal to 1. * \param res The result of the calculation, a matrix. A pointer to an * initialized matrix, to be more precise. The matrix will be * resized if needed. It will have the same @@ -62,8 +61,8 @@ * \endclist * \param cutoff The maximal length of paths that will be considered. * When the distance of two vertices is greater than this value, - * it will be returned as \c IGRAPH_INFINITY. Negative cutoffs are - * treated as infinity. + * it will be returned as \c IGRAPH_INFINITY. Negative cutoffs and + * \ref IGRAPH_UNLIMITED are treated as infinity. * \return Error code: * \clist * \cli IGRAPH_ENOMEM @@ -83,19 +82,39 @@ * * \example examples/simple/distances.c */ -igraph_error_t igraph_distances_cutoff(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t from, const igraph_vs_t to, - igraph_neimode_t mode, igraph_real_t cutoff) { +igraph_error_t igraph_distances_cutoff( + const igraph_t *graph, + const igraph_vector_t *weights, + igraph_matrix_t *res, + const igraph_vs_t from, const igraph_vs_t to, + igraph_neimode_t mode, + igraph_real_t cutoff) { + + if (weights == NULL) { + /* Unweighted distances */ + return igraph_i_distances_unweighted_cutoff(graph, res, from, to, mode, cutoff); + } else { + /* Dijkstra's algorithm; will return an error if there are negative weights */ + return igraph_distances_dijkstra_cutoff(graph, res, from, to, weights, mode, cutoff); + } +} + +igraph_error_t igraph_i_distances_unweighted_cutoff( + const igraph_t *graph, + igraph_matrix_t *res, + const igraph_vs_t from, const igraph_vs_t to, + igraph_neimode_t mode, + igraph_real_t cutoff) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_from, no_of_to; - igraph_integer_t *already_counted; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_from, no_of_to; + igraph_int_t *already_counted; igraph_adjlist_t adjlist; igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; igraph_vector_int_t *neis; igraph_bool_t all_to; - igraph_integer_t i, j; + igraph_int_t i, j; igraph_vit_t fromvit, tovit; igraph_vector_int_t indexv; @@ -111,7 +130,7 @@ igraph_error_t igraph_distances_cutoff(const igraph_t *graph, igraph_matrix_t *r IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); - already_counted = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + already_counted = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(already_counted, "Insufficient memory for graph distance calculation."); IGRAPH_FINALLY(igraph_free, already_counted); @@ -126,7 +145,7 @@ igraph_error_t igraph_distances_cutoff(const igraph_t *graph, igraph_matrix_t *r IGRAPH_FINALLY(igraph_vit_destroy, &tovit); no_of_to = IGRAPH_VIT_SIZE(tovit); for (i = 0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit)) { - igraph_integer_t v = IGRAPH_VIT_GET(tovit); + igraph_int_t v = IGRAPH_VIT_GET(tovit); if (VECTOR(indexv)[v]) { IGRAPH_ERROR("Target vertex list must not have any duplicates.", IGRAPH_EINVAL); @@ -141,7 +160,7 @@ igraph_error_t igraph_distances_cutoff(const igraph_t *graph, igraph_matrix_t *r for (IGRAPH_VIT_RESET(fromvit), i = 0; !IGRAPH_VIT_END(fromvit); IGRAPH_VIT_NEXT(fromvit), i++) { - igraph_integer_t reached = 0; + igraph_int_t reached = 0; IGRAPH_CHECK(igraph_dqueue_int_push(&q, IGRAPH_VIT_GET(fromvit))); IGRAPH_CHECK(igraph_dqueue_int_push(&q, 0)); already_counted[ IGRAPH_VIT_GET(fromvit) ] = i + 1; @@ -149,8 +168,8 @@ igraph_error_t igraph_distances_cutoff(const igraph_t *graph, igraph_matrix_t *r IGRAPH_ALLOW_INTERRUPTION(); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t act = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); + igraph_int_t act = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); if (cutoff >= 0 && actdist > cutoff) { continue; @@ -170,9 +189,9 @@ igraph_error_t igraph_distances_cutoff(const igraph_t *graph, igraph_matrix_t *r } neis = igraph_adjlist_get(&adjlist, act); - igraph_integer_t nei_count = igraph_vector_int_size(neis); + igraph_int_t nei_count = igraph_vector_int_size(neis); for (j = 0; j < nei_count; j++) { - igraph_integer_t neighbor = VECTOR(*neis)[j]; + igraph_int_t neighbor = VECTOR(*neis)[j]; if (already_counted[neighbor] == i + 1) { continue; } @@ -205,6 +224,8 @@ igraph_error_t igraph_distances_cutoff(const igraph_t *graph, igraph_matrix_t *r * \brief Length of the shortest paths between vertices. * * \param graph The graph object. + * \param weights Optional edge weights. If \c NULL, the graph is considered + * unweighted, i.e. all edge weights are 1. * \param res The result of the calculation, a matrix. A pointer to an * initialized matrix, to be more precise. The matrix will be * resized if needed. It will have the same @@ -249,24 +270,58 @@ igraph_error_t igraph_distances_cutoff(const igraph_t *graph, igraph_matrix_t *r * * \example examples/simple/distances.c */ -igraph_error_t igraph_distances(const igraph_t *graph, igraph_matrix_t *res, - const igraph_vs_t from, const igraph_vs_t to, - igraph_neimode_t mode) { - return igraph_distances_cutoff(graph, res, from, to, mode, -1); -} +igraph_error_t igraph_distances( + const igraph_t *graph, + const igraph_vector_t *weights, + igraph_matrix_t *res, + const igraph_vs_t from, const igraph_vs_t to, + igraph_neimode_t mode) { + + igraph_real_t vcount_real = igraph_vcount(graph); + igraph_real_t ecount_real = igraph_ecount(graph); + igraph_real_t ecount_threshold; + igraph_int_t from_size; + igraph_bool_t negative_weights = false; + + IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights)); + + if (!igraph_is_directed(graph)) { + mode = IGRAPH_ALL; + } -/** - * \function igraph_shortest_paths - * \brief Length of the shortest paths between vertices. - * - * \deprecated-by igraph_distances 0.10.0 - */ -igraph_error_t igraph_shortest_paths(const igraph_t *graph, - igraph_matrix_t *res, - const igraph_vs_t from, - const igraph_vs_t to, - igraph_neimode_t mode) { - return igraph_distances(graph, res, from, to, mode); + /* Edge count threshold for using Floyd-Warshall for all-to-all case. + * Based on experiments, this is faster than Dijkstra for densities + * above 0.1, provided that the graph has more than about 50 vertices. + * See also https://github.com/igraph/igraph/issues/2822 */ + ecount_threshold = vcount_real * vcount_real * 0.1; + if (ecount_threshold < 250) ecount_threshold = 250; + + if (!weights) { + /* Unweighted case */ + return igraph_i_distances_unweighted_cutoff(graph, res, from, to, mode, -1); + } else if (igraph_vs_is_all(&from) && ecount_real > ecount_threshold) { + /* All-to-all distances with dense graph */ + return igraph_distances_floyd_warshall(graph, res, from, to, weights, mode, IGRAPH_FLOYD_WARSHALL_AUTOMATIC); + } else if (!negative_weights) { + /* Non-negative weights: use Dijkstra's algorithm. */ + return igraph_i_distances_dijkstra_cutoff(graph, res, from, to, weights, mode, -1); + } else { + /* Negative weights: use Bellman-Ford or Johnson's algorithm. + * + * In the undirected case we always use Bellman-Ford. Normally, a negative weight + * undirected edge triggers an error as it is effectively a negative cycle. + * However, with Bellman-Ford the negative edge might be avoided if it is + * not reachable from the 'from' vertices. In cotrast, Johnson will always raise + * an error. + */ + if (mode != IGRAPH_ALL) { + IGRAPH_CHECK(igraph_vs_size(graph, &from, &from_size)); + if (from_size > 100) { + return igraph_i_distances_johnson(graph, res, from, to, weights, mode); + } + } + return igraph_i_distances_bellman_ford(graph, res, from, to, weights, mode); + } } /** @@ -280,6 +335,8 @@ igraph_error_t igraph_shortest_paths(const igraph_t *graph, * to find \em all shortest paths. * * \param graph The graph object. + * \param weights Optional edge weights. If \c NULL, the graph is considered + * unweighted, i.e. all edge weights are equal to 1. * \param vertices The result, the IDs of the vertices along the paths. * This is a list of integer vectors where each element is an * \ref igraph_vector_int_t object. The list will be resized as needed. @@ -344,28 +401,53 @@ igraph_error_t igraph_shortest_paths(const igraph_t *graph, * * \example examples/simple/igraph_get_shortest_paths.c */ -igraph_error_t igraph_get_shortest_paths(const igraph_t *graph, - igraph_vector_int_list_t *vertices, - igraph_vector_int_list_t *edges, - igraph_integer_t from, const igraph_vs_t to, - igraph_neimode_t mode, - igraph_vector_int_t *parents, - igraph_vector_int_t *inbound_edges) { +igraph_error_t igraph_get_shortest_paths( + const igraph_t *graph, + const igraph_vector_t *weights, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_int_t from, const igraph_vs_t to, + igraph_neimode_t mode, + igraph_vector_int_t *parents, + igraph_vector_int_t *inbound_edges) { + + igraph_bool_t negative_weights; + IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights)); + + if (weights == NULL) { + return igraph_i_get_shortest_paths_unweighted(graph, vertices, edges, from, to, mode, parents, inbound_edges); + } else if (!negative_weights) { + /* Dijkstra's algorithm */ + return igraph_i_get_shortest_paths_dijkstra(graph, vertices, edges, from, to, weights, mode, parents, inbound_edges); + } else { + /* Negative weights; will use Bellman-Ford algorithm */ + return igraph_i_get_shortest_paths_bellman_ford(graph, vertices, edges, from, to, weights, mode, parents, inbound_edges); + } +} + +igraph_error_t igraph_i_get_shortest_paths_unweighted( + const igraph_t *graph, + igraph_vector_int_list_t *vertices, + igraph_vector_int_list_t *edges, + igraph_int_t from, igraph_vs_t to, + igraph_neimode_t mode, + igraph_vector_int_t *parents, + igraph_vector_int_t *inbound_edges) { /* TODO: use inclist_t if to is long (longer than 1?) */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t *parent_eids; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t *parent_eids; igraph_dqueue_int_t q = IGRAPH_DQUEUE_NULL; - igraph_integer_t i, j, vsize; + igraph_int_t i, j, vsize; igraph_vector_int_t tmp = IGRAPH_VECTOR_NULL; igraph_vit_t vit; - igraph_integer_t to_reach; - igraph_integer_t reached = 0; + igraph_int_t to_reach; + igraph_int_t reached = 0; if (from < 0 || from >= no_of_nodes) { IGRAPH_ERROR("Index of source vertex is out of range.", IGRAPH_EINVVID); @@ -385,7 +467,7 @@ igraph_error_t igraph_get_shortest_paths(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_int_list_resize(edges, IGRAPH_VIT_SIZE(vit))); } - parent_eids = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + parent_eids = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(parent_eids, "Insufficient memory for shortest path calculation."); IGRAPH_FINALLY(igraph_free, parent_eids); @@ -423,13 +505,13 @@ igraph_error_t igraph_get_shortest_paths(const igraph_t *graph, parent_eids[ from ] = 1; while (!igraph_dqueue_int_empty(&q) && reached < to_reach) { - igraph_integer_t act = igraph_dqueue_int_pop(&q) - 1; + igraph_int_t act = igraph_dqueue_int_pop(&q) - 1; - IGRAPH_CHECK(igraph_incident(graph, &tmp, act, mode)); + IGRAPH_CHECK(igraph_incident(graph, &tmp, act, mode, IGRAPH_LOOPS)); vsize = igraph_vector_int_size(&tmp); for (j = 0; j < vsize; j++) { - igraph_integer_t edge = VECTOR(tmp)[j]; - igraph_integer_t neighbor = IGRAPH_OTHER(graph, edge, act); + igraph_int_t edge = VECTOR(tmp)[j]; + igraph_int_t neighbor = IGRAPH_OTHER(graph, edge, act); if (parent_eids[neighbor] > 0) { continue; } else if (parent_eids[neighbor] < 0) { @@ -482,7 +564,7 @@ igraph_error_t igraph_get_shortest_paths(const igraph_t *graph, for (IGRAPH_VIT_RESET(vit), j = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), j++) { - igraph_integer_t node = IGRAPH_VIT_GET(vit); + igraph_int_t node = IGRAPH_VIT_GET(vit); igraph_vector_int_t *vvec = 0, *evec = 0; if (vertices) { vvec = igraph_vector_int_list_get_ptr(vertices, j); @@ -496,9 +578,9 @@ igraph_error_t igraph_get_shortest_paths(const igraph_t *graph, IGRAPH_ALLOW_INTERRUPTION(); if (parent_eids[node] > 0) { - igraph_integer_t act = node; - igraph_integer_t size = 0; - igraph_integer_t edge; + igraph_int_t act = node; + igraph_int_t size = 0; + igraph_int_t edge; while (parent_eids[act] > 1) { size++; edge = parent_eids[act] - 2; @@ -552,6 +634,8 @@ igraph_error_t igraph_get_shortest_paths(const igraph_t *graph, * \param graph The input graph, it can be directed or * undirected. Directed paths are considered in directed * graphs. + * \param weights Optional edge weights. If \c NULL, the graph is considered + * unweighted, i.e. all edge weights are equal to 1. * \param vertices Pointer to an initialized vector or a null * pointer. If not a null pointer, then the vertex IDs along * the path are stored here, including the source and target @@ -575,13 +659,13 @@ igraph_error_t igraph_get_shortest_paths(const igraph_t *graph, * \sa \ref igraph_get_shortest_paths() for the version with more target * vertices. */ - -igraph_error_t igraph_get_shortest_path(const igraph_t *graph, - igraph_vector_int_t *vertices, - igraph_vector_int_t *edges, - igraph_integer_t from, - igraph_integer_t to, - igraph_neimode_t mode) { +igraph_error_t igraph_get_shortest_path( + const igraph_t *graph, + const igraph_vector_t *weights, + igraph_vector_int_t *vertices, + igraph_vector_int_t *edges, + igraph_int_t from, igraph_int_t to, + igraph_neimode_t mode) { igraph_vector_int_list_t vertices2, *vp = &vertices2; igraph_vector_int_list_t edges2, *ep = &edges2; @@ -599,18 +683,18 @@ igraph_error_t igraph_get_shortest_path(const igraph_t *graph, ep = NULL; } - IGRAPH_CHECK(igraph_get_shortest_paths(graph, vp, ep, from, + IGRAPH_CHECK(igraph_get_shortest_paths(graph, weights, vp, ep, from, igraph_vss_1(to), mode, NULL, NULL)); /* We use the constant time vector_swap() instead of the linear-time vector_update() to move the result to the output parameter. */ if (edges) { - IGRAPH_CHECK(igraph_vector_int_swap(edges, igraph_vector_int_list_get_ptr(&edges2, 0))); + igraph_vector_int_swap(edges, igraph_vector_int_list_get_ptr(&edges2, 0)); igraph_vector_int_list_destroy(&edges2); IGRAPH_FINALLY_CLEAN(1); } if (vertices) { - IGRAPH_CHECK(igraph_vector_int_swap(vertices, igraph_vector_int_list_get_ptr(&vertices2, 0))); + igraph_vector_int_swap(vertices, igraph_vector_int_list_get_ptr(&vertices2, 0)); igraph_vector_int_list_destroy(&vertices2); IGRAPH_FINALLY_CLEAN(1); } diff --git a/src/vendor/cigraph/src/paths/voronoi.c b/src/vendor/cigraph/src/paths/voronoi.c index 146a556daad..4646b281def 100644 --- a/src/vendor/cigraph/src/paths/voronoi.c +++ b/src/vendor/cigraph/src/paths/voronoi.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -35,8 +35,8 @@ static igraph_error_t igraph_i_voronoi( igraph_neimode_t mode, igraph_voronoi_tiebreaker_t tiebreaker) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_generators = igraph_vector_int_size(generators); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_generators = igraph_vector_int_size(generators); igraph_adjlist_t al; igraph_dqueue_int_t q; @@ -55,7 +55,6 @@ static igraph_error_t igraph_i_voronoi( if (tiebreaker == IGRAPH_VORONOI_RANDOM) { IGRAPH_VECTOR_INT_INIT_FINALLY(&tie_count, no_of_nodes); - RNG_BEGIN(); } IGRAPH_CHECK(igraph_vector_int_resize(membership, no_of_nodes)); @@ -70,8 +69,8 @@ static igraph_error_t igraph_i_voronoi( * is shorter than what was recorded so far in 'mindist', we update 'mindist' and * assign that vertex to the current generator. */ - for (igraph_integer_t i=0; i < no_of_generators; i++) { - igraph_integer_t g = VECTOR(*generators)[i]; + for (igraph_int_t i=0; i < no_of_generators; i++) { + igraph_int_t g = VECTOR(*generators)[i]; IGRAPH_ALLOW_INTERRUPTION(); @@ -84,10 +83,10 @@ static igraph_error_t igraph_i_voronoi( IGRAPH_CHECK(igraph_dqueue_int_push(&q, 0)); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t vid = igraph_dqueue_int_pop(&q); - igraph_integer_t dist = igraph_dqueue_int_pop(&q); + igraph_int_t vid = igraph_dqueue_int_pop(&q); + igraph_int_t dist = igraph_dqueue_int_pop(&q); - /* Attention! This must be igraph_real_t, not igraph_integer_t + /* Attention! This must be igraph_real_t, not igraph_int_t * because later it will be compared with another igraph_real_t * whose value may be infinite. */ igraph_real_t md = VECTOR(*mindist)[vid]; @@ -129,9 +128,9 @@ static igraph_error_t igraph_i_voronoi( } igraph_vector_int_t *neis = igraph_adjlist_get(&al, vid); - igraph_integer_t nei_count = igraph_vector_int_size(neis); - for (igraph_integer_t j = 0; j < nei_count; j++) { - igraph_integer_t neighbor = VECTOR(*neis)[j]; + igraph_int_t nei_count = igraph_vector_int_size(neis); + for (igraph_int_t j = 0; j < nei_count; j++) { + igraph_int_t neighbor = VECTOR(*neis)[j]; if (VECTOR(already_counted)[neighbor] == i + 1) { continue; } @@ -143,7 +142,6 @@ static igraph_error_t igraph_i_voronoi( } if (tiebreaker == IGRAPH_VORONOI_RANDOM) { - RNG_END(); igraph_vector_int_destroy(&tie_count); IGRAPH_FINALLY_CLEAN(1); } @@ -166,9 +164,9 @@ static igraph_error_t igraph_i_voronoi_dijkstra( igraph_neimode_t mode, igraph_voronoi_tiebreaker_t tiebreaker) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_generators = igraph_vector_int_size(generators); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_generators = igraph_vector_int_size(generators); igraph_inclist_t il; igraph_2wheap_t q; @@ -199,7 +197,6 @@ static igraph_error_t igraph_i_voronoi_dijkstra( if (tiebreaker == IGRAPH_VORONOI_RANDOM) { IGRAPH_VECTOR_INT_INIT_FINALLY(&tie_count, no_of_nodes); - RNG_BEGIN(); } IGRAPH_CHECK(igraph_vector_int_resize(membership, no_of_nodes)); @@ -214,8 +211,8 @@ static igraph_error_t igraph_i_voronoi_dijkstra( * is shorter than what was recorded so far in 'mindist', we update 'mindist' and * assign that vertex to the current generator. */ - for (igraph_integer_t i=0; i < no_of_generators; i++) { - igraph_integer_t g = VECTOR(*generators)[i]; + for (igraph_int_t i=0; i < no_of_generators; i++) { + igraph_int_t g = VECTOR(*generators)[i]; /* Weighted shortest path implementation using Dijkstra's algorithm */ @@ -229,7 +226,7 @@ static igraph_error_t igraph_i_voronoi_dijkstra( IGRAPH_CHECK(igraph_2wheap_push_with_index(&q, g, -0.0)); while (!igraph_2wheap_empty(&q)) { - igraph_integer_t vid = igraph_2wheap_max_index(&q); + igraph_int_t vid = igraph_2wheap_max_index(&q); igraph_real_t dist = -igraph_2wheap_deactivate_max(&q); igraph_real_t md = VECTOR(*mindist)[vid]; @@ -272,9 +269,9 @@ static igraph_error_t igraph_i_voronoi_dijkstra( } igraph_vector_int_t *inc_edges = igraph_inclist_get(&il, vid); - igraph_integer_t inc_count = igraph_vector_int_size(inc_edges); - for (igraph_integer_t j=0; j < inc_count; j++) { - igraph_integer_t edge = VECTOR(*inc_edges)[j]; + igraph_int_t inc_count = igraph_vector_int_size(inc_edges); + for (igraph_int_t j=0; j < inc_count; j++) { + igraph_int_t edge = VECTOR(*inc_edges)[j]; igraph_real_t weight = VECTOR(*weights)[edge]; /* Optimization: do not follow infinite-weight edges. */ @@ -282,7 +279,7 @@ static igraph_error_t igraph_i_voronoi_dijkstra( continue; } - igraph_integer_t to = IGRAPH_OTHER(graph, edge, vid); + igraph_int_t to = IGRAPH_OTHER(graph, edge, vid); igraph_real_t altdist = dist + weight; if (! igraph_2wheap_has_elem(&q, to)) { @@ -300,7 +297,6 @@ static igraph_error_t igraph_i_voronoi_dijkstra( } if (tiebreaker == IGRAPH_VORONOI_RANDOM) { - RNG_END(); igraph_vector_int_destroy(&tie_count); IGRAPH_FINALLY_CLEAN(1); } @@ -317,8 +313,6 @@ static igraph_error_t igraph_i_voronoi_dijkstra( * \function igraph_voronoi * \brief Voronoi partitioning of a graph. * - * \experimental - * * To obtain a Voronoi partitioning of a graph, we start with a set of generator * vertices, which will define the partitions. Each vertex is assigned to the generator * vertex from (or to) which it is closest. @@ -371,7 +365,7 @@ igraph_error_t igraph_voronoi( igraph_neimode_t mode, igraph_voronoi_tiebreaker_t tiebreaker) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t *pmembership; igraph_vector_int_t imembership; igraph_vector_t *pdistances; diff --git a/src/vendor/cigraph/src/paths/widest_paths.c b/src/vendor/cigraph/src/paths/widest_paths.c index 075076ee37f..02dab7ed53c 100644 --- a/src/vendor/cigraph/src/paths/widest_paths.c +++ b/src/vendor/cigraph/src/paths/widest_paths.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -104,7 +102,7 @@ igraph_error_t igraph_get_widest_paths(const igraph_t *graph, igraph_vector_int_list_t *vertices, igraph_vector_int_list_t *edges, - igraph_integer_t from, + igraph_int_t from, igraph_vs_t to, const igraph_vector_t *weights, igraph_neimode_t mode, @@ -126,15 +124,15 @@ igraph_error_t igraph_get_widest_paths(const igraph_t *graph, path from a vertex to a vertex it cannot reach as negative infinity. */ - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_vit_t vit; igraph_2wheap_t Q; igraph_lazy_inclist_t inclist; igraph_vector_t widths; - igraph_integer_t *parent_eids; + igraph_int_t *parent_eids; bool *is_target; - igraph_integer_t i, to_reach; + igraph_int_t i, to_reach; if (!weights) { IGRAPH_ERROR("Weight vector is required.", IGRAPH_EINVAL); @@ -168,7 +166,7 @@ igraph_error_t igraph_get_widest_paths(const igraph_t *graph, IGRAPH_VECTOR_INIT_FINALLY(&widths, vcount); igraph_vector_fill(&widths, -IGRAPH_INFINITY); - parent_eids = IGRAPH_CALLOC(vcount, igraph_integer_t); + parent_eids = IGRAPH_CALLOC(vcount, igraph_int_t); IGRAPH_CHECK_OOM(parent_eids, "Insufficient memory for widest paths."); IGRAPH_FINALLY(igraph_free, parent_eids); @@ -191,7 +189,7 @@ igraph_error_t igraph_get_widest_paths(const igraph_t *graph, igraph_2wheap_push_with_index(&Q, from, IGRAPH_INFINITY); while (!igraph_2wheap_empty(&Q) && to_reach > 0) { - igraph_integer_t nlen, maxnei = igraph_2wheap_max_index(&Q); + igraph_int_t nlen, maxnei = igraph_2wheap_max_index(&Q); igraph_real_t maxwidth = igraph_2wheap_delete_max(&Q); igraph_vector_int_t *neis; @@ -207,8 +205,8 @@ igraph_error_t igraph_get_widest_paths(const igraph_t *graph, IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); nlen = igraph_vector_int_size(neis); for (i = 0; i < nlen; i++) { - igraph_integer_t edge = VECTOR(*neis)[i]; - igraph_integer_t tto = IGRAPH_OTHER(graph, edge, maxnei); + igraph_int_t edge = VECTOR(*neis)[i]; + igraph_int_t tto = IGRAPH_OTHER(graph, edge, maxnei); igraph_real_t edgewidth = VECTOR(*weights)[edge]; igraph_real_t altwidth = maxwidth < edgewidth ? maxwidth : edgewidth; igraph_real_t curwidth = VECTOR(widths)[tto]; @@ -268,8 +266,8 @@ igraph_error_t igraph_get_widest_paths(const igraph_t *graph, /* Reconstruct the widest paths based on vertex and/or edge IDs */ if (vertices || edges) { for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t v = IGRAPH_VIT_GET(vit); - igraph_integer_t size, act, edge; + igraph_int_t v = IGRAPH_VIT_GET(vit); + igraph_int_t size, act, edge; igraph_vector_int_t *vvec = 0, *evec = 0; if (vertices) { @@ -367,8 +365,8 @@ igraph_error_t igraph_get_widest_paths(const igraph_t *graph, igraph_error_t igraph_get_widest_path(const igraph_t *graph, igraph_vector_int_t *vertices, igraph_vector_int_t *edges, - igraph_integer_t from, - igraph_integer_t to, + igraph_int_t from, + igraph_int_t to, const igraph_vector_t *weights, igraph_neimode_t mode) { @@ -468,8 +466,8 @@ igraph_error_t igraph_widest_path_widths_floyd_warshall(const igraph_t *graph, path from a vertex to a vertex it cannot reach as negative infinity. */ - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_bool_t in = false, out = false; if (! weights) { @@ -507,13 +505,13 @@ igraph_error_t igraph_widest_path_widths_floyd_warshall(const igraph_t *graph, /* Fill out adjacency matrix */ IGRAPH_CHECK(igraph_matrix_resize(res, vcount, vcount)); igraph_matrix_fill(res, -IGRAPH_INFINITY); - for (igraph_integer_t i=0; i < vcount; i++) { + for (igraph_int_t i=0; i < vcount; i++) { MATRIX(*res, i, i) = IGRAPH_INFINITY; } - for (igraph_integer_t edge=0; edge < ecount; edge++) { - igraph_integer_t from = IGRAPH_FROM(graph, edge); - igraph_integer_t to = IGRAPH_TO(graph, edge); + for (igraph_int_t edge=0; edge < ecount; edge++) { + igraph_int_t from = IGRAPH_FROM(graph, edge); + igraph_int_t to = IGRAPH_TO(graph, edge); igraph_real_t w = VECTOR(*weights)[edge]; if (w == -IGRAPH_INFINITY) { @@ -526,15 +524,15 @@ igraph_error_t igraph_widest_path_widths_floyd_warshall(const igraph_t *graph, } /* Run modified Floyd Warshall */ - for (igraph_integer_t k = 0; k < vcount; k++) { + for (igraph_int_t k = 0; k < vcount; k++) { /* Iterate in column-major order for better performance */ - for (igraph_integer_t j = 0; j < vcount; j++) { + for (igraph_int_t j = 0; j < vcount; j++) { igraph_real_t width_kj = MATRIX(*res, k, j); if (j == k || width_kj == -IGRAPH_INFINITY) continue; IGRAPH_ALLOW_INTERRUPTION(); - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { if (i == j || i == k) continue; /* alternative_width := min(A(i,k), A(k,j)) @@ -617,13 +615,13 @@ igraph_error_t igraph_widest_path_widths_dijkstra(const igraph_t *graph, path from a vertex to a vertex it cannot reach as negative infinity. */ - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_2wheap_t Q; igraph_vit_t fromvit, tovit; - igraph_integer_t no_of_from, no_of_to; + igraph_int_t no_of_from, no_of_to; igraph_lazy_inclist_t inclist; - igraph_integer_t i, j; + igraph_int_t i, j; igraph_bool_t all_to; igraph_vector_int_t indexv; @@ -659,7 +657,7 @@ igraph_error_t igraph_widest_path_widths_dijkstra(const igraph_t *graph, IGRAPH_FINALLY(igraph_vit_destroy, &tovit); no_of_to = IGRAPH_VIT_SIZE(tovit); for (i = 0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit)) { - igraph_integer_t v = IGRAPH_VIT_GET(tovit); + igraph_int_t v = IGRAPH_VIT_GET(tovit); if (VECTOR(indexv)[v]) { IGRAPH_ERROR("Duplicate vertices in target vertex set, this is not allowed.", IGRAPH_EINVAL); @@ -675,16 +673,16 @@ igraph_error_t igraph_widest_path_widths_dijkstra(const igraph_t *graph, !IGRAPH_VIT_END(fromvit); IGRAPH_VIT_NEXT(fromvit), i++) { - igraph_integer_t reached = 0; - igraph_integer_t source = IGRAPH_VIT_GET(fromvit); + igraph_int_t reached = 0; + igraph_int_t source = IGRAPH_VIT_GET(fromvit); igraph_2wheap_clear(&Q); igraph_2wheap_push_with_index(&Q, source, IGRAPH_INFINITY); while (!igraph_2wheap_empty(&Q)) { - igraph_integer_t maxnei = igraph_2wheap_max_index(&Q); + igraph_int_t maxnei = igraph_2wheap_max_index(&Q); igraph_real_t maxwidth = igraph_2wheap_deactivate_max(&Q); igraph_vector_int_t *neis; - igraph_integer_t nlen; + igraph_int_t nlen; IGRAPH_ALLOW_INTERRUPTION(); @@ -706,8 +704,8 @@ igraph_error_t igraph_widest_path_widths_dijkstra(const igraph_t *graph, IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); nlen = igraph_vector_int_size(neis); for (j = 0; j < nlen; j++) { - igraph_integer_t edge = VECTOR(*neis)[j]; - igraph_integer_t tto = IGRAPH_OTHER(graph, edge, maxnei); + igraph_int_t edge = VECTOR(*neis)[j]; + igraph_int_t tto = IGRAPH_OTHER(graph, edge, maxnei); igraph_real_t edgewidth = VECTOR(*weights)[edge]; igraph_real_t altwidth = maxwidth < edgewidth ? maxwidth : edgewidth; igraph_bool_t active = igraph_2wheap_has_active(&Q, tto); diff --git a/src/vendor/cigraph/src/properties/basic_properties.c b/src/vendor/cigraph/src/properties/basic_properties.c index af296de1456..d6e457b94f9 100644 --- a/src/vendor/cigraph/src/properties/basic_properties.c +++ b/src/vendor/cigraph/src/properties/basic_properties.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -44,48 +42,70 @@ * \p loops parameter. * * - * Note that density is ill-defined for graphs which have multiple edges - * between some pairs of vertices. Consider calling \ref igraph_simplify() - * on such graphs. This function does not check whether the graph has - * parallel edges. The result it returns for such graphs is not meaningful. + * The classic definition of the density is formulated for unweighted + * graphs without multi-edges. This function allows multigraphs and + * weighted graphs as well. In this case, it computes the ratio of the + * total edge weight to the largest possible number of adjacent vertex + * pairs the graph could have. This value may be larger than 1. + * + * + * If you need the density concept for simple graphs, make sure to + * eliminate any multi-edges appropriately. This can be done using + * \ref igraph_simplify(). * * \param graph The input graph object. It must not have parallel edges. * \param res Pointer to a real number, the result will be stored here. + * \param weights Vector of edge weights. Pass \c NULL to to perform + * an unweighted density calculation. * \param loops Boolean constant, whether to include self-loops in the * calculation. If this constant is \c true then * loop edges are thought to be possible in the graph (this does not * necessarily mean that the graph really contains any loops). If * this is \c false then the result is only correct if the graph does not - * contain loops. + * contain loops. This function does not check if loops are actually + * present. * \return Error code. * * Time complexity: O(1). */ -igraph_error_t igraph_density(const igraph_t *graph, igraph_real_t *res, - igraph_bool_t loops) { - - igraph_real_t no_of_nodes = (igraph_real_t) igraph_vcount(graph); - igraph_real_t no_of_edges = (igraph_real_t) igraph_ecount(graph); - igraph_bool_t directed = igraph_is_directed(graph); - - if (no_of_nodes == 0) { +igraph_error_t igraph_density( + const igraph_t *graph, + const igraph_vector_t *weights, + igraph_real_t *res, + igraph_bool_t loops) { + + const igraph_bool_t directed = igraph_is_directed(graph); + const igraph_int_t ecount = igraph_ecount(graph); + const igraph_real_t vcount = (igraph_real_t) igraph_vcount(graph); /* note real type */ + igraph_real_t total_weight; + + if (vcount == 0) { *res = IGRAPH_NAN; return IGRAPH_SUCCESS; } + if (weights) { + if (igraph_vector_size(weights) != ecount) { + IGRAPH_ERROR("Weight vector length does not match edge count.", IGRAPH_EINVAL); + } + total_weight = igraph_vector_sum(weights); + } else { + total_weight = ecount; + } + if (!loops) { - if (no_of_nodes == 1) { + if (vcount == 1) { *res = IGRAPH_NAN; } else if (directed) { - *res = no_of_edges / no_of_nodes / (no_of_nodes - 1); + *res = total_weight / vcount / (vcount - 1); } else { - *res = no_of_edges / no_of_nodes * 2.0 / (no_of_nodes - 1); + *res = total_weight / vcount * 2.0 / (vcount - 1); } } else { if (directed) { - *res = no_of_edges / no_of_nodes / no_of_nodes; + *res = total_weight / vcount / vcount; } else { - *res = no_of_edges / no_of_nodes * 2.0 / (no_of_nodes + 1); + *res = total_weight / vcount * 2.0 / (vcount + 1); } } @@ -96,8 +116,6 @@ igraph_error_t igraph_density(const igraph_t *graph, igraph_real_t *res, * \function igraph_mean_degree * \brief The mean degree of a graph. * - * \experimental - * * This is a convenience function that computes the average of all vertex * degrees. In directed graphs, the average of out-degrees and in-degrees is * the same; this is the number that is returned. For the null graph, which @@ -114,8 +132,8 @@ igraph_error_t igraph_density(const igraph_t *graph, igraph_real_t *res, igraph_error_t igraph_mean_degree(const igraph_t *graph, igraph_real_t *res, igraph_bool_t loops) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t directed = igraph_is_directed(graph); if (no_of_nodes == 0) { @@ -124,7 +142,7 @@ igraph_error_t igraph_mean_degree(const igraph_t *graph, igraph_real_t *res, } if (! loops) { - igraph_integer_t loop_count; + igraph_int_t loop_count; IGRAPH_CHECK(igraph_count_loops(graph, &loop_count)); no_of_edges -= loop_count; } @@ -175,8 +193,8 @@ igraph_error_t igraph_mean_degree(const igraph_t *graph, igraph_real_t *res, igraph_error_t igraph_diversity(const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_t *res, const igraph_vs_t vids) { - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t k, i; + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t k, i; igraph_vector_int_t incident; igraph_bool_t has_multiple; igraph_vit_t vit; @@ -217,9 +235,9 @@ igraph_error_t igraph_diversity(const igraph_t *graph, const igraph_vector_t *we for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) { igraph_real_t d; - igraph_integer_t v = IGRAPH_VIT_GET(vit); + igraph_int_t v = IGRAPH_VIT_GET(vit); - IGRAPH_CHECK(igraph_incident(graph, &incident, v, /*mode=*/ IGRAPH_ALL)); + IGRAPH_CHECK(igraph_incident(graph, &incident, v, IGRAPH_ALL, IGRAPH_LOOPS)); k = igraph_vector_int_size(&incident); /* degree */ /* @@ -308,9 +326,9 @@ igraph_error_t igraph_reciprocity(const igraph_t *graph, igraph_real_t *res, igraph_bool_t ignore_loops, igraph_reciprocity_t mode) { - igraph_integer_t nonrec = 0, rec = 0, loops = 0; + igraph_int_t nonrec = 0, rec = 0, loops = 0; igraph_vector_int_t inneis, outneis; - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); if (mode != IGRAPH_RECIPROCITY_DEFAULT && mode != IGRAPH_RECIPROCITY_RATIO) { @@ -326,10 +344,14 @@ igraph_error_t igraph_reciprocity(const igraph_t *graph, igraph_real_t *res, IGRAPH_VECTOR_INT_INIT_FINALLY(&inneis, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&outneis, 0); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - igraph_integer_t ip, op, indeg, outdeg; - IGRAPH_CHECK(igraph_neighbors(graph, &inneis, i, IGRAPH_IN)); - IGRAPH_CHECK(igraph_neighbors(graph, &outneis, i, IGRAPH_OUT)); + for (igraph_int_t i = 0; i < no_of_nodes; i++) { + igraph_int_t ip, op, indeg, outdeg; + IGRAPH_CHECK(igraph_neighbors( + graph, &inneis, i, IGRAPH_IN, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE + )); + IGRAPH_CHECK(igraph_neighbors( + graph, &outneis, i, IGRAPH_OUT, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE + )); indeg = igraph_vector_int_size(&inneis); outdeg = igraph_vector_int_size(&outneis); diff --git a/src/vendor/cigraph/src/properties/complete.c b/src/vendor/cigraph/src/properties/complete.c index 15b9f81177d..088a2103982 100644 --- a/src/vendor/cigraph/src/properties/complete.c +++ b/src/vendor/cigraph/src/properties/complete.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2024 The igraph development team This program is free software; you can redistribute it and/or modify it under @@ -20,15 +20,12 @@ #include "igraph_structural.h" #include "core/interruption.h" -#include "graph/internal.h" /** * \ingroup structural * \function igraph_is_complete * \brief Decides whether the graph is complete. * - * \experimental - * * A graph is considered complete if all pairs of different vertices are * adjacent. * @@ -45,9 +42,9 @@ igraph_error_t igraph_is_complete(const igraph_t *graph, igraph_bool_t *res) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); - igraph_integer_t complete_ecount; + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); + igraph_int_t complete_ecount; igraph_bool_t simple, directed = igraph_is_directed(graph); igraph_vector_int_t neighbours; int iter = 0; @@ -120,7 +117,7 @@ igraph_error_t igraph_is_complete(const igraph_t *graph, igraph_bool_t *res) { } /* If the graph is simple, compare and conclude */ - IGRAPH_CHECK(igraph_is_simple(graph, &simple)); + IGRAPH_CHECK(igraph_is_simple(graph, &simple, IGRAPH_DIRECTED)); if (simple) { *res = (ecount == complete_ecount); @@ -130,11 +127,13 @@ igraph_error_t igraph_is_complete(const igraph_t *graph, igraph_bool_t *res) { /* Allocate memory for vector of size v */ IGRAPH_VECTOR_INT_INIT_FINALLY(&neighbours, vcount); - for (igraph_integer_t i = 0; i < vcount; ++i) { + for (igraph_int_t i = 0; i < vcount; ++i) { IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 8); - IGRAPH_CHECK(igraph_i_neighbors(graph, &neighbours, i, IGRAPH_OUT, - IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neighbours, i, IGRAPH_OUT, IGRAPH_NO_LOOPS, + IGRAPH_NO_MULTIPLE + )); if ((igraph_vector_int_size(&neighbours) < vcount - 1)) { *res = false; @@ -161,7 +160,7 @@ static igraph_error_t is_clique(const igraph_t *graph, igraph_vs_t candidate, igraph_bool_t directed, igraph_bool_t *res, igraph_bool_t independent_set) { igraph_vector_int_t vids; - igraph_integer_t n; /* clique size */ + igraph_int_t n; /* clique size */ igraph_bool_t result = true; /* be optimistic */ int iter = 0; @@ -173,14 +172,14 @@ static igraph_error_t is_clique(const igraph_t *graph, igraph_vs_t candidate, n = igraph_vector_int_size(&vids); - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t u = VECTOR(vids)[i]; - for (igraph_integer_t j = directed ? 0 : i+1; j < n; j++) { - igraph_integer_t v = VECTOR(vids)[j]; + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t u = VECTOR(vids)[i]; + for (igraph_int_t j = directed ? 0 : i+1; j < n; j++) { + igraph_int_t v = VECTOR(vids)[j]; /* Compare u and v for equality instead of i and j in case * the vertex list contained duplicates. */ if (u != v) { - igraph_integer_t eid; + igraph_int_t eid; IGRAPH_CHECK(igraph_get_eid(graph, &eid, u, v, directed, false)); if (independent_set) { if (eid != -1) { @@ -213,8 +212,6 @@ static igraph_error_t is_clique(const igraph_t *graph, igraph_vs_t candidate, * \function igraph_is_clique * \brief Does a set of vertices form a clique? * - * \experimental - * * Tests if all pairs within a set of vertices are adjacent, i.e. whether they * form a clique. An empty set and singleton set are considered to be a clique. * @@ -251,8 +248,6 @@ igraph_error_t igraph_is_clique(const igraph_t *graph, igraph_vs_t candidate, * \function igraph_is_independent_vertex_set * \brief Does a set of vertices form an independent set? * - * \experimental - * * Tests if no pairs within a set of vertices are adjacenct, i.e. whether they * form an independent set. An empty set and singleton set are both considered * to be an independent set. @@ -274,7 +269,7 @@ igraph_error_t igraph_is_independent_vertex_set(const igraph_t *graph, igraph_vs /* Note: igraph_count_loops() already makes use of the cache. */ if (igraph_vs_is_all(&candidate)) { - igraph_integer_t loop_count; + igraph_int_t loop_count; igraph_count_loops(graph, &loop_count); *res = (igraph_ecount(graph) - loop_count) == 0; return IGRAPH_SUCCESS; diff --git a/src/vendor/cigraph/src/properties/constraint.c b/src/vendor/cigraph/src/properties/constraint.c index 878eb25c21c..357aedadf1d 100644 --- a/src/vendor/cigraph/src/properties/constraint.c +++ b/src/vendor/cigraph/src/properties/constraint.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -78,12 +76,12 @@ igraph_error_t igraph_constraint(const igraph_t *graph, igraph_vector_t *res, igraph_vs_t vids, const igraph_vector_t *weights) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_vit_t vit; - igraph_integer_t nodes_to_calc; - igraph_integer_t a, b, c, i, j, q, vsize, vsize2; - igraph_integer_t edge, edge2; + igraph_int_t nodes_to_calc; + igraph_int_t a, b, c, i, j, q, vsize, vsize2; + igraph_int_t edge, edge2; igraph_vector_t contrib; igraph_vector_t degree; @@ -113,10 +111,8 @@ igraph_error_t igraph_constraint(const igraph_t *graph, igraph_vector_t *res, i = IGRAPH_VIT_GET(vit); /* get neighbors of i */ - IGRAPH_CHECK(igraph_incident(graph, &ineis_in, i, - IGRAPH_IN)); - IGRAPH_CHECK(igraph_incident(graph, &ineis_out, i, - IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(graph, &ineis_in, i, IGRAPH_IN, IGRAPH_LOOPS)); + IGRAPH_CHECK(igraph_incident(graph, &ineis_out, i, IGRAPH_OUT, IGRAPH_LOOPS)); /* NaN for isolates */ if (igraph_vector_int_size(&ineis_in) == 0 && @@ -176,10 +172,8 @@ igraph_error_t igraph_constraint(const igraph_t *graph, igraph_vector_t *res, if (i == j) { continue; } - IGRAPH_CHECK(igraph_incident(graph, &jneis_in, j, - IGRAPH_IN)); - IGRAPH_CHECK(igraph_incident(graph, &jneis_out, j, - IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(graph, &jneis_in, j, IGRAPH_IN, IGRAPH_LOOPS)); + IGRAPH_CHECK(igraph_incident(graph, &jneis_out, j, IGRAPH_OUT, IGRAPH_LOOPS)); vsize2 = igraph_vector_int_size(&jneis_in); for (c = 0; c < vsize2; c++) { edge2 = VECTOR(jneis_in)[c]; @@ -221,10 +215,8 @@ igraph_error_t igraph_constraint(const igraph_t *graph, igraph_vector_t *res, if (i == j) { continue; } - IGRAPH_CHECK(igraph_incident(graph, &jneis_in, j, - IGRAPH_IN)); - IGRAPH_CHECK(igraph_incident(graph, &jneis_out, j, - IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(graph, &jneis_in, j, IGRAPH_IN, IGRAPH_LOOPS)); + IGRAPH_CHECK(igraph_incident(graph, &jneis_out, j, IGRAPH_OUT, IGRAPH_LOOPS)); vsize2 = igraph_vector_int_size(&jneis_in); for (c = 0; c < vsize2; c++) { edge2 = VECTOR(jneis_in)[c]; diff --git a/src/vendor/cigraph/src/properties/convergence_degree.c b/src/vendor/cigraph/src/properties/convergence_degree.c index 661818f6aac..6bedb9d776b 100644 --- a/src/vendor/cigraph/src/properties/convergence_degree.c +++ b/src/vendor/cigraph/src/properties/convergence_degree.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -72,10 +70,10 @@ */ igraph_error_t igraph_convergence_degree(const igraph_t *graph, igraph_vector_t *result, igraph_vector_t *ins, igraph_vector_t *outs) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t i, j, k, n; - igraph_integer_t *geodist; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t i, j, k, n; + igraph_int_t *geodist; igraph_vector_int_t *eids; igraph_vector_t *ins_p, *outs_p, ins_v, outs_v; igraph_dqueue_int_t q; @@ -106,7 +104,7 @@ igraph_error_t igraph_convergence_degree(const igraph_t *graph, igraph_vector_t igraph_vector_null(outs_p); } - geodist = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + geodist = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); if (geodist == 0) { IGRAPH_ERROR("Cannot calculate convergence degrees", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } @@ -127,13 +125,13 @@ igraph_error_t igraph_convergence_degree(const igraph_t *graph, igraph_vector_t IGRAPH_CHECK(igraph_dqueue_int_push(&q, i)); IGRAPH_CHECK(igraph_dqueue_int_push(&q, 0)); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); IGRAPH_ALLOW_INTERRUPTION(); eids = igraph_inclist_get(&inclist, actnode); n = igraph_vector_int_size(eids); for (j = 0; j < n; j++) { - igraph_integer_t neighbor = IGRAPH_OTHER(graph, VECTOR(*eids)[j], actnode); + igraph_int_t neighbor = IGRAPH_OTHER(graph, VECTOR(*eids)[j], actnode); if (geodist[neighbor] != 0) { /* we've already seen this node, another shortest path? */ if (geodist[neighbor] - 1 == actdist + 1) { diff --git a/src/vendor/cigraph/src/properties/dag.c b/src/vendor/cigraph/src/properties/dag.c index afad5efbd61..0550cbd4162 100644 --- a/src/vendor/cigraph/src/properties/dag.c +++ b/src/vendor/cigraph/src/properties/dag.c @@ -1,32 +1,24 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. - Copyright (C) 2005-2021 The igraph development team + igraph library. + Copyright (C) 2005-2024 The igraph development team - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any later + version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + You should have received a copy of the GNU General Public License along with + this program. If not, see . */ -#include "igraph_topology.h" +#include "igraph_cycles.h" -#include "igraph_constructors.h" #include "igraph_dqueue.h" #include "igraph_interface.h" -#include "igraph_stack.h" /** * \function igraph_topological_sorting @@ -65,12 +57,12 @@ igraph_error_t igraph_topological_sorting( /* Note: This function ignores self-loops, there it cannot * use the IGRAPH_PROP_IS_DAG property cache entry. */ - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t degrees; igraph_vector_int_t neis; igraph_dqueue_int_t sources; igraph_neimode_t deg_mode; - igraph_integer_t node, i, j; + igraph_int_t node, i, j; if (mode == IGRAPH_ALL || !igraph_is_directed(graph)) { IGRAPH_ERROR("Topological sorting does not make sense for undirected graphs.", @@ -87,7 +79,7 @@ igraph_error_t igraph_topological_sorting( IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); IGRAPH_CHECK(igraph_dqueue_int_init(&sources, 0)); IGRAPH_FINALLY(igraph_dqueue_int_destroy, &sources); - IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), deg_mode, 0)); + IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), deg_mode, IGRAPH_NO_LOOPS)); igraph_vector_int_clear(res); @@ -106,7 +98,7 @@ igraph_error_t igraph_topological_sorting( /* Exclude the node from further source searches */ VECTOR(degrees)[node] = -1; /* Get the neighbors and decrease their degrees by one */ - IGRAPH_CHECK(igraph_neighbors(graph, &neis, node, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, node, mode, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE)); j = igraph_vector_int_size(&neis); for (i = 0; i < j; i++) { VECTOR(degrees)[ VECTOR(neis)[i] ]--; @@ -138,7 +130,7 @@ igraph_error_t igraph_topological_sorting( * A directed acyclic graph (DAG) is a directed graph with no cycles. * * - * This function returns false for undirected graphs. + * This function returns \c false for undirected graphs. * * * The return value of this function is cached in the graph itself; calling @@ -157,7 +149,7 @@ igraph_error_t igraph_topological_sorting( * sorting of a DAG. */ igraph_error_t igraph_is_dag(const igraph_t* graph, igraph_bool_t *res) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t degrees; igraph_vector_int_t neis; igraph_dqueue_int_t sources; @@ -173,12 +165,12 @@ igraph_error_t igraph_is_dag(const igraph_t* graph, igraph_bool_t *res) { IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); IGRAPH_DQUEUE_INT_INIT_FINALLY(&sources, 0); - IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), IGRAPH_IN, /* loops */ true)); + IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS)); - igraph_integer_t vertices_left = no_of_nodes; + igraph_int_t vertices_left = no_of_nodes; /* Do we have nodes with no incoming edges? */ - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { if (VECTOR(degrees)[i] == 0) { IGRAPH_CHECK(igraph_dqueue_int_push(&sources, i)); } @@ -186,15 +178,15 @@ igraph_error_t igraph_is_dag(const igraph_t* graph, igraph_bool_t *res) { /* Take all nodes with no incoming edges and remove them */ while (!igraph_dqueue_int_empty(&sources)) { - igraph_integer_t node = igraph_dqueue_int_pop(&sources); + igraph_int_t node = igraph_dqueue_int_pop(&sources); /* Exclude the node from further source searches */ VECTOR(degrees)[node] = -1; vertices_left--; /* Get the neighbors and decrease their degrees by one */ - IGRAPH_CHECK(igraph_neighbors(graph, &neis, node, IGRAPH_OUT)); - igraph_integer_t n = igraph_vector_int_size(&neis); - for (igraph_integer_t i = 0; i < n; i++) { - igraph_integer_t nei = VECTOR(neis)[i]; + IGRAPH_CHECK(igraph_neighbors(graph, &neis, node, IGRAPH_OUT, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE)); + igraph_int_t n = igraph_vector_int_size(&neis); + for (igraph_int_t i = 0; i < n; i++) { + igraph_int_t nei = VECTOR(neis)[i]; if (nei == node) { /* Found a self-loop, graph is not a DAG */ *res = false; @@ -220,96 +212,3 @@ igraph_error_t igraph_is_dag(const igraph_t* graph, igraph_bool_t *res) { return IGRAPH_SUCCESS; } - -/* Create the transitive closure of a tree graph. - This is fairly simple, we just collect all ancestors of a vertex - using a depth-first search. - */ -igraph_error_t igraph_transitive_closure_dag(const igraph_t *graph, igraph_t *closure) { - - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_vector_int_t deg; - igraph_vector_int_t new_edges; - igraph_vector_int_t ancestors; - igraph_integer_t root; - igraph_vector_int_t neighbors; - igraph_stack_int_t path; - igraph_vector_bool_t done; - - if (!igraph_is_directed(graph)) { - IGRAPH_ERROR("Tree transitive closure of a directed graph", - IGRAPH_EINVAL); - } - - IGRAPH_VECTOR_INT_INIT_FINALLY(&new_edges, 0); - IGRAPH_VECTOR_INT_INIT_FINALLY(°, no_of_nodes); - IGRAPH_VECTOR_INT_INIT_FINALLY(&ancestors, 0); - IGRAPH_VECTOR_INT_INIT_FINALLY(&neighbors, 0); - IGRAPH_CHECK(igraph_stack_int_init(&path, 0)); - IGRAPH_FINALLY(igraph_stack_int_destroy, &path); - IGRAPH_CHECK(igraph_vector_bool_init(&done, no_of_nodes)); - IGRAPH_FINALLY(igraph_vector_bool_destroy, &done); - - IGRAPH_CHECK(igraph_degree(graph, °, igraph_vss_all(), - IGRAPH_OUT, IGRAPH_LOOPS)); - -#define STAR (-1) - - for (root = 0; root < no_of_nodes; root++) { - if (VECTOR(deg)[root] != 0) { - continue; - } - IGRAPH_CHECK(igraph_stack_int_push(&path, root)); - - while (!igraph_stack_int_empty(&path)) { - igraph_integer_t node = igraph_stack_int_top(&path); - if (node == STAR) { - /* Leaving a node */ - igraph_integer_t j, n; - igraph_stack_int_pop(&path); - node = igraph_stack_int_pop(&path); - if (!VECTOR(done)[node]) { - igraph_vector_int_pop_back(&ancestors); - VECTOR(done)[node] = true; - } - n = igraph_vector_int_size(&ancestors); - for (j = 0; j < n; j++) { - IGRAPH_CHECK(igraph_vector_int_push_back(&new_edges, node)); - IGRAPH_CHECK(igraph_vector_int_push_back(&new_edges, - VECTOR(ancestors)[j])); - } - } else { - /* Getting into a node */ - igraph_integer_t n, j; - if (!VECTOR(done)[node]) { - IGRAPH_CHECK(igraph_vector_int_push_back(&ancestors, node)); - } - IGRAPH_CHECK(igraph_neighbors(graph, &neighbors, - node, IGRAPH_IN)); - n = igraph_vector_int_size(&neighbors); - IGRAPH_CHECK(igraph_stack_int_push(&path, STAR)); - for (j = 0; j < n; j++) { - igraph_integer_t nei = VECTOR(neighbors)[j]; - IGRAPH_CHECK(igraph_stack_int_push(&path, nei)); - } - } - } - } - -#undef STAR - - igraph_vector_bool_destroy(&done); - igraph_stack_int_destroy(&path); - igraph_vector_int_destroy(&neighbors); - igraph_vector_int_destroy(&ancestors); - igraph_vector_int_destroy(°); - IGRAPH_FINALLY_CLEAN(5); - - IGRAPH_CHECK(igraph_create(closure, &new_edges, no_of_nodes, - IGRAPH_DIRECTED)); - - igraph_vector_int_destroy(&new_edges); - IGRAPH_FINALLY_CLEAN(1); - - return IGRAPH_SUCCESS; -} diff --git a/src/vendor/cigraph/src/properties/degrees.c b/src/vendor/cigraph/src/properties/degrees.c index 5096803c1da..1e3f702512b 100644 --- a/src/vendor/cigraph/src/properties/degrees.c +++ b/src/vendor/cigraph/src/properties/degrees.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2023 The igraph development team This program is free software; you can redistribute it and/or modify @@ -31,7 +29,7 @@ * 0 is returned, as this is the smallest possible value for degrees. * * \param graph The input graph. - * \param res Pointer to an integer (\c igraph_integer_t), the result + * \param res Pointer to an integer (\c igraph_int_t), the result * will be stored here. * \param vids Vector giving the vertex IDs for which the maximum degree will * be calculated. @@ -41,8 +39,10 @@ * \c IGRAPH_ALL, total degree (sum of the * in- and out-degree). * This parameter is ignored for undirected graphs. - * \param loops Boolean, gives whether the self-loops should be - * counted. + * \param loops Specifies how to treat loop edges when calculating the + * degree. \c IGRAPH_NO_LOOPS ignores loop edges; \c IGRAPH_LOOPS_ONCE + * counts each loop edge only once; \c IGRAPH_LOOPS_TWICE counts each + * loop edge twice in undirected graphs and once in directed graphs. * \return Error code: * \c IGRAPH_EINVVID: invalid vertex ID. * \c IGRAPH_EINVMODE: invalid mode argument. @@ -53,9 +53,10 @@ * * \sa \ref igraph_degree() to retrieve the degrees for several vertices. */ -igraph_error_t igraph_maxdegree(const igraph_t *graph, igraph_integer_t *res, - igraph_vs_t vids, igraph_neimode_t mode, - igraph_bool_t loops) { +igraph_error_t igraph_maxdegree( + const igraph_t *graph, igraph_int_t *res, igraph_vs_t vids, + igraph_neimode_t mode, igraph_loops_t loops +) { igraph_vector_int_t tmp; @@ -82,14 +83,14 @@ static igraph_error_t avg_nearest_neighbor_degree_weighted(const igraph_t *graph igraph_vector_t *knnk, const igraph_vector_t *weights) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t neis, edge_neis; - igraph_integer_t no_vids; + igraph_int_t no_vids; igraph_vit_t vit; igraph_vector_t my_knn_v, *my_knn = knn; igraph_vector_t strength; igraph_vector_int_t deg; - igraph_integer_t maxdeg; + igraph_int_t maxdeg; igraph_vector_t deghist; if (igraph_vector_size(weights) != igraph_ecount(graph)) { @@ -131,18 +132,18 @@ static igraph_error_t avg_nearest_neighbor_degree_weighted(const igraph_t *graph IGRAPH_VECTOR_INIT_FINALLY(°hist, maxdeg); } - for (igraph_integer_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { + for (igraph_int_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { igraph_real_t sum = 0.0; - igraph_integer_t v = IGRAPH_VIT_GET(vit); - igraph_integer_t nv; + igraph_int_t v = IGRAPH_VIT_GET(vit); + igraph_int_t nv; igraph_real_t str = VECTOR(strength)[v]; /* Get neighbours and incident edges */ - IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, mode)); - IGRAPH_CHECK(igraph_incident(graph, &edge_neis, v, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); + IGRAPH_CHECK(igraph_incident(graph, &edge_neis, v, mode, IGRAPH_LOOPS)); nv = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < nv; j++) { - igraph_integer_t nei = VECTOR(neis)[j]; - igraph_integer_t e = VECTOR(edge_neis)[j]; + for (igraph_int_t j = 0; j < nv; j++) { + igraph_int_t nei = VECTOR(neis)[j]; + igraph_int_t e = VECTOR(edge_neis)[j]; igraph_real_t w = VECTOR(*weights)[e]; sum += w * VECTOR(deg)[nei]; } @@ -162,7 +163,7 @@ static igraph_error_t avg_nearest_neighbor_degree_weighted(const igraph_t *graph IGRAPH_FINALLY_CLEAN(2); if (knnk) { - for (igraph_integer_t i = 0; i < maxdeg; i++) { + for (igraph_int_t i = 0; i < maxdeg; i++) { igraph_real_t dh = VECTOR(deghist)[i]; if (dh != 0) { VECTOR(*knnk)[i] /= dh; @@ -267,13 +268,13 @@ igraph_error_t igraph_avg_nearest_neighbor_degree(const igraph_t *graph, igraph_vector_t *knnk, const igraph_vector_t *weights) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t neis; - igraph_integer_t no_vids; + igraph_int_t no_vids; igraph_vit_t vit; igraph_vector_t my_knn_v, *my_knn = knn; igraph_vector_int_t deg; - igraph_integer_t maxdeg; + igraph_int_t maxdeg; igraph_vector_int_t deghist; if (weights) { @@ -305,14 +306,14 @@ igraph_error_t igraph_avg_nearest_neighbor_degree(const igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(°hist, maxdeg); } - for (igraph_integer_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { + for (igraph_int_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { igraph_real_t sum = 0.0; - igraph_integer_t v = IGRAPH_VIT_GET(vit); - igraph_integer_t nv; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, mode)); + igraph_int_t v = IGRAPH_VIT_GET(vit); + igraph_int_t nv; + IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); nv = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < nv; j++) { - igraph_integer_t nei = VECTOR(neis)[j]; + for (igraph_int_t j = 0; j < nv; j++) { + igraph_int_t nei = VECTOR(neis)[j]; sum += VECTOR(deg)[nei]; } if (nv != 0) { @@ -327,8 +328,8 @@ igraph_error_t igraph_avg_nearest_neighbor_degree(const igraph_t *graph, } if (knnk) { - for (igraph_integer_t i = 0; i < maxdeg; i++) { - igraph_integer_t dh = VECTOR(deghist)[i]; + for (igraph_int_t i = 0; i < maxdeg; i++) { + igraph_int_t dh = VECTOR(deghist)[i]; if (dh != 0) { VECTOR(*knnk)[i] /= dh; } else { @@ -356,8 +357,6 @@ igraph_error_t igraph_avg_nearest_neighbor_degree(const igraph_t *graph, * \function igraph_degree_correlation_vector * \brief Degree correlation function. * - * \experimental - * * Computes the degree correlation function k_nn(k), defined as the * mean degree of the targets of directed edges whose source has degree \c k. * The averaging is done over all directed edges. The \p from_mode and \p to_mode @@ -434,9 +433,9 @@ igraph_error_t igraph_degree_correlation_vector( igraph_neimode_t from_mode, igraph_neimode_t to_mode, igraph_bool_t directed_neighbors) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t maxdeg; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t maxdeg; igraph_vector_t weight_sums; igraph_vector_int_t *deg_from, *deg_to, deg_out, deg_in, deg_all; @@ -493,11 +492,11 @@ igraph_error_t igraph_degree_correlation_vector( IGRAPH_CHECK(igraph_vector_resize(knnk, maxdeg+1)); igraph_vector_null(knnk); - for (igraph_integer_t eid=0; eid < no_of_edges; eid++) { - igraph_integer_t from = IGRAPH_FROM(graph, eid); - igraph_integer_t to = IGRAPH_TO(graph, eid); - igraph_integer_t fromdeg = VECTOR(*deg_from)[from]; - igraph_integer_t todeg = VECTOR(*deg_to)[to]; + for (igraph_int_t eid=0; eid < no_of_edges; eid++) { + igraph_int_t from = IGRAPH_FROM(graph, eid); + igraph_int_t to = IGRAPH_TO(graph, eid); + igraph_int_t fromdeg = VECTOR(*deg_from)[from]; + igraph_int_t todeg = VECTOR(*deg_to)[to]; igraph_real_t w = weights ? VECTOR(*weights)[eid] : 1; VECTOR(weight_sums)[fromdeg] += w; @@ -541,8 +540,8 @@ static igraph_error_t strength_all( const igraph_vector_t *weights) { // When calculating strength for all vertices, iterating over edges is faster - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes)); igraph_vector_null(res); @@ -553,27 +552,27 @@ static igraph_error_t strength_all( if (loops) { if (mode & IGRAPH_OUT) { - for (igraph_integer_t edge = 0; edge < no_of_edges; ++edge) { + for (igraph_int_t edge = 0; edge < no_of_edges; ++edge) { VECTOR(*res)[IGRAPH_FROM(graph, edge)] += VECTOR(*weights)[edge]; } } if (mode & IGRAPH_IN) { - for (igraph_integer_t edge = 0; edge < no_of_edges; ++edge) { + for (igraph_int_t edge = 0; edge < no_of_edges; ++edge) { VECTOR(*res)[IGRAPH_TO(graph, edge)] += VECTOR(*weights)[edge]; } } } else { if (mode & IGRAPH_OUT) { - for (igraph_integer_t edge = 0; edge < no_of_edges; ++edge) { - igraph_integer_t from = IGRAPH_FROM(graph, edge); + for (igraph_int_t edge = 0; edge < no_of_edges; ++edge) { + igraph_int_t from = IGRAPH_FROM(graph, edge); if (from != IGRAPH_TO(graph, edge)) { VECTOR(*res)[from] += VECTOR(*weights)[edge]; } } } if (mode & IGRAPH_IN) { - for (igraph_integer_t edge = 0; edge < no_of_edges; ++edge) { - igraph_integer_t to = IGRAPH_TO(graph, edge); + for (igraph_int_t edge = 0; edge < no_of_edges; ++edge) { + igraph_int_t to = IGRAPH_TO(graph, edge); if (IGRAPH_FROM(graph, edge) != to) { VECTOR(*res)[to] += VECTOR(*weights)[edge]; } @@ -599,7 +598,11 @@ static igraph_error_t strength_all( * \param mode Gives whether to count only outgoing (\c IGRAPH_OUT), * incoming (\c IGRAPH_IN) edges or both (\c IGRAPH_ALL). * This parameter is ignored for undirected graphs. - * \param loops Boolean, whether to count loop edges as well. + * \param loops Constant of type \ref igraph_loops_t. Specifies how to treat + * loop edges when calculating the strength. \c IGRAPH_NO_LOOPS ignores loop + * edges; \c IGRAPH_LOOPS_ONCE counts each loop edge only once; + * \c IGRAPH_LOOPS_TWICE counts each loop edge twice in undirected graphs and + * once in directed graphs. * \param weights A vector giving the edge weights. If this is a \c NULL * pointer, then \ref igraph_degree() is called to perform the * calculation. @@ -610,13 +613,14 @@ static igraph_error_t strength_all( * * \sa \ref igraph_degree() for the traditional, non-weighted version. */ -igraph_error_t igraph_strength(const igraph_t *graph, igraph_vector_t *res, - const igraph_vs_t vids, igraph_neimode_t mode, - igraph_bool_t loops, const igraph_vector_t *weights) { +igraph_error_t igraph_strength( + const igraph_t *graph, igraph_vector_t *res, const igraph_vs_t vids, + igraph_neimode_t mode, igraph_loops_t loops, const igraph_vector_t *weights +) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vit_t vit; - igraph_integer_t no_vids; + igraph_int_t no_vids; igraph_vector_int_t degrees; igraph_vector_int_t neis; @@ -624,7 +628,7 @@ igraph_error_t igraph_strength(const igraph_t *graph, igraph_vector_t *res, IGRAPH_VECTOR_INT_INIT_FINALLY(°rees, no_of_nodes); IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes)); IGRAPH_CHECK(igraph_degree(graph, °rees, vids, mode, loops)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + for (igraph_int_t i = 0; i < no_of_nodes; i++) { VECTOR(*res)[i] = VECTOR(degrees)[i]; } igraph_vector_int_destroy(°rees); @@ -653,27 +657,12 @@ igraph_error_t igraph_strength(const igraph_t *graph, igraph_vector_t *res, IGRAPH_CHECK(igraph_vector_resize(res, no_vids)); igraph_vector_null(res); - if (loops) { - for (igraph_integer_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - IGRAPH_CHECK(igraph_incident(graph, &neis, IGRAPH_VIT_GET(vit), mode)); - const igraph_integer_t n = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t edge = VECTOR(neis)[j]; - VECTOR(*res)[i] += VECTOR(*weights)[edge]; - } - } - } else { - for (igraph_integer_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - IGRAPH_CHECK(igraph_incident(graph, &neis, IGRAPH_VIT_GET(vit), mode)); - const igraph_integer_t n = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t edge = VECTOR(neis)[j]; - igraph_integer_t from = IGRAPH_FROM(graph, edge); - igraph_integer_t to = IGRAPH_TO(graph, edge); - if (from != to) { - VECTOR(*res)[i] += VECTOR(*weights)[edge]; - } - } + for (igraph_int_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { + IGRAPH_CHECK(igraph_incident(graph, &neis, IGRAPH_VIT_GET(vit), mode, loops)); + const igraph_int_t n = igraph_vector_int_size(&neis); + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t edge = VECTOR(neis)[j]; + VECTOR(*res)[i] += VECTOR(*weights)[edge]; } } @@ -703,8 +692,10 @@ igraph_error_t igraph_strength(const igraph_t *graph, igraph_vector_t *res, * \c IGRAPH_ALL, total degree (sum of the * in- and out-degree). * This parameter is ignored for undirected graphs. - * \param loops Boolean, gives whether the self-loops should be - * counted. + * \param loops Specifies how to treat loop edges when calculating the + * degrees. \c IGRAPH_NO_LOOPS ignores loop edges; \c IGRAPH_LOOPS_ONCE + * counts each loop edge only once; \c IGRAPH_LOOPS_TWICE counts each + * loop edge twice in undirected graphs and once in directed graphs. * \param order Specifies whether the ordering should be ascending * (\c IGRAPH_ASCENDING) or descending (\c IGRAPH_DESCENDING). * \param only_indices If true, then return a sorted list of indices @@ -718,14 +709,12 @@ igraph_error_t igraph_strength(const igraph_t *graph, igraph_vector_t *res, * \c IGRAPH_EINVMODE: invalid mode argument. * */ -igraph_error_t igraph_sort_vertex_ids_by_degree(const igraph_t *graph, - igraph_vector_int_t *outvids, - igraph_vs_t vids, - igraph_neimode_t mode, - igraph_bool_t loops, - igraph_order_t order, - igraph_bool_t only_indices) { - igraph_integer_t i, n; +igraph_error_t igraph_sort_vertex_ids_by_degree( + const igraph_t *graph, igraph_vector_int_t *outvids, + igraph_vs_t vids, igraph_neimode_t mode, igraph_loops_t loops, + igraph_order_t order, igraph_bool_t only_indices +) { + igraph_int_t i, n; igraph_vector_int_t degrees; igraph_vector_int_t vs_vec; IGRAPH_VECTOR_INT_INIT_FINALLY(°rees, 0); diff --git a/src/vendor/cigraph/src/properties/ecc.c b/src/vendor/cigraph/src/properties/ecc.c index 5701596f0c8..4a5dd7bfd19 100644 --- a/src/vendor/cigraph/src/properties/ecc.c +++ b/src/vendor/cigraph/src/properties/ecc.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -34,7 +34,7 @@ static igraph_error_t igraph_i_ecc3_1( const igraph_t *graph, igraph_vector_t *res, const igraph_es_t eids, igraph_bool_t offset, igraph_bool_t normalize) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t degree; igraph_adjlist_t al; igraph_eit_t eit; @@ -51,12 +51,12 @@ static igraph_error_t igraph_i_ecc3_1( IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_EIT_SIZE(eit))); - for (igraph_integer_t i=0; + for (igraph_int_t i=0; ! IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit), i++) { - igraph_integer_t edge = IGRAPH_EIT_GET(eit); - igraph_integer_t v1 = IGRAPH_FROM(graph, edge), v2 = IGRAPH_TO(graph, edge); + igraph_int_t edge = IGRAPH_EIT_GET(eit); + igraph_int_t v1 = IGRAPH_FROM(graph, edge), v2 = IGRAPH_TO(graph, edge); igraph_real_t z; /* number of triangles the edge participates in */ igraph_real_t s; /* max number of triangles the edge could be part of */ @@ -69,7 +69,7 @@ static igraph_error_t igraph_i_ecc3_1( s = 0.0; } else { const igraph_vector_int_t *a1 = igraph_adjlist_get(&al, v1), *a2 = igraph_adjlist_get(&al, v2); - igraph_integer_t d1 = VECTOR(degree)[v1], d2 = VECTOR(degree)[v2]; + igraph_int_t d1 = VECTOR(degree)[v1], d2 = VECTOR(degree)[v2]; z = igraph_vector_int_intersection_size_sorted(a1, a2); s = (d1 < d2 ? d1 : d2) - 1.0; @@ -105,12 +105,12 @@ static igraph_error_t igraph_i_ecc3_2( IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_EIT_SIZE(eit))); - for (igraph_integer_t i=0; + for (igraph_int_t i=0; ! IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit), i++) { - igraph_integer_t edge = IGRAPH_EIT_GET(eit); - igraph_integer_t v1 = IGRAPH_FROM(graph, edge), v2 = IGRAPH_TO(graph, edge); + igraph_int_t edge = IGRAPH_EIT_GET(eit); + igraph_int_t v1 = IGRAPH_FROM(graph, edge), v2 = IGRAPH_TO(graph, edge); igraph_real_t z; /* number of triangles the edge participates in */ igraph_real_t s; /* max number of triangles the edge could be part of */ @@ -125,7 +125,7 @@ static igraph_error_t igraph_i_ecc3_2( igraph_vector_int_t *a1 = igraph_lazy_adjlist_get(&al, v1); igraph_vector_int_t *a2 = igraph_lazy_adjlist_get(&al, v2); - igraph_integer_t d1, d2; + igraph_int_t d1, d2; IGRAPH_CHECK(igraph_degree_1(graph, &d1, v1, IGRAPH_ALL, IGRAPH_LOOPS)); IGRAPH_CHECK(igraph_degree_1(graph, &d2, v2, IGRAPH_ALL, IGRAPH_LOOPS)); @@ -150,7 +150,7 @@ static igraph_error_t igraph_i_ecc4_1( const igraph_t *graph, igraph_vector_t *res, const igraph_es_t eids, igraph_bool_t offset, igraph_bool_t normalize) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t degree; igraph_adjlist_t al; igraph_eit_t eit; @@ -167,12 +167,12 @@ static igraph_error_t igraph_i_ecc4_1( IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_EIT_SIZE(eit))); - for (igraph_integer_t i=0; + for (igraph_int_t i=0; ! IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit), i++) { - igraph_integer_t edge = IGRAPH_EIT_GET(eit); - igraph_integer_t v1 = IGRAPH_FROM(graph, edge), v2 = IGRAPH_TO(graph, edge); + igraph_int_t edge = IGRAPH_EIT_GET(eit); + igraph_int_t v1 = IGRAPH_FROM(graph, edge), v2 = IGRAPH_TO(graph, edge); igraph_real_t z; /* number of 4-cycles the edge participates in */ igraph_real_t s; /* max number of 4-cycles the edge could be part of */ @@ -185,16 +185,16 @@ static igraph_error_t igraph_i_ecc4_1( } else { /* ensure that v1 is the vertex with the smaller degree */ if (VECTOR(degree)[v1] > VECTOR(degree)[v2]) { - igraph_integer_t tmp = v1; + igraph_int_t tmp = v1; v1 = v2; v2 = tmp; } z = 0.0; const igraph_vector_int_t *a1 = igraph_adjlist_get(&al, v1); - const igraph_integer_t n = igraph_vector_int_size(a1); - for (igraph_integer_t j=0; j < n; j++) { - igraph_integer_t v3 = VECTOR(*a1)[j]; + const igraph_int_t n = igraph_vector_int_size(a1); + for (igraph_int_t j=0; j < n; j++) { + igraph_int_t v3 = VECTOR(*a1)[j]; /* It is not possible that v3 == v1 because self-loops have been removed from the adjlist. */ @@ -205,7 +205,7 @@ static igraph_error_t igraph_i_ecc4_1( z += igraph_vector_int_intersection_size_sorted(a2, a3) - 1.0; } - igraph_integer_t d1 = VECTOR(degree)[v1], d2 = VECTOR(degree)[v2]; + igraph_int_t d1 = VECTOR(degree)[v1], d2 = VECTOR(degree)[v2]; s = (d1 - 1.0) * (d2 - 1.0); } @@ -239,19 +239,19 @@ static igraph_error_t igraph_i_ecc4_2( IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_EIT_SIZE(eit))); - for (igraph_integer_t i=0; + for (igraph_int_t i=0; ! IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit), i++) { - igraph_integer_t edge = IGRAPH_EIT_GET(eit); - igraph_integer_t v1 = IGRAPH_FROM(graph, edge), v2 = IGRAPH_TO(graph, edge); + igraph_int_t edge = IGRAPH_EIT_GET(eit); + igraph_int_t v1 = IGRAPH_FROM(graph, edge), v2 = IGRAPH_TO(graph, edge); igraph_real_t z; /* number of 4-cycles the edge participates in */ igraph_real_t s; /* max number of 4-cycles the edge could be part of */ IGRAPH_ALLOW_INTERRUPTION(); - igraph_integer_t d1, d2; + igraph_int_t d1, d2; IGRAPH_CHECK(igraph_degree_1(graph, &d1, v1, IGRAPH_ALL, IGRAPH_LOOPS)); IGRAPH_CHECK(igraph_degree_1(graph, &d2, v2, IGRAPH_ALL, IGRAPH_LOOPS)); @@ -261,7 +261,7 @@ static igraph_error_t igraph_i_ecc4_2( } else { /* ensure that v1 is the vertex with the smaller degree */ if (d1 > d2) { - igraph_integer_t tmp = v1; + igraph_int_t tmp = v1; v1 = v2; v2 = tmp; @@ -274,9 +274,9 @@ static igraph_error_t igraph_i_ecc4_2( igraph_vector_int_t *a1 = igraph_lazy_adjlist_get(&al, v1); - const igraph_integer_t n = igraph_vector_int_size(a1); - for (igraph_integer_t j=0; j < n; j++) { - igraph_integer_t v3 = VECTOR(*a1)[j]; + const igraph_int_t n = igraph_vector_int_size(a1); + for (igraph_int_t j=0; j < n; j++) { + igraph_int_t v3 = VECTOR(*a1)[j]; /* It is not possible that v3 == v1 because self-loops have been removed from the adjlist. */ @@ -307,8 +307,6 @@ static igraph_error_t igraph_i_ecc4_2( * \function igraph_ecc * \brief Edge clustering coefficient of some edges. * - * \experimental - * * The edge clustering coefficient C^(k)_ij of an edge (i, j) * is defined based on the number of k-cycles the edge participates in, * z^(k)_ij, and the largest number of such cycles it could @@ -359,7 +357,7 @@ static igraph_error_t igraph_i_ecc4_2( * When \p k is 4, O(|V| d log d + |E| d^2). d denotes the degree of vertices. */ igraph_error_t igraph_ecc(const igraph_t *graph, igraph_vector_t *res, - const igraph_es_t eids, igraph_integer_t k, + const igraph_es_t eids, igraph_int_t k, igraph_bool_t offset, igraph_bool_t normalize) { if (k < 3) { diff --git a/src/vendor/cigraph/src/properties/girth.c b/src/vendor/cigraph/src/properties/girth.c index 28ee98be96b..c5195f55a33 100644 --- a/src/vendor/cigraph/src/properties/girth.c +++ b/src/vendor/cigraph/src/properties/girth.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -60,9 +58,9 @@ * \param graph The input graph. Edge directions will be ignored. * \param girth Pointer to an \c igraph_real_t, if not \c NULL then the result * will be stored here. - * \param circle Pointer to an initialized vector, the vertex IDs in - * the shortest circle will be stored here. If \c NULL then it is - * ignored. + * \param cycle Pointer to an initialized vector, the vertex IDs in + * the shortest cycle of length at least 3 will be stored here. + * If \c NULL then it is ignored. * \return Error code. * * Time complexity: O((|V|+|E|)^2), |V| is the number of vertices, |E| @@ -72,20 +70,21 @@ * * \example examples/simple/igraph_girth.c */ -igraph_error_t igraph_girth(const igraph_t *graph, igraph_real_t *girth, - igraph_vector_int_t *circle) { +igraph_error_t igraph_girth(const igraph_t *graph, + igraph_real_t *girth, + igraph_vector_int_t *cycle) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_dqueue_int_t q; igraph_lazy_adjlist_t adjlist; - igraph_integer_t mincirc = IGRAPH_INTEGER_MAX, minvertex = 0; - igraph_integer_t node; + igraph_int_t mincirc = IGRAPH_INTEGER_MAX, minvertex = 0; + igraph_int_t node; igraph_bool_t triangle = false; igraph_vector_int_t *neis; igraph_vector_int_t level; - igraph_integer_t stoplevel = no_of_nodes + 1; + igraph_int_t stoplevel = no_of_nodes + 1; igraph_bool_t anycircle = false; - igraph_integer_t t1 = 0, t2 = 0; + igraph_int_t t1 = 0, t2 = 0; IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist); @@ -113,9 +112,9 @@ igraph_error_t igraph_girth(const igraph_t *graph, igraph_real_t *girth, IGRAPH_ALLOW_INTERRUPTION(); while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - igraph_integer_t actlevel = VECTOR(level)[actnode]; - igraph_integer_t i, n; + igraph_int_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actlevel = VECTOR(level)[actnode]; + igraph_int_t i, n; if (actlevel >= stoplevel) { break; @@ -126,8 +125,8 @@ igraph_error_t igraph_girth(const igraph_t *graph, igraph_real_t *girth, n = igraph_vector_int_size(neis); for (i = 0; i < n; i++) { - igraph_integer_t nei = VECTOR(*neis)[i]; - igraph_integer_t neilevel = VECTOR(level)[nei]; + igraph_int_t nei = VECTOR(*neis)[i]; + igraph_int_t neilevel = VECTOR(level)[nei]; if (neilevel != 0) { if (neilevel == actlevel - 1) { continue; @@ -150,7 +149,7 @@ igraph_error_t igraph_girth(const igraph_t *graph, igraph_real_t *girth, } } } else { - igraph_dqueue_int_push(&q, nei); + IGRAPH_CHECK(igraph_dqueue_int_push(&q, nei)); VECTOR(level)[nei] = actlevel + 1; } } @@ -171,42 +170,42 @@ igraph_error_t igraph_girth(const igraph_t *graph, igraph_real_t *girth, } /* Store the actual circle, if needed */ - if (circle) { - IGRAPH_CHECK(igraph_vector_int_resize(circle, mincirc)); + if (cycle) { + IGRAPH_CHECK(igraph_vector_int_resize(cycle, mincirc)); if (mincirc != 0) { - igraph_integer_t i, n, idx = 0; + igraph_int_t i, n, idx = 0; igraph_dqueue_int_clear(&q); - igraph_vector_int_null(&level); /* used for father pointers */ -#define FATHER(x) (VECTOR(level)[(x)]) + igraph_vector_int_null(&level); /* used for parent pointers */ +#define PARENT(x) (VECTOR(level)[(x)]) IGRAPH_CHECK(igraph_dqueue_int_push(&q, minvertex)); - FATHER(minvertex) = minvertex; - while (FATHER(t1) == 0 || FATHER(t2) == 0) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); + PARENT(minvertex) = minvertex; + while (PARENT(t1) == 0 || PARENT(t2) == 0) { + igraph_int_t actnode = igraph_dqueue_int_pop(&q); neis = igraph_lazy_adjlist_get(&adjlist, actnode); IGRAPH_CHECK_OOM(neis, "Failed to query neighbors."); n = igraph_vector_int_size(neis); for (i = 0; i < n; i++) { - igraph_integer_t nei = VECTOR(*neis)[i]; - if (FATHER(nei) == 0) { - FATHER(nei) = actnode + 1; - igraph_dqueue_int_push(&q, nei); + igraph_int_t nei = VECTOR(*neis)[i]; + if (PARENT(nei) == 0) { + PARENT(nei) = actnode + 1; + IGRAPH_CHECK(igraph_dqueue_int_push(&q, nei)); } } } /* while q !empty */ - /* Ok, now use FATHER to create the path */ + /* Ok, now use PARENT to create the path */ while (t1 != minvertex) { - VECTOR(*circle)[idx++] = t1; - t1 = FATHER(t1) - 1; + VECTOR(*cycle)[idx++] = t1; + t1 = PARENT(t1) - 1; } - VECTOR(*circle)[idx] = minvertex; + VECTOR(*cycle)[idx] = minvertex; idx = mincirc - 1; while (t2 != minvertex) { - VECTOR(*circle)[idx--] = t2; - t2 = FATHER(t2) - 1; + VECTOR(*cycle)[idx--] = t2; + t2 = PARENT(t2) - 1; } } /* anycircle */ } /* circle */ -#undef FATHER +#undef PARENT igraph_vector_int_destroy(&level); igraph_dqueue_int_destroy(&q); diff --git a/src/vendor/cigraph/src/properties/loops.c b/src/vendor/cigraph/src/properties/loops.c index 36866a04ac2..e77a7de8d2d 100644 --- a/src/vendor/cigraph/src/properties/loops.c +++ b/src/vendor/cigraph/src/properties/loops.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -48,7 +46,7 @@ * \example examples/simple/igraph_is_loop.c */ igraph_error_t igraph_has_loop(const igraph_t *graph, igraph_bool_t *res) { - igraph_integer_t i, m = igraph_ecount(graph); + igraph_int_t i, m = igraph_ecount(graph); IGRAPH_RETURN_IF_CACHED_BOOL(graph, IGRAPH_PROP_HAS_LOOP, res); @@ -100,8 +98,8 @@ igraph_error_t igraph_is_loop(const igraph_t *graph, igraph_vector_bool_t *res, goto done; } - for (igraph_integer_t i = 0; !IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t e = IGRAPH_EIT_GET(eit); + for (igraph_int_t i = 0; !IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) { + igraph_int_t e = IGRAPH_EIT_GET(eit); igraph_bool_t is_loop = (IGRAPH_FROM(graph, e) == IGRAPH_TO(graph, e)); VECTOR(*res)[i] = is_loop; if (is_loop) { @@ -126,8 +124,6 @@ igraph_error_t igraph_is_loop(const igraph_t *graph, igraph_vector_bool_t *res, * \function igraph_count_loops * \brief Counts the self-loops in the graph. * - * \experimental - * * Counts loop edges, i.e. edges whose two endpoints coincide. * * \param graph The input graph. @@ -138,9 +134,9 @@ igraph_error_t igraph_is_loop(const igraph_t *graph, igraph_vector_bool_t *res, * * \example examples/simple/igraph_is_loop.c */ -igraph_error_t igraph_count_loops(const igraph_t *graph, igraph_integer_t *loop_count) { - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t count; +igraph_error_t igraph_count_loops(const igraph_t *graph, igraph_int_t *loop_count) { + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t count; /* Nothing to do if we know that there are no loops. */ if (igraph_i_property_cache_has(graph, IGRAPH_PROP_HAS_LOOP) && @@ -150,7 +146,7 @@ igraph_error_t igraph_count_loops(const igraph_t *graph, igraph_integer_t *loop_ } count = 0; - for (igraph_integer_t e=0; e < no_of_edges; e++) { + for (igraph_int_t e=0; e < no_of_edges; e++) { if (IGRAPH_FROM(graph, e) == IGRAPH_TO(graph, e)) { count++; } diff --git a/src/vendor/cigraph/src/properties/multiplicity.c b/src/vendor/cigraph/src/properties/multiplicity.c index d41678597e5..51b48248c18 100644 --- a/src/vendor/cigraph/src/properties/multiplicity.c +++ b/src/vendor/cigraph/src/properties/multiplicity.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -37,6 +35,11 @@ * \param graph The input graph. * \param res Pointer to a boolean constant, the result * is stored here. + * \param directed Whether to consider the directions of edges. \c IGRAPH_UNDIRECTED + * means that edge directions will be ignored and a directed graph with at + * least one mutual edge pair will be considered non-simple. \c IGRAPH_DIRECTED + * means that edge directions will be considered. Ignored for + * undirected graphs. * \return Error code. * * \sa \ref igraph_is_loop() and \ref igraph_is_multiple() to @@ -46,9 +49,9 @@ * * Time complexity: O(|V|+|E|). */ -igraph_error_t igraph_is_simple(const igraph_t *graph, igraph_bool_t *res) { - igraph_integer_t vc = igraph_vcount(graph); - igraph_integer_t ec = igraph_ecount(graph); +igraph_error_t igraph_is_simple(const igraph_t *graph, igraph_bool_t *res, igraph_bool_t directed) { + igraph_int_t vc = igraph_vcount(graph); + igraph_int_t ec = igraph_ecount(graph); /* Is it already known whether the graph has loops or multi-edges? */ igraph_bool_t known_loop, known_multi; @@ -56,12 +59,15 @@ igraph_error_t igraph_is_simple(const igraph_t *graph, igraph_bool_t *res) { /* If it is known, does the graph have them? */ igraph_bool_t has_loop, has_multi; + /* Will we need to check mutual edges explicitly? */ + igraph_bool_t need_to_check_mutual = directed == IGRAPH_UNDIRECTED && igraph_is_directed(graph); + known_loop = igraph_i_property_cache_has(graph, IGRAPH_PROP_HAS_LOOP); if (known_loop) { has_loop = igraph_i_property_cache_get_bool(graph, IGRAPH_PROP_HAS_LOOP); if (has_loop) { *res = false; - return IGRAPH_SUCCESS; + goto early_exit; } } @@ -70,15 +76,13 @@ igraph_error_t igraph_is_simple(const igraph_t *graph, igraph_bool_t *res) { has_multi = igraph_i_property_cache_get_bool(graph, IGRAPH_PROP_HAS_MULTI); if (has_multi) { *res = false; - return IGRAPH_SUCCESS; + goto early_exit; } } - if (known_loop && known_multi) { - if (!has_loop && !has_multi) { - *res = true; - return IGRAPH_SUCCESS; - } + if (known_loop && known_multi && !has_loop && !has_multi) { + *res = true; + goto early_exit; } /* Up to now, these variables were used to store the cache status. @@ -94,10 +98,12 @@ igraph_error_t igraph_is_simple(const igraph_t *graph, igraph_bool_t *res) { } else { igraph_vector_int_t neis; IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); - for (igraph_integer_t i = 0; i < vc; i++) { - IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, IGRAPH_OUT)); - const igraph_integer_t n = igraph_vector_int_size(&neis); - for (igraph_integer_t j = 0; j < n; j++) { + for (igraph_int_t i = 0; i < vc; i++) { + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, i, IGRAPH_OUT, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); + const igraph_int_t n = igraph_vector_int_size(&neis); + for (igraph_int_t j = 0; j < n; j++) { if (VECTOR(neis)[j] == i) { known_loop = true; has_loop = true; break; } @@ -126,6 +132,19 @@ igraph_error_t igraph_is_simple(const igraph_t *graph, igraph_bool_t *res) { igraph_i_property_cache_set_bool_checked(graph, IGRAPH_PROP_HAS_MULTI, has_multi); } +early_exit: + /* If at this point we have concluded that the graph is simple, _but_ the user + * asked us to ignore edge directions, we need to look for mutual edge pairs + * and return false if we find one. */ + if (*res && need_to_check_mutual) { + /* If the graph is undirected, we also check for mutual edges. */ + igraph_bool_t has_mutual; + IGRAPH_CHECK(igraph_has_mutual(graph, &has_mutual, false)); + if (has_mutual) { + *res = false; + } + } + return IGRAPH_SUCCESS; } @@ -155,8 +174,8 @@ igraph_error_t igraph_is_simple(const igraph_t *graph, igraph_bool_t *res) { * \example examples/simple/igraph_has_multiple.c */ igraph_error_t igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res) { - igraph_integer_t vc = igraph_vcount(graph); - igraph_integer_t ec = igraph_ecount(graph); + igraph_int_t vc = igraph_vcount(graph); + igraph_int_t ec = igraph_ecount(graph); igraph_bool_t directed = igraph_is_directed(graph); IGRAPH_RETURN_IF_CACHED_BOOL(graph, IGRAPH_PROP_HAS_MULTI, res); @@ -165,12 +184,13 @@ igraph_error_t igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res) { *res = false; } else { igraph_vector_int_t neis; - igraph_integer_t i, j, n; + igraph_int_t i, j, n; igraph_bool_t found = false; IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); for (i = 0; i < vc && !found; i++) { - IGRAPH_CHECK(igraph_neighbors(graph, &neis, i, - IGRAPH_OUT)); + IGRAPH_CHECK(igraph_neighbors( + graph, &neis, i, IGRAPH_OUT, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); n = igraph_vector_int_size(&neis); for (j = 1; j < n; j++) { if (VECTOR(neis)[j - 1] == VECTOR(neis)[j]) { @@ -229,7 +249,7 @@ igraph_error_t igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res) { igraph_error_t igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *res, igraph_es_t es) { igraph_eit_t eit; - igraph_integer_t i, j, n; + igraph_int_t i, j, n; igraph_lazy_inclist_t inclist; IGRAPH_CHECK(igraph_eit_create(graph, es, &eit)); @@ -241,9 +261,9 @@ igraph_error_t igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *r IGRAPH_CHECK(igraph_vector_bool_resize(res, IGRAPH_EIT_SIZE(eit))); for (i = 0; !IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t e = IGRAPH_EIT_GET(eit); - igraph_integer_t from = IGRAPH_FROM(graph, e); - igraph_integer_t to = IGRAPH_TO(graph, e); + igraph_int_t e = IGRAPH_EIT_GET(eit); + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); igraph_vector_int_t *neis = igraph_lazy_inclist_get(&inclist, from); IGRAPH_CHECK_OOM(neis, "Failed to query incident edges."); @@ -252,8 +272,8 @@ igraph_error_t igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *r n = igraph_vector_int_size(neis); for (j = 0; j < n; j++) { - igraph_integer_t e2 = VECTOR(*neis)[j]; - igraph_integer_t to2 = IGRAPH_OTHER(graph, e2, from); + igraph_int_t e2 = VECTOR(*neis)[j]; + igraph_int_t to2 = IGRAPH_OTHER(graph, e2, from); if (to2 == to && e2 < e) { VECTOR(*res)[i] = true; } @@ -293,7 +313,7 @@ igraph_error_t igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *r igraph_error_t igraph_count_multiple(const igraph_t *graph, igraph_vector_int_t *res, igraph_es_t es) { igraph_eit_t eit; - igraph_integer_t i, j, n; + igraph_int_t i, j, n; igraph_lazy_adjlist_t adjlist; IGRAPH_CHECK(igraph_eit_create(graph, es, &eit)); @@ -304,9 +324,9 @@ igraph_error_t igraph_count_multiple(const igraph_t *graph, igraph_vector_int_t IGRAPH_CHECK(igraph_vector_int_resize(res, IGRAPH_EIT_SIZE(eit))); for (i = 0; !IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t e = IGRAPH_EIT_GET(eit); - igraph_integer_t from = IGRAPH_FROM(graph, e); - igraph_integer_t to = IGRAPH_TO(graph, e); + igraph_int_t e = IGRAPH_EIT_GET(eit); + igraph_int_t from = IGRAPH_FROM(graph, e); + igraph_int_t to = IGRAPH_TO(graph, e); igraph_vector_int_t *neis = igraph_lazy_adjlist_get(&adjlist, from); IGRAPH_CHECK_OOM(neis, "Failed to query adjacent vertices."); @@ -344,16 +364,18 @@ igraph_error_t igraph_count_multiple(const igraph_t *graph, igraph_vector_int_t * * Time complexity: O(d), where d is the out-degree of the tail of the edge. */ -igraph_error_t igraph_count_multiple_1(const igraph_t *graph, igraph_integer_t *res, - igraph_integer_t eid) +igraph_error_t igraph_count_multiple_1(const igraph_t *graph, igraph_int_t *res, + igraph_int_t eid) { - igraph_integer_t i, n, count; - igraph_integer_t from = IGRAPH_FROM(graph, eid); - igraph_integer_t to = IGRAPH_TO(graph, eid); + igraph_int_t i, n, count; + igraph_int_t from = IGRAPH_FROM(graph, eid); + igraph_int_t to = IGRAPH_TO(graph, eid); igraph_vector_int_t vids; IGRAPH_VECTOR_INT_INIT_FINALLY(&vids, 0); - IGRAPH_CHECK(igraph_neighbors(graph, &vids, from, IGRAPH_OUT)); + IGRAPH_CHECK(igraph_neighbors( + graph, &vids, from, IGRAPH_OUT, IGRAPH_LOOPS, IGRAPH_MULTIPLE + )); count = 0; n = igraph_vector_int_size(&vids); @@ -406,7 +428,7 @@ igraph_error_t igraph_is_mutual(const igraph_t *graph, igraph_vector_bool_t *res igraph_eit_t eit; igraph_lazy_adjlist_t adjlist; - igraph_integer_t i; + igraph_int_t i; /* How many edges do we have? */ IGRAPH_CHECK(igraph_eit_create(graph, es, &eit)); @@ -426,9 +448,9 @@ igraph_error_t igraph_is_mutual(const igraph_t *graph, igraph_vector_bool_t *res IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist); for (i = 0; ! IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) { - igraph_integer_t edge = IGRAPH_EIT_GET(eit); - igraph_integer_t from = IGRAPH_FROM(graph, edge); - igraph_integer_t to = IGRAPH_TO(graph, edge); + igraph_int_t edge = IGRAPH_EIT_GET(eit); + igraph_int_t from = IGRAPH_FROM(graph, edge); + igraph_int_t to = IGRAPH_TO(graph, edge); if (from == to) { VECTOR(*res)[i] = loops; @@ -477,7 +499,7 @@ igraph_error_t igraph_is_mutual(const igraph_t *graph, igraph_vector_bool_t *res */ igraph_error_t igraph_has_mutual(const igraph_t *graph, igraph_bool_t *res, igraph_bool_t loops) { - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_lazy_adjlist_t adjlist; if (! igraph_is_directed(graph)) { @@ -507,9 +529,9 @@ igraph_error_t igraph_has_mutual(const igraph_t *graph, igraph_bool_t *res, IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist); *res = false; /* assume no mutual edges */ - for (igraph_integer_t edge=0; edge < no_of_edges; edge++) { - igraph_integer_t from = IGRAPH_FROM(graph, edge); - igraph_integer_t to = IGRAPH_TO(graph, edge); + for (igraph_int_t edge=0; edge < no_of_edges; edge++) { + igraph_int_t from = IGRAPH_FROM(graph, edge); + igraph_int_t to = IGRAPH_TO(graph, edge); if (from == to) { if (loops) { diff --git a/src/vendor/cigraph/src/properties/neighborhood.c b/src/vendor/cigraph/src/properties/neighborhood.c index 070eed61acf..58e44a88416 100644 --- a/src/vendor/cigraph/src/properties/neighborhood.c +++ b/src/vendor/cigraph/src/properties/neighborhood.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -70,14 +68,14 @@ * the calculation is performed, d is the average degree, o is the order. */ igraph_error_t igraph_neighborhood_size(const igraph_t *graph, igraph_vector_int_t *res, - igraph_vs_t vids, igraph_integer_t order, + igraph_vs_t vids, igraph_int_t order, igraph_neimode_t mode, - igraph_integer_t mindist) { + igraph_int_t mindist) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_dqueue_int_t q; igraph_vit_t vit; - igraph_integer_t *added; + igraph_int_t *added; igraph_vector_int_t neis; igraph_bool_t inf_order = false; @@ -98,7 +96,7 @@ igraph_error_t igraph_neighborhood_size(const igraph_t *graph, igraph_vector_int IGRAPH_EINVAL, order, mindist); } - added = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + added = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(added, "Insufficient memory to calculate neighborhood sizes."); IGRAPH_FINALLY(igraph_free, added); @@ -108,9 +106,9 @@ igraph_error_t igraph_neighborhood_size(const igraph_t *graph, igraph_vector_int IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); IGRAPH_CHECK(igraph_vector_int_resize(res, IGRAPH_VIT_SIZE(vit))); - for (igraph_integer_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - const igraph_integer_t node = IGRAPH_VIT_GET(vit); - igraph_integer_t size = mindist == 0 ? 1 : 0; + for (igraph_int_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { + const igraph_int_t node = IGRAPH_VIT_GET(vit); + igraph_int_t size = mindist == 0 ? 1 : 0; added[node] = i + 1; igraph_dqueue_int_clear(&q); if (order > 0) { @@ -119,16 +117,16 @@ igraph_error_t igraph_neighborhood_size(const igraph_t *graph, igraph_vector_int } while (!igraph_dqueue_int_empty(&q)) { - const igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - const igraph_integer_t actdist = igraph_dqueue_int_pop(&q); + const igraph_int_t actnode = igraph_dqueue_int_pop(&q); + const igraph_int_t actdist = igraph_dqueue_int_pop(&q); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode)); - const igraph_integer_t n = igraph_vector_int_size(&neis); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); + const igraph_int_t n = igraph_vector_int_size(&neis); if (actdist < order - 1) { /* we add them to the q */ - for (igraph_integer_t j = 0; j < n; j++) { - igraph_integer_t nei = VECTOR(neis)[j]; + for (igraph_int_t j = 0; j < n; j++) { + igraph_int_t nei = VECTOR(neis)[j]; if (added[nei] != i + 1) { added[nei] = i + 1; IGRAPH_CHECK(igraph_dqueue_int_push(&q, nei)); @@ -140,8 +138,8 @@ igraph_error_t igraph_neighborhood_size(const igraph_t *graph, igraph_vector_int } } else { /* we just count them, but don't add them */ - for (igraph_integer_t j = 0; j < n; j++) { - const igraph_integer_t nei = VECTOR(neis)[j]; + for (igraph_int_t j = 0; j < n; j++) { + const igraph_int_t nei = VECTOR(neis)[j]; if (added[nei] != i + 1) { added[nei] = i + 1; if (actdist + 1 >= mindist) { @@ -208,13 +206,13 @@ igraph_error_t igraph_neighborhood_size(const igraph_t *graph, igraph_vector_int * order. */ igraph_error_t igraph_neighborhood(const igraph_t *graph, igraph_vector_int_list_t *res, - igraph_vs_t vids, igraph_integer_t order, - igraph_neimode_t mode, igraph_integer_t mindist) { + igraph_vs_t vids, igraph_int_t order, + igraph_neimode_t mode, igraph_int_t mindist) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_dqueue_int_t q; igraph_vit_t vit; - igraph_integer_t *added; + igraph_int_t *added; igraph_vector_int_t neis; igraph_vector_int_t tmp; igraph_bool_t inf_order = false; @@ -232,7 +230,7 @@ igraph_error_t igraph_neighborhood(const igraph_t *graph, igraph_vector_int_list IGRAPH_EINVAL, order, mindist); } - added = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + added = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(added, "Insufficient memory to calculate neighborhood sizes."); IGRAPH_FINALLY(igraph_free, added); @@ -244,8 +242,8 @@ igraph_error_t igraph_neighborhood(const igraph_t *graph, igraph_vector_int_list IGRAPH_CHECK(igraph_vector_int_list_reserve(res, IGRAPH_VIT_SIZE(vit))); igraph_vector_int_list_clear(res); - for (igraph_integer_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - const igraph_integer_t node = IGRAPH_VIT_GET(vit); + for (igraph_int_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { + const igraph_int_t node = IGRAPH_VIT_GET(vit); added[node] = i + 1; igraph_vector_int_clear(&tmp); if (mindist == 0) { @@ -257,16 +255,16 @@ igraph_error_t igraph_neighborhood(const igraph_t *graph, igraph_vector_int_list } while (!igraph_dqueue_int_empty(&q)) { - const igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - const igraph_integer_t actdist = igraph_dqueue_int_pop(&q); + const igraph_int_t actnode = igraph_dqueue_int_pop(&q); + const igraph_int_t actdist = igraph_dqueue_int_pop(&q); - IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode)); - const igraph_integer_t n = igraph_vector_int_size(&neis); + IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); + const igraph_int_t n = igraph_vector_int_size(&neis); if (actdist < order - 1) { /* we add them to the q */ - for (igraph_integer_t j = 0; j < n; j++) { - const igraph_integer_t nei = VECTOR(neis)[j]; + for (igraph_int_t j = 0; j < n; j++) { + const igraph_int_t nei = VECTOR(neis)[j]; if (added[nei] != i + 1) { added[nei] = i + 1; IGRAPH_CHECK(igraph_dqueue_int_push(&q, nei)); @@ -278,8 +276,8 @@ igraph_error_t igraph_neighborhood(const igraph_t *graph, igraph_vector_int_list } } else { /* we just count them but don't add them to q */ - for (igraph_integer_t j = 0; j < n; j++) { - const igraph_integer_t nei = VECTOR(neis)[j]; + for (igraph_int_t j = 0; j < n; j++) { + const igraph_int_t nei = VECTOR(neis)[j]; if (added[nei] != i + 1) { added[nei] = i + 1; if (actdist + 1 >= mindist) { @@ -352,13 +350,13 @@ igraph_error_t igraph_neighborhood(const igraph_t *graph, igraph_vector_int_list * vertices and edges in the original input graph. */ igraph_error_t igraph_neighborhood_graphs(const igraph_t *graph, igraph_graph_list_t *res, - igraph_vs_t vids, igraph_integer_t order, + igraph_vs_t vids, igraph_int_t order, igraph_neimode_t mode, - igraph_integer_t mindist) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t mindist) { + const igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_dqueue_int_t q; igraph_vit_t vit; - igraph_integer_t *added; + igraph_int_t *added; igraph_vector_int_t neis; igraph_vector_int_t tmp; igraph_t newg; @@ -377,7 +375,7 @@ igraph_error_t igraph_neighborhood_graphs(const igraph_t *graph, igraph_graph_li IGRAPH_EINVAL, order, mindist); } - added = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + added = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(added, "Insufficient memory to calculate neighborhood graphs."); IGRAPH_FINALLY(igraph_free, added); @@ -389,8 +387,8 @@ igraph_error_t igraph_neighborhood_graphs(const igraph_t *graph, igraph_graph_li igraph_graph_list_clear(res); - for (igraph_integer_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - const igraph_integer_t node = IGRAPH_VIT_GET(vit); + for (igraph_int_t i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { + const igraph_int_t node = IGRAPH_VIT_GET(vit); added[node] = i + 1; igraph_vector_int_clear(&tmp); if (mindist == 0) { @@ -402,16 +400,16 @@ igraph_error_t igraph_neighborhood_graphs(const igraph_t *graph, igraph_graph_li } while (!igraph_dqueue_int_empty(&q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&q); - igraph_integer_t actdist = igraph_dqueue_int_pop(&q); - igraph_integer_t n; - IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode)); + igraph_int_t actnode = igraph_dqueue_int_pop(&q); + igraph_int_t actdist = igraph_dqueue_int_pop(&q); + igraph_int_t n; + IGRAPH_CHECK(igraph_neighbors(graph, &neis, actnode, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); n = igraph_vector_int_size(&neis); if (actdist < order - 1) { /* we add them to the q */ - for (igraph_integer_t j = 0; j < n; j++) { - const igraph_integer_t nei = VECTOR(neis)[j]; + for (igraph_int_t j = 0; j < n; j++) { + const igraph_int_t nei = VECTOR(neis)[j]; if (added[nei] != i + 1) { added[nei] = i + 1; IGRAPH_CHECK(igraph_dqueue_int_push(&q, nei)); @@ -423,8 +421,8 @@ igraph_error_t igraph_neighborhood_graphs(const igraph_t *graph, igraph_graph_li } } else { /* we just count them but don't add them to q */ - for (igraph_integer_t j = 0; j < n; j++) { - const igraph_integer_t nei = VECTOR(neis)[j]; + for (igraph_int_t j = 0; j < n; j++) { + const igraph_int_t nei = VECTOR(neis)[j]; if (added[nei] != i + 1) { added[nei] = i + 1; if (actdist + 1 >= mindist) { diff --git a/src/vendor/cigraph/src/properties/perfect.c b/src/vendor/cigraph/src/properties/perfect.c index de1b42623c8..f931427a467 100644 --- a/src/vendor/cigraph/src/properties/perfect.c +++ b/src/vendor/cigraph/src/properties/perfect.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -23,7 +22,7 @@ #include "igraph_constructors.h" #include "igraph_interface.h" #include "igraph_operators.h" -#include "igraph_topology.h" +#include "igraph_isomorphism.h" #include "core/interruption.h" @@ -57,10 +56,10 @@ igraph_error_t igraph_is_perfect(const igraph_t *graph, igraph_bool_t *perfect) igraph_bool_t is_bipartite, is_chordal, iso, is_simple; igraph_real_t girth, comp_girth; - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t start; - igraph_integer_t cycle_len; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t start; + igraph_int_t cycle_len; igraph_t comp_graph, cycle; // If the graph is directed return error. @@ -69,7 +68,7 @@ igraph_error_t igraph_is_perfect(const igraph_t *graph, igraph_bool_t *perfect) } // If the graph isn't simple then return an error. - IGRAPH_CHECK(igraph_is_simple(graph, &is_simple)); + IGRAPH_CHECK(igraph_is_simple(graph, &is_simple, IGRAPH_DIRECTED)); if (!is_simple) { IGRAPH_ERROR("Perfect graph testing is implemented for simple graphs only. Simplify the graph.", IGRAPH_EINVAL); } @@ -130,13 +129,13 @@ igraph_error_t igraph_is_perfect(const igraph_t *graph, igraph_bool_t *perfect) // If the girth (or the smallest circle in the graph) is bigger than 3 and have odd number of vertices then // the graph isn't perfect. IGRAPH_CHECK(igraph_girth(graph, &girth, NULL)); - if ((girth > 3) && (((igraph_integer_t)girth) % 2 == 1)) { + if ((girth > 3) && (((igraph_int_t)girth) % 2 == 1)) { *perfect = false; goto clean1; } IGRAPH_CHECK(igraph_girth(&comp_graph, &comp_girth, NULL)); - if ((comp_girth > 3) && (((igraph_integer_t)comp_girth) % 2 == 1)) { + if ((comp_girth > 3) && (((igraph_int_t)comp_girth) % 2 == 1)) { *perfect = false; goto clean1; } @@ -146,7 +145,7 @@ igraph_error_t igraph_is_perfect(const igraph_t *graph, igraph_bool_t *perfect) // Strong perfect graph theorem: // A graph is perfect iff neither it or its complement contains an induced odd cycle of length >= 5 // (i.e. an odd hole). TODO: Find a more efficient way to check for odd holes. - start = (igraph_integer_t) (girth < comp_girth ? girth : comp_girth); + start = (igraph_int_t) (girth < comp_girth ? girth : comp_girth); start = start % 2 == 0 ? start + 1 : start + 2; for (cycle_len = start; cycle_len <= no_of_nodes ; cycle_len += 2) { @@ -156,7 +155,7 @@ igraph_error_t igraph_is_perfect(const igraph_t *graph, igraph_bool_t *perfect) IGRAPH_FINALLY(igraph_destroy, &cycle); if (cycle_len > girth) { - IGRAPH_CHECK(igraph_subisomorphic_lad(&cycle, graph, NULL, &iso, NULL, NULL, /* induced */ 1, 0)); + IGRAPH_CHECK(igraph_subisomorphic_lad(&cycle, graph, NULL, &iso, NULL, NULL, /* induced */ 1)); if (iso) { *perfect = false; goto clean2; @@ -164,7 +163,7 @@ igraph_error_t igraph_is_perfect(const igraph_t *graph, igraph_bool_t *perfect) } if (cycle_len > comp_girth) { - IGRAPH_CHECK(igraph_subisomorphic_lad(&cycle, &comp_graph, NULL, &iso, NULL, NULL, /* induced */ 1, 0)); + IGRAPH_CHECK(igraph_subisomorphic_lad(&cycle, &comp_graph, NULL, &iso, NULL, NULL, /* induced */ 1)); if (iso) { *perfect = false; goto clean2; diff --git a/src/vendor/cigraph/src/properties/properties_internal.h b/src/vendor/cigraph/src/properties/properties_internal.h index b12b1b43341..e16b6e5f92b 100644 --- a/src/vendor/cigraph/src/properties/properties_internal.h +++ b/src/vendor/cigraph/src/properties/properties_internal.h @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2011-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -24,11 +23,11 @@ #include "igraph_decls.h" #include "igraph_iterators.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS igraph_error_t igraph_i_trans4_al_simplify(igraph_adjlist_t *al, const igraph_vector_int_t *rank); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/properties/rich_club.c b/src/vendor/cigraph/src/properties/rich_club.c index f771315acea..30076270b53 100644 --- a/src/vendor/cigraph/src/properties/rich_club.c +++ b/src/vendor/cigraph/src/properties/rich_club.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2025 The igraph development team This program is free software; you can redistribute it and/or modify @@ -19,7 +19,7 @@ #include "igraph_structural.h" #include "igraph_interface.h" -#include "igraph_topology.h" +#include "igraph_isomorphism.h" /* Returns the total number of possible edges given the number of vertices in a graph, * whether it is directed, and whether loops should be assumed possible. @@ -29,7 +29,7 @@ * Loops, undirected: n * (n+1) / 2 * Loops, directed: n^2 */ -static igraph_real_t total_possible_edges(igraph_integer_t vcount, +static igraph_real_t total_possible_edges(igraph_int_t vcount, igraph_bool_t directed, igraph_bool_t loops) { igraph_real_t nv = (igraph_real_t) vcount; @@ -95,8 +95,8 @@ igraph_error_t igraph_rich_club_sequence( igraph_bool_t normalized, igraph_bool_t loops, igraph_bool_t directed) { - const igraph_integer_t vcount = igraph_vcount(graph); - const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); igraph_vector_int_t order_of; // Error handling: invalid vertex_order and weights sizes @@ -126,32 +126,32 @@ igraph_error_t igraph_rich_club_sequence( igraph_bool_t warning_issued = false; // remaining_total_weight vector: number of edges (or total edge weight) removed by index - for (igraph_integer_t eid = 0; eid < ecount; eid++) { - igraph_integer_t v1 = IGRAPH_FROM(graph, eid); - igraph_integer_t v2 = IGRAPH_TO(graph, eid); + for (igraph_int_t eid = 0; eid < ecount; eid++) { + igraph_int_t v1 = IGRAPH_FROM(graph, eid); + igraph_int_t v2 = IGRAPH_TO(graph, eid); if (!loops && normalized && !warning_issued && v1 == v2) { IGRAPH_WARNING("Self-loops were requested to be assumed absent, " "but encountered a self-loop. Density calculations will proceed " "with the assumption of no loops."); warning_issued = true; } - igraph_integer_t order_v1 = VECTOR(order_of)[v1]; // order of endpoints - igraph_integer_t order_v2 = VECTOR(order_of)[v2]; + igraph_int_t order_v1 = VECTOR(order_of)[v1]; // order of endpoints + igraph_int_t order_v2 = VECTOR(order_of)[v2]; - igraph_integer_t edge_removal_index = (order_v1 < order_v2 ? order_v1 : order_v2); + igraph_int_t edge_removal_index = (order_v1 < order_v2 ? order_v1 : order_v2); VECTOR(*res)[edge_removal_index] += (weights ? VECTOR(*weights)[eid] : 1); } // remaining_total_weight vector: edges (or total edge weight) remaining after i removals igraph_real_t total = 0; - for (igraph_integer_t i = vcount - 1; i >= 0; i--) { + for (igraph_int_t i = vcount - 1; i >= 0; i--) { total += VECTOR(*res)[i]; VECTOR(*res)[i] = total; } // Normalize edge counts to densities if (normalized) { - for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_int_t i = 0; i < vcount; i++) { // (vcount - i) = the number of vertices left in this loop VECTOR(*res)[i] = VECTOR(*res)[i] / diff --git a/src/vendor/cigraph/src/properties/spectral.c b/src/vendor/cigraph/src/properties/spectral.c index e362cef7454..fa6df094a29 100644 --- a/src/vendor/cigraph/src/properties/spectral.c +++ b/src/vendor/cigraph/src/properties/spectral.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -32,7 +30,7 @@ static igraph_error_t igraph_i_laplacian_validate_weights( const igraph_t* graph, const igraph_vector_t* weights ) { - igraph_integer_t no_of_edges; + igraph_int_t no_of_edges; if (weights == NULL) { return IGRAPH_SUCCESS; @@ -104,11 +102,11 @@ igraph_error_t igraph_get_laplacian( igraph_laplacian_normalization_t normalization, const igraph_vector_t *weights ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t directed = igraph_is_directed(graph); igraph_vector_t degree; - igraph_integer_t i; + igraph_int_t i; IGRAPH_ASSERT(res != NULL); @@ -154,8 +152,8 @@ igraph_error_t igraph_get_laplacian( } for (i = 0; i < no_of_edges; i++) { - igraph_integer_t from = IGRAPH_FROM(graph, i); - igraph_integer_t to = IGRAPH_TO(graph, i); + igraph_int_t from = IGRAPH_FROM(graph, i); + igraph_int_t to = IGRAPH_TO(graph, i); igraph_real_t weight = weights ? VECTOR(*weights)[i] : 1.0; igraph_real_t norm; @@ -256,12 +254,12 @@ igraph_error_t igraph_get_laplacian_sparse( igraph_laplacian_normalization_t normalization, const igraph_vector_t *weights ) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t directed = igraph_is_directed(graph); igraph_vector_t degree; - igraph_integer_t i; - igraph_integer_t nz; + igraph_int_t i; + igraph_int_t nz; if (directed) { IGRAPH_SAFE_ADD(no_of_edges, no_of_nodes, &nz); @@ -305,8 +303,8 @@ igraph_error_t igraph_get_laplacian_sparse( } for (i = 0; i < no_of_edges; i++) { - igraph_integer_t from = IGRAPH_FROM(graph, i); - igraph_integer_t to = IGRAPH_TO(graph, i); + igraph_int_t from = IGRAPH_FROM(graph, i); + igraph_int_t to = IGRAPH_TO(graph, i); igraph_real_t weight = weights ? VECTOR(*weights)[i] : 1.0; igraph_real_t norm; @@ -373,59 +371,3 @@ igraph_error_t igraph_get_laplacian_sparse( return IGRAPH_SUCCESS; } - -/** - * \function igraph_laplacian - * \brief Returns the Laplacian matrix of a graph (deprecated). - * - * This function produces the Laplacian matrix of a graph in either dense or - * sparse format. When \p normalized is set to true, the type of normalization - * used depends on the directnedness of the graph: symmetric normalization - * is used for undirected graphs and left stochastic normalization for - * directed graphs. - * - * \param graph Pointer to the graph to convert. - * \param res Pointer to an initialized matrix object or \c NULL. The dense matrix - * result will be stored here. - * \param sparseres Pointer to an initialized sparse matrix object or \c NULL. - * The sparse matrix result will be stored here. - * \param mode Controls whether to use out- or in-degrees in directed graphs. - * If set to \c IGRAPH_ALL, edge directions will be ignored. - * \param normalized Boolean, whether to normalize the result. - * \param weights An optional vector containing non-negative edge weights, - * to calculate the weighted Laplacian matrix. Set it to a null pointer to - * calculate the unweighted Laplacian. - * \return Error code. - * - * \deprecated-by igraph_get_laplacian 0.10.0 - */ - -igraph_error_t igraph_laplacian( - const igraph_t *graph, igraph_matrix_t *res, igraph_sparsemat_t *sparseres, - igraph_bool_t normalized, const igraph_vector_t *weights -) { - igraph_laplacian_normalization_t norm_method = IGRAPH_LAPLACIAN_UNNORMALIZED; - - if (!res && !sparseres) { - IGRAPH_ERROR("Laplacian: specify at least one of 'res' or 'sparseres'", - IGRAPH_EINVAL); - } - - if (normalized) { - if (igraph_is_directed(graph)) { - norm_method = IGRAPH_LAPLACIAN_LEFT; - } else { - norm_method = IGRAPH_LAPLACIAN_SYMMETRIC; - } - } - - if (res) { - IGRAPH_CHECK(igraph_get_laplacian(graph, res, IGRAPH_OUT, norm_method, weights)); - } - - if (sparseres) { - IGRAPH_CHECK(igraph_get_laplacian_sparse(graph, sparseres, IGRAPH_OUT, norm_method, weights)); - } - - return IGRAPH_SUCCESS; -} diff --git a/src/vendor/cigraph/src/properties/trees.c b/src/vendor/cigraph/src/properties/trees.c index a10ab58643c..2ab6620f22c 100644 --- a/src/vendor/cigraph/src/properties/trees.c +++ b/src/vendor/cigraph/src/properties/trees.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2021 The igraph development team This program is free software; you can redistribute it and/or modify @@ -22,10 +20,10 @@ */ #include "igraph_structural.h" -#include "igraph_topology.h" #include "igraph_bitset.h" #include "igraph_constructors.h" +#include "igraph_cycles.h" #include "igraph_dqueue.h" #include "igraph_interface.h" #include "igraph_stack.h" @@ -60,10 +58,10 @@ igraph_error_t igraph_unfold_tree(const igraph_t *graph, igraph_t *tree, igraph_neimode_t mode, const igraph_vector_int_t *roots, igraph_vector_int_t *vertex_index) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_roots = igraph_vector_int_size(roots); - igraph_integer_t tree_vertex_count = no_of_nodes; + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_roots = igraph_vector_int_size(roots); + igraph_int_t tree_vertex_count = no_of_nodes; igraph_vector_int_t edges; igraph_bitset_t seen_vertices; @@ -72,7 +70,7 @@ igraph_error_t igraph_unfold_tree(const igraph_t *graph, igraph_t *tree, igraph_dqueue_int_t Q; igraph_vector_int_t neis; - igraph_integer_t v_ptr = no_of_nodes; + igraph_int_t v_ptr = no_of_nodes; if (! igraph_vector_int_isininterval(roots, 0, no_of_nodes-1)) { IGRAPH_ERROR("All roots should be vertices of the graph.", IGRAPH_EINVVID); @@ -89,24 +87,24 @@ igraph_error_t igraph_unfold_tree(const igraph_t *graph, igraph_t *tree, IGRAPH_CHECK(igraph_vector_int_range(vertex_index, 0, no_of_nodes)); } - for (igraph_integer_t r = 0; r < no_of_roots; r++) { + for (igraph_int_t r = 0; r < no_of_roots; r++) { - igraph_integer_t root = VECTOR(*roots)[r]; + igraph_int_t root = VECTOR(*roots)[r]; IGRAPH_BIT_SET(seen_vertices, root); IGRAPH_CHECK(igraph_dqueue_int_push(&Q, root)); while (!igraph_dqueue_int_empty(&Q)) { - igraph_integer_t actnode = igraph_dqueue_int_pop(&Q); + igraph_int_t actnode = igraph_dqueue_int_pop(&Q); - IGRAPH_CHECK(igraph_incident(graph, &neis, actnode, mode)); + IGRAPH_CHECK(igraph_incident(graph, &neis, actnode, mode, IGRAPH_LOOPS)); - igraph_integer_t n = igraph_vector_int_size(&neis); - for (igraph_integer_t i = 0; i < n; i++) { + igraph_int_t n = igraph_vector_int_size(&neis); + for (igraph_int_t i = 0; i < n; i++) { - igraph_integer_t edge = VECTOR(neis)[i]; - igraph_integer_t from = IGRAPH_FROM(graph, edge); - igraph_integer_t to = IGRAPH_TO(graph, edge); - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, actnode); + igraph_int_t edge = VECTOR(neis)[i]; + igraph_int_t from = IGRAPH_FROM(graph, edge); + igraph_int_t to = IGRAPH_TO(graph, edge); + igraph_int_t nei = IGRAPH_OTHER(graph, edge, actnode); if (! IGRAPH_BIT_TEST(seen_edges, edge)) { @@ -159,11 +157,11 @@ igraph_error_t igraph_unfold_tree(const igraph_t *graph, igraph_t *tree, /* igraph_is_tree -- check if a graph is a tree */ /* count the number of vertices reachable from the root */ -static igraph_error_t igraph_i_is_tree_visitor(const igraph_t *graph, igraph_integer_t root, igraph_neimode_t mode, igraph_integer_t *visited_count) { +static igraph_error_t igraph_i_is_tree_visitor(const igraph_t *graph, igraph_int_t root, igraph_neimode_t mode, igraph_int_t *visited_count) { igraph_stack_int_t stack; igraph_bitset_t visited; igraph_vector_int_t neighbors; - igraph_integer_t i; + igraph_int_t i; IGRAPH_VECTOR_INT_INIT_FINALLY(&neighbors, 0); @@ -178,8 +176,8 @@ static igraph_error_t igraph_i_is_tree_visitor(const igraph_t *graph, igraph_int IGRAPH_CHECK(igraph_stack_int_push(&stack, root)); while (! igraph_stack_int_empty(&stack)) { - igraph_integer_t u; - igraph_integer_t ncount; + igraph_int_t u; + igraph_int_t ncount; /* take a vertex from the stack, mark it as visited */ u = igraph_stack_int_pop(&stack); @@ -189,10 +187,10 @@ static igraph_error_t igraph_i_is_tree_visitor(const igraph_t *graph, igraph_int } /* register all its yet-unvisited neighbours for future processing */ - IGRAPH_CHECK(igraph_neighbors(graph, &neighbors, u, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, &neighbors, u, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); ncount = igraph_vector_int_size(&neighbors); for (i = 0; i < ncount; ++i) { - igraph_integer_t v = VECTOR(neighbors)[i]; + igraph_int_t v = VECTOR(neighbors)[i]; if (! IGRAPH_BIT_TEST(visited, v)) { IGRAPH_CHECK(igraph_stack_int_push(&stack, v)); } @@ -250,12 +248,12 @@ static igraph_error_t igraph_i_is_tree_visitor(const igraph_t *graph, igraph_int * * \example examples/simple/igraph_kary_tree.c */ -igraph_error_t igraph_is_tree(const igraph_t *graph, igraph_bool_t *res, igraph_integer_t *root, igraph_neimode_t mode) { +igraph_error_t igraph_is_tree(const igraph_t *graph, igraph_bool_t *res, igraph_int_t *root, igraph_neimode_t mode) { igraph_bool_t is_tree = false; igraph_bool_t treat_as_undirected = !igraph_is_directed(graph) || mode == IGRAPH_ALL; - igraph_integer_t iroot = 0; - igraph_integer_t visited_count; - igraph_integer_t vcount, ecount; + igraph_int_t iroot = 0; + igraph_int_t visited_count; + igraph_int_t vcount, ecount; vcount = igraph_vcount(graph); ecount = igraph_ecount(graph); @@ -327,12 +325,12 @@ igraph_error_t igraph_is_tree(const igraph_t *graph, igraph_bool_t *res, igraph_ case IGRAPH_IN: case IGRAPH_OUT: { igraph_vector_int_t degree; - igraph_integer_t i; + igraph_int_t i; IGRAPH_CHECK(igraph_vector_int_init(°ree, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, °ree); - IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), mode == IGRAPH_IN ? IGRAPH_OUT : IGRAPH_IN, IGRAPH_LOOPS)); + IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_REVERSE_MODE(mode), IGRAPH_LOOPS)); for (i = 0; i < vcount; ++i) { if (VECTOR(degree)[i] == 0) { @@ -402,11 +400,11 @@ igraph_error_t igraph_is_tree(const igraph_t *graph, igraph_bool_t *res, igraph_ * including 'root' itself. */ static igraph_error_t igraph_i_is_forest_visitor( - const igraph_t *graph, igraph_integer_t root, igraph_neimode_t mode, + const igraph_t *graph, igraph_int_t root, igraph_neimode_t mode, igraph_bitset_t *visited, igraph_stack_int_t *stack, igraph_vector_int_t *neis, - igraph_integer_t *visited_count, igraph_bool_t *res) + igraph_int_t *visited_count, igraph_bool_t *res) { - igraph_integer_t i; + igraph_int_t i; igraph_stack_int_clear(stack); @@ -414,8 +412,8 @@ static igraph_error_t igraph_i_is_forest_visitor( IGRAPH_CHECK(igraph_stack_int_push(stack, root)); while (! igraph_stack_int_empty(stack)) { - igraph_integer_t u; - igraph_integer_t ncount; + igraph_int_t u; + igraph_int_t ncount; /* Take a vertex from stack and check if it is already visited. * If yes, then we found a cycle: the graph is not a forest. @@ -432,11 +430,11 @@ static igraph_error_t igraph_i_is_forest_visitor( } /* Vertex discovery: Register all its neighbours for future processing */ - IGRAPH_CHECK(igraph_neighbors(graph, neis, u, mode)); + IGRAPH_CHECK(igraph_neighbors(graph, neis, u, mode, IGRAPH_LOOPS, IGRAPH_MULTIPLE)); ncount = igraph_vector_int_size(neis); for (i = 0; i < ncount; ++i) { - igraph_integer_t v = VECTOR(*neis)[i]; + igraph_int_t v = VECTOR(*neis)[i]; if (mode == IGRAPH_ALL) { /* In the undirected case, we avoid returning to the predecessor @@ -516,7 +514,8 @@ static igraph_error_t igraph_i_is_forest( * number of vertices plus the number of edges in the graph. * * \sa \ref igraph_is_tree() to check if a graph is a tree, i.e. a forest with - * a single component. + * a single component; \ref igraph_is_acyclic() to check if a graph lacks + * (undirected or directed) cycles. */ igraph_error_t igraph_is_forest(const igraph_t *graph, igraph_bool_t *res, igraph_vector_int_t *roots, igraph_neimode_t mode) { @@ -587,9 +586,9 @@ static igraph_error_t igraph_i_is_forest( igraph_bitset_t visited; igraph_vector_int_t neis; igraph_stack_int_t stack; - igraph_integer_t visited_count = 0; - igraph_integer_t vcount, ecount; - igraph_integer_t v; + igraph_int_t visited_count = 0; + igraph_int_t vcount, ecount; + igraph_int_t v; igraph_bool_t result; vcount = igraph_vcount(graph); @@ -674,7 +673,7 @@ static igraph_error_t igraph_i_is_forest( IGRAPH_VECTOR_INT_INIT_FINALLY(°ree, 0); IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), - IGRAPH_REVERSE_MODE(mode), /* loops = */ 1)); + IGRAPH_REVERSE_MODE(mode), IGRAPH_LOOPS)); for (v = 0; v < vcount; ++v) { /* In an out-tree, roots have in-degree 0, @@ -733,6 +732,11 @@ static igraph_error_t igraph_i_is_forest( * This function checks whether a graph has any cycles. Edge directions are * considered, i.e. in directed graphs, only directed cycles are searched for. * + * + * The result of this function is cached in the graph itself; calling + * the function multiple times with no modifications to the graph in between + * will return a cached value in O(1) time. + * * \param graph The input graph. * \param res Pointer to a boolean constant, the result is stored here. @@ -740,7 +744,8 @@ static igraph_error_t igraph_i_is_forest( * * \sa \ref igraph_find_cycle() to find a cycle that demonstrates * that the graph is not acyclic; \ref igraph_is_forest() to look - * for undirected cycles even in directed graphs. + * for undirected cycles even in directed graphs; \ref igraph_is_dag() + * to test specifically for directed acyclic graphs. * * Time complexity: O(|V|+|E|), where |V| and |E| are the number of * vertices and edges in the original input graph. diff --git a/src/vendor/cigraph/src/properties/triangles.c b/src/vendor/cigraph/src/properties/triangles.c index ea21c355f2f..eaed274feb2 100644 --- a/src/vendor/cigraph/src/properties/triangles.c +++ b/src/vendor/cigraph/src/properties/triangles.c @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -81,7 +79,7 @@ igraph_error_t igraph_transitivity_avglocal_undirected(const igraph_t *graph, igraph_real_t *res, igraph_transitivity_mode_t mode) { - igraph_integer_t i, no_of_nodes = igraph_vcount(graph), nans = 0; + igraph_int_t i, no_of_nodes = igraph_vcount(graph), nans = 0; igraph_real_t sum = 0.0; igraph_vector_t vec; @@ -130,16 +128,16 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, const igraph_vs_t vids, igraph_transitivity_mode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vit_t vit; - igraph_integer_t nodes_to_calc, affected_nodes; - igraph_integer_t maxdegree = 0; - igraph_integer_t i, j, k, nn; + igraph_int_t nodes_to_calc, affected_nodes; + igraph_int_t maxdegree = 0; + igraph_int_t i, j, k, nn; igraph_lazy_adjlist_t adjlist; igraph_vector_int_t degree; igraph_vector_t indexv, avids, rank, triangles; igraph_vector_int_t order; - igraph_integer_t *neis; + igraph_int_t *neis; IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); @@ -153,9 +151,9 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_reserve(&avids, nodes_to_calc)); k = 0; for (i = 0; i < nodes_to_calc; IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t v = IGRAPH_VIT_GET(vit); + igraph_int_t v = IGRAPH_VIT_GET(vit); igraph_vector_int_t *neis2; - igraph_integer_t neilen; + igraph_int_t neilen; if (VECTOR(indexv)[v] == 0) { VECTOR(indexv)[v] = k + 1; k++; IGRAPH_CHECK(igraph_vector_push_back(&avids, v)); @@ -166,7 +164,7 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, neilen = igraph_vector_int_size(neis2); for (j = 0; j < neilen; j++) { - igraph_integer_t nei = VECTOR(*neis2)[j]; + igraph_int_t nei = VECTOR(*neis2)[j]; if (VECTOR(indexv)[nei] == 0) { VECTOR(indexv)[nei] = k + 1; k++; IGRAPH_CHECK(igraph_vector_push_back(&avids, nei)); @@ -179,9 +177,9 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&order, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(°ree, affected_nodes); for (i = 0; i < affected_nodes; i++) { - igraph_integer_t v = VECTOR(avids)[i]; + igraph_int_t v = VECTOR(avids)[i]; igraph_vector_int_t *neis2; - igraph_integer_t deg; + igraph_int_t deg; neis2 = igraph_lazy_adjlist_get(&adjlist, v); IGRAPH_CHECK_OOM(neis2, "Failed to query neighbors."); VECTOR(degree)[i] = deg = igraph_vector_int_size(neis2); @@ -189,7 +187,7 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, maxdegree = deg; } } - IGRAPH_CHECK(igraph_vector_int_order1(°ree, &order, maxdegree + 1)); + IGRAPH_CHECK(igraph_i_vector_int_order(°ree, &order, maxdegree + 1)); igraph_vector_int_destroy(°ree); IGRAPH_FINALLY_CLEAN(1); IGRAPH_VECTOR_INIT_FINALLY(&rank, affected_nodes); @@ -197,7 +195,7 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, VECTOR(rank)[ VECTOR(order)[i] ] = affected_nodes - i - 1; } - neis = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); + neis = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); if (neis == 0) { IGRAPH_ERROR("Insufficient memory for local transitivity calculation.", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } @@ -205,11 +203,11 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, IGRAPH_VECTOR_INIT_FINALLY(&triangles, affected_nodes); for (nn = affected_nodes - 1; nn >= 0; nn--) { - igraph_integer_t node = VECTOR(avids) [ VECTOR(order)[nn] ]; + igraph_int_t node = VECTOR(avids) [ VECTOR(order)[nn] ]; igraph_vector_int_t *neis1, *neis2; - igraph_integer_t neilen1, neilen2; - igraph_integer_t nodeindex = VECTOR(indexv)[node]; - igraph_integer_t noderank = VECTOR(rank) [nodeindex - 1]; + igraph_int_t neilen1, neilen2; + igraph_int_t nodeindex = VECTOR(indexv)[node]; + igraph_int_t noderank = VECTOR(rank) [nodeindex - 1]; IGRAPH_ALLOW_INTERRUPTION(); @@ -218,13 +216,13 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, neilen1 = igraph_vector_int_size(neis1); for (i = 0; i < neilen1; i++) { - igraph_integer_t nei = VECTOR(*neis1)[i]; + igraph_int_t nei = VECTOR(*neis1)[i]; neis[nei] = node + 1; } for (i = 0; i < neilen1; i++) { - igraph_integer_t nei = VECTOR(*neis1)[i]; - igraph_integer_t neiindex = VECTOR(indexv)[nei]; - igraph_integer_t neirank = VECTOR(rank)[neiindex - 1]; + igraph_int_t nei = VECTOR(*neis1)[i]; + igraph_int_t neiindex = VECTOR(indexv)[nei]; + igraph_int_t neirank = VECTOR(rank)[neiindex - 1]; /* fprintf(stderr, " nei %li (indexv %li, rank %li)\n", nei, */ /* neiindex, neirank); */ @@ -233,9 +231,9 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, IGRAPH_CHECK_OOM(neis2, "Failed to query neighbors."); neilen2 = igraph_vector_int_size(neis2); for (j = 0; j < neilen2; j++) { - igraph_integer_t nei2 = VECTOR(*neis2)[j]; - igraph_integer_t nei2index = VECTOR(indexv)[nei2]; - igraph_integer_t nei2rank = VECTOR(rank)[nei2index - 1]; + igraph_int_t nei2 = VECTOR(*neis2)[j]; + igraph_int_t nei2index = VECTOR(indexv)[nei2]; + igraph_int_t nei2rank = VECTOR(rank)[nei2index - 1]; /* fprintf(stderr, " triple %li %li %li\n", node, nei, nei2); */ if (nei2rank < neirank) { continue; @@ -256,10 +254,10 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc)); IGRAPH_VIT_RESET(vit); for (i = 0; i < nodes_to_calc; i++, IGRAPH_VIT_NEXT(vit)) { - igraph_integer_t node = IGRAPH_VIT_GET(vit); - igraph_integer_t idx = VECTOR(indexv)[node] - 1; + igraph_int_t node = IGRAPH_VIT_GET(vit); + igraph_int_t idx = VECTOR(indexv)[node] - 1; igraph_vector_int_t *neis2 = igraph_lazy_adjlist_get(&adjlist, node); - igraph_integer_t deg; + igraph_int_t deg; IGRAPH_CHECK_OOM(neis2, "Failed to query neighbors."); @@ -290,8 +288,8 @@ static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, /* Note: Also used in scan.c */ igraph_error_t igraph_i_trans4_al_simplify(igraph_adjlist_t *al, const igraph_vector_int_t *rank) { - igraph_integer_t i; - igraph_integer_t n = al->length; + igraph_int_t i; + igraph_int_t n = al->length; igraph_vector_int_t mark; IGRAPH_CHECK(igraph_vector_int_init(&mark, n)); @@ -299,11 +297,11 @@ igraph_error_t igraph_i_trans4_al_simplify(igraph_adjlist_t *al, for (i = 0; i < n; i++) { igraph_vector_int_t *v = &al->adjs[i]; - igraph_integer_t j, l = igraph_vector_int_size(v); - igraph_integer_t irank = VECTOR(*rank)[i]; + igraph_int_t j, l = igraph_vector_int_size(v); + igraph_int_t irank = VECTOR(*rank)[i]; VECTOR(mark)[i] = i + 1; for (j = 0; j < l; /* nothing */) { - igraph_integer_t e = VECTOR(*v)[j]; + igraph_int_t e = VECTOR(*v)[j]; if (VECTOR(*rank)[e] > irank && VECTOR(mark)[e] != i + 1) { VECTOR(mark)[e] = i + 1; j++; @@ -381,7 +379,7 @@ igraph_error_t igraph_transitivity_local_undirected(const igraph_t *graph, return transitivity_local_undirected4(graph, res, mode); } else { igraph_vit_t vit; - igraph_integer_t size; + igraph_int_t size; IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); size = IGRAPH_VIT_SIZE(vit); @@ -411,7 +409,7 @@ static igraph_error_t adjacent_triangles4(const igraph_t *graph, static igraph_error_t count_triangles_and_triples( const igraph_t *graph, igraph_real_t *triangles, igraph_real_t *connected_triples) { - const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_int_t vcount = igraph_vcount(graph); igraph_vector_int_t mark; igraph_adjlist_t al; @@ -441,28 +439,28 @@ static igraph_error_t count_triangles_and_triples( * * Some other functions achieve the same via igraph_i_trans4_al_simplify(). */ - for (igraph_integer_t v1 = 0; v1 < vcount; v1++) { + for (igraph_int_t v1 = 0; v1 < vcount; v1++) { const igraph_vector_int_t *nei1 = igraph_adjlist_get(&al, v1); - const igraph_integer_t d1 = igraph_vector_int_size(nei1); + const igraph_int_t d1 = igraph_vector_int_size(nei1); if (d1 > 1) { if (connected_triples) { *connected_triples += (igraph_real_t) d1 * (d1 - 1.0) / 2.0; } - for (igraph_integer_t i=0; i < d1; i++) { - const igraph_integer_t v2 = VECTOR(*nei1)[i]; + for (igraph_int_t i=0; i < d1; i++) { + const igraph_int_t v2 = VECTOR(*nei1)[i]; if (v2 >= v1) break; VECTOR(mark)[v2] = v1+1; } - for (igraph_integer_t i=0; i < d1; i++) { - const igraph_integer_t v2 = VECTOR(*nei1)[i]; + for (igraph_int_t i=0; i < d1; i++) { + const igraph_int_t v2 = VECTOR(*nei1)[i]; if (v2 >= v1) break; const igraph_vector_int_t *nei2 = igraph_adjlist_get(&al, v2); - const igraph_integer_t d2 = igraph_vector_int_size(nei2); - for (igraph_integer_t j=0; j < d2; j++) { - const igraph_integer_t v3 = VECTOR(*nei2)[j]; + const igraph_int_t d2 = igraph_vector_int_size(nei2); + for (igraph_int_t j=0; j < d2; j++) { + const igraph_int_t v3 = VECTOR(*nei2)[j]; if (v3 >= v2) break; if (VECTOR(mark)[v3] == v1+1) { @@ -534,28 +532,6 @@ igraph_error_t igraph_count_adjacent_triangles(const igraph_t *graph, } } -/** - * \function igraph_adjacent_triangles - * \brief Count the number of triangles a vertex is part of (deprecated alias). - * - * \deprecated-by igraph_count_adjacent_triangles 0.10.15 - * - * \param graph The input graph. Edge directions and multiplicities are ignored. - * \param res Initiliazed vector, the results are stored here. - * \param vids The vertices to perform the calculation for. - * \return Error mode. - * - * \sa \ref igraph_list_triangles() to list them. - * - * Time complexity: O(d^2 n), d is the average vertex degree of the - * queried vertices, n is their number. - */ - -igraph_error_t igraph_adjacent_triangles(const igraph_t *graph, - igraph_vector_t *res, - const igraph_vs_t vids) { - return igraph_count_adjacent_triangles(graph, res, vids); -} /** * \function igraph_list_triangles @@ -576,7 +552,7 @@ igraph_error_t igraph_adjacent_triangles(const igraph_t *graph, * \return Error code. * * \sa \ref igraph_count_triangles() to count the triangles, - * \ref igraph_adjacent_triangles() to count the triangles a vertex + * \ref igraph_count_adjacent_triangles() to count the triangles a vertex * participates in, \ref igraph_transitivity_undirected() to compute * the global clustering coefficient. * @@ -663,14 +639,14 @@ static igraph_error_t transitivity_barrat1( const igraph_vector_t *weights, igraph_transitivity_mode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vit_t vit; - igraph_integer_t nodes_to_calc; + igraph_int_t nodes_to_calc; igraph_vector_int_t *adj1, *adj2; igraph_vector_int_t neis; igraph_vector_t actw; igraph_lazy_inclist_t incident; - igraph_integer_t i; + igraph_int_t i; igraph_vector_t strength; /* Precondition: weight vector is not null, its length equals the number of @@ -697,8 +673,8 @@ static igraph_error_t transitivity_barrat1( IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc)); for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t node = IGRAPH_VIT_GET(vit); - igraph_integer_t adjlen1, adjlen2, j, k; + igraph_int_t node = IGRAPH_VIT_GET(vit); + igraph_int_t adjlen1, adjlen2, j, k; igraph_real_t triples, triangles; IGRAPH_ALLOW_INTERRUPTION(); @@ -708,8 +684,8 @@ static igraph_error_t transitivity_barrat1( adjlen1 = igraph_vector_int_size(adj1); /* Mark the neighbors of the node */ for (j = 0; j < adjlen1; j++) { - igraph_integer_t edge = VECTOR(*adj1)[j]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, node); + igraph_int_t edge = VECTOR(*adj1)[j]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, node); VECTOR(neis)[nei] = i + 1; VECTOR(actw)[nei] = VECTOR(*weights)[edge]; } @@ -717,15 +693,15 @@ static igraph_error_t transitivity_barrat1( triangles = 0.0; for (j = 0; j < adjlen1; j++) { - igraph_integer_t edge1 = VECTOR(*adj1)[j]; + igraph_int_t edge1 = VECTOR(*adj1)[j]; igraph_real_t weight1 = VECTOR(*weights)[edge1]; - igraph_integer_t v = IGRAPH_OTHER(graph, edge1, node); + igraph_int_t v = IGRAPH_OTHER(graph, edge1, node); adj2 = igraph_lazy_inclist_get(&incident, v); IGRAPH_CHECK_OOM(adj2, "Failed to query incident edges."); adjlen2 = igraph_vector_int_size(adj2); for (k = 0; k < adjlen2; k++) { - igraph_integer_t edge2 = VECTOR(*adj2)[k]; - igraph_integer_t v2 = IGRAPH_OTHER(graph, edge2, v); + igraph_int_t edge2 = VECTOR(*adj2)[k]; + igraph_int_t v2 = IGRAPH_OTHER(graph, edge2, v); if (VECTOR(neis)[v2] == i + 1) { triangles += (VECTOR(actw)[v2] + weight1) / 2.0; } @@ -754,17 +730,17 @@ static igraph_error_t transitivity_barrat4( const igraph_vector_t *weights, igraph_transitivity_mode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vector_int_t order; igraph_vector_int_t degree; igraph_vector_t strength; igraph_vector_t rank; - igraph_integer_t maxdegree; + igraph_int_t maxdegree; igraph_inclist_t incident; igraph_vector_int_t neis; igraph_vector_int_t *adj1, *adj2; igraph_vector_t actw; - igraph_integer_t i, nn; + igraph_int_t i, nn; /* Precondition: weight vector is not null, its length equals the number of * edges, and the graph has at least one vertex. The graph must not have @@ -778,7 +754,7 @@ static igraph_error_t transitivity_barrat4( IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS)); maxdegree = igraph_vector_int_max(°ree) + 1; - IGRAPH_CHECK(igraph_vector_int_order1(°ree, &order, maxdegree)); + IGRAPH_CHECK(igraph_i_vector_int_order(°ree, &order, maxdegree)); IGRAPH_CHECK(igraph_strength(graph, &strength, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS, weights)); @@ -800,9 +776,9 @@ static igraph_error_t transitivity_barrat4( igraph_vector_null(res); for (nn = no_of_nodes - 1; nn >= 0; nn--) { - igraph_integer_t adjlen1, adjlen2; + igraph_int_t adjlen1, adjlen2; igraph_real_t triples; - igraph_integer_t node = VECTOR(order)[nn]; + igraph_int_t node = VECTOR(order)[nn]; IGRAPH_ALLOW_INTERRUPTION(); @@ -811,24 +787,24 @@ static igraph_error_t transitivity_barrat4( triples = VECTOR(strength)[node] * (adjlen1 - 1) / 2.0; /* Mark the neighbors of the node */ for (i = 0; i < adjlen1; i++) { - igraph_integer_t edge = VECTOR(*adj1)[i]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge, node); + igraph_int_t edge = VECTOR(*adj1)[i]; + igraph_int_t nei = IGRAPH_OTHER(graph, edge, node); VECTOR(neis)[nei] = node + 1; VECTOR(actw)[nei] = VECTOR(*weights)[edge]; } for (i = 0; i < adjlen1; i++) { - igraph_integer_t edge1 = VECTOR(*adj1)[i]; + igraph_int_t edge1 = VECTOR(*adj1)[i]; igraph_real_t weight1 = VECTOR(*weights)[edge1]; - igraph_integer_t nei = IGRAPH_OTHER(graph, edge1, node); - igraph_integer_t j; + igraph_int_t nei = IGRAPH_OTHER(graph, edge1, node); + igraph_int_t j; if (VECTOR(rank)[nei] > VECTOR(rank)[node]) { adj2 = igraph_inclist_get(&incident, nei); adjlen2 = igraph_vector_int_size(adj2); for (j = 0; j < adjlen2; j++) { - igraph_integer_t edge2 = VECTOR(*adj2)[j]; + igraph_int_t edge2 = VECTOR(*adj2)[j]; igraph_real_t weight2 = VECTOR(*weights)[edge2]; - igraph_integer_t nei2 = IGRAPH_OTHER(graph, edge2, nei); + igraph_int_t nei2 = IGRAPH_OTHER(graph, edge2, nei); if (VECTOR(rank)[nei2] < VECTOR(rank)[nei]) { continue; } @@ -903,8 +879,8 @@ igraph_error_t igraph_transitivity_barrat(const igraph_t *graph, const igraph_vs_t vids, const igraph_vector_t *weights, igraph_transitivity_mode_t mode) { - igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_integer_t no_of_edges = igraph_ecount(graph); + igraph_int_t no_of_nodes = igraph_vcount(graph); + igraph_int_t no_of_edges = igraph_ecount(graph); igraph_bool_t has_multiple; /* Handle fallback to unweighted version and common cases */ diff --git a/src/vendor/cigraph/src/properties/triangles_template.h b/src/vendor/cigraph/src/properties/triangles_template.h index 77dfc6edc38..c18bf97d08d 100644 --- a/src/vendor/cigraph/src/properties/triangles_template.h +++ b/src/vendor/cigraph/src/properties/triangles_template.h @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -26,16 +24,16 @@ #define TRANSIT_TRIEDGES #endif -igraph_integer_t no_of_nodes = igraph_vcount(graph); -igraph_integer_t node, i, j, nn; +igraph_int_t no_of_nodes = igraph_vcount(graph); +igraph_int_t node, i, j, nn; igraph_adjlist_t allneis; igraph_vector_int_t *neis1, *neis2; -igraph_integer_t neilen1, neilen2; -igraph_integer_t *neis; -igraph_integer_t maxdegree; +igraph_int_t neilen1, neilen2; +igraph_int_t *neis; +igraph_int_t maxdegree; #ifdef TRANSIT_TRIEDGES -igraph_integer_t deg1; +igraph_int_t deg1; #endif igraph_vector_int_t order; @@ -62,7 +60,7 @@ for (i = 0; i < no_of_nodes; i++) { } maxdegree = igraph_vector_int_max(°ree) + 1; -IGRAPH_CHECK(igraph_vector_int_order1(°ree, &order, maxdegree)); +IGRAPH_CHECK(igraph_i_vector_int_order(°ree, &order, maxdegree)); IGRAPH_VECTOR_INT_INIT_FINALLY(&rank, no_of_nodes); for (i = 0; i < no_of_nodes; i++) { VECTOR(rank)[ VECTOR(order)[i] ] = no_of_nodes - i - 1; @@ -70,7 +68,7 @@ for (i = 0; i < no_of_nodes; i++) { IGRAPH_CHECK(igraph_i_trans4_al_simplify(&allneis, &rank)); -neis = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); +neis = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(neis, "Insufficient memory to count triangles."); IGRAPH_FINALLY(igraph_free, neis); @@ -99,11 +97,11 @@ for (nn = no_of_nodes - 1; nn >= 0; nn--) { } for (i = 0; i < neilen1; i++) { - igraph_integer_t nei = VECTOR(*neis1)[i]; + igraph_int_t nei = VECTOR(*neis1)[i]; neis2 = igraph_adjlist_get(&allneis, nei); neilen2 = igraph_vector_int_size(neis2); for (j = 0; j < neilen2; j++) { - igraph_integer_t nei2 = VECTOR(*neis2)[j]; + igraph_int_t nei2 = VECTOR(*neis2)[j]; if (neis[nei2] == node + 1) { #ifndef TRIANGLES VECTOR(*res)[nei2] += 1; diff --git a/src/vendor/cigraph/src/properties/triangles_template1.h b/src/vendor/cigraph/src/properties/triangles_template1.h index f495b5ff68a..8e33a5328ac 100644 --- a/src/vendor/cigraph/src/properties/triangles_template1.h +++ b/src/vendor/cigraph/src/properties/triangles_template1.h @@ -1,7 +1,5 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -22,14 +20,14 @@ */ -igraph_integer_t no_of_nodes = igraph_vcount(graph); +igraph_int_t no_of_nodes = igraph_vcount(graph); igraph_vit_t vit; -igraph_integer_t nodes_to_calc; +igraph_int_t nodes_to_calc; igraph_vector_int_t *neis1, *neis2; igraph_real_t triangles; -igraph_integer_t i, j, k; -igraph_integer_t neilen1, neilen2; -igraph_integer_t *neis; +igraph_int_t i, j, k; +igraph_int_t neilen1, neilen2; +igraph_int_t *neis; igraph_lazy_adjlist_t adjlist; IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); @@ -43,7 +41,7 @@ if (nodes_to_calc == 0) { return IGRAPH_SUCCESS; } -neis = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); +neis = IGRAPH_CALLOC(no_of_nodes, igraph_int_t); IGRAPH_CHECK_OOM(neis, "Insufficient memory to count triangles."); IGRAPH_FINALLY(igraph_free, neis); @@ -53,7 +51,7 @@ IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, IGRAPH_ALL, IGRAPH_NO_LOO IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist); for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { - igraph_integer_t node = IGRAPH_VIT_GET(vit); + igraph_int_t node = IGRAPH_VIT_GET(vit); IGRAPH_ALLOW_INTERRUPTION(); @@ -66,12 +64,12 @@ for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { triangles = 0; for (j = 0; j < neilen1; j++) { - igraph_integer_t v = VECTOR(*neis1)[j]; + igraph_int_t v = VECTOR(*neis1)[j]; neis2 = igraph_lazy_adjlist_get(&adjlist, v); IGRAPH_CHECK_OOM(neis2, "Failed to query neighbors."); neilen2 = igraph_vector_int_size(neis2); for (k = 0; k < neilen2; k++) { - igraph_integer_t v2 = VECTOR(*neis2)[k]; + igraph_int_t v2 = VECTOR(*neis2)[k]; if (neis[v2] == i + 1) { triangles += 1.0; } diff --git a/src/vendor/cigraph/src/random/random.c b/src/vendor/cigraph/src/random/random.c index df9a2d8f05b..708fba0192c 100644 --- a/src/vendor/cigraph/src/random/random.c +++ b/src/vendor/cigraph/src/random/random.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2005-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA @@ -30,7 +29,6 @@ #include "igraph_vector.h" #include "core/interruption.h" -#include "core/math.h" #include "math/safe_intop.h" #include "random/random_internal.h" @@ -43,6 +41,7 @@ #include #include #include /* DBL_MANT_DIG */ +#include /** * \section about_rngs @@ -146,32 +145,32 @@ * igraph_rng_set_default() function. */ -extern IGRAPH_THREAD_LOCAL igraph_rng_t igraph_i_rng_default; /* defined in rng_pcg32.c */ +extern igraph_rng_t igraph_i_rng_default; /* defined in rng_pcg32.c */ +IGRAPH_THREAD_LOCAL igraph_rng_t *igraph_i_rng_default_ptr = &igraph_i_rng_default; /** * \function igraph_rng_set_default * \brief Set the default igraph random number generator. * - * This function \em copies the internal structure of the given \type igraph_rng_t - * object to igraph's internal default RNG structure. The structure itself - * contains two pointers only, one to the "methods" of the RNG and one to the - * memory buffer holding the internal state of the RNG. This means that if you - * keep on generating random numbers from the RNG after setting it as the - * default, it will affect the state of the default RNG as well because the two - * share the same state pointer. However, do \em not expect - * \ref igraph_rng_default() to return the same pointer as the one you passed - * in here - the state is shared, but the entire structure is not. + * This function updates the default RNG used by igraph to be the one + * pointed to by \p rng, and returns a pointer to the previous default + * RNG. Future calls to \ref igraph_rng_default() will return the same + * pointer as \p rng. The RNG pointed to by \p rng must not be destroyed + * for as long as it is used as the default. * * \param rng The random number generator to use as default from now * on. Calling \ref igraph_rng_destroy() on it, while it is still * being used as the default will result in crashes and/or * unpredictable results. + * \return Pointer the previous default RNG. * * Time complexity: O(1). */ -void igraph_rng_set_default(igraph_rng_t *rng) { - igraph_i_rng_default = (*rng); +igraph_rng_t *igraph_rng_set_default(igraph_rng_t *rng) { + igraph_rng_t *old_rng = igraph_i_rng_default_ptr; + igraph_i_rng_default_ptr = rng; + return old_rng; } @@ -187,7 +186,7 @@ void igraph_rng_set_default(igraph_rng_t *rng) { */ igraph_rng_t *igraph_rng_default(void) { - return &igraph_i_rng_default; + return igraph_i_rng_default_ptr; } /* ------------------------------------ */ @@ -208,7 +207,7 @@ static uint64_t igraph_i_rng_get_uint64_bounded(igraph_rng_t *rng, uint64_t rang static double igraph_i_norm_rand(igraph_rng_t *rng); static double igraph_i_exp_rand(igraph_rng_t *rng); -static double igraph_i_rbinom(igraph_rng_t *rng, igraph_integer_t n, double pp); +static double igraph_i_rbinom(igraph_rng_t *rng, igraph_int_t n, double pp); static double igraph_i_rexp(igraph_rng_t *rng, double rate); static double igraph_i_rgamma(igraph_rng_t *rng, double shape, double scale); static double igraph_i_rpois(igraph_rng_t *rng, double rate); @@ -275,7 +274,7 @@ igraph_error_t igraph_rng_seed(igraph_rng_t *rng, igraph_uint_t seed) { * * Time complexity: O(1). */ -igraph_integer_t igraph_rng_bits(const igraph_rng_t* rng) { +igraph_int_t igraph_rng_bits(const igraph_rng_t* rng) { return rng->type->bits; } @@ -336,7 +335,7 @@ const char *igraph_rng_name(const igraph_rng_t *rng) { */ static igraph_uint_t igraph_i_rng_get_random_bits(igraph_rng_t *rng, uint8_t bits) { const igraph_rng_type_t *type = rng->type; - igraph_integer_t rng_bitwidth = igraph_rng_bits(rng); + igraph_int_t rng_bitwidth = igraph_rng_bits(rng); igraph_uint_t result; if (rng_bitwidth >= bits) { @@ -375,7 +374,7 @@ static igraph_uint_t igraph_i_rng_get_random_bits(igraph_rng_t *rng, uint8_t bit */ static uint64_t igraph_i_rng_get_random_bits_uint64(igraph_rng_t *rng, uint8_t bits) { const igraph_rng_type_t *type = rng->type; - igraph_integer_t rng_bitwidth = igraph_rng_bits(rng); + igraph_int_t rng_bitwidth = igraph_rng_bits(rng); uint64_t result; if (rng_bitwidth >= bits) { @@ -562,7 +561,7 @@ static igraph_uint_t igraph_i_rng_get_uint_bounded(igraph_rng_t *rng, igraph_uin igraph_bool_t igraph_rng_get_bool(igraph_rng_t *rng) { const igraph_rng_type_t *type = rng->type; - const igraph_integer_t rng_bitwidth = igraph_rng_bits(rng); + const igraph_int_t rng_bitwidth = igraph_rng_bits(rng); /* Keep the highest bit as RNGs sometimes tend to have lower entropy in * low bits than in high bits. * @@ -589,8 +588,8 @@ igraph_bool_t igraph_rng_get_bool(igraph_rng_t *rng) { * \ref igraph_rng_bits(rng). */ -igraph_integer_t igraph_rng_get_integer( - igraph_rng_t *rng, igraph_integer_t l, igraph_integer_t h +igraph_int_t igraph_rng_get_integer( + igraph_rng_t *rng, igraph_int_t l, igraph_int_t h ) { const igraph_rng_type_t *type = rng->type; igraph_uint_t range; @@ -608,9 +607,9 @@ igraph_integer_t igraph_rng_get_integer( if (IGRAPH_UNLIKELY(l == IGRAPH_INTEGER_MIN && h == IGRAPH_INTEGER_MAX)) { /* Full uint range is needed, we can just grab a random number from * the uint range and cast it to a signed integer */ - return (igraph_integer_t) igraph_i_rng_get_uint(rng); + return (igraph_int_t) igraph_i_rng_get_uint(rng); } else if (l >= 0 || h < 0) { - /* this is okay, (h - l) will not overflow an igraph_integer_t */ + /* this is okay, (h - l) will not overflow an igraph_int_t */ range = (igraph_uint_t)(h - l) + 1; } else { /* (h - l) could potentially overflow so we need to play it safe. If we @@ -768,7 +767,7 @@ igraph_real_t igraph_rng_get_geom(igraph_rng_t *rng, igraph_real_t p) { * Time complexity: depends on the RNG. */ -igraph_real_t igraph_rng_get_binom(igraph_rng_t *rng, igraph_integer_t n, igraph_real_t p) { +igraph_real_t igraph_rng_get_binom(igraph_rng_t *rng, igraph_int_t n, igraph_real_t p) { const igraph_rng_type_t *type = rng->type; if (type->get_binom) { return type->get_binom(rng->state, n, p); @@ -873,16 +872,16 @@ igraph_real_t igraph_rng_get_pois(igraph_rng_t *rng, igraph_real_t rate) { */ static void igraph_i_random_sample_alga(igraph_vector_int_t *res, - igraph_integer_t l, igraph_integer_t h, - igraph_integer_t length) { + igraph_int_t l, igraph_int_t h, + igraph_int_t length) { /* Vitter: Variables V, quot, Nreal, and top are of type real */ - igraph_integer_t N = h - l + 1; - igraph_integer_t n = length; + igraph_int_t N = h - l + 1; + igraph_int_t n = length; igraph_real_t top = N - n; igraph_real_t Nreal = N; - igraph_integer_t S = 0; + igraph_int_t S = 0; igraph_real_t V, quot; l = l - 1; @@ -947,23 +946,23 @@ static void igraph_i_random_sample_alga(igraph_vector_int_t *res, * \example examples/simple/igraph_random_sample.c */ -igraph_error_t igraph_random_sample(igraph_vector_int_t *res, igraph_integer_t l, igraph_integer_t h, - igraph_integer_t length) { - igraph_integer_t N; /* := h - l + 1 */ +igraph_error_t igraph_random_sample(igraph_vector_int_t *res, igraph_int_t l, igraph_int_t h, + igraph_int_t length) { + igraph_int_t N; /* := h - l + 1 */ IGRAPH_SAFE_ADD(h, -l, &N); IGRAPH_SAFE_ADD(N, 1, &N); - igraph_integer_t n = length; + igraph_int_t n = length; igraph_real_t nreal = length; igraph_real_t ninv = (nreal != 0) ? 1.0 / nreal : 0.0; igraph_real_t Nreal = N; igraph_real_t Vprime; - igraph_integer_t qu1 = -n + 1 + N; + igraph_int_t qu1 = -n + 1 + N; igraph_real_t qu1real = -nreal + 1.0 + Nreal; igraph_real_t negalphainv = -13; igraph_real_t threshold = -negalphainv * n; - igraph_integer_t S; + igraph_int_t S; /* getting back some sense of sanity */ if (l > h) { @@ -986,7 +985,7 @@ igraph_error_t igraph_random_sample(igraph_vector_int_t *res, igraph_integer_t l } if (length == N) { IGRAPH_CHECK(igraph_vector_int_resize(res, length)); - for (igraph_integer_t i = 0; i < length; i++) { + for (igraph_int_t i = 0; i < length; i++) { VECTOR(*res)[i] = l++; } return IGRAPH_SUCCESS; @@ -995,8 +994,6 @@ igraph_error_t igraph_random_sample(igraph_vector_int_t *res, igraph_integer_t l igraph_vector_int_clear(res); IGRAPH_CHECK(igraph_vector_int_reserve(res, length)); - RNG_BEGIN(); - Vprime = exp(log(RNG_UNIF01()) * ninv); l = l - 1; @@ -1061,8 +1058,6 @@ igraph_error_t igraph_random_sample(igraph_vector_int_t *res, igraph_integer_t l igraph_vector_int_push_back(res, l); /* allocated */ } - RNG_END(); - return IGRAPH_SUCCESS; } @@ -1101,13 +1096,13 @@ static void igraph_i_random_sample_alga_real(igraph_vector_t *res, /** * \ingroup nongraph - * \function igraph_random_sample_real + * \function igraph_i_random_sample_real * \brief Generates an increasing random sequence of integers (igraph_real_t version). * * This function is the 'real' version of \ref igraph_random_sample(), and was added * so \ref igraph_erdos_renyi_game_gnm() and related functions can use a random sample * of doubles instead of integers to prevent overflows on systems with 32-bit - * \type igraph_integer_t. + * \type igraph_int_t. * * \param res Pointer to an initialized vector. This will hold the * result. It will be resized to the proper size. @@ -1126,11 +1121,11 @@ static void igraph_i_random_sample_alga_real(igraph_vector_t *res, * size of the candidate pool. */ -igraph_error_t igraph_random_sample_real(igraph_vector_t *res, igraph_real_t l, - igraph_real_t h, igraph_integer_t length) { +igraph_error_t igraph_i_random_sample_real(igraph_vector_t *res, igraph_real_t l, + igraph_real_t h, igraph_int_t length) { /* This function is the 'real' version of igraph_random_sample, and was added * so erdos_renyi_game_gnm can use a random sample of doubles instead of integers - * to prevent overflows on systems with 32-bits igraph_integer_t. + * to prevent overflows on systems with 32-bits igraph_int_t. */ igraph_real_t N = h - l + 1; igraph_real_t n = length; @@ -1172,7 +1167,7 @@ igraph_error_t igraph_random_sample_real(igraph_vector_t *res, igraph_real_t l, } if (length == N) { IGRAPH_CHECK(igraph_vector_resize(res, length)); - for (igraph_integer_t i = 0; i < length; i++) { + for (igraph_int_t i = 0; i < length; i++) { VECTOR(*res)[i] = l++; } return IGRAPH_SUCCESS; @@ -1181,8 +1176,6 @@ igraph_error_t igraph_random_sample_real(igraph_vector_t *res, igraph_real_t l, igraph_vector_clear(res); IGRAPH_CHECK(igraph_vector_reserve(res, length)); - RNG_BEGIN(); - Vprime = exp(log(RNG_UNIF01()) * ninv); l = l - 1; @@ -1252,8 +1245,6 @@ igraph_error_t igraph_random_sample_real(igraph_vector_t *res, igraph_real_t l, igraph_vector_push_back(res, l); /* allocated */ } - RNG_END(); - return IGRAPH_SUCCESS; } @@ -1404,7 +1395,7 @@ igraph_error_t igraph_random_sample_real(igraph_vector_t *res, igraph_real_t l, #define R_DT_log(p) (lower_tail? R_D_log(p) : R_D_LExp(p))/* log(p) in qF */ #define R_DT_Clog(p) (lower_tail? R_D_LExp(p): R_D_log(p))/* log(1-p) in qF*/ #define R_DT_Log(p) (lower_tail? (p) : R_Log1_Exp(p)) -/* == R_DT_log when we already "know" log_p == TRUE :*/ +/* == R_DT_log when we already "know" log_p == true :*/ #define R_Q_P01_check(p) \ if ((log_p && p > 0) || \ @@ -1524,11 +1515,11 @@ static double igraph_i_qnorm5(double p, double mu, double sigma, igraph_bool_t l return mu + sigma * val; } -static igraph_integer_t imax2(igraph_integer_t x, igraph_integer_t y) { +static igraph_int_t imax2(igraph_int_t x, igraph_int_t y) { return (x < y) ? y : x; } -static igraph_integer_t imin2(igraph_integer_t x, igraph_integer_t y) { +static igraph_int_t imin2(igraph_int_t x, igraph_int_t y) { return (x < y) ? x : y; } @@ -1615,8 +1606,6 @@ static double igraph_i_exp_rand(igraph_rng_t *rng) { #define repeat for(;;) -#define FALSE 0 -#define TRUE 1 #define M_1_SQRT_2PI 0.398942280401432677939946059934 /* 1/sqrt(2pi) */ static double igraph_i_rpois(igraph_rng_t *rng, double mu) { @@ -1627,7 +1616,7 @@ static double igraph_i_rpois(igraph_rng_t *rng, double mu) { /* These are static --- persistent between calls for same mu : */ static IGRAPH_THREAD_LOCAL int l; - static IGRAPH_THREAD_LOCAL igraph_integer_t m; + static IGRAPH_THREAD_LOCAL igraph_int_t m; static IGRAPH_THREAD_LOCAL double b1, b2, c, c0, c1, c2, c3; static IGRAPH_THREAD_LOCAL double pp[36], p0, p, q, s, d, omega; @@ -1637,7 +1626,9 @@ static double igraph_i_rpois(igraph_rng_t *rng, double mu) { /* Local Vars [initialize some for -Wall]: */ double del, difmuk = 0., E = 0., fk = 0., fx, fy, g, px, py, t, u = 0., v, x; double pois = -1.; - int k, kflag, big_mu, new_big_mu = FALSE; + int k, big_mu; + bool new_big_mu = false; + bool kflag; if (!isfinite(mu) || mu < 0) { ML_ERR_return_NAN; @@ -1649,13 +1640,13 @@ static double igraph_i_rpois(igraph_rng_t *rng, double mu) { big_mu = mu >= 10.; if (big_mu) { - new_big_mu = FALSE; + new_big_mu = false; } if (!(big_mu && mu == muprev)) {/* maybe compute new persistent par.s */ if (big_mu) { - new_big_mu = TRUE; + new_big_mu = true; /* Case A. (recalculation of s,d,l because mu has changed): * The Poisson probabilities pk exceed the discrete normal * probabilities fk whenever k >= m(mu). @@ -1672,7 +1663,7 @@ static double igraph_i_rpois(igraph_rng_t *rng, double mu) { /*muprev = 0.;-* such that next time, mu != muprev ..*/ if (mu != muprev) { muprev = mu; - m = imax2(1, (igraph_integer_t) mu); + m = imax2(1, (igraph_int_t) mu); l = 0; /* pp[] is already ok up to pp[l] */ q = p0 = p = exp(-mu); } @@ -1757,7 +1748,7 @@ static double igraph_i_rpois(igraph_rng_t *rng, double mu) { if (g >= 0.) { /* 'Subroutine' F is called (kflag=0 for correct return) */ - kflag = 0; + kflag = false; goto Step_F; } @@ -1777,7 +1768,7 @@ static double igraph_i_rpois(igraph_rng_t *rng, double mu) { difmuk = mu - fk; /* 'subroutine' F is called (kflag=1 for correct return) */ - kflag = 1; + kflag = true; Step_F: /* 'subroutine' F : calculation of px,py,fx,fy. */ @@ -1803,7 +1794,7 @@ static double igraph_i_rpois(igraph_rng_t *rng, double mu) { x *= x;/* x^2 */ fx = -0.5 * x; fy = omega * (((c3 * x + c2) * x + c1) * x + c0); - if (kflag > 0) { + if (kflag) { /* Step H. Hat acceptance (E is repeated on rejection) */ if (c * fabs(u) <= py * exp(px + E) - fy * exp(fx + E)) { break; @@ -1830,18 +1821,18 @@ static double igraph_i_rpois(igraph_rng_t *rng, double mu) { #define repeat for(;;) -static double igraph_i_rbinom(igraph_rng_t *rng, igraph_integer_t n, double pp) { +static double igraph_i_rbinom(igraph_rng_t *rng, igraph_int_t n, double pp) { static IGRAPH_THREAD_LOCAL double c, fm, npq, p1, p2, p3, p4, qn; static IGRAPH_THREAD_LOCAL double xl, xll, xlr, xm, xr; static IGRAPH_THREAD_LOCAL double psave = -1.0; - static IGRAPH_THREAD_LOCAL igraph_integer_t nsave = -1; - static IGRAPH_THREAD_LOCAL igraph_integer_t m; + static IGRAPH_THREAD_LOCAL igraph_int_t nsave = -1; + static IGRAPH_THREAD_LOCAL igraph_int_t m; double f, f1, f2, u, v, w, w2, x, x1, x2, z, z2; double p, q, np, g, r, al, alv, amaxp, ffm, ynorm; - igraph_integer_t i, ix, k; + igraph_int_t i, ix, k; if (!isfinite(pp) || /* n=0, p=0, p=1 are not errors */ @@ -2236,32 +2227,3 @@ static double igraph_i_rgamma(igraph_rng_t *rng, double a, double scale) { x = s + 0.5 * t; return scale * x * x; } - -igraph_error_t igraph_rng_get_dirichlet(igraph_rng_t *rng, - const igraph_vector_t *alpha, - igraph_vector_t *result) { - - igraph_integer_t len = igraph_vector_size(alpha); - igraph_real_t sum = 0.0; - - if (len < 2) { - IGRAPH_ERROR("Dirichlet parameter vector too short, must have at least two entries.", - IGRAPH_EINVAL); - } - if (igraph_vector_min(alpha) <= 0) { - IGRAPH_ERROR("Dirichlet concentration parameters must be positive.", - IGRAPH_EINVAL); - } - - IGRAPH_CHECK(igraph_vector_resize(result, len)); - - for (igraph_integer_t i = 0; i < len; i++) { - VECTOR(*result)[i] = igraph_rng_get_gamma(rng, VECTOR(*alpha)[i], 1.0); - sum += VECTOR(*result)[i]; - } - for (igraph_integer_t i = 0; i < len; i++) { - VECTOR(*result)[i] /= sum; - } - - return IGRAPH_SUCCESS; -} diff --git a/src/vendor/cigraph/src/random/random_device.cpp b/src/vendor/cigraph/src/random/random_device.cpp new file mode 100644 index 00000000000..2a79a6b1cf5 --- /dev/null +++ b/src/vendor/cigraph/src/random/random_device.cpp @@ -0,0 +1,43 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + this program. If not, see . +*/ + +#include "random/random_internal.h" + +#include +#include + +/* This function attempts to produce an unpredictable number suitable for + * seeding the RNG upon startup. It makes an effort to avoid producing the + * same number when called within different processes, even if called + * approximately at the same time. However, it cannot guarantee this on + * all systems under all circumstancs. + * + * This function cannot fail. + */ +igraph_uint_t igraph_i_get_random_seed(void) { + try { + // Try to use C++'s std::random_device. This may fail, either because + // the systems's random device ran out of entropy or because the system + // does not offer this functionality. + return std::random_device()(); + } catch (...) { + // If random_device fails, use a time-based seed. A combination of + // time() (calendar time, low resolution) and clock() (processor time + // used, higher resolution) reduces the risk of seed collisions. + return igraph_uint_t(std::clock()) + igraph_uint_t(std::time(NULL)); + } +} diff --git a/src/vendor/cigraph/src/random/random_internal.h b/src/vendor/cigraph/src/random/random_internal.h index 25110da1a34..3a3c3afd550 100644 --- a/src/vendor/cigraph/src/random/random_internal.h +++ b/src/vendor/cigraph/src/random/random_internal.h @@ -1,23 +1,18 @@ -/* -*- mode: C -*- */ /* - IGraph library. - Copyright (C) 2021 The igraph development team + igraph library. + Copyright (C) 2021-2025 The igraph development team - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any later + version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + You should have received a copy of the GNU General Public License along with + this program. If not, see . */ #ifndef IGRAPH_RANDOM_INTERNAL_H @@ -27,12 +22,14 @@ #include "igraph_types.h" #include "igraph_vector.h" -__BEGIN_DECLS +IGRAPH_BEGIN_C_DECLS -igraph_error_t igraph_random_sample_real( +igraph_error_t igraph_i_random_sample_real( igraph_vector_t *res, igraph_real_t l, igraph_real_t h, - igraph_integer_t length); + igraph_int_t length); + +igraph_uint_t igraph_i_get_random_seed(void); -__END_DECLS +IGRAPH_END_C_DECLS #endif diff --git a/src/vendor/cigraph/src/random/rng_glibc2.c b/src/vendor/cigraph/src/random/rng_glibc2.c index 968f5d46e81..fd9cf41431a 100644 --- a/src/vendor/cigraph/src/random/rng_glibc2.c +++ b/src/vendor/cigraph/src/random/rng_glibc2.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify diff --git a/src/vendor/cigraph/src/random/rng_mt19937.c b/src/vendor/cigraph/src/random/rng_mt19937.c index adff540a312..c30988a0e82 100644 --- a/src/vendor/cigraph/src/random/rng_mt19937.c +++ b/src/vendor/cigraph/src/random/rng_mt19937.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify diff --git a/src/vendor/cigraph/src/random/rng_pcg32.c b/src/vendor/cigraph/src/random/rng_pcg32.c index d821b386d7a..d8990a11175 100644 --- a/src/vendor/cigraph/src/random/rng_pcg32.c +++ b/src/vendor/cigraph/src/random/rng_pcg32.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify @@ -23,8 +23,6 @@ #include "pcg/pcg_variants.h" -#include "config.h" /* IGRAPH_THREAD_LOCAL */ - /* The original implementation of the 32-bit PCG random number generator in this * file was obtained from https://github.com/imneme/pcg-c * @@ -115,10 +113,10 @@ const igraph_rng_type_t igraph_rngtype_pcg32 = { static pcg32_random_t igraph_i_rng_default_state = PCG32_INITIALIZER; -IGRAPH_THREAD_LOCAL igraph_rng_t igraph_i_rng_default = { +igraph_rng_t igraph_i_rng_default = { addr(igraph_rngtype_pcg32), addr(igraph_i_rng_default_state), - /* is_seeded = */ true + /* is_seeded = */ false }; #undef addr diff --git a/src/vendor/cigraph/src/random/rng_pcg64.c b/src/vendor/cigraph/src/random/rng_pcg64.c index c460b4ae4d0..c5040944f10 100644 --- a/src/vendor/cigraph/src/random/rng_pcg64.c +++ b/src/vendor/cigraph/src/random/rng_pcg64.c @@ -1,5 +1,5 @@ /* - IGraph library. + igraph library. Copyright (C) 2022 The igraph development team This program is free software; you can redistribute it and/or modify diff --git a/src/vendor/cigraph/src/random/sampling.c b/src/vendor/cigraph/src/random/sampling.c new file mode 100644 index 00000000000..3d51ab64538 --- /dev/null +++ b/src/vendor/cigraph/src/random/sampling.c @@ -0,0 +1,192 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + +*/ + +#include "igraph_sampling.h" + +/** + * \function igraph_rng_sample_sphere_surface + * \brief Sample points uniformly from the surface of a sphere. + * + * The center of the sphere is at the origin. + * + * \param rng The random number generator to use. + * \param dim The dimension of the random vectors. + * \param n The number of vectors to sample. + * \param radius Radius of the sphere, it must be positive. + * \param positive Whether to restrict sampling to the positive + * orthant. + * \param res Pointer to an initialized matrix, the result is + * stored here, each column will be a sampled vector. The matrix is + * resized, as needed. + * \return Error code. + * + * Time complexity: O(n*dim*g), where g is the time complexity of + * generating a standard normal random number. + * + * \sa \ref igraph_rng_sample_sphere_volume(), \ref + * igraph_rng_sample_dirichlet() for other similar samplers. + */ +igraph_error_t igraph_rng_sample_sphere_surface( + igraph_rng_t* rng, igraph_int_t dim, igraph_int_t n, igraph_real_t radius, + igraph_bool_t positive, igraph_matrix_t *res +) { + igraph_int_t i, j; + + if (dim < 2) { + IGRAPH_ERROR("Sphere must be at least two dimensional to sample from " + "surface.", IGRAPH_EINVAL); + } + if (n < 0) { + IGRAPH_ERROR("Number of samples must be non-negative.", IGRAPH_EINVAL); + } + if (radius <= 0) { + IGRAPH_ERROR("Sphere radius must be positive.", IGRAPH_EINVAL); + } + + IGRAPH_CHECK(igraph_matrix_resize(res, dim, n)); + + for (i = 0; i < n; i++) { + igraph_real_t *col = &MATRIX(*res, 0, i); + igraph_real_t sum = 0.0; + for (j = 0; j < dim; j++) { + col[j] = igraph_rng_get_normal(rng, 0, 1); + sum += col[j] * col[j]; + } + sum = sqrt(sum); + for (j = 0; j < dim; j++) { + col[j] = radius * col[j] / sum; + } + if (positive) { + for (j = 0; j < dim; j++) { + col[j] = fabs(col[j]); + } + } + } + + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_rng_sample_sphere_volume + * \brief Sample points uniformly from the volume of a sphere. + * + * The center of the sphere is at the origin. + * + * \param rng The random number generator to use. + * \param dim The dimension of the random vectors. + * \param n The number of vectors to sample. + * \param radius Radius of the sphere, it must be positive. + * \param positive Whether to restrict sampling to the positive + * orthant. + * \param res Pointer to an initialized matrix, the result is + * stored here, each column will be a sampled vector. The matrix is + * resized, as needed. + * \return Error code. + * + * Time complexity: O(n*dim*g), where g is the time complexity of + * generating a standard normal random number. + * + * \sa \ref igraph_rng_sample_sphere_surface(), \ref + * igraph_rng_sample_dirichlet() for other similar samplers. + */ +igraph_error_t igraph_rng_sample_sphere_volume( + igraph_rng_t* rng, igraph_int_t dim, igraph_int_t n, igraph_real_t radius, + igraph_bool_t positive, igraph_matrix_t *res +) { + + igraph_int_t i, j; + + /* Arguments are checked by the following call */ + + IGRAPH_CHECK(igraph_rng_sample_sphere_surface(rng, dim, n, radius, positive, res)); + + for (i = 0; i < n; i++) { + igraph_real_t *col = &MATRIX(*res, 0, i); + igraph_real_t U = pow(igraph_rng_get_unif01(rng), 1.0 / dim); + for (j = 0; j < dim; j++) { + col[j] *= U; + } + } + + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_rng_sample_dirichlet + * \brief Sample points from a Dirichlet distribution. + * + * \param rng The random number generator to use. + * \param n The number of vectors to sample. + * \param alpha The parameters of the Dirichlet distribution. They + * must be positive. The length of this vector gives the dimension + * of the generated samples. + * \param res Pointer to an initialized matrix, the result is stored + * here, one sample in each column. It will be resized, as needed. + * \return Error code. + * + * Time complexity: O(n * dim * g), where dim is the dimension of the + * sample vectors, set by the length of alpha, and g is the time + * complexity of sampling from a Gamma distribution. + * + * \sa \ref igraph_rng_sample_sphere_surface() and + * \ref igraph_rng_sample_sphere_volume() for other methods to sample + * latent vectors. + */ +igraph_error_t igraph_rng_sample_dirichlet( + igraph_rng_t* rng, igraph_int_t n, const igraph_vector_t *alpha, + igraph_matrix_t *res +) { + + igraph_int_t len = igraph_vector_size(alpha); + igraph_int_t i, j; + igraph_real_t sum, num; + + if (n < 0) { + IGRAPH_ERRORF("Number of samples should be non-negative, got %" IGRAPH_PRId ".", + IGRAPH_EINVAL, n); + } + + if (len < 2) { + IGRAPH_ERRORF("Dirichlet parameter vector too short, must " + "have at least two entries, got %" IGRAPH_PRId + ".", IGRAPH_EINVAL, len); + } + + if (igraph_vector_min(alpha) <= 0) { + IGRAPH_ERRORF("Dirichlet concentration parameters must be positive, got %g.", + IGRAPH_EINVAL, igraph_vector_min(alpha)); + } + + IGRAPH_CHECK(igraph_matrix_resize(res, len, n)); + + for (i = 0; i < n; i++) { + for (j = 0, sum = 0.0; j < len; j++) { + num = igraph_rng_get_gamma(rng, VECTOR(*alpha)[j], 1.0); + sum += num; + MATRIX(*res, j, i) = num; + } + for (j = 0; j < len; j++) { + MATRIX(*res, j, i) /= sum; + } + } + + return IGRAPH_SUCCESS; +} diff --git a/src/vendor/cigraph/src/spatial/beta_skeleton.cpp b/src/vendor/cigraph/src/spatial/beta_skeleton.cpp new file mode 100644 index 00000000000..20baaa87927 --- /dev/null +++ b/src/vendor/cigraph/src/spatial/beta_skeleton.cpp @@ -0,0 +1,816 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "igraph_spatial.h" + +#include "igraph_constructors.h" +#include "igraph_error.h" +#include "igraph_matrix.h" +#include "igraph_types.h" +#include "igraph_vector.h" + +#include "core/exceptions.h" +#include "spatial/nanoflann_internal.hpp" +#include "spatial/spatial_internal.h" +#include + +#define TOLERANCE (128 * DBL_EPSILON) + +// Some methods to get distances between two vectors, including when one or both are embedded in a matrix. +static inline igraph_real_t ind_ind_sqr_distance(igraph_int_t a, igraph_int_t b, + const igraph_matrix_t *points) { + igraph_real_t distance = 0; + igraph_int_t dims = igraph_matrix_ncol(points); + for (igraph_int_t i = 0; i < dims; i++) { + igraph_real_t temp = MATRIX(*points, a, i) - MATRIX(*points, b, i); + distance += temp * temp; + } + return distance; +} + +static inline igraph_real_t vec_vec_sqr_dist(const igraph_vector_t *a, const igraph_vector_t *b) { + igraph_real_t distance = 0; + igraph_int_t dims = igraph_vector_size(a); + for (igraph_int_t i = 0; i < dims; i++) { + igraph_real_t temp = VECTOR(*a)[i] - VECTOR(*b)[i]; + distance += temp * temp; + } + return distance; +} + +static inline igraph_real_t vec_vec_sqr_dist(const std::vector &a, const std::vector &b) { + igraph_real_t distance = 0; + igraph_int_t dims = a.size(); + for (igraph_int_t i = 0; i < dims; i++) { + igraph_real_t temp = a[i] - b[i]; + distance += temp * temp; + } + return distance; +} + +static inline igraph_real_t vec_ind_sqr_dist(const igraph_vector_t *a, const igraph_int_t b, const igraph_matrix_t *points) { + igraph_real_t distance = 0; + igraph_int_t dims = igraph_matrix_ncol(points); + for (igraph_int_t i = 0; i < dims; i++) { + igraph_real_t temp = VECTOR(*a)[i] - MATRIX(*points, b, i); + distance += temp * temp; + } + return distance; +} +static inline igraph_real_t vec_ind_sqr_dist(const std::vector &a, const igraph_int_t b, const igraph_matrix_t *points) { + igraph_real_t distance = 0; + igraph_int_t dims = igraph_matrix_ncol(points); + for (igraph_int_t i = 0; i < dims; i++) { + igraph_real_t temp = a[i] - MATRIX(*points, b, i); + distance += temp * temp; + } + return distance; +} + +// Adapted from code by Szabolcs at https://github.com/szhorvat/IGraphM +// Used in is_union_empty +class NeighborCounts { + const igraph_real_t radius; // L2 search radius + const igraph_int_t a, b; // edge endpoints; excluded from the count + igraph_bool_t short_circuit; + igraph_int_t found; + +public: + // Boilerplate for nanoflann + using DistanceType = igraph_real_t; + NeighborCounts(igraph_real_t radius, igraph_int_t a, igraph_int_t b, igraph_bool_t short_circuit) + : radius(radius), a(a), b(b), short_circuit(short_circuit) { + init(); + } + + void init() { + clear(); + } + + void clear() { + found = 0; + } + + size_t size() const { + return found; + } + + bool full() const { + return true; + } + + void sort() const {} + + igraph_real_t worstDist() const { + return radius; + } + + // Business logic + // Add the point if it's close enough + bool addPoint(igraph_real_t dist, igraph_int_t index) { + if (dist < radius && index != a && index != b) { + found += 1; + if (short_circuit) { + // Don't continue searching if it only matters if there's one or more. + return false; + } + } + return true; + } +}; + +// Helper result class for listing the points in the intersection of two spheres +// and counting how many are within the lune. +// Used in is_intersection_empty. +// Adapted from code by Szabolcs at https://github.com/szhorvat/IGraphM. +class IntersectionCounts { + const igraph_real_t radius; // Half height of intersection lune + const igraph_real_t beta_radius; // Radius of circles + const igraph_bool_t short_circuit; // Whether to stop after one point has been found + const igraph_int_t a, b; // Edge endpoints; excluded from the count. + const std::vector &a_center, &b_center; // Circle centers. + const igraph_matrix_t *points; // List of points, used to test if points are in range + size_t count; // how many are found. +public: + // Boilerplate for nanoflann + using DistanceType = igraph_real_t; + IntersectionCounts( + igraph_real_t radius_, igraph_real_t beta_radius_, + bool short_circuit_, + igraph_int_t a, igraph_int_t b, const std::vector &a_center, const std::vector &b_center, const igraph_matrix_t *points) + : radius(radius_), beta_radius(beta_radius_), + short_circuit(short_circuit_), + a(a), b(b), + a_center(a_center), b_center(b_center), points(points) { + init(); + } + + void init() { + clear(); + } + + void clear() { + count = 0; + } + + size_t size() const { + return count; + } + + bool full() const { + return true; + } + + void sort() const {} + + igraph_real_t worstDist() const { + return radius; + } + + // Business logic is all contained here. + // Count the point if it is within the radius from both centers, and if it's not one of the endpoints. + bool addPoint(igraph_real_t dist, igraph_int_t index) { + if (dist < radius && index != a && index != b) { + igraph_real_t pd1 = vec_ind_sqr_dist(a_center, index, points); + igraph_real_t pd2 = vec_ind_sqr_dist(b_center, index, points); + if (pd1 < beta_radius && pd2 < beta_radius) { + count++; + // Stop searching if it only matters to have at least one point. + if (short_circuit) { + return false; + } + } + } + return true; + } +}; + +// Shrinks type signatures significantly. +template +using KDTree = nanoflann::KDTreeSingleIndexAdaptor < + nanoflann::L2_Adaptor, + ig_point_adaptor, Dimension, igraph_int_t >; + +// give a known good superset of edges for a given value of beta. +// In the case of beta < 1, that is a complete graph, for +// beta >= 1 it is the delaunay triangulation of the points. +static igraph_error_t beta_skeleton_edge_superset(igraph_vector_int_t *edges, + const igraph_matrix_t *points, + igraph_real_t beta) { + + igraph_int_t num_points = igraph_matrix_nrow(points); + igraph_int_t num_dims = igraph_matrix_ncol(points); + + if (beta >= 1 && num_points > num_dims) { + // Large beta and enough points, subset of delaunay. + IGRAPH_CHECK(igraph_i_delaunay_edges(edges, points)); + } else { + // Small beta, not subset of Delaunay, give complete graph. + // Or Delaunay not calculable due to point count + // TODO: update when/if Delaunay supports small numbers. + igraph_int_t numpoints = igraph_matrix_nrow(points); + for (igraph_int_t a = 0; a < numpoints - 1; a++) { + for (igraph_int_t b = a + 1; b < numpoints; b++) { + IGRAPH_CHECK(igraph_vector_int_push_back(edges, a)); + IGRAPH_CHECK(igraph_vector_int_push_back(edges, b)); + } + } + } + return IGRAPH_SUCCESS; +} + +static inline igraph_real_t calculate_r(igraph_real_t beta) { + if (beta < 1) { + return 0.5 / beta; + } + return 0.5 * beta; +} + + +/* -!- center construction interface -!- + * igraph_vector_t *a_center, b_center : Expects an initialized vector of the + * correct size, will be written to. + * + * igraph_int_t a, b: the indices of the points, + * + * igraph_real_t r: the circles will be constructed with radius r * (distance a-> b) + * + * const igraph_matrix_t *points: point set containing the points a and b + */ + +typedef void CenterConstructor( + std::vector &a_centre, + std::vector &b_centre, + igraph_int_t a, + igraph_int_t b, + igraph_real_t beta, + const igraph_matrix_t *points); + +// construct the centers of the points for lune based beta skeletons with beta +// >= 1. The points lie on the line from a to b, such that the points lie on one +// of the circles. +// formula is a_center = a + (r-1) * (a - b), similar for b_center +static void construct_lune_centers(std::vector &a_centre, + std::vector &b_centre, + igraph_int_t a, + igraph_int_t b, + igraph_real_t r, + const igraph_matrix_t *points) { + igraph_int_t dims = igraph_matrix_ncol(points); + a_centre.resize(dims); + b_centre.resize(dims); + for (igraph_int_t i = 0; i < dims; i++) { + a_centre[i] = MATRIX(*points, a, i) + (r - 1) * (MATRIX(*points, a, i) - MATRIX(*points, b, i)); + b_centre[i] = MATRIX(*points, b, i) + (r - 1) * (MATRIX(*points, b, i) - MATRIX(*points, a, i)); + } +} + +// construct the centers of the circles for beta < 1, or circle based beta +// skeletons. +// Since it relies on a 90-degree rotation around the axis perpendicular +// to the line AB, it is only well-defined in 2d. +static void construct_perp_centers(std::vector &a_centre, + std::vector &b_centre, + igraph_int_t a, + igraph_int_t b, + igraph_real_t r, + const igraph_matrix_t *points) { + igraph_real_t mid[2], perp[2]; + + for (igraph_int_t i = 0; i < 2; i++) { + mid[i] = (MATRIX(*points, a, i) + MATRIX(*points, b, i)) * 0.5; + perp[i] = (MATRIX(*points, a, i) - MATRIX(*points, b, i)) * sqrt(r * r - 0.25); + } + + // Since this is only well-defined for 2d, a manual 90-degree rotation works and is simpler. + // The rotation being x = -y, y = x, 90 degrees counter-clockwise. + igraph_real_t temp = perp[0]; + perp[0] = - perp[1]; + perp[1] = temp; + + a_centre.resize(2); + b_centre.resize(2); + for (igraph_int_t i = 0; i < 2; i++) { + a_centre[i] = mid[i] + perp[i]; + b_centre[i] = mid[i] - perp[i]; + } +} + +/* -!- Filter interface -!- + * igraph_bool_t *result : will be overwritten with the result + * kdTree <-1> &tree : used for nanoflann check, should be + * initialized and filed with points. igraph_int_t a, b : the + * endpoints of the edge being evaluated. igraph_real_t beta : + * parameter for beta-skeletons. const igraph_matrix_t *points: matrix + * containing all the points. + */ +typedef bool FilterFunc( + const KDTree<-1> &tree, + igraph_int_t a, + igraph_int_t b, + const igraph_matrix_t *points, + igraph_real_t beta +); + + +// Test whether the intersection of the two circles as generated +// by center_positions is empty of points except for a and b. +template +static bool is_intersection_empty( + const KDTree<-1> &tree, + igraph_int_t a, + igraph_int_t b, + const igraph_matrix_t *points, + igraph_real_t beta) { + + igraph_real_t r = calculate_r(beta); + igraph_real_t sqr_dist = ind_ind_sqr_distance(a, b, points); + + std::vector midpoint; + igraph_int_t dims = igraph_matrix_ncol(points); + + std::vector a_centre, b_centre; + center_positions(a_centre, b_centre, a, b, r, points); + + midpoint.resize(dims); + for (igraph_int_t i = 0; i < dims; i++) { + midpoint[i] = 0.5 * (a_centre[i] + b_centre[i]); + } + // squared half-height of lune + igraph_real_t lune_height = sqr_dist - vec_vec_sqr_dist(midpoint, a_centre); + igraph_real_t tol = is_closed ? 1 + TOLERANCE : 1 - TOLERANCE; + IntersectionCounts intersections(lune_height * tol * tol, sqr_dist * r * r * tol * tol, true, a, b, a_centre, b_centre, points); + + tree.findNeighbors(intersections, midpoint.data()); + return intersections.size() == 0; +} + +// Test whether the union of the circles given by center_positions +// is empty of other points except for a and b. +template +static bool is_union_empty( + const KDTree<-1> &tree, + igraph_int_t a, + igraph_int_t b, + const igraph_matrix_t *points, + igraph_real_t beta) { + + igraph_real_t sqr_dist = ind_ind_sqr_distance(a, b, points); + igraph_real_t r = calculate_r(beta); + std::vector a_centre, b_centre; + + center_positions(a_centre, b_centre, a, b, r, points); + + NeighborCounts neighbor_search(sqr_dist * r * r * (1 + TOLERANCE), a, b, true); + + tree.findNeighbors(neighbor_search, a_centre.data()); + + if (neighbor_search.size() > 0) { + return false; + } else { + neighbor_search.clear(); + tree.findNeighbors(neighbor_search, b_centre.data()); + return neighbor_search.size() == 0; + } +} + +// Iterate through the edges given, applying the provided filter. +// Currently used with is_intersection_empty and is_union_empty. +// TODO: specialize for multiple dimensions? +template +static igraph_error_t filter_edges(igraph_vector_int_t *edges, const igraph_matrix_t *points, igraph_real_t beta) { + igraph_int_t available_edges = igraph_vector_int_size(edges); + igraph_int_t added_edges = 0; + ig_point_adaptor adaptor(points); + igraph_int_t dim = igraph_matrix_ncol(points); + KDTree<-1> tree(dim, adaptor, nanoflann::KDTreeSingleIndexAdaptorParams(10)); + tree.buildIndex(); + for (igraph_int_t i = 0; i * 2 < available_edges; i++) { + if (filter(tree, VECTOR(*edges)[2 * i], VECTOR(*edges)[2 * i + 1], points, beta)) { + VECTOR(*edges)[added_edges * 2] = VECTOR(*edges)[i * 2]; + VECTOR(*edges)[added_edges * 2 + 1] = VECTOR(*edges)[i * 2 + 1]; + added_edges += 1; + } + } + IGRAPH_CHECK(igraph_vector_int_resize(edges, added_edges * 2)); + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_lune_beta_skeleton + * \brief The lune based β-skeleton of a spatial point set. + * + * \experimental + * + * This function constructs the lune-based β-skeleton of an n-dimensional + * spatial point set. + * + * + * A larger β results in a larger region, and a sparser graph. + * Values of β < 1 are only supported in 2D, and are considerably slower. + * + * + * The Gabriel graph is a special case of beta skeleton where β = 1. + * + * + * The Relative Neighborhood graph is a special case of beta skeleton where + * β approaches + * + * \param graph A pointer to the graph that will be created. + * \param points A matrix containing the points that will be used to create the + * graph. Each row is a point, dimensionality is inferred from the column count. + * + * \return Error code. + * + * Time Complexity: Around O(n^floor(d/2) log n), where n is the number of points + * and d is the dimensionality of the point set. + * + */ +igraph_error_t igraph_lune_beta_skeleton(igraph_t *graph, const igraph_matrix_t *points, igraph_real_t beta) { + IGRAPH_HANDLE_EXCEPTIONS_BEGIN; + + igraph_vector_int_t potential_edges; + IGRAPH_VECTOR_INT_INIT_FINALLY(&potential_edges, 0); + + IGRAPH_CHECK(beta_skeleton_edge_superset(&potential_edges, points, beta)); + // determine filter required based on beta. + if (beta >= 1) { + IGRAPH_CHECK((filter_edges>(&potential_edges, points, beta))); + } else { + if (igraph_matrix_ncol(points) != 2) { + IGRAPH_ERROR("Beta skeletons with beta < 1 are only supported in 2 dimensions.", IGRAPH_UNIMPLEMENTED); + } + + IGRAPH_CHECK((filter_edges>(&potential_edges, points, beta))); + } + + IGRAPH_CHECK(igraph_create(graph, &potential_edges, igraph_matrix_nrow(points), false)); + + igraph_vector_int_destroy(&potential_edges); + IGRAPH_FINALLY_CLEAN(1); + + IGRAPH_HANDLE_EXCEPTIONS_END; + + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_circle_beta_skeleton + * \brief The circle based β-skeleton of a 2D spatial point set. + * + * \experimental + * + * This function constructs the circle based β-skeleton of a 2D spatial point set. + * + * + * A larger \p beta value results in a larger region, and a sparser graph. + * Values of beta < 1 are considerably slower + * + * \param graph A pointer to the graph that will be created. + * \param points An n-by-2 matrix containing the points that will be used to + * create the graph. Each row is a point. + * \param beta A positive real value used to parameterize the graph. + * \return Error code. + * + * Time Complexity: Around O(n^floor(d/2) log n), where n is the number of points + * and d is the dimensionality of the point set. + * + */ +igraph_error_t igraph_circle_beta_skeleton(igraph_t *graph, const igraph_matrix_t *points, igraph_real_t beta) { + IGRAPH_HANDLE_EXCEPTIONS_BEGIN; + + igraph_vector_int_t potential_edges; + IGRAPH_VECTOR_INT_INIT_FINALLY(&potential_edges, 0); + + if (igraph_matrix_ncol(points) != 2) { + IGRAPH_ERROR("Circle based beta skeletons are only supported in 2 dimensions.", IGRAPH_UNIMPLEMENTED); + } + + IGRAPH_CHECK(beta_skeleton_edge_superset(&potential_edges, points, beta)); + if (beta >= 1) { + IGRAPH_CHECK(filter_edges>(&potential_edges, points, beta)); + } else { + IGRAPH_CHECK((filter_edges>(&potential_edges, points, beta))); + } + + IGRAPH_CHECK(igraph_create(graph, &potential_edges, igraph_matrix_nrow(points), false)); + + igraph_vector_int_destroy(&potential_edges); + IGRAPH_FINALLY_CLEAN(1); + + IGRAPH_HANDLE_EXCEPTIONS_END; + + return IGRAPH_SUCCESS; +} + +// Derived from code by Szabolcs at github.com/szhorvat/IGraphM + +class BetaFinder { + const igraph_real_t max_beta; + const igraph_real_t tol; + const igraph_int_t ai, bi; + const igraph_matrix_t *ps; + const igraph_real_t ab2; + + igraph_real_t smallest_beta; + igraph_real_t max_radius; + +public: + using DistanceType = igraph_real_t; + using IndexType = igraph_int_t; + BetaFinder(igraph_real_t max_beta, igraph_real_t tol, igraph_int_t v1, igraph_int_t v2, const igraph_matrix_t *ps) : + max_beta(max_beta), tol(tol), ai(v1), bi(v2), ps(ps), + ab2(ind_ind_sqr_distance(ai, bi, ps)) { + init(); + } + + void init() { + clear(); + } + + void clear() { + smallest_beta = IGRAPH_INFINITY; + max_radius = luneHalfHeight2(max_beta); + } + + bool full() const { + return true; + } + + size_t size() const { + return 1; + } + + igraph_real_t luneHalfHeight2(igraph_real_t beta) const { + if (beta == 0) { + return 0; + } + return (ab2 / 4) * (2 * beta - 1); + } + + // Calculate the beta at which point index would make the edge a-b disappear. + // If calculated beta is under 1, it would not appear in the gabriel graph, so a 0 is returned + // which is to be interpreted as the edge being missing. + igraph_real_t pointBeta(igraph_int_t index) const { + if (index == ai || index == bi) { + return IGRAPH_INFINITY; + } + + igraph_real_t ap2 = ind_ind_sqr_distance(ai, index, ps); + igraph_real_t bp2 = ind_ind_sqr_distance(bi, index, ps); + + if (ap2 > bp2) { + std::swap(ap2, bp2); + } + + igraph_real_t denom = ab2 + ap2 - bp2; + + if (denom <= 0) { + return IGRAPH_INFINITY; + } + + igraph_real_t beta = 2 * ap2 / denom; + return beta < 1 + tol ? 0 : beta; + } + + bool addPoint(igraph_real_t dist, igraph_int_t index) { + if (dist < max_radius) { + igraph_real_t beta = pointBeta(index); + if (beta < smallest_beta && beta < max_beta) { + smallest_beta = beta; + max_radius = luneHalfHeight2(beta); + } + } + + return true; + } + + igraph_real_t worstDist() const { + return max_radius; + } + + void sort() {} + + igraph_real_t thresholdBeta() const { + return smallest_beta; + } +}; + +/** + * \function igraph_beta_weighted_gabriel_graph + * \brief A Gabriel graph, with edges weighted by the β value at which it disappears. + * + * \experimental + * + * This function generates a Gabriel graph, and for each edge of this graph it + * computes the threshold β value at which the edge ceases to be part of the + * lune-based β-skeleton. For edges that continue to be part of β-skeletons + * for arbitrarily large β, \c IGRAPH_INFINITΥ is returned. + * + * + * The \p max_beta cutoff parameter controls the largest β value to consider + * For edges that persist above this β value, \c IGRAPH_INFINITΥ is returned. + * This parameter serves to improve performance: the smaller this cutoff, + * the faster the computation. Pass \c IGRAPH_INFINITY to use no cutoff. + * + * \param graph A pointer to the graph that will be created. + * \param weights Will contain the edge weights corresponding to the edge + * indices from the graph. + * \param points A matrix containing the points that will be used. + * Each row is a point, dimensionality is inferred from the column count. + * There must be no duplicate points. + * \param max_beta Maximum value of beta to search to, higher values will be + * represented as \c IGRAPH_INFINITY. + * \return Error code. + * + * \sa \ref igraph_lune_beta_skeleton() or \ref igraph_circle_beta_skeleton() + * to generate a graph with a given value of beta; \ref igraph_gabriel_graph() + * to only generate a Gabriel graph, without edge weights. + * + * + * Time Complexity: Around O(n^floor(d/2) log n), where n is the number of points + * and d is the dimensionality of the point set. Though large values of max_beta + * can cause long run times if there are edges that disappear only at large betas. + * + */ +igraph_error_t igraph_beta_weighted_gabriel_graph( + igraph_t *graph, + igraph_vector_t *weights, + const igraph_matrix_t *points, + igraph_real_t max_beta) { + + IGRAPH_HANDLE_EXCEPTIONS_BEGIN; + + igraph_vector_int_t edges; + IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); + + igraph_int_t dim = igraph_matrix_ncol(points); + igraph_int_t point_count = igraph_matrix_nrow(points); + ig_point_adaptor adaptor(points); + + IGRAPH_CHECK(igraph_i_delaunay_edges(&edges, points)); + igraph_int_t edge_count = igraph_vector_int_size(&edges) / 2; + + IGRAPH_CHECK(igraph_vector_resize(weights, edge_count)); + + KDTree<-1> tree(dim, adaptor, nanoflann::KDTreeSingleIndexAdaptorParams(10)); + tree.buildIndex(); + + igraph_vector_t midpoint; + IGRAPH_VECTOR_INIT_FINALLY(&midpoint, dim); + + for (igraph_int_t i = 0; i < edge_count; i++) { + BetaFinder finder(max_beta, TOLERANCE, VECTOR(edges)[2 * i], VECTOR(edges)[2 * i + 1], points); + + for (igraph_int_t axis = 0; axis < dim; axis++) { + VECTOR(midpoint)[axis] = 0.5 * ( + MATRIX(*points, VECTOR(edges)[2 * i], axis) + + MATRIX(*points, VECTOR(edges)[2 * i + 1], axis) + ); + } + + tree.findNeighbors(finder, VECTOR(midpoint)); + VECTOR(*weights)[i] = finder.thresholdBeta(); + } + + // Filter out edges with beta == 0. + igraph_int_t added_edges = 0; + for (igraph_int_t i = 0; i < edge_count; i++) { + if (VECTOR(*weights)[i] != 0) { + VECTOR(*weights)[added_edges] = VECTOR(*weights)[i]; + VECTOR(edges)[added_edges * 2] = VECTOR(edges)[i * 2]; + VECTOR(edges)[added_edges * 2 + 1] = VECTOR(edges)[i * 2 + 1]; + added_edges += 1; + } + } + + IGRAPH_CHECK(igraph_vector_int_resize(&edges, added_edges * 2)); + IGRAPH_CHECK(igraph_vector_resize(weights, added_edges)); + + IGRAPH_CHECK(igraph_create(graph, &edges, point_count, false)); + + igraph_vector_int_destroy(&edges); + igraph_vector_destroy(&midpoint); + IGRAPH_FINALLY_CLEAN(2); + + IGRAPH_HANDLE_EXCEPTIONS_END; + + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_gabriel_graph + * \brief The Gabriel graph of a point set. + * + * \experimental + * + * In the Gabriel graph of a point set, two points A and B are connected if + * there is no other point C within the closed ball of which AB is a diameter. + * The Gabriel graph is connected, and in 2D it is planar. igraph supports + * computing the Gabriel graph of arbitrary dimensional point sets. + * + * + * The Gabriel graph is a special case of lune-based and circle-based β-skeletons + * with β=1. + * + * \param graph A pointer to the graph to be created. + * \param points The point set that will be used. Each row is a point, + * dimensionality is inferred from column count. + * + * \return Error Code. + * \sa The Gabriel graph is a special case of + * \ref igraph_lune_beta_skeleton() and \ref igraph_circle_beta_skeleton() + * where β = 1. + * + * Time Complexity: Around O(n^floor(d/2) log n), where n is the number of points + * and d is the dimensionality of the point set. + * + */ +igraph_error_t igraph_gabriel_graph(igraph_t *graph, const igraph_matrix_t *points) { + IGRAPH_HANDLE_EXCEPTIONS_BEGIN; + + igraph_vector_int_t potential_edges; + IGRAPH_VECTOR_INT_INIT_FINALLY(&potential_edges, 0); + + IGRAPH_CHECK(beta_skeleton_edge_superset(&potential_edges, points, 1)); + + IGRAPH_CHECK((filter_edges>(&potential_edges, points, 1))); + + IGRAPH_CHECK(igraph_create(graph, &potential_edges, igraph_matrix_nrow(points), false)); + + igraph_vector_int_destroy(&potential_edges); + IGRAPH_FINALLY_CLEAN(1); + + IGRAPH_HANDLE_EXCEPTIONS_END; + + return IGRAPH_SUCCESS; +} + +/** + * \function igraph_relative_neighborhood_graph + * \brief The relative neighborhood graph of a point set. + * + * \experimental + * + * The relative neighborhood graph is constructed from a set of points in space. + * Two points A and B are connected if and only if there is no other point C so + * that AC < AB and BC < AB, with the inequalities being strict. + * + * + * Most authors define the relative neighborhood graph to coincide with a + * lune-based β-skeleton for β = 2. In igraph, there is a subtle + * difference: the β = 2 skeleton connects points A and B when there + * is no point C so that AC <= AB and BC <= AB. Therefore, three points + * forming an equilateral triangle are connected in the relative neighborhood graph, + * but disconnected in the β = 2 skeleton. + * + * + * With these definitions, the relative neighborhood graph is always connected, + * while the β = 2 skeleton is always triangle-free. + * + * \param graph A pointer to the graph that will be created. + * \param points The point set that will be used, each row is a point. + * Dimensionality is inferred from the column number. + * \return Error code. + * + * \sa \ref igraph_lune_beta_skeleton() to compute the lune based β-skeleton + * for β = 2 or other β values. + * + * Time Complexity: Around O(n^floor(d/2) log n), where n is the number of points + * and d is the dimensionality of the point set. + * + */ +igraph_error_t igraph_relative_neighborhood_graph(igraph_t *graph, const igraph_matrix_t *points) { + IGRAPH_HANDLE_EXCEPTIONS_BEGIN; + + igraph_vector_int_t potential_edges; + IGRAPH_VECTOR_INT_INIT_FINALLY(&potential_edges, 0); + + IGRAPH_CHECK(beta_skeleton_edge_superset(&potential_edges, points, 1)); + + IGRAPH_CHECK((filter_edges>(&potential_edges, points, 2))); + + IGRAPH_CHECK(igraph_create(graph, &potential_edges, igraph_matrix_nrow(points), false)); + + igraph_vector_int_destroy(&potential_edges); + IGRAPH_FINALLY_CLEAN(1); + + IGRAPH_HANDLE_EXCEPTIONS_END; + + return IGRAPH_SUCCESS; +} diff --git a/src/vendor/cigraph/src/spatial/convex_hull.c b/src/vendor/cigraph/src/spatial/convex_hull.c new file mode 100644 index 00000000000..f815c3d7b67 --- /dev/null +++ b/src/vendor/cigraph/src/spatial/convex_hull.c @@ -0,0 +1,188 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "igraph_spatial.h" + +/** + * \function igraph_convex_hull_2d + * \brief Determines the convex hull of a given set of points in the 2D plane. + * + * + * The convex hull is determined by the Graham scan algorithm. + * See the following reference for details: + * + * + * Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford + * Stein. Introduction to Algorithms, Second Edition. MIT Press and + * McGraw-Hill, 2001. ISBN 0262032937. Pages 949-955 of section 33.3: + * Finding the convex hull. + * + * \param data vector containing the coordinates. The length of the + * vector must be even, since it contains X-Y coordinate pairs. + * \param resverts the vector containing the result, e.g. the vector of + * vertex indices used as the corners of the convex hull. Supply + * \c NULL here if you are only interested in the coordinates of + * the convex hull corners. + * \param rescoords the matrix containing the coordinates of the selected + * corner vertices. Supply \c NULL here if you are only interested in + * the vertex indices. + * \return Error code: + * \c IGRAPH_ENOMEM: not enough memory + * + * Time complexity: O(n log(n)) where n is the number of vertices. + */ +igraph_error_t igraph_convex_hull_2d( + const igraph_matrix_t *data, + igraph_vector_int_t *resverts, + igraph_matrix_t *rescoords) +{ + igraph_int_t no_of_nodes; + igraph_int_t i, pivot_idx = 0, last_idx, before_last_idx, next_idx, j; + igraph_vector_t angles; + igraph_vector_int_t order, stack; + igraph_real_t px, py, cp; + + no_of_nodes = igraph_matrix_nrow(data); + if (igraph_matrix_ncol(data) != 2) { + IGRAPH_ERROR("Only two-dimensional point sets are supports, matrix must have two columns.", IGRAPH_EINVAL); + } + if (no_of_nodes == 0) { + if (resverts) { + igraph_vector_int_clear(resverts); + } + if (rescoords) { + IGRAPH_CHECK(igraph_matrix_resize(rescoords, 0, 2)); + } + /**************************** this is an exit here *********/ + return IGRAPH_SUCCESS; + } + + IGRAPH_VECTOR_INIT_FINALLY(&angles, no_of_nodes); + IGRAPH_VECTOR_INT_INIT_FINALLY(&stack, 0); + + /* Search for the pivot vertex */ + for (i = 1; i < no_of_nodes; i++) { + if (MATRIX(*data, i, 1) < MATRIX(*data, pivot_idx, 1)) { + pivot_idx = i; + } else if (MATRIX(*data, i, 1) == MATRIX(*data, pivot_idx, 1) && + MATRIX(*data, i, 0) < MATRIX(*data, pivot_idx, 0)) { + pivot_idx = i; + } + } + px = MATRIX(*data, pivot_idx, 0); + py = MATRIX(*data, pivot_idx, 1); + + /* Create angle array */ + for (i = 0; i < no_of_nodes; i++) { + if (i == pivot_idx) { + /* We can't calculate the angle of the pivot point with itself, + * so we use 10 here. This way, after sorting the angle vector, + * the pivot point will always be the first one, since the range + * of atan2 is -3.14..3.14 */ + VECTOR(angles)[i] = 10; + } else { + VECTOR(angles)[i] = atan2(MATRIX(*data, i, 1) - py, MATRIX(*data, i, 0) - px); + } + } + + /* Sort points by angles */ + IGRAPH_VECTOR_INT_INIT_FINALLY(&order, no_of_nodes); + IGRAPH_CHECK(igraph_vector_sort_ind(&angles, &order, IGRAPH_ASCENDING)); + + /* Check if two points have the same angle. If so, keep only the point that + * is farthest from the pivot */ + j = 0; + last_idx = VECTOR(order)[0]; + pivot_idx = VECTOR(order)[no_of_nodes - 1]; + for (i = 1; i < no_of_nodes; i++) { + next_idx = VECTOR(order)[i]; + if (VECTOR(angles)[last_idx] == VECTOR(angles)[next_idx]) { + /* Keep the vertex that is farther from the pivot, drop the one that is + * closer */ + px = pow(MATRIX(*data, last_idx, 0) - MATRIX(*data, pivot_idx, 0), 2) + + pow(MATRIX(*data, last_idx, 1) - MATRIX(*data, pivot_idx, 1), 2); + py = pow(MATRIX(*data, next_idx, 0) - MATRIX(*data, pivot_idx, 0), 2) + + pow(MATRIX(*data, next_idx, 1) - MATRIX(*data, pivot_idx, 1), 2); + if (px > py) { + VECTOR(order)[i] = -1; + } else { + VECTOR(order)[j] = -1; + last_idx = next_idx; + j = i; + } + } else { + last_idx = next_idx; + j = i; + } + } + + j = 0; + last_idx = -1; + before_last_idx = -1; + while (!igraph_vector_int_empty(&order)) { + next_idx = igraph_vector_int_tail(&order); + if (next_idx < 0) { + /* This vertex should be skipped; was excluded in an earlier step */ + igraph_vector_int_pop_back(&order); + continue; + } + /* Determine whether we are at a left or right turn */ + if (j < 2) { + /* Pretend that we are turning into the right direction if we have less + * than two items in the stack */ + cp = -1; + } else { + cp = (MATRIX(*data, last_idx, 0) - MATRIX(*data, before_last_idx, 0)) * + (MATRIX(*data, next_idx, 1) - MATRIX(*data, before_last_idx, 1)) - + (MATRIX(*data, next_idx, 0) - MATRIX(*data, before_last_idx, 0)) * + (MATRIX(*data, last_idx, 1) - MATRIX(*data, before_last_idx, 1)); + } + + if (cp < 0) { + /* We are turning into the right direction */ + igraph_vector_int_pop_back(&order); + IGRAPH_CHECK(igraph_vector_int_push_back(&stack, next_idx)); + before_last_idx = last_idx; + last_idx = next_idx; + j++; + } else { + /* No, skip back and try again in the next iteration */ + igraph_vector_int_pop_back(&stack); + j--; + last_idx = before_last_idx; + before_last_idx = (j >= 2) ? VECTOR(stack)[j - 2] : -1; + } + } + + /* Create result vector */ + if (resverts != 0) { + igraph_vector_int_clear(resverts); + IGRAPH_CHECK(igraph_vector_int_append(resverts, &stack)); + } + if (rescoords != 0) { + igraph_matrix_select_rows(data, rescoords, &stack); + } + + /* Free everything */ + igraph_vector_int_destroy(&order); + igraph_vector_int_destroy(&stack); + igraph_vector_destroy(&angles); + IGRAPH_FINALLY_CLEAN(3); + + return IGRAPH_SUCCESS; +} diff --git a/src/vendor/cigraph/src/spatial/delaunay.c b/src/vendor/cigraph/src/spatial/delaunay.c new file mode 100644 index 00000000000..0668aa3dd41 --- /dev/null +++ b/src/vendor/cigraph/src/spatial/delaunay.c @@ -0,0 +1,280 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "igraph_spatial.h" + +#include "igraph_bitset.h" +#include "igraph_constructors.h" +#include "igraph_error.h" +#include "igraph_matrix.h" +#include "igraph_memory.h" +#include "igraph_types.h" +#include "igraph_vector.h" + +#include "internal/utils.h" +#include "spatial/spatial_internal.h" + +#include "qhull/libqhull_r/libqhull_r.h" + +/** + * Raises an error if a spatial point set is invalid. + * The coordinate matrix must have at least one column and must not + * contain NaN or infinities. + * + * \param points Matrix, each row is a spatial point. + * \return Error code. + */ +igraph_error_t igraph_i_check_spatial_points(const igraph_matrix_t *points) { + const igraph_int_t dim = igraph_matrix_ncol(points); + const igraph_int_t n = igraph_matrix_nrow(points); + + /* Special case: we allow zero columns when there are zero rows, i.e. no points. + * Some languages cannot represent size-zero matrices and length-zero point + * lists may translate as a 0-by-0 matrix to igraph. */ + if (dim == 0 && n > 0) { + IGRAPH_ERROR("Point sets must not be zero-dimensional.", IGRAPH_EINVAL); + } + + if (!igraph_vector_is_all_finite(&points->data)) { + IGRAPH_ERROR("Coordinates must not be NaN or infinite.", IGRAPH_EINVAL); + } + + return IGRAPH_SUCCESS; +} + +// Append an undirected clique of the indices in destination to source. +// Assumes that source is an initialized vector. +static igraph_error_t add_clique(igraph_vector_int_t *destination, const igraph_vector_int_t *source) { + igraph_int_t num_points = igraph_vector_int_size(source); + for (igraph_int_t a = 0; a < num_points - 1; a++) { + for (igraph_int_t b = a + 1; b < num_points; b++) { + IGRAPH_CHECK(igraph_vector_int_push_back(destination, VECTOR(*source)[a])); + IGRAPH_CHECK(igraph_vector_int_push_back(destination, VECTOR(*source)[b])); + } + } + return IGRAPH_SUCCESS; +} + + +// Helper that can go on the finally stack to free qhT Qhull data structure in case of an error. +static void destroy_qhull(qhT *qh) { + int curlong, totlong; + qh->NOerrexit = True; /* no more setjmp */ + qh_freeqhull(qh, !qh_ALL); + qh_memfreeshort(qh, &curlong, &totlong); +} + + +/* In the 1D case we simply connect points in sorted order. + * This function assumes that there is at least one point. */ +static igraph_error_t delaunay_edges_1d(igraph_vector_int_t *edges, const igraph_matrix_t *points) { + const igraph_int_t numpoints = igraph_matrix_nrow(points); + const igraph_vector_t coords = igraph_vector_view(&MATRIX(*points, 0, 0), numpoints); + igraph_vector_int_t order; + + IGRAPH_ASSERT(igraph_matrix_ncol(points) == 1); + + IGRAPH_VECTOR_INT_INIT_FINALLY(&order, numpoints); + + IGRAPH_CHECK(igraph_vector_sort_ind(&coords, &order, IGRAPH_ASCENDING)); + + IGRAPH_CHECK(igraph_vector_int_resize(edges, 2*(numpoints-1))); + + for (igraph_int_t i=0; i < numpoints-1; i++) { + igraph_int_t from = VECTOR(order)[i]; + igraph_int_t to = VECTOR(order)[i+1]; + VECTOR(*edges)[2*i] = from; + VECTOR(*edges)[2*i + 1] = to; + if (VECTOR(coords)[from] == VECTOR(coords)[to]) { + IGRAPH_ERROR("Duplicate points for Delaunay triangulation.", IGRAPH_EINVAL); + } + } + + igraph_vector_int_destroy(&order); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} + +igraph_error_t igraph_i_delaunay_edges(igraph_vector_int_t *edges, const igraph_matrix_t *points) { + const igraph_int_t numpoints = igraph_matrix_nrow(points) ; + const igraph_int_t dim = igraph_matrix_ncol(points); + int exitcode; + qhT qh_qh; /* Qhull's data structure. First argument of most Qhull calls. */ + qhT *qh = &qh_qh; /* Convenience pointer. */ + + /* Error checks */ + + /* Validate point set. */ + IGRAPH_CHECK(igraph_i_check_spatial_points(points)); + + /* No edges for one or zero points. */ + if (numpoints <= 1) { + igraph_vector_int_clear(edges); + return IGRAPH_SUCCESS; + } + + /* Qhull does not support the 1D case. */ + if (dim == 1) { + return delaunay_edges_1d(edges, points); + } + + if (dim >= numpoints) { + IGRAPH_ERRORF("Not enough points to create simplex, need at least %" IGRAPH_PRId ".", IGRAPH_EINVAL, dim); + } + + /* Prevent overflow in igraph_int_t -> int conversions below. + * Note that Qhull will likely already fail for a much smaller point count. */ + if (numpoints > INT_MAX) { + IGRAPH_ERROR("Too many points for Qhull.", IGRAPH_EOVERFLOW); + } + + /* Prepare point set in row-major format for Qhull */ + + coordT *qhull_points = IGRAPH_CALLOC(dim*numpoints, igraph_real_t); + IGRAPH_CHECK_OOM(qhull_points, "Insufficient memory for constructing Delaunay graph."); + IGRAPH_FINALLY(igraph_free, qhull_points); + igraph_matrix_copy_to(points, qhull_points, IGRAPH_ROW_MAJOR); + + /* Call Qhull. + * + * This is mainly based on qdelaunay/qdelaun_r.c and qh_new_qhull() in user_r.c. + * + * Note that output routines in userprintf_r.c are patched to not print + * when passing NULL as a file pointer, which is what we do here. */ + + /* Check for compatible library. Not technically necessary, as igraph + * vendors Qhull due to the need to override output routines. Would + * become necessary if linking to an external Qhull. */ + QHULL_LIB_CHECK + + /* Initializes qh, sets qh->qhull_command. */ + qh_init_A(qh, NULL, NULL, NULL, 0, NULL); + IGRAPH_FINALLY(destroy_qhull, qh); + + exitcode = setjmp(qh->errexit); + if (!exitcode) { + qh->NOerrexit = False; + + /* qh_option() does not change the operation of Qhull. It simply records options to be + * output with error messages. Here we manually keep it in sync with the settings below. */ + qh_option(qh, "delaunay Qz-infinity-point Q3-no-merge-vertices", NULL, NULL); + + qh->PROJECTdelaunay = True; // project points to parabola to calculate delaunay triangulation + qh->DELAUNAY = True; // 'd' + qh->ATinfinity = True; // 'Qz', required for cocircular points + qh->MERGEvertices = False; // 'Q3', do not merge identical vertices + + qh_initflags(qh, qh->qhull_command); + qh_init_B(qh, qhull_points, numpoints, dim, /*ismalloc=*/ False); // read points and project them to parabola. + qh_qhull(qh); // do the triangulation + qh_triangulate(qh); // this guarantees that everything is simplicial + + igraph_vector_int_t simplex; + IGRAPH_VECTOR_INT_INIT_FINALLY(&simplex, dim + 1); // a simplex in n dimensions has n+1 incident vertices. + + facetT *facet; // required for FORALLfacets + vertexT *vertex, **vertexp; // required for FOREACHvertex_ + + FORALLfacets { + if (!facet->upperdelaunay) { + igraph_int_t curr_vert = 0; + FOREACHvertex_(facet->vertices) { + VECTOR(simplex)[curr_vert++] = qh_pointid(qh, vertex->point); + } + IGRAPH_CHECK(add_clique(edges, &simplex)); + } + } + igraph_i_simplify_edge_list(edges, true, true, false); + + /* Check if there are any points/vertices that do not appear in the edge list. + * This happens when there are duplicate points, as Qhull ignores one of them. + * We raise an error when there are duplicates. */ + igraph_int_t edges_size = igraph_vector_int_size(edges); + igraph_bitset_t in_edge_list; + + IGRAPH_BITSET_INIT_FINALLY(&in_edge_list, numpoints); + for (igraph_int_t i = 0; i < edges_size; i++) { + IGRAPH_BIT_SET(in_edge_list, VECTOR(*edges)[i]); + } + if (igraph_bitset_is_any_zero(&in_edge_list)) { + IGRAPH_ERROR("Duplicate points for Delaunay triangulation.", IGRAPH_EINVAL); + } + + igraph_bitset_destroy(&in_edge_list); + igraph_vector_int_destroy(&simplex); + destroy_qhull(qh); + igraph_free(qhull_points); + IGRAPH_FINALLY_CLEAN(4); + } else { + switch (qh->last_errcode) { + /* TODO: More specific error descriptions for common Qhull errors. */ + default: + /* TODO: Report Qhull error text? */ + IGRAPH_ERRORF("Error while computing Delaunay triangulation, Qhull error code %d.", IGRAPH_EINVAL, qh->last_errcode); + } + } + + return IGRAPH_SUCCESS; +} + + +/** + * \function igraph_delaunay_graph + * \brief Computes the Delaunay graph of a spatial point set. + * + * \experimental + * + * This function constructs the graph corresponding to the Delaunay triangulation + * of an n-dimensional spatial point set. + * + * + * The current implementation uses Qhull. + * + * + * Reference: + * + * + * Barber, C. Bradford, David P. Dobkin, and Hannu Huhdanpaa. + * The Quickhull Algorithm for Convex Hulls. + * ACM Transactions on Mathematical Software 22, no. 4 (1996): 469–83. + * https://doi.org/10.1145/235815.235821. + * + * \param graph A pointer to the graph that will be created. + * \param points A matrix containing the points that will be used to create the graph. + * Each row is a point, dimensionality is inferred from the column count. + * There must not be duplicate points. + * \return Error code. + * + * Time complexity: According to Theorem 3.2 in the Qhull paper, + * O(n log n) for d <= 3 and O(n^floor(d/2) / floor(d/2)!) where + * n is the number of points and d is the dimensionality of the point set. + */ +igraph_error_t igraph_delaunay_graph(igraph_t *graph, const igraph_matrix_t *points) { + igraph_vector_int_t edges; + const igraph_int_t numpoints = igraph_matrix_nrow(points); + + IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); + IGRAPH_CHECK(igraph_i_delaunay_edges(&edges, points)); + IGRAPH_CHECK(igraph_create(graph, &edges, numpoints, IGRAPH_UNDIRECTED)); + + igraph_vector_int_destroy(&edges); + IGRAPH_FINALLY_CLEAN(1); + + return IGRAPH_SUCCESS; +} diff --git a/src/vendor/cigraph/src/spatial/edge_lengths.c b/src/vendor/cigraph/src/spatial/edge_lengths.c new file mode 100644 index 00000000000..7b5f19ef8db --- /dev/null +++ b/src/vendor/cigraph/src/spatial/edge_lengths.c @@ -0,0 +1,119 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "igraph_spatial.h" + +#include "igraph_datatype.h" +#include "igraph_error.h" +#include "igraph_interface.h" +#include "igraph_matrix.h" +#include "igraph_vector.h" + +#include /* sqrt, fabs */ + +/** + * \function igraph_spatial_edge_lengths + * \brief Edge lengths based on spatial vertex coordinates. + * + * \experimental + * + * The length of each edge is computed based on spatial coordinates. The length + * can be employed by several igraph functions, such as \ref igraph_voronoi(), + * \ref igraph_betweenness(), \ref igraph_closeness() and others. + * + * \param graph The graph whose edge lengths are to be computed. + * \param lengths An initialized vector. Length will be stored here, in the + * order of edge IDs. It will be resized as needed. + * \param points A matrix of vertex coordinates. Each row contains the + * coordinates of the corresponding vertex, in the order of vertex IDs. + * Arbitrary dimensional point sets are supported. + * \param metric The distance metric to use. See \ref igraph_metric_t for + * valid values. + * \return Error code. + * + * \sa \ref igraph_nearest_neighbor_graph() computes a k nearest neighbor graph + * and \ref igraph_delaunay_graph() computes a Delaunay graph based on a set of + * spatial points. + * + * Time complexity: O(|E| d) where |E| is the number of edges and d is the + * dimensionality of the point set. + */ +igraph_error_t igraph_spatial_edge_lengths( + const igraph_t *graph, + igraph_vector_t *lengths, + const igraph_matrix_t *points, + igraph_metric_t metric) { + + const igraph_int_t vcount = igraph_vcount(graph); + const igraph_int_t ecount = igraph_ecount(graph); + const igraph_int_t dim = igraph_matrix_ncol(points); + + /* Validate input. + * + * We opt not to check for Inf/NaN, as these can safely propagate to the result. */ + + if (igraph_matrix_nrow(points) != vcount) { + IGRAPH_ERROR("Number of vertex coordinates must match the vertex count.", IGRAPH_EINVAL); + } + + /* Special case: we allow zero columns when there are zero rows, i.e. no points. + * Some languages cannot represent size-zero matrices and length-zero point + * lists may translate as a 0-by-0 matrix to igraph. */ + if (dim == 0 && vcount > 0) { + IGRAPH_ERROR("Vertex coordinates must not be zero-dimensional.", IGRAPH_EINVAL); + } + + IGRAPH_CHECK(igraph_vector_resize(lengths, ecount)); + + /* Validate distance metric. The switch statement is helpful because + * compilers tend to show warnings when some enum values are missing. */ + switch (metric) { + case IGRAPH_METRIC_EUCLIDEAN: + case IGRAPH_METRIC_MANHATTAN: + break; + default: + IGRAPH_ERROR("Invalid distance metric.", IGRAPH_EINVAL); + } + + /* Compute edge lengths. */ + + for (igraph_int_t eid=0; eid < ecount; eid++) { + const igraph_int_t from = IGRAPH_FROM(graph, eid); + const igraph_int_t to = IGRAPH_TO(graph, eid); + igraph_real_t length = 0.0; + + for (igraph_int_t i=0; i < dim; i++) { + igraph_real_t diff = MATRIX(*points, from, i) - MATRIX(*points, to, i); + + switch (metric) { + case IGRAPH_METRIC_EUCLIDEAN: + length += diff*diff; break; + case IGRAPH_METRIC_MANHATTAN: + length += fabs(diff); break; + } + } + + if (metric == IGRAPH_METRIC_EUCLIDEAN) { + length = sqrt(length); + } + + VECTOR(*lengths)[eid] = length; + } + + return IGRAPH_SUCCESS; +} diff --git a/src/vendor/cigraph/src/spatial/nanoflann_internal.hpp b/src/vendor/cigraph/src/spatial/nanoflann_internal.hpp new file mode 100644 index 00000000000..93f62e0a977 --- /dev/null +++ b/src/vendor/cigraph/src/spatial/nanoflann_internal.hpp @@ -0,0 +1,121 @@ +#ifndef SPATIAL_NANOFLANN_INTERNAL_H +#define SPATIAL_NANOFLANN_INTERNAL_H + +#include "igraph_decls.h" +#include "igraph_types.h" + +#include "igraph_matrix.h" + +#include "nanoflann/nanoflann.hpp" + +#include + + +class ig_point_adaptor { + const igraph_matrix_t *points; + const igraph_int_t point_count; + +public: + explicit ig_point_adaptor(const igraph_matrix_t *points) : + points(points), point_count(igraph_matrix_nrow(points)) { } + + size_t kdtree_get_point_count() const { + return point_count; + } + + igraph_real_t kdtree_get_pt(const size_t idx, const size_t dim) const { + return MATRIX(*points, idx, dim); + } + template + bool kdtree_get_bbox(BoundingBox &bb) const { + IGRAPH_UNUSED(bb); + return false; // indicates that it should use default + } +}; + + +class GraphBuildingResultSet { + igraph_int_t added_count = 0; + const igraph_real_t max_distance; + const igraph_int_t max_neighbors; + +public: + igraph_int_t current_vertex = 0; + std::vector neighbors; + std::vector distances; + + using DistanceType = igraph_real_t; + using IndexType = igraph_int_t; + + GraphBuildingResultSet(const igraph_int_t max_neighbors, const igraph_real_t max_distance) : + max_distance(max_distance), + max_neighbors(max_neighbors), + neighbors(0), + distances(0) { } + + bool addPoint(const igraph_real_t distance, const igraph_int_t index) { + igraph_int_t i; + + if (index == current_vertex) { + return true; + } + + for (i = added_count; i > 0; i--) { + // TODO: Stabilize result in case of multiple points at exactly the same distance? + // See NANOFLANN_FIRST_MATCH in RKNNResultSet in nanoflann.hpp for reference. + if (distances[i - 1] > distance) { + registerPoint(i, neighbors[i - 1], distances[i - 1]); + } else { + break; + } + } + if (i < max_neighbors) { + registerPoint(i, index, distance); + } + if (added_count != max_neighbors) { + added_count++; + } + return true; + } + + void registerPoint(igraph_int_t where, igraph_int_t index, igraph_real_t distance) { + if (neighbors.size() == where) { + neighbors.push_back(index); + distances.push_back(distance); + } else { + neighbors[where] = index; + distances[where] = distance; + } + + } + + void reset(igraph_int_t current_vertex_) { + added_count = 0; + current_vertex = current_vertex_; + } + + // Never called. Necessary to conform to the interface. + void sort() { } + + igraph_int_t size() const { + return added_count; + } + + bool full() const { + return added_count == max_neighbors; + } + + bool empty() const { + return added_count == 0; + } + + igraph_real_t worstDist() const { + if (added_count < max_neighbors || added_count == 0) { + return max_distance; + } + return distances[added_count - 1]; + } +}; + + +#endif // SPATIAL_NANOFLANN_INTERNAL_H diff --git a/src/vendor/cigraph/src/spatial/nearest_neighbor.cpp b/src/vendor/cigraph/src/spatial/nearest_neighbor.cpp new file mode 100644 index 00000000000..4650cd05f3c --- /dev/null +++ b/src/vendor/cigraph/src/spatial/nearest_neighbor.cpp @@ -0,0 +1,189 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "igraph_spatial.h" + +#include "igraph_constructors.h" +#include "igraph_conversion.h" +#include "igraph_error.h" +#include "igraph_interface.h" +#include "igraph_matrix.h" +#include "igraph_types.h" +#include "igraph_vector.h" + +#include "spatial/nanoflann_internal.hpp" + +#include "core/exceptions.h" +#include "core/interruption.h" +#include "spatial/spatial_internal.h" + +#include "nanoflann/nanoflann.hpp" + +#include + +template +static igraph_error_t neighbor_helper( + igraph_t *graph, + const igraph_matrix_t *points, + igraph_int_t k, + igraph_real_t cutoff, + igraph_int_t dimension, + igraph_bool_t directed) { + + const igraph_int_t point_count = igraph_matrix_nrow(points); + ig_point_adaptor adaptor(points); + int iter = 0; + + using kdTree = nanoflann::KDTreeSingleIndexAdaptor; + kdTree tree(dimension, adaptor, nanoflann::KDTreeSingleIndexAdaptorParams(10)); + + tree.buildIndex(); + + igraph_vector_t current_point; + IGRAPH_VECTOR_INIT_FINALLY(¤t_point, dimension); + + igraph_int_t neighbor_count = k >= 0 ? k : point_count; + + GraphBuildingResultSet results(neighbor_count, cutoff); + std::vector edges; + for (igraph_int_t i = 0; i < point_count; i++) { + results.reset(i); + IGRAPH_CHECK(igraph_matrix_get_row(points, ¤t_point, i)); + + tree.findNeighbors(results, VECTOR(current_point), nanoflann::SearchParameters(0, false)); + for (igraph_int_t j = 0; j < results.size(); j++) { + edges.push_back(i); + edges.push_back(results.neighbors[j]); + } + + IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 10); + } + + igraph_vector_destroy(¤t_point); + IGRAPH_FINALLY_CLEAN(1); + + // Overflow check, ensures that edges.size() is not too large for igraph vectors. + if (edges.size() > IGRAPH_INTEGER_MAX) { + IGRAPH_ERROR("Too many edges.", IGRAPH_EOVERFLOW); + } + + const igraph_vector_int_t edge_view = igraph_vector_int_view(edges.data(), edges.size()); + IGRAPH_CHECK(igraph_create(graph, &edge_view, point_count, true)); + + if (! directed) { + IGRAPH_CHECK(igraph_to_undirected(graph, IGRAPH_TO_UNDIRECTED_COLLAPSE, NULL)); + } + + return IGRAPH_SUCCESS; +} + + +template +static igraph_error_t dimension_dispatcher( + igraph_t *graph, + const igraph_matrix_t *points, + igraph_int_t k, + igraph_real_t cutoff, + igraph_int_t dimension, + igraph_bool_t directed) { + + switch (dimension) { + case 0: + IGRAPH_ERROR("0-dimensional points are not supported.", IGRAPH_EINVAL); + case 1: + return neighbor_helper(graph, points, k, cutoff, dimension, directed); + case 2: + return neighbor_helper(graph, points, k, cutoff, dimension, directed); + case 3: + return neighbor_helper(graph, points, k, cutoff, dimension, directed); + default: + return neighbor_helper(graph, points, k, cutoff, dimension, directed); + } +} + + +/** + * \function igraph_nearest_neighbor_graph + * \brief Computes the nearest neighbor graph for a spatial point set. + * + * \experimental + * + * This function constructs the \p k nearest neighbor graph of a given point + * set. Each point is connected to at most \p k spatial neighbors within a + * radius of \p cutoff. + * + * \param graph A pointer to the graph that will be created. + * \param points A matrix containing the points that will be used to create + * the graph. Each row is a point, dimensionality is inferred from the + * column count. + * \param metric The distance metric to use. See \ref igraph_metric_t. + * \param k At most how many neighbors will be added for each vertex, set to + * a negative value to ignore. + * \param cutoff Maximum distance at which connections will be made, set to a + * negative value or \c IGRAPH_INFINITY to ignore. + * \param directed Whether to create a directed graph. + * \return Error code. + * + * Time complexity: O(n log(n)) where n is the number of points. + */ +igraph_error_t igraph_nearest_neighbor_graph(igraph_t *graph, + const igraph_matrix_t *points, + igraph_metric_t metric, + igraph_int_t k, + igraph_real_t cutoff, + igraph_bool_t directed) { + + const igraph_int_t dimension = igraph_matrix_ncol(points); + + // Negative cutoff values signify that no cutoff should be used. + cutoff = cutoff >= 0 ? cutoff : IGRAPH_INFINITY; + + // Handle null graph separately. + // The number of matrix columns is not meaningful when there are zero rows. + // This prevents throwing an error when both the column and the row counts are zero. + if (igraph_matrix_nrow(points) == 0) { + return igraph_empty(graph, 0, directed); + } + + IGRAPH_CHECK(igraph_i_check_spatial_points(points)); + + IGRAPH_HANDLE_EXCEPTIONS_BEGIN; + + switch (metric) { + case IGRAPH_METRIC_L2: + return dimension_dispatcher >( + graph, + points, + k, + cutoff * cutoff, // L2 uses square distances, so adjust for that here. + dimension, + directed); + case IGRAPH_METRIC_L1: + return dimension_dispatcher >( + graph, + points, + k, + cutoff, + dimension, + directed); + default: + IGRAPH_ERROR("Invalid metric.", IGRAPH_EINVAL); + } + + IGRAPH_HANDLE_EXCEPTIONS_END; +} diff --git a/src/vendor/cigraph/src/spatial/spatial_internal.h b/src/vendor/cigraph/src/spatial/spatial_internal.h new file mode 100644 index 00000000000..eb42367b98c --- /dev/null +++ b/src/vendor/cigraph/src/spatial/spatial_internal.h @@ -0,0 +1,34 @@ +/* + igraph library. + Copyright (C) 2025 The igraph development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef IGRAPH_SPATIAL_INTERNAL_H +#define IGRAPH_SPATIAL_INTERNAL_H + +#include "igraph_decls.h" +#include "igraph_error.h" +#include "igraph_vector.h" +#include "igraph_matrix.h" + +IGRAPH_BEGIN_C_DECLS + +igraph_error_t igraph_i_delaunay_edges(igraph_vector_int_t *edges, const igraph_matrix_t *points); +igraph_error_t igraph_i_check_spatial_points(const igraph_matrix_t *points); + +IGRAPH_END_C_DECLS + +#endif /* IGRAPH_SPATIAL_INTERNAL_H */ diff --git a/src/vendor/cigraph/src/version.c b/src/vendor/cigraph/src/version.c index f0bf43917df..7df72226392 100644 --- a/src/vendor/cigraph/src/version.c +++ b/src/vendor/cigraph/src/version.c @@ -1,6 +1,6 @@ /* - IGraph library. - Copyright (C) 2008-2022 The igraph development team + igraph library. + Copyright (C) 2008-2024 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,15 +26,17 @@ static const char *igraph_version_string = IGRAPH_VERSION; * \function igraph_version * \brief The version of the igraph C library. * - * \param version_string Pointer to a string pointer. If not null, it - * is set to the igraph version string, e.g. "0.9.11" or "0.10.0". This - * string must not be modified or deallocated. - * \param major If not a null pointer, then it is set to the major - * igraph version. E.g. for version "0.9.11" this is 0. - * \param minor If not a null pointer, then it is set to the minor - * igraph version. E.g. for version "0.9.11" this is 11. - * \param subminor If not a null pointer, then it is set to the - * subminor igraph version. E.g. for version "0.9.11" this is 11. + * \param version_string Pointer to a string pointer. If not \c NULL, it + * is set to the igraph version string, e.g. "0.10.13", "1.2.0", or + * "0.10.13-14-g997f59ad7". It consists of three dot-separated numerical + * parts and potentially of a dash-separated suffix, used in prerelease + * versions. This string must not be modified or deallocated. + * \param major If not a \c NULL pointer, then it is set to the major + * igraph version. E.g. for version "0.10.13" this is 0. + * \param minor If not a \c NULL pointer, then it is set to the minor + * igraph version. E.g. for version "0.10.13" this is 10. + * \param patch If not a \c NULL pointer, then it is set to the + * subminor igraph version. E.g. for version "0.10.13" this is 13. * * \example examples/simple/igraph_version.c */ @@ -42,11 +44,11 @@ static const char *igraph_version_string = IGRAPH_VERSION; void igraph_version(const char **version_string, int *major, int *minor, - int *subminor) { + int *patch) { int i1, i2, i3; int *p1 = major ? major : &i1; int *p2 = minor ? minor : &i2; - int *p3 = subminor ? subminor : &i3; + int *p3 = patch ? patch : &i3; if (version_string) { *version_string = igraph_version_string; diff --git a/src/vendor/cigraph/vendor/CMakeLists.txt b/src/vendor/cigraph/vendor/CMakeLists.txt index 9befa6fa1ae..3aa40eaffc8 100644 --- a/src/vendor/cigraph/vendor/CMakeLists.txt +++ b/src/vendor/cigraph/vendor/CMakeLists.txt @@ -1,7 +1,9 @@ add_subdirectory(cs) add_subdirectory(f2c) add_subdirectory(glpk) +add_subdirectory(infomap) add_subdirectory(lapack) add_subdirectory(mini-gmp) add_subdirectory(pcg) add_subdirectory(plfit) +add_subdirectory(qhull) diff --git a/src/vendor/cigraph/vendor/cs/cs.h b/src/vendor/cigraph/vendor/cs/cs.h index a505ca55aa6..f6ce945b8f8 100644 --- a/src/vendor/cigraph/vendor/cs/cs.h +++ b/src/vendor/cigraph/vendor/cs/cs.h @@ -3,7 +3,7 @@ * here: * * - Dependency on SuiteSparse_long was removed - * - CXSparse is configured to use igraph_integer_t as cs_long_t + * - CXSparse is configured to use igraph_int_t as cs_long_t * - CXSparse function prefix is set to cs_igraph instead of cs_igraph * - Unneeded CXSparse function variants are removed * @@ -61,7 +61,7 @@ extern "C" { #define CS_COPYRIGHT "Copyright (c) Timothy A. Davis, 2006-2016" #define CXSPARSE -#define cs_long_t igraph_integer_t +#define cs_long_t igraph_int_t #define cs_long_t_id "%" IGRAPH_PRId #define cs_long_t_max IGRAPH_INTEGER_MAX diff --git a/src/vendor/cigraph/vendor/cs/cs_randperm.c b/src/vendor/cigraph/vendor/cs/cs_randperm.c index 4570da0f854..937187ec742 100644 --- a/src/vendor/cigraph/vendor/cs/cs_randperm.c +++ b/src/vendor/cigraph/vendor/cs/cs_randperm.c @@ -14,7 +14,6 @@ CS_INT *cs_randperm (CS_INT n, CS_INT seed) for (k = 0 ; k < n ; k++) p [k] = n-k-1 ; if (seed == -1) return (p) ; /* return reverse permutation */ /* srand (seed) ; /\* get new random number seed *\/ */ - RNG_BEGIN(); for (k = 0 ; k < n ; k++) { /* j = k + (rand ( ) % (n-k)) ; /\* j = rand CS_INT in range k to n-1 *\/ */ @@ -23,6 +22,5 @@ CS_INT *cs_randperm (CS_INT n, CS_INT seed) p [j] = p [k] ; p [k] = t ; } - RNG_END(); return (p) ; } diff --git a/src/vendor/cigraph/vendor/infomap/CITATION.cff b/src/vendor/cigraph/vendor/infomap/CITATION.cff new file mode 100644 index 00000000000..4acf57c22d6 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/CITATION.cff @@ -0,0 +1,16 @@ +cff-version: 2.8.0 +message: "If you use this software, please cite it as below." +authors: +- family-names: "Edler" + given-names: "Daniel" + orcid: "https://orcid.org/0000-0001-5420-0591" +- family-names: "Holmgren" + given-names: "Anton" + orcid: "https://orcid.org/0000-0001-5859-4073" +- family-names: "Rosvall" + given-names: "Martin" + orcid: "https://orcid.org/0000-0002-7181-9940" +title: "The MapEquation software package" +version: 2.8.0 +date-released: 2024-06-20 +url: "https://mapequation.org/" diff --git a/src/vendor/cigraph/vendor/infomap/CMakeLists.txt b/src/vendor/cigraph/vendor/infomap/CMakeLists.txt new file mode 100644 index 00000000000..111c9e204ec --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/CMakeLists.txt @@ -0,0 +1,48 @@ +# Declare the files needed to compile our vendored Infomap copy +add_library(infomap_vendored + OBJECT + EXCLUDE_FROM_ALL + src/core/MetaMapEquation.cpp + src/core/MemMapEquation.cpp + src/core/InfoEdge.cpp + src/core/BiasedMapEquation.cpp + src/core/StateNetwork.cpp + src/core/iterators/InfomapIterator.cpp + src/core/InfomapBase.cpp + src/core/InfoNode.cpp + src/io/Network.cpp + src/io/ClusterMap.cpp + src/io/ProgramInterface.cpp + src/io/Output.cpp + src/io/Config.cpp + src/utils/Log.cpp + src/utils/FileURI.cpp + src/utils/FlowCalculator.cpp +) + +target_include_directories( + infomap_vendored + + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src/ + + PRIVATE + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_BINARY_DIR}/include + ${PROJECT_BINARY_DIR}/src # config.h +) + +if(BUILD_SHARED_LIBS) + set_property(TARGET infomap_vendored PROPERTY POSITION_INDEPENDENT_CODE ON) +endif() + +# Since these are included as object files, they should call the +# function as is (without visibility specification) +target_compile_definitions(infomap_vendored PRIVATE IGRAPH_STATIC) + +# Infomap uses unsigned indices in OpenMP loops, which requires +# at least OpenMP 3.0. As of 2025, MSVC only supports OpenMP 2.0, +# thus this check is necessary. +if(IGRAPH_OPENMP_SUPPORT AND OpenMP_CXX_VERSION VERSION_GREATER_EQUAL 3) + target_link_libraries(infomap_vendored PRIVATE OpenMP::OpenMP_CXX) +endif() diff --git a/src/vendor/cigraph/vendor/infomap/LICENSE_GPLv3.txt b/src/vendor/cigraph/vendor/infomap/LICENSE_GPLv3.txt new file mode 100644 index 00000000000..e72bfddabc1 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/LICENSE_GPLv3.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/src/vendor/cigraph/vendor/infomap/README.rst b/src/vendor/cigraph/vendor/infomap/README.rst new file mode 100644 index 00000000000..b5819b0eb69 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/README.rst @@ -0,0 +1,162 @@ +.. image:: https://github.com/mapequation/infomap/actions/workflows/build.yml/badge.svg + +Infomap +======= + +Infomap is a network clustering algorithm based on the `Map equation`_. + +For detailed documentation, see `mapequation.org/infomap`_. + +For a list of recent changes, see `CHANGELOG.md`_ in the source directory. + +.. _Map equation: https://www.mapequation.org/publications.html#Rosvall-Axelsson-Bergstrom-2009-Map-equation +.. _`mapequation.org/infomap`: https://www.mapequation.org/infomap +.. _`CHANGELOG.md`: https://github.com/mapequation/infomap/blob/master/CHANGELOG.md + +Getting started +--------------- + +Infomap can be installed either from `PyPI`_ using ``pip`` or by +compiling from source. + +An experimental Javascript version for browsers is available on `NPM`_. + +.. _PyPI: https://pypi.org/project/infomap/ + +Using pip +--------- + +A pre-compiled version is available for macOS users. + +Installing on other operating systems requires a +working ``gcc`` or ``clang`` compiler. + +To install, run:: + + pip install infomap + + +To upgrade, run:: + + pip install --upgrade infomap + + +When the Python package is installed, an executable called +``infomap`` (with lowercase i) is available from any directory. + +To get started, read `Infomap Python API`_. + +.. _`Infomap Python API`: https://mapequation.github.io/infomap/python/ + +Using Docker +------------ + +There are currently two Docker images available on `Docker Hub`_. + +- ``mapequation/infomap`` +- ``mapequation/infomap:notebook`` based on ``jupyter/scipy-notebook`` + +The image ``mapequation/infomap`` can be started with + +.. code-block:: bash + + docker run -it --rm \ + -v `pwd`:/data \ + mapequation/infomap + [infomap arguments] + +You can also use the supplied `docker-compose.yml`_: + +.. code-block:: bash + + docker-compose run --rm infomap + +The image ``mapequation/infomap:notebook`` can be started with + +.. code-block:: bash + + docker run \ + -v `pwd`:/home/jovyan/work \ + -p 8888:8888 \ + mapequation/infomap:notebook \ + start.sh jupyter lab + +Or similarly, using docker-compose: + +.. code-block:: bash + + docker-compose up notebook + +.. _`Docker Hub`: https://hub.docker.com/r/mapequation/infomap +.. _`docker-compose.yml`: https://github.com/mapequation/infomap/blob/master/docker-compose.yml + +Compiling from source +--------------------- + +Installing Infomap from source requires a working ``gcc`` or ``clang`` compiler. + +To download and compile the newest version from `Github`_, clone the repository +by running + +.. code-block:: shell + + git clone git@github.com:mapequation/infomap.git + cd infomap + make + +This creates the binary ``Infomap``, run it using:: + + ./Infomap [options] network_data destination + +For a list of options, run:: + + ./Infomap --help + +Read `the documentation`_ to learn more about the different options. + +.. _Github: https://www.github.com/mapequation/infomap +.. _the documentation: https://www.mapequation.org/infomap + +Npm package +----------- + +An experimental Javascript web worker is available on `NPM`_. + +To install it, run + +.. code-block:: shell + + npm install @mapequation/infomap + +.. _NPM: https://www.npmjs.com/package/@mapequation/infomap + +Feedback +-------- + +If you have any questions, suggestions or issues regarding the software, +please add them to `GitHub issues`_. + +.. _Github issues: http://www.github.com/mapequation/infomap/issues + +Authors +------- + +Daniel Edler, Anton Holmgren, Martin Rosvall + +For contact information, see `mapequation.org/about.html`_. + +.. _`mapequation.org/about.html`: https://www.mapequation.org/about.html + +Terms of use +------------ + +Infomap is released under a dual licence. + +To give everyone maximum freedom to make use of Infomap +and derivative works, we make the code open source under +the GNU General Public License version 3 or any +later version (see `LICENSE_GPLv3.txt`_). + +For a non-copyleft license, please contact us. + +.. _LICENSE_GPLv3.txt: https://github.com/mapequation/infomap/blob/master/LICENSE_GPLv3.txt diff --git a/src/vendor/cigraph/vendor/infomap/src/Infomap.h b/src/vendor/cigraph/vendor/infomap/src/Infomap.h new file mode 100644 index 00000000000..9ebcd6fd0b3 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/Infomap.h @@ -0,0 +1,103 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef INFOMAP_H_ +#define INFOMAP_H_ + +#include "core/InfomapBase.h" +#include "io/Config.h" + +#include +#include +#include + +namespace infomap { + +// Wrapper class for the Python API +struct InfomapWrapper : public InfomapBase { +public: + InfomapWrapper() : InfomapBase() { } + InfomapWrapper(const std::string& flags) : InfomapBase(flags) { } + InfomapWrapper(const Config& conf) : InfomapBase(conf) { } + virtual ~InfomapWrapper() = default; + + // =================================================== + // Wrapper methods + // =================================================== + + void readInputData(std::string filename = "", bool accumulate = true) { m_network.readInputData(std::move(filename), accumulate); } + + void addNode(unsigned int id) { m_network.addNode(id); } + void addNode(unsigned int id, std::string name) { m_network.addNode(id, std::move(name)); } + void addNode(unsigned int id, double weight) { m_network.addNode(id, weight); } + void addNode(unsigned int id, std::string name, double weight) { m_network.addNode(id, std::move(name), weight); } + + void addName(unsigned int id, const std::string& name) { m_network.addName(id, name); } + std::string getName(unsigned int id) const + { + auto& names = m_network.names(); + auto it = names.find(id); + return it != names.end() ? it->second : ""; + } + + const std::map& getNames() const { return m_network.names(); } + + void addPhysicalNode(unsigned int id, const std::string& name = "") { m_network.addPhysicalNode(id, name); } + void addStateNode(unsigned int id, unsigned int physId) { m_network.addStateNode(id, physId); } + + void addLink(unsigned int sourceId, unsigned int targetId, double weight = 1.0) { m_network.addLink(sourceId, targetId, weight); } + void addLink(unsigned int sourceId, unsigned int targetId, unsigned long weight) { m_network.addLink(sourceId, targetId, weight); } + void addMultilayerLink(unsigned int layer1, unsigned int n1, unsigned int layer2, unsigned int n2, double weight = 1.0) { m_network.addMultilayerLink(layer1, n1, layer2, n2, weight); } + void addMultilayerIntraLink(unsigned int layer, unsigned int n1, unsigned int n2, double weight) { m_network.addMultilayerIntraLink(layer, n1, n2, weight); } + void addMultilayerInterLink(unsigned int layer1, unsigned int n, unsigned int layer2, double interWeight) { m_network.addMultilayerInterLink(layer1, n, layer2, interWeight); } + + void setBipartiteStartId(unsigned int startId) { m_network.setBipartiteStartId(startId); } + + std::map, double> getLinks(bool flow) const + { + std::map, double> links; + + for (const auto& node : m_network.nodeLinkMap()) { + const auto sourceId = node.first.id; + + for (const auto& link : node.second) { + const auto targetId = link.first.id; + links[{ sourceId, targetId }] = flow ? link.second.flow : link.second.weight; + } + } + + return links; + } + + std::map getModules(int level = 1, bool states = false) + { + if (haveMemory() && !states) { + throw std::runtime_error("Cannot get modules on higher-order network without states."); + } + std::map modules; + for (auto it = iterTree(level); !it.isEnd(); ++it) { + auto& node = *it; + if (node.isLeaf()) { + modules[states ? node.stateId : node.physicalId] = it.moduleId(); + } + } + return modules; + } + + using InfomapBase::codelength; + using InfomapBase::getEntropyRate; + using InfomapBase::getMultilevelModules; + using InfomapBase::iterLeafNodes; + using InfomapBase::iterTree; + using InfomapBase::run; +}; + +} // namespace infomap + +#endif // INFOMAP_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/BiasedMapEquation.cpp b/src/vendor/cigraph/vendor/infomap/src/core/BiasedMapEquation.cpp new file mode 100644 index 00000000000..8ae9ad61b2a --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/BiasedMapEquation.cpp @@ -0,0 +1,240 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "BiasedMapEquation.h" +#include "FlowData.h" +#include "InfoNode.h" + +#include +#include +#include +#include "StateNetwork.h" + +namespace infomap { + +double BiasedMapEquation::s_totalDegree = 1; +unsigned int BiasedMapEquation::s_numNodes = 0; + +void BiasedMapEquation::setNetworkProperties(const StateNetwork& network) +{ + s_totalDegree = network.sumWeightedDegree(); + // Negative entropy bias is based on discrete counts, if average weight is below 1, use unweighted total degree + if (s_totalDegree < network.sumDegree()) { + s_totalDegree = network.sumDegree(); + } + s_numNodes = network.numNodes(); +} + +double BiasedMapEquation::getIndexCodelength() const +{ + return indexCodelength + indexEntropyBiasCorrection; +} + +double BiasedMapEquation::getModuleCodelength() const +{ + return moduleCodelength + biasedCost + moduleEntropyBiasCorrection; +} + +double BiasedMapEquation::getCodelength() const +{ + return codelength + biasedCost + getEntropyBiasCorrection(); +} + +double BiasedMapEquation::getEntropyBiasCorrection() const +{ + return indexEntropyBiasCorrection + moduleEntropyBiasCorrection; +} + +// =================================================== +// IO +// =================================================== + +std::ostream& BiasedMapEquation::print(std::ostream& out) const +{ + out << indexCodelength << " + " << moduleCodelength; + if (preferredNumModules != 0) { + out << " + " << biasedCost; + } + if (useEntropyBiasCorrection) { + out << " + " << getEntropyBiasCorrection(); + } + out << " = " << io::toPrecision(getCodelength()); + return out; +} + +std::ostream& operator<<(std::ostream& out, const BiasedMapEquation& mapEq) +{ + return mapEq.print(out); +} + +// =================================================== +// Init +// =================================================== + +void BiasedMapEquation::init(const Config& config) +{ + Log(3) << "BiasedMapEquation::init()...\n"; + preferredNumModules = config.preferredNumberOfModules; + useEntropyBiasCorrection = config.entropyBiasCorrection; + entropyBiasCorrectionMultiplier = config.entropyBiasCorrectionMultiplier; +} + +void BiasedMapEquation::initNetwork(InfoNode& root) +{ + Log(3) << "BiasedMapEquation::initNetwork()...\n"; + Base::initNetwork(root); +} + +void BiasedMapEquation::initPartition(std::vector& nodes) +{ + calculateCodelength(nodes); +} + +// =================================================== +// Codelength +// =================================================== + +double BiasedMapEquation::calcNumModuleCost(unsigned int numModules) const +{ + if (preferredNumModules == 0) return 0; + int deltaNumModules = numModules - preferredNumModules; + return 1 * std::abs(deltaNumModules); +} + +double BiasedMapEquation::calcIndexEntropyBiasCorrection(unsigned int numModules) const +{ + return useEntropyBiasCorrection ? entropyBiasCorrectionMultiplier * (numModules - 1) / (2 * s_totalDegree) : 0; +} + +double BiasedMapEquation::calcModuleEntropyBiasCorrection() const +{ + return useEntropyBiasCorrection ? entropyBiasCorrectionMultiplier * s_numNodes / (2 * s_totalDegree) : 0; +} + +double BiasedMapEquation::calcEntropyBiasCorrection(unsigned int numModules) const +{ + return useEntropyBiasCorrection ? entropyBiasCorrectionMultiplier * (numModules - 1 + s_numNodes) / (2 * s_totalDegree) : 0; +} + +void BiasedMapEquation::calculateCodelength(std::vector& nodes) +{ + calculateCodelengthTerms(nodes); + + calculateCodelengthFromCodelengthTerms(); + + currentNumModules = nodes.size(); + + biasedCost = calcNumModuleCost(currentNumModules); + + indexEntropyBiasCorrection = calcIndexEntropyBiasCorrection(currentNumModules); + moduleEntropyBiasCorrection = calcModuleEntropyBiasCorrection(); +} + +double BiasedMapEquation::calcCodelength(const InfoNode& parent) const +{ + return parent.isLeafModule() + ? calcCodelengthOnModuleOfLeafNodes(parent) + : calcCodelengthOnModuleOfModules(parent); +} + +double BiasedMapEquation::calcCodelengthOnModuleOfModules(const InfoNode& parent) const +{ + double L = Base::calcCodelengthOnModuleOfModules(parent); + if (!useEntropyBiasCorrection) + return L; + + return L + entropyBiasCorrectionMultiplier * parent.childDegree() / (2 * s_totalDegree); +} + +double BiasedMapEquation::calcCodelengthOnModuleOfLeafNodes(const InfoNode& parent) const +{ + double L = Base::calcCodelength(parent); + if (!useEntropyBiasCorrection) + return L; + + return L + entropyBiasCorrectionMultiplier * parent.childDegree() / (2 * s_totalDegree); +} + +int BiasedMapEquation::getDeltaNumModulesIfMoving(unsigned int oldModule, + unsigned int newModule, + std::vector& moduleMembers) +{ + bool removeOld = moduleMembers[oldModule] == 1; + bool createNew = moduleMembers[newModule] == 0; + int deltaNumModules = removeOld && !createNew ? -1 : (!removeOld && createNew ? 1 : 0); + return deltaNumModules; +} + +double BiasedMapEquation::getDeltaCodelengthOnMovingNode(InfoNode& current, + DeltaFlow& oldModuleDelta, + DeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) +{ + double deltaL = Base::getDeltaCodelengthOnMovingNode(current, oldModuleDelta, newModuleDelta, moduleFlowData, moduleMembers); + + if (preferredNumModules == 0) + return deltaL; + + int deltaNumModules = getDeltaNumModulesIfMoving(oldModuleDelta.module, newModuleDelta.module, moduleMembers); + + double deltaBiasedCost = calcNumModuleCost(currentNumModules + deltaNumModules) - biasedCost; + + double deltaEntropyBiasCorrection = calcEntropyBiasCorrection(currentNumModules + deltaNumModules) - getEntropyBiasCorrection(); + + return deltaL + deltaBiasedCost + deltaEntropyBiasCorrection; +} + +// =================================================== +// Consolidation +// =================================================== + +void BiasedMapEquation::updateCodelengthOnMovingNode(InfoNode& current, + DeltaFlow& oldModuleDelta, + DeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) +{ + Base::updateCodelengthOnMovingNode(current, oldModuleDelta, newModuleDelta, moduleFlowData, moduleMembers); + + if (preferredNumModules == 0) + return; + + int deltaNumModules = getDeltaNumModulesIfMoving(oldModuleDelta.module, newModuleDelta.module, moduleMembers); + + currentNumModules += deltaNumModules; + biasedCost = calcNumModuleCost(currentNumModules); + indexEntropyBiasCorrection = calcIndexEntropyBiasCorrection(currentNumModules); + moduleEntropyBiasCorrection = calcModuleEntropyBiasCorrection(); +} + +void BiasedMapEquation::consolidateModules(std::vector& modules) +{ + unsigned int numModules = 0; + for (auto& module : modules) { + if (module == nullptr) + continue; + ++numModules; + } + currentNumModules = numModules; +} + +#if 0 +// =================================================== +// Debug +// =================================================== + +void BiasedMapEquation::printDebug() const +{ + std::cout << "BiasedMapEquation\n"; + Base::printDebug(); +} +#endif + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/core/BiasedMapEquation.h b/src/vendor/cigraph/vendor/infomap/src/core/BiasedMapEquation.h new file mode 100644 index 00000000000..6f043e8125c --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/BiasedMapEquation.h @@ -0,0 +1,180 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef BIASED_MAPEQUATION_H_ +#define BIASED_MAPEQUATION_H_ + +#include "MapEquation.h" +#include "FlowData.h" +#include "../utils/Log.h" +#include +#include +#include +#include + +namespace infomap { + +class InfoNode; +class StateNetwork; + +class BiasedMapEquation : private MapEquation<> { + using Base = MapEquation<>; + +public: + using FlowDataType = FlowData; + using DeltaFlowDataType = DeltaFlow; + + // =================================================== + // Getters + // =================================================== + + double getIndexCodelength() const override; + + double getModuleCodelength() const override; + + double getCodelength() const override; + + double getEntropyBiasCorrection() const; + + // =================================================== + // IO + // =================================================== + + std::ostream& print(std::ostream& out) const override; + + friend std::ostream& operator<<(std::ostream&, const BiasedMapEquation&); + + // =================================================== + // Init + // =================================================== + + void init(const Config& config) override; + + void initTree(InfoNode& /*root*/) override { } + + void initNetwork(InfoNode& root) override; + + using Base::initSuperNetwork; + + using Base::initSubNetwork; + + void initPartition(std::vector& nodes) override; + + // =================================================== + // Codelength + // =================================================== + + double calcCodelength(const InfoNode& parent) const override; + + using Base::addMemoryContributions; + + double getDeltaCodelengthOnMovingNode(InfoNode& current, + DeltaFlow& oldModuleDelta, + DeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) override; + + // =================================================== + // Consolidation + // =================================================== + + void updateCodelengthOnMovingNode(InfoNode& current, + DeltaFlow& oldModuleDelta, + DeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) override; + + void consolidateModules(std::vector& modules) override; + +#if 0 + // =================================================== + // Debug + // =================================================== + + void printDebug() const override; +#endif + +private: + // =================================================== + // Private member functions + // =================================================== + double calcCodelengthOnModuleOfLeafNodes(const InfoNode& parent) const override; + double calcCodelengthOnModuleOfModules(const InfoNode& parent) const override; + + static int getDeltaNumModulesIfMoving(unsigned int oldModule, unsigned int newModule, std::vector& moduleMembers); + + // =================================================== + // Init + // =================================================== + + // =================================================== + // Codelength + // =================================================== + + void calculateCodelength(std::vector& nodes) override; + + using Base::calculateCodelengthTerms; + + using Base::calculateCodelengthFromCodelengthTerms; + + double calcNumModuleCost(unsigned int numModules) const; + + double calcIndexEntropyBiasCorrection(unsigned int numModules) const; + double calcModuleEntropyBiasCorrection() const; + double calcEntropyBiasCorrection(unsigned int numModules) const; + + // =================================================== + // Consolidation + // =================================================== + +public: + // =================================================== + // Public member variables + // =================================================== + + using Base::codelength; + using Base::indexCodelength; + using Base::moduleCodelength; + +private: + // =================================================== + // Private member variables + // =================================================== + + using Base::enter_log_enter; + using Base::enterFlow; + using Base::enterFlow_log_enterFlow; + using Base::exit_log_exit; + using Base::flow_log_flow; // node.(flow + exitFlow) + using Base::nodeFlow_log_nodeFlow; // constant while the leaf network is the same + + // For hierarchical + using Base::exitNetworkFlow; + using Base::exitNetworkFlow_log_exitNetworkFlow; + + // For biased + unsigned int preferredNumModules = 0; + unsigned int currentNumModules = 0; + double biasedCost = 0.0; + + // For entropy bias correction + bool useEntropyBiasCorrection = false; + double entropyBiasCorrectionMultiplier = 1; + double indexEntropyBiasCorrection = 0; + double moduleEntropyBiasCorrection = 0; + static double s_totalDegree; + static unsigned int s_numNodes; + +public: + static void setNetworkProperties(const StateNetwork& network); +}; + +} // namespace infomap + +#endif // BIASED_MAPEQUATION_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/FlowData.h b/src/vendor/cigraph/vendor/infomap/src/core/FlowData.h new file mode 100644 index 00000000000..8b70d9b6121 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/FlowData.h @@ -0,0 +1,165 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef FLOWDATA_H_ +#define FLOWDATA_H_ + +#include +#include + +namespace infomap { + +struct FlowData { + double flow = 0.0; + double enterFlow = 0.0; + double exitFlow = 0.0; + double teleportFlow = 0.0; + double teleportSourceFlow = 0.0; + double teleportWeight = 0.0; + double danglingFlow = 0.0; + + FlowData() = default; + FlowData(double flow) : flow(flow) { } + + FlowData& operator+=(const FlowData& other) + { + flow += other.flow; + enterFlow += other.enterFlow; + exitFlow += other.exitFlow; + teleportFlow += other.teleportFlow; + teleportSourceFlow += other.teleportSourceFlow; + teleportWeight += other.teleportWeight; + danglingFlow += other.danglingFlow; + return *this; + } + + FlowData& operator-=(const FlowData& other) + { + flow -= other.flow; + enterFlow -= other.enterFlow; + exitFlow -= other.exitFlow; + teleportFlow -= other.teleportFlow; + teleportSourceFlow -= other.teleportSourceFlow; + teleportWeight -= other.teleportWeight; + danglingFlow -= other.danglingFlow; + return *this; + } + + friend std::ostream& operator<<(std::ostream& out, const FlowData& data) + { + return out << "flow: " << data.flow << ", enter: " << data.enterFlow << ", exit: " << data.exitFlow + << ", teleWeight: " << data.teleportWeight << ", danglingFlow: " << data.danglingFlow + << ", teleFlow: " << data.teleportFlow; + } +}; + +struct DeltaFlow { + unsigned int module = 0; + double deltaExit = 0.0; + double deltaEnter = 0.0; + unsigned int count = 0; + + explicit DeltaFlow(unsigned int module, double deltaExit, double deltaEnter) + : module(module), + deltaExit(deltaExit), + deltaEnter(deltaEnter) { } + + DeltaFlow() = default; + DeltaFlow(const DeltaFlow&) = default; + DeltaFlow(DeltaFlow&&) = default; + DeltaFlow& operator=(const DeltaFlow&) = default; + DeltaFlow& operator=(DeltaFlow&&) = default; + virtual ~DeltaFlow() = default; + + DeltaFlow& operator+=(const DeltaFlow& other) + { + module = other.module; + deltaExit += other.deltaExit; + deltaEnter += other.deltaEnter; + ++count; + return *this; + } + + virtual void reset() + { + module = 0; + deltaExit = 0.0; + deltaEnter = 0.0; + count = 0; + } + + friend void swap(DeltaFlow& first, DeltaFlow& second) noexcept + { + std::swap(first.module, second.module); + std::swap(first.deltaExit, second.deltaExit); + std::swap(first.deltaEnter, second.deltaEnter); + std::swap(first.count, second.count); + } + + friend std::ostream& operator<<(std::ostream& out, const DeltaFlow& data) + { + return out << "module: " << data.module << ", deltaEnter: " << data.deltaEnter << ", deltaExit: " << data.deltaExit << ", count: " << data.count; + } +}; + +struct MemDeltaFlow : DeltaFlow { + double sumDeltaPlogpPhysFlow = 0.0; + double sumPlogpPhysFlow = 0.0; + + MemDeltaFlow() = default; + + explicit MemDeltaFlow(unsigned int module, double deltaExit, double deltaEnter, double sumDeltaPlogpPhysFlow = 0.0, double sumPlogpPhysFlow = 0.0) + : DeltaFlow(module, deltaExit, deltaEnter), + sumDeltaPlogpPhysFlow(sumDeltaPlogpPhysFlow), + sumPlogpPhysFlow(sumPlogpPhysFlow) { } + + MemDeltaFlow& operator+=(const MemDeltaFlow& other) + { + DeltaFlow::operator+=(other); + sumDeltaPlogpPhysFlow += other.sumDeltaPlogpPhysFlow; + sumPlogpPhysFlow += other.sumPlogpPhysFlow; + return *this; + } + + void reset() override + { + DeltaFlow::reset(); + sumDeltaPlogpPhysFlow = 0.0; + sumPlogpPhysFlow = 0.0; + } + + friend void swap(MemDeltaFlow& first, MemDeltaFlow& second) noexcept + { + swap(static_cast(first), static_cast(second)); + std::swap(first.sumDeltaPlogpPhysFlow, second.sumDeltaPlogpPhysFlow); + std::swap(first.sumPlogpPhysFlow, second.sumPlogpPhysFlow); + } + + friend std::ostream& operator<<(std::ostream& out, const MemDeltaFlow& data) + { + return out << "module: " << data.module << ", deltaEnter: " << data.deltaEnter << ", deltaExit: " << data.deltaExit << ", count: " << data.count << ", sumDeltaPlogpPhysFlow: " << data.sumDeltaPlogpPhysFlow << ", sumPlogpPhysFlow: " << data.sumPlogpPhysFlow; + } +}; + +struct PhysData { + unsigned int physNodeIndex; + double sumFlowFromM2Node; // The amount of flow from the memory node in this physical node + + explicit PhysData(unsigned int physNodeIndex, double sumFlowFromM2Node = 0.0) + : physNodeIndex(physNodeIndex), sumFlowFromM2Node(sumFlowFromM2Node) { } + + friend std::ostream& operator<<(std::ostream& out, const PhysData& data) + { + return out << "physNodeIndex: " << data.physNodeIndex << ", sumFlowFromM2Node: " << data.sumFlowFromM2Node; + } +}; + +} // namespace infomap + +#endif // FLOWDATA_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/InfoEdge.cpp b/src/vendor/cigraph/vendor/infomap/src/core/InfoEdge.cpp new file mode 100644 index 00000000000..6bcb7039e69 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/InfoEdge.cpp @@ -0,0 +1,26 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "InfoEdge.h" +#include "InfoNode.h" + +namespace infomap { + +InfoNode& infomap::InfoEdge::other(InfoNode& node) const +{ + return (node == *source) ? *target : *source; +} + +std::ostream& operator<<(std::ostream& out, const InfoEdge& edge) +{ + return out << "(" << *edge.source << ") -> (" << *edge.target << "), flow: " + << edge.data.flow; +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/core/InfoEdge.h b/src/vendor/cigraph/vendor/infomap/src/core/InfoEdge.h new file mode 100644 index 00000000000..e2d245fb64d --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/InfoEdge.h @@ -0,0 +1,47 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef INFOEDGE_H_ +#define INFOEDGE_H_ + +#include + +namespace infomap { + +struct EdgeData { +public: + EdgeData() = default; + + EdgeData(double weight, double flow) : weight(weight), flow(flow) { } + + double weight; + double flow; +}; + +class InfoNode; + +class InfoEdge { +public: + InfoEdge(InfoNode& source, InfoNode& target, double weight, double flow) + : data(weight, flow), + source(&source), + target(&target) { } + + InfoNode& other(InfoNode& node) const; + + friend std::ostream& operator<<(std::ostream& out, const InfoEdge& edge); + + EdgeData data; + InfoNode* source; + InfoNode* target; +}; + +} // namespace infomap + +#endif // INFOEDGE_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/InfoNode.cpp b/src/vendor/cigraph/vendor/infomap/src/core/InfoNode.cpp new file mode 100644 index 00000000000..b7a7b0aa412 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/InfoNode.cpp @@ -0,0 +1,405 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "InfoNode.h" +#include "InfomapBase.h" +#include + +namespace infomap { + +InfoNode::~InfoNode() noexcept +{ + if (m_infomap != nullptr) { + delete m_infomap; + } + + deleteChildren(); + + if (next != nullptr) + next->previous = previous; + if (previous != nullptr) + previous->next = next; + if (parent != nullptr) { + if (parent->firstChild == this) + parent->firstChild = next; + if (parent->lastChild == this) + parent->lastChild = previous; + } + + // Delete outgoing edges. + // TODO: Renders ingoing edges invalid. Assume or assert that all nodes on the same level are deleted? + for (edge_iterator outEdgeIt(begin_outEdge()); + outEdgeIt != end_outEdge(); + ++outEdgeIt) { + delete *outEdgeIt; + } +} + +InfomapBase& InfoNode::setInfomap(InfomapBase* infomap) +{ + disposeInfomap(); + m_infomap = infomap; + if (infomap == nullptr) + throw std::logic_error("InfoNode::setInfomap(...) called with null infomap"); + return *m_infomap; +} + +InfomapBase& InfoNode::getInfomap() +{ + if (m_infomap == nullptr) + throw std::logic_error("InfoNode::getInfomap() called but infomap is null"); + return *m_infomap; +} + +const InfomapBase& InfoNode::getInfomap() const +{ + if (m_infomap == nullptr) + throw std::logic_error("InfoNode::getInfomap() called but infomap is null"); + return *m_infomap; +} + +InfoNode* InfoNode::getInfomapRoot() noexcept +{ + return m_infomap != nullptr ? &m_infomap->root() : nullptr; +} + +InfoNode const* InfoNode::getInfomapRoot() const noexcept +{ + return m_infomap != nullptr ? &m_infomap->root() : nullptr; +} + +bool InfoNode::disposeInfomap() noexcept +{ + if (m_infomap != nullptr) { + delete m_infomap; + m_infomap = nullptr; + return true; + } + return false; +} + +unsigned int InfoNode::depth() const noexcept +{ + unsigned int depth = 0; + InfoNode* n = parent; + while (n != nullptr) { + ++depth; + n = n->parent; + } + return depth; +} + +unsigned int InfoNode::firstDepthBelow() const noexcept +{ + unsigned int depthBelow = 0; + InfoNode* child = firstChild; + while (child != nullptr) { + ++depthBelow; + child = child->firstChild; + } + return depthBelow; +} + +unsigned int InfoNode::childIndex() const noexcept +{ + unsigned int childIndex = 0; + const InfoNode* n(this); + while (n->previous) { + n = n->previous; + ++childIndex; + } + return childIndex; +} + +std::vector InfoNode::calculatePath() const noexcept +{ + const InfoNode* current = this; + std::vector path; + while (current->parent != nullptr) { + path.push_back(current->childIndex() + 1); + current = current->parent; + if (current->owner != nullptr) { + current = current->owner; + } + } + std::reverse(path.begin(), path.end()); + return path; +} + +unsigned int InfoNode::infomapChildDegree() const noexcept +{ + return m_infomap == nullptr ? childDegree() : m_infomap->root().childDegree(); +} + +void InfoNode::addChild(InfoNode* child) noexcept +{ + if (firstChild == nullptr) { + child->previous = nullptr; + firstChild = child; + } else { + child->previous = lastChild; + lastChild->next = child; + } + lastChild = child; + child->next = nullptr; + child->parent = this; + ++m_childDegree; +} + +void InfoNode::releaseChildren() noexcept +{ + firstChild = nullptr; + lastChild = nullptr; + m_childDegree = 0; +} + +InfoNode& InfoNode::replaceChildrenWithOneNode() +{ + if (childDegree() == 1) + return *firstChild; + if (firstChild == nullptr) + throw std::logic_error("replaceChildrenWithOneNode called on a node without any children."); + if (firstChild->firstChild == nullptr) + throw std::logic_error("replaceChildrenWithOneNode called on a node without any grandchildren."); + auto* middleNode = new InfoNode(); + InfoNode::child_iterator nodeIt = begin_child(); + unsigned int numOriginalChildrenLeft = m_childDegree; + auto d0 = m_childDegree; + do { + InfoNode* n = nodeIt.current(); + ++nodeIt; + middleNode->addChild(n); + } while (--numOriginalChildrenLeft != 0); + + releaseChildren(); + addChild(middleNode); + auto d1 = middleNode->replaceChildrenWithGrandChildren(); + if (d1 != d0) + throw std::logic_error("replaceChildrenWithOneNode replaced different number of children as having before"); + return *middleNode; +} + +unsigned int InfoNode::replaceChildrenWithGrandChildren() noexcept +{ + if (firstChild == nullptr) + return 0; + InfoNode::child_iterator nodeIt = begin_child(); + unsigned int numOriginalChildrenLeft = m_childDegree; + unsigned int numChildrenReplaced = 0; + do { + InfoNode* n = nodeIt.current(); + ++nodeIt; + numChildrenReplaced += n->replaceWithChildren(); + } while (--numOriginalChildrenLeft != 0); + return numChildrenReplaced; +} + +unsigned int InfoNode::replaceWithChildren() noexcept +{ + if (isLeaf() || isRoot()) + return 0; + + // Re-parent children + unsigned int deltaChildDegree = 0; + InfoNode* child = firstChild; + do { + child->parent = parent; + child = child->next; + ++deltaChildDegree; + } while (child != nullptr); + parent->m_childDegree += deltaChildDegree - 1; // -1 as this node is deleted + + firstChild->previous = previous; + lastChild->next = next; + + if (parent->firstChild == this) { + parent->firstChild = firstChild; + } else { + previous->next = firstChild; + } + + if (parent->lastChild == this) { + parent->lastChild = lastChild; + } else { + next->previous = lastChild; + } + + // Release connected nodes before delete, otherwise children are deleted and neighbours are reconnected. + firstChild = nullptr; + lastChild = nullptr; + next = nullptr; + previous = nullptr; + parent = nullptr; + delete this; + return 1; +} + +void InfoNode::replaceChildrenWithGrandChildrenDebug() noexcept +{ + if (firstChild == nullptr) + return; + InfoNode::child_iterator nodeIt = begin_child(); + unsigned int numOriginalChildrenLeft = m_childDegree; + do { + InfoNode* n = nodeIt.current(); + ++nodeIt; + n->replaceWithChildrenDebug(); + } while (--numOriginalChildrenLeft != 0); +} + +void InfoNode::replaceWithChildrenDebug() noexcept +{ + if (isLeaf() || isRoot()) + return; + + // Re-parent children + unsigned int deltaChildDegree = 0; + InfoNode* child = firstChild; + do { + child->parent = parent; + child = child->next; + ++deltaChildDegree; + } while (child != nullptr); + parent->m_childDegree += deltaChildDegree - 1; // -1 as this node is deleted + + if (parent->firstChild == this) { + parent->firstChild = firstChild; + } else { + previous->next = firstChild; + firstChild->previous = previous; + } + + if (parent->lastChild == this) { + parent->lastChild = lastChild; + } else { + next->previous = lastChild; + lastChild->next = next; + } + + // Release connected nodes before delete, otherwise children are deleted and neighbours are reconnected. + firstChild = nullptr; + lastChild = nullptr; + next = nullptr; + previous = nullptr; + parent = nullptr; + + delete this; +} + +void InfoNode::remove(bool removeChildren) noexcept +{ + firstChild = removeChildren ? nullptr : firstChild; + delete this; +} + +void InfoNode::deleteChildren() noexcept +{ + if (firstChild == nullptr) + return; + + child_iterator nodeIt = begin_child(); + do { + InfoNode* n = nodeIt.current(); + ++nodeIt; + delete n; + } while (nodeIt.current() != nullptr); + + firstChild = nullptr; + lastChild = nullptr; + m_childDegree = 0; +} + +void InfoNode::calcChildDegree() noexcept +{ + m_childrenChanged = false; + if (firstChild == nullptr) + m_childDegree = 0; + else if (firstChild == lastChild) + m_childDegree = 1; + else { + m_childDegree = 0; + for (auto& child : children()) { + (void)child; + ++m_childDegree; + } + } +} + +void InfoNode::setChildDegree(unsigned int value) noexcept +{ + m_childDegree = value; + m_childrenChanged = false; +} + +void InfoNode::initClean() noexcept +{ + releaseChildren(); + previous = next = parent = nullptr; + + physicalNodes.clear(); +} + +void InfoNode::sortChildrenOnFlow(bool recurse) noexcept +{ + if (childDegree() == 0) + return; + std::vector nodes(childDegree()); + double lastFlow = 1.0; + bool isSorted = true; + unsigned int i = 0; + for (InfoNode& child : children()) { + if (child.data.flow > lastFlow) { + isSorted = false; + } + nodes[i] = &child; + lastFlow = child.data.flow; + ++i; + } + if (!isSorted) { + std::sort(nodes.begin(), nodes.end(), [](const InfoNode* a, const InfoNode* b) { + return b->data.flow < a->data.flow; + }); + releaseChildren(); + for (auto node : nodes) { + addChild(node); + } + } + if (recurse) { + for (InfoNode& child : children()) { + auto newRoot = child.getInfomapRoot(); + InfoNode& node = newRoot ? *newRoot : child; + node.sortChildrenOnFlow(recurse); + } + } +} + +unsigned int InfoNode::collapseChildren() noexcept +{ + std::swap(collapsedFirstChild, firstChild); + std::swap(collapsedLastChild, lastChild); + unsigned int numCollapsedChildren = childDegree(); + releaseChildren(); + return numCollapsedChildren; +} + +unsigned int InfoNode::expandChildren() +{ + bool haveCollapsedChildren = collapsedFirstChild != nullptr; + if (haveCollapsedChildren) { + if (firstChild != nullptr || lastChild != nullptr) + throw std::logic_error("Expand collapsed children called on a node that already has children."); + std::swap(collapsedFirstChild, firstChild); + std::swap(collapsedLastChild, lastChild); + calcChildDegree(); + return childDegree(); + } + return 0; +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/core/InfoNode.h b/src/vendor/cigraph/vendor/infomap/src/core/InfoNode.h new file mode 100644 index 00000000000..5d2c5e85341 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/InfoNode.h @@ -0,0 +1,374 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef INFONODE_H_ +#define INFONODE_H_ + +#include "FlowData.h" +#include "InfoEdge.h" +#include "iterators/infomapIterators.h" +#include "iterators/IterWrapper.h" +#include "../utils/MetaCollection.h" + +#include +#include +#include +#include +#include + +namespace infomap { + +class InfomapBase; + +class InfoNode { +public: + using child_iterator = ChildIterator; + using const_child_iterator = ChildIterator; + using infomap_child_iterator = InfomapChildIterator; + using const_infomap_child_iterator = InfomapChildIterator; + + using tree_iterator = TreeIterator; + using const_tree_iterator = TreeIterator; + + using leaf_node_iterator = LeafNodeIterator; + using const_leaf_node_iterator = LeafNodeIterator; + using leaf_module_iterator = LeafModuleIterator; + using const_leaf_module_iterator = LeafModuleIterator; + + using post_depth_first_iterator = DepthFirstIterator; + using const_post_depth_first_iterator = DepthFirstIterator; + + using edge_iterator = std::vector::iterator; + using const_edge_iterator = std::vector::const_iterator; + + using edge_iterator_wrapper = IterWrapper; + using const_edge_iterator_wrapper = IterWrapper; + + using infomap_iterator_wrapper = IterWrapper; + using const_infomap_iterator_wrapper = IterWrapper; + + using child_iterator_wrapper = IterWrapper; + using const_child_iterator_wrapper = IterWrapper; + + using infomap_child_iterator_wrapper = IterWrapper; + using const_infomap_child_iterator_wrapper = IterWrapper; + +public: + FlowData data; + unsigned int index = 0; // Temporary index used in finding best module + unsigned int stateId = 0; // Unique state node id for the leaf nodes + unsigned int physicalId = 0; // Physical id equals stateId for first order networks, otherwise can be non-unique + unsigned int layerId = 0; // Layer id for multilayer networks + std::vector metaData; // Categorical value for each meta data dimension + + InfoNode* owner = nullptr; // Infomap owner (if this is an Infomap root) + InfoNode* parent = nullptr; + InfoNode* previous = nullptr; // sibling + InfoNode* next = nullptr; // sibling + InfoNode* firstChild = nullptr; + InfoNode* lastChild = nullptr; + InfoNode* collapsedFirstChild = nullptr; + InfoNode* collapsedLastChild = nullptr; + double codelength = 0.0; // TODO: Better design for hierarchical stuff!? + bool dirty = false; + + std::vector physicalNodes; + MetaCollection metaCollection; // For modules + std::vector stateNodes; // For physically aggregated nodes + +private: + unsigned int m_childDegree = 0; + bool m_childrenChanged = false; + unsigned int m_numLeafMembers = 0; + + std::vector m_outEdges; + std::vector m_inEdges; + + InfomapBase* m_infomap = nullptr; + +public: + InfoNode(const FlowData& flowData) + : data(flowData) {}; + + // For first order nodes, physicalId equals stateId + InfoNode(const FlowData& flowData, unsigned int stateId) + : data(flowData), stateId(stateId), physicalId(stateId) {}; + + InfoNode(const FlowData& flowData, unsigned int stateId, unsigned int physicalId) + : data(flowData), stateId(stateId), physicalId(physicalId) {}; + + InfoNode(const FlowData& flowData, unsigned int stateId, unsigned int physicalId, unsigned int layerId) + : data(flowData), stateId(stateId), physicalId(physicalId), layerId(layerId) {}; + + InfoNode() = default; + + InfoNode(const InfoNode& other) + : data(other.data), + index(other.index), + stateId(other.stateId), + physicalId(other.physicalId), + layerId(other.layerId), + metaData(other.metaData), + parent(other.parent), + previous(other.previous), + next(other.next), + firstChild(other.firstChild), + lastChild(other.lastChild), + collapsedFirstChild(other.collapsedFirstChild), + collapsedLastChild(other.collapsedLastChild), + codelength(other.codelength), + dirty(other.dirty), + metaCollection(other.metaCollection), + m_childDegree(other.m_childDegree), + m_childrenChanged(other.m_childrenChanged), + m_numLeafMembers(other.m_numLeafMembers) { } + + ~InfoNode() noexcept; + + InfoNode& operator=(const InfoNode& other) + { + data = other.data; + index = other.index; + stateId = other.stateId; + physicalId = other.physicalId; + layerId = other.layerId; + metaData = other.metaData; + parent = other.parent; + previous = other.previous; + next = other.next; + firstChild = other.firstChild; + lastChild = other.lastChild; + collapsedFirstChild = other.collapsedFirstChild; + collapsedLastChild = other.collapsedLastChild; + codelength = other.codelength; + dirty = other.dirty; + metaCollection = other.metaCollection; + m_childDegree = other.m_childDegree; + m_childrenChanged = other.m_childrenChanged; + m_numLeafMembers = other.m_numLeafMembers; + return *this; + } + + // ---------------------------- Getters ---------------------------- + + unsigned int getMetaData(unsigned int dimension = 0) noexcept + { + if (dimension >= metaData.size()) { + return 0; + } + auto meta = metaData[dimension]; + return meta < 0 ? 0 : static_cast(meta); + } + + // ---------------------------- Infomap ---------------------------- + InfomapBase& getInfomap(); + + const InfomapBase& getInfomap() const; + + InfomapBase& setInfomap(InfomapBase*); + + InfoNode* getInfomapRoot() noexcept; + + InfoNode const* getInfomapRoot() const noexcept; + + /** + * Dispose the Infomap instance if it exists + * @return true if an existing Infomap instance was deleted + */ + bool disposeInfomap() noexcept; + + /** + * Number of physical nodes in memory nodes + */ + unsigned int numPhysicalNodes() const noexcept { return physicalNodes.size(); } + + // ---------------------------- Tree iterators ---------------------------- + + // Default iteration on children + child_iterator begin() noexcept { return { this }; } + + child_iterator end() noexcept { return { nullptr }; } + + const_child_iterator begin() const noexcept { return { this }; } + + const_child_iterator end() const noexcept { return { nullptr }; } + + child_iterator begin_child() noexcept { return { this }; } + + child_iterator end_child() noexcept { return { nullptr }; } + + const_child_iterator begin_child() const noexcept { return { this }; } + + const_child_iterator end_child() const noexcept { return { nullptr }; } + + child_iterator_wrapper children() noexcept { return { { this }, { nullptr } }; } + + const_child_iterator_wrapper children() const noexcept { return { { this }, { nullptr } }; } + + infomap_child_iterator_wrapper infomap_children() noexcept { return { { this }, { nullptr } }; } + + const_infomap_child_iterator_wrapper infomap_children() const noexcept { return { { this }, { nullptr } }; } + + post_depth_first_iterator begin_post_depth_first() noexcept { return { this }; } + + leaf_node_iterator begin_leaf_nodes() noexcept { return { this }; } + + leaf_module_iterator begin_leaf_modules() noexcept { return { this }; } + + tree_iterator begin_tree(unsigned int maxClusterLevel = std::numeric_limits::max()) noexcept { return { this, static_cast(maxClusterLevel) }; } + + tree_iterator end_tree() noexcept { return { nullptr }; } + + const_tree_iterator begin_tree(unsigned int maxClusterLevel = std::numeric_limits::max()) const noexcept { return { this, static_cast(maxClusterLevel) }; } + + const_tree_iterator end_tree() const noexcept { return { nullptr }; } + + infomap_iterator_wrapper infomapTree(unsigned int maxClusterLevel = std::numeric_limits::max()) noexcept { return { { this, static_cast(maxClusterLevel) }, { nullptr } }; } + + const_infomap_iterator_wrapper infomapTree(unsigned int maxClusterLevel = std::numeric_limits::max()) const noexcept { return { { this, static_cast(maxClusterLevel) }, { nullptr } }; } + + // ---------------------------- Graph iterators ---------------------------- + + edge_iterator begin_outEdge() noexcept { return m_outEdges.begin(); } + + edge_iterator end_outEdge() noexcept { return m_outEdges.end(); } + + edge_iterator begin_inEdge() noexcept { return m_inEdges.begin(); } + + edge_iterator end_inEdge() noexcept { return m_inEdges.end(); } + + edge_iterator_wrapper outEdges() noexcept { return { m_outEdges }; } + + edge_iterator_wrapper inEdges() noexcept { return { m_inEdges }; } + + // ---------------------------- Capacity ---------------------------- + + unsigned int childDegree() const noexcept { return m_childDegree; } + + bool isLeaf() const noexcept { return firstChild == nullptr; } + + // TODO: Safe to assume all children are leaves if first child is leaf? + bool isLeafModule() const noexcept { return m_infomap == nullptr && firstChild != nullptr && firstChild->firstChild == nullptr; } + + bool isRoot() const noexcept { return parent == nullptr; } + + unsigned int depth() const noexcept; + + unsigned int firstDepthBelow() const noexcept; + + unsigned int numLeafMembers() const noexcept { return m_numLeafMembers; } + + bool isDangling() const noexcept { return m_outEdges.empty(); } + + unsigned int outDegree() const noexcept { return m_outEdges.size(); } + + unsigned int inDegree() const noexcept { return m_inEdges.size(); } + + unsigned int degree() const noexcept { return outDegree() + inDegree(); } + + // ---------------------------- Order ---------------------------- + bool isFirst() const noexcept { return !parent || parent->firstChild == this; } + + bool isLast() const noexcept { return !parent || parent->lastChild == this; } + + unsigned int childIndex() const noexcept; + + // Generate 1-based tree path + std::vector calculatePath() const noexcept; + + unsigned int infomapChildDegree() const noexcept; + + unsigned int id() const noexcept { return stateId; } + + // ---------------------------- Operators ---------------------------- + + bool operator==(const InfoNode& rhs) const noexcept { return this == &rhs; } + + bool operator!=(const InfoNode& rhs) const noexcept { return this != &rhs; } + + friend std::ostream& operator<<(std::ostream& out, const InfoNode& node) noexcept + { + if (node.isLeaf()) + out << "[" << node.physicalId << "]"; + else + out << "[module]"; + return out; + } + + // ---------------------------- Mutators ---------------------------- + + /** + * Clear a cloned node to initial state + */ + void initClean() noexcept; + + void sortChildrenOnFlow(bool recurse = true) noexcept; + + /** + * Release the children and store the child pointers for later expansion + * @return the number of children collapsed + */ + unsigned int collapseChildren() noexcept; + + /** + * Expand collapsed children + * @return the number of collapsed children expanded + */ + unsigned int expandChildren(); + + // ------ OLD ----- + + // After change, set the child degree if known instead of lazily computing it by traversing the linked list + void setChildDegree(unsigned int value) noexcept; + + void setNumLeafNodes(unsigned int value) noexcept { m_numLeafMembers = value; } + + void addChild(InfoNode* child) noexcept; + + void releaseChildren() noexcept; + + /** + * If not already having a single child, replace children + * with a single new node, assuming grandchildren. + * @return the single child + */ + InfoNode& replaceChildrenWithOneNode(); + + /** + * @return 1 if the node is removed, otherwise 0 + */ + unsigned int replaceWithChildren() noexcept; + + void replaceWithChildrenDebug() noexcept; + + /** + * @return The number of children removed + */ + unsigned int replaceChildrenWithGrandChildren() noexcept; + + void replaceChildrenWithGrandChildrenDebug() noexcept; + + void remove(bool removeChildren) noexcept; + + void deleteChildren() noexcept; + + void addOutEdge(InfoNode& target, double weight, double flow = 0.0) noexcept + { + auto* edge = new InfoEdge(*this, target, weight, flow); + m_outEdges.push_back(edge); + target.m_inEdges.push_back(edge); + } + +private: + void calcChildDegree() noexcept; +}; + +} // namespace infomap + +#endif // INFONODE_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/InfomapBase.cpp b/src/vendor/cigraph/vendor/infomap/src/core/InfomapBase.cpp new file mode 100644 index 00000000000..1eada521b38 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/InfomapBase.cpp @@ -0,0 +1,2182 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "InfomapBase.h" +#include "InfomapConfig.h" +#include "InfoNode.h" +#include "FlowData.h" +#include "BiasedMapEquation.h" +#include "MemMapEquation.h" +#include "MetaMapEquation.h" +#include "InfomapOptimizer.h" +#include "../io/SafeFile.h" +#include "../utils/FileURI.h" +#include "../utils/FlowCalculator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _OPENMP +#include +#endif + +namespace infomap { + +std::map> InfomapBase::getMultilevelModules(bool states) +{ + if (haveMemory() && !states) { + throw std::runtime_error("Cannot get multilevel modules on higher-order network without states."); + } + unsigned int maxDepth = maxTreeDepth(); + unsigned int numModuleLevels = maxDepth - 1; + std::map> modules; + if (maxDepth < 2) return modules; + for (unsigned int level = 1; level <= numModuleLevels; ++level) { + for (auto it(iterLeafNodes(static_cast(level))); !it.isEnd(); ++it) { + auto& node = *it; + auto nodeId = states ? node.stateId : node.physicalId; + modules[nodeId].push_back(it.moduleId()); + } + } + return modules; +} + +// =================================================== +// IO +// =================================================== + +std::ostream& operator<<(std::ostream& out, const InfomapBase& infomap) +{ + return infomap.toString(out); +} + +// =================================================== +// Getters +// =================================================== + +unsigned int InfomapBase::numLevels() const +{ + // TODO: Make sure this is not called unless tree is guaranteed to have even depth! + unsigned int depth = 0; + InfoNode* n = m_root.firstChild; + while (n != nullptr) { + ++depth; + n = n->firstChild; + } + return depth; +} + +unsigned int InfomapBase::maxTreeDepth() const +{ + unsigned int maxDepth = 0; + for (auto it = root().begin_tree(); !it.isEnd(); ++it) { + const InfoNode& node = *it; + if (node.isLeaf()) { + if (it.depth() > maxDepth) { + maxDepth = it.depth(); + } + } + } + return maxDepth; +} + +// =================================================== +// Run +// =================================================== + +void InfomapBase::run(const std::string& parameters) +{ + if (!isMainInfomap()) { + runPartition(); + return; + } + + m_elapsedTime = Stopwatch(true); + m_startDate = Date(); + + std::string currentParameters = io::Str() << m_initialParameters << (parameters.empty() ? "" : " ") << parameters; + if (currentParameters != m_currentParameters) { + m_currentParameters = currentParameters; + setConfig(Config(m_currentParameters, isCLI)); + m_network.setConfig(*this); + } + + Log::init(verbosity, silent, verboseNumberPrecision); + + Log() << "=======================================================\n"; + Log() << " Infomap v" << INFOMAP_VERSION << " starts at " << m_startDate << "\n"; + Log() << " -> Input network: " << networkFile << "\n"; + if (noFileOutput) + Log() << " -> No file output!\n"; + else + Log() << " -> Output path: " << outDirectory << "\n"; + if (!parsedOptions.empty()) { + for (unsigned int i = 0; i < parsedOptions.size(); ++i) + Log() << (i == 0 ? " -> Configuration: " : " ") << parsedOptions[i] << "\n"; + } + if (!m_initialPartition.empty()) { + Log() << " -> " << m_initialPartition.size() << " initial module ids provided\n"; + } + Log() << "=======================================================\n"; +#ifdef _OPENMP +#pragma omp parallel +#pragma omp master + { + Log() << " OpenMP " << _OPENMP << " detected with " << omp_get_num_threads() << " threads...\n"; + } +#endif + + m_network.postProcessInputData(); + if (m_network.numNodes() == 0) { + m_network.readInputData(networkFile); + } + + if (!metaDataFile.empty()) { + initMetaData(metaDataFile); + } + + run(m_network); + + Log() << "===================================================\n"; + Log() << " Infomap ends at " << m_endDate << "\n"; + Log() << " (Elapsed time: " << m_elapsedTime << ")\n"; + Log() << "===================================================\n"; +} + +void InfomapBase::run(Network& network) +{ + if (!isMainInfomap()) + throw std::logic_error("Can't run a non-main Infomap with an input network"); + + if (network.numNodes() == 0) { + network.postProcessInputData(); + if (network.numNodes() == 0) { + throw std::domain_error("Network is empty"); + } + } + + if (printStateNetwork) { + std::string filename = outDirectory + outName + "_states.net"; + Log() << "Writing state network to '" << filename << "'... "; + network.writeStateNetwork(filename); + Log() << "done!\n"; + } + + if (printPajekNetwork) { + std::string filename; + if (printStates()) { + filename = outDirectory + outName + "_states_as_physical.net"; + Log() << "Writing state network as first order Pajek network to '" << filename << "'... "; + } else { + // Non-memory input + filename = outDirectory + outName + ".net"; + Log() << "Writing Pajek network to '" << filename << "'... "; + } + network.writePajekNetwork(filename); + Log() << "done!\n"; + } + + if (network.haveMemoryInput()) { + Log() << " -> Found higher order network input, using the Map Equation for higher order network flows\n"; + setStateInput(); + setStateOutput(); + + if (network.isMultilayerNetwork() && !isMultilayerNetwork()) { + setMultilayerInput(); + } + } else { + if (haveMemory() || network.higherOrderInputMethodCalled()) { + Log() << " -> Warning: Higher order network specified but no higher order input found.\n"; + // Use state output anyway for consistency even in the special case when input is first order + setStateOutput(); + } + Log() << " -> Ordinary network input, using the Map Equation for first order network flows\n"; + } + + if (network.haveDirectedInput() && isUndirectedFlow()) { + Log() << " -> Notice: Directed input found, changing flow model from '" << flowModel << "' to '" << FlowModel(FlowModel::directed) << "'\n"; + flowModel = FlowModel::directed; + } + network.setConfig(*this); + + calculateFlow(network, *this); + + if (network.isBipartite()) { + bipartite = true; + } + + initNetwork(network); + + if (numLeafNodes() == 0) + throw std::domain_error("No nodes to partition"); + + if (printFlowNetwork) { + std::string filename; + if (printStates()) { + filename = outDirectory + outName + "_states_as_physical_flow.net"; + Log() << "Writing flow state network as first order Pajek network to '" << filename << "'... "; + } else { + // Non-memory input + filename = outDirectory + outName + "_flow.net"; + Log() << "Writing flow network to '" << filename << "'... "; + } + network.writePajekNetwork(filename, true); + Log() << "done!\n"; + } + + // If used as a library, we may want to reuse the network instance, else clear to use less memory + // TODO: May have to use some meta data for output? + if (isCLI) { + network.clearLinks(); + } + + if (haveMemory()) + Log(2) << "Run Infomap with memory...\n"; + else + Log(2) << "Run Infomap...\n"; + + std::ostringstream bestSolutionStatistics; + unsigned int bestNumLevels = 0; + double bestHierarchicalCodelength = std::numeric_limits::max(); + m_codelengths.clear(); + NodePaths bestTree(numLeafNodes()); + unsigned int bestTrialIndex = 0; + + unsigned int numTrials = this->numTrials; + + for (unsigned int i = 0; i < numTrials; ++i) { + removeModules(); + auto startDate = Date(); + Stopwatch timer(true); + + if (isMainInfomap()) { + Log() << "\n"; + Log() << "================================================\n"; + Log() << "Trial " << (i + 1) << "/" << numTrials << " starting at " << startDate << "\n"; + Log() << "================================================\n"; + + if (!clusterDataFile.empty()) + initPartition(clusterDataFile, clusterDataIsHard, &network); + else if (!m_initialPartition.empty()) + initPartition(m_initialPartition, clusterDataIsHard); + } + + if (!noInfomap) + runPartition(); + else + m_hierarchicalCodelength = calcCodelengthOnTree(root(), true); + + if (haveHardPartition()) + restoreHardPartition(); + + if (isMainInfomap()) { + Log() << "\n=> Trial " << (i + 1) << "/" << numTrials << " finished in " << timer.getElapsedTimeInSec() << "s with codelength " << m_hierarchicalCodelength << "\n"; + m_codelengths.push_back(m_hierarchicalCodelength); + + if (printAllTrials && numTrials > 1) { + writeResult(static_cast(i + 1)); + } + + if (m_hierarchicalCodelength < bestHierarchicalCodelength - 1e-10) { + bestSolutionStatistics.clear(); + bestSolutionStatistics.str(""); + bestNumLevels = printPerLevelCodelength(root(), bestSolutionStatistics); + bestHierarchicalCodelength = m_hierarchicalCodelength; + bestTrialIndex = i; + root().sortChildrenOnFlow(); + writeResult(); + if (numTrials > 1) { + bestTree.clear(); + for (auto it(iterLeafNodes()); !it.isEnd(); ++it) { + bestTree.emplace_back(it->stateId, it.path()); + } + } + } + } + } + if (isMainInfomap()) { + m_elapsedTime.stop(); + m_endDate = Date(); + Log() << "\n\n"; + Log() << "================================================\n"; + Log() << "Summary after " << numTrials << (numTrials > 1 ? " trials\n" : " trial\n"); + Log() << "================================================\n"; + if (numTrials > 1) { + if (bestTrialIndex < numTrials - 1) { + // Restore Infomap tree to best solution + initTree(bestTree); + writeResult(); // Overwrite result to get total elapsed time in output file header + } + + Log() << std::fixed << std::setprecision(9); + double averageCodelength = 0.0; + double minCodelength = m_codelengths[0]; + double maxCodelength = m_codelengths[0]; + Log() << "Codelengths: ["; + for (auto codelength : m_codelengths) { + Log() << codelength << ", "; + averageCodelength += codelength; + minCodelength = std::min(minCodelength, codelength); + maxCodelength = std::max(maxCodelength, codelength); + } + averageCodelength /= numTrials; + Log() << "\b\b]\n"; + Log() << "[min, average, max] codelength: [" << minCodelength << ", " << averageCodelength << ", " << maxCodelength << "]\n\n"; + } + + Log() << "Best end modular solution in " << bestNumLevels << " levels"; + if (bestHierarchicalCodelength > m_oneLevelCodelength) + Log() << " (warning: worse than one-level solution)"; + Log() << ":\n"; + Log() << bestSolutionStatistics.str() << '\n'; + } +} + +// =================================================== +// Run: Init: * +// =================================================== + +InfomapBase& InfomapBase::initMetaData(const std::string& metaDataFile) +{ + m_network.readMetaData(metaDataFile); + return *this; +} + +InfomapBase& InfomapBase::initNetwork(Network& network) +{ + if (network.numNodes() == 0) + throw std::domain_error("No nodes in network"); + if (m_root.childDegree() > 0) { + m_root.deleteChildren(); + m_leafNodes.clear(); + } + generateSubNetwork(network); + + initOptimizer(); + + init(); + return *this; +} + +InfomapBase& InfomapBase::initNetwork(InfoNode& parent, bool asSuperNetwork) +{ + generateSubNetwork(parent); + + if (asSuperNetwork) + transformNodeFlowToEnterFlow(m_root); + + init(); + return *this; +} + +InfomapBase& InfomapBase::initPartition(const std::string& clusterDataFile, bool hard, const Network* network) +{ + FileURI file(clusterDataFile); + ClusterMap clusterMap; + if (this->isMultilayerNetwork() && network != nullptr) { + auto map = network->layerNodeToStateId(); + clusterMap.readClusterData(clusterDataFile, false, &map); + } else { + clusterMap.readClusterData(clusterDataFile); + } + + Log() << "Init partition from file '" << clusterDataFile << "'... "; + + const auto& ext = clusterMap.extension(); + + if (ext == "tree" || ext == "ftree") { + initTree(clusterMap.nodePaths()); + } else if (ext == "clu") { + initPartition(clusterMap.clusterIds(), hard); + } + + Log() << "done! Generated " << numLevels() << " levels with codelength " << getIndexCodelength() << " + " << (m_hierarchicalCodelength - getIndexCodelength()) << " = " << io::toPrecision(m_hierarchicalCodelength) << '\n'; + + return *this; +} + +InfomapBase& InfomapBase::initTree(const NodePaths& tree) +{ + Log(4) << "Init tree... " << std::setprecision(9); + auto maxDepth = 2; + std::map nodeIdToIndex; + auto leafIndex = 0; + for (auto& leafNode : m_leafNodes) { + // Also detach leaf nodes to delete all modules, safe to call multiple times + leafNode->parent->releaseChildren(); + // Set parent to nullptr to be able to collect any orphaned nodes in the end + leafNode->parent = nullptr; + nodeIdToIndex[leafNode->stateId] = leafIndex; + ++leafIndex; + } + m_root.deleteChildren(); + + auto numNodesFound = 0; + auto numNodesNotInNetwork = 0; + for (const auto& nodePath : tree) { + ++numNodesFound; + InfoNode* node = &root(); + auto depth = 0; + const auto& path = nodePath.second; + const auto nodeId = nodePath.first; + InfoNode* leafNode = nullptr; + + try { + auto nodeIndex = nodeIdToIndex.at(nodeId); + leafNode = m_leafNodes[nodeIndex]; + } catch (std::exception& e) { + ++numNodesNotInNetwork; + continue; + } + + for (size_t i = 0; i < path.size(); ++i) { + auto childNumber = path[i]; // 1-based indexing + + // Create new node if path doesn't exist + // TODO: Check correct tree indexing? + if (node->childDegree() < childNumber) { + InfoNode* child = leafNode; + if (i + 1 < path.size()) { + child = new InfoNode(); + } + node->addChild(child); + } + + node = node->lastChild; + ++depth; + } + maxDepth = std::max(maxDepth, depth); + } + + if (numNodesNotInNetwork > 0) { + Log(1) << "\n -> " << numNodesNotInNetwork << "/" << numNodesFound << " nodes in tree not found in network."; + } + + auto numNodesAddedToNeighbouringModules = 0; + auto numNodesWithoutClusterInfo = 0; + + // Set orphaned nodes to their own or neighbouring module + for (auto& leafNode : m_leafNodes) { + if (leafNode->parent != nullptr) { + continue; + } + + ++numNodesWithoutClusterInfo; + if (assignToNeighbouringModule) { + // Take first neighbour that has a module assigned + for (auto& edge : leafNode->outEdges()) { + if (edge->target->parent != nullptr) { + edge->target->parent->addChild(leafNode); + ++numNodesAddedToNeighbouringModules; + break; + } + } + // Check incoming links if still orphan + if (leafNode->parent == nullptr) { + for (auto& edge : leafNode->inEdges()) { + if (edge->source->parent != nullptr) { + edge->source->parent->addChild(leafNode); + ++numNodesAddedToNeighbouringModules; + break; + } + } + } + // Set to own module if no neighbour module available + if (leafNode->parent == nullptr) { + auto module = new InfoNode(); + root().addChild(module); + module->addChild(leafNode); + } + } else { + // Set to own module if no neighbour module available + auto module = new InfoNode(); + root().addChild(module); + module->addChild(leafNode); + } + } + if (numNodesWithoutClusterInfo > 0) { + if (assignToNeighbouringModule) { + Log() << "\n -> " << numNodesWithoutClusterInfo << " nodes not found in tree, " << numNodesAddedToNeighbouringModules << " are put into neighbouring modules and " << (numNodesWithoutClusterInfo - numNodesAddedToNeighbouringModules) << " in separate."; + } else { + Log() << "\n -> " << numNodesWithoutClusterInfo << " nodes not found in tree are put into separate modules."; + } + } + + aggregateFlowValuesFromLeafToRoot(); + initTree(); + initNetwork(); + m_numNonTrivialTopModules = calculateNumNonTrivialTopModules(); + // Init partition to calculate indexCodelength and moduleCodelength + if (haveModules()) + setActiveNetworkFromChildrenOfRoot(); + else + setActiveNetworkFromLeafs(); + initPartition(); + + m_hierarchicalCodelength = calcCodelengthOnTree(root(), true); + Log() << "\n -> Initiated to codelength " << m_hierarchicalCodelength << " in " << maxDepth << " levels with " << numTopModules() << " top modules.\n"; + Log() << std::setprecision(6); + return *this; +} + +/** + * clusterIds is a map from nodeId -> clusterId + */ +InfomapBase& InfomapBase::initPartition(const std::map& clusterIds, bool hard) +{ + // Generate map from node id to index in leaf node vector + std::map nodeIdToIndex; + unsigned int leafIndex = 0; + for (auto& nodePtr : m_leafNodes) { + auto& leafNode = *nodePtr; + nodeIdToIndex[leafNode.stateId] = leafIndex; + ++leafIndex; + } + + // Remap clusterIds to vector from leaf node index to module index instead of nodeId -> clusterId + std::map> clusterIdToNodeIds; + for (auto it : clusterIds) { + clusterIdToNodeIds[it.second].insert(it.first); + } + unsigned int numNodes = numLeafNodes(); + std::vector modules(numNodes); + std::vector selectedNodes(numNodes, 0); + unsigned int moduleIndex = 0; + for (const auto& it : clusterIdToNodeIds) { + auto& nodes = it.second; + for (auto& nodeId : nodes) { + auto nodeIndex = nodeIdToIndex[nodeId]; + modules[nodeIndex] = moduleIndex; + ++selectedNodes[nodeIndex]; + } + ++moduleIndex; + } + + unsigned int numNodesWithoutClusterInfo = 0; + for (auto& count : selectedNodes) { + if (count == 0) { + ++numNodesWithoutClusterInfo; + } + } + + if (numNodesWithoutClusterInfo == 0) { + return initPartition(modules, hard); + } + + if (assignToNeighbouringModule) { + Log() << "\n -> " << numNodesWithoutClusterInfo << " nodes not found in cluster file are put into neighbouring modules if possible. "; + for (unsigned int i = 0; i < numNodes; ++i) { + if (selectedNodes[i] == 0) { + // Check out edges greedily for connected modules + auto& node = *m_leafNodes[i]; + for (auto& e : node.outEdges()) { + auto& edge = *e; + auto targetNodeIndex = nodeIdToIndex[edge.target->stateId]; + if (selectedNodes[targetNodeIndex] != 0) { + selectedNodes[i] = 1; + modules[i] = modules[targetNodeIndex]; + break; + } + } + if (selectedNodes[i] == 0) { + // Check in edges greedily for connected modules + for (auto& e : node.inEdges()) { + auto& edge = *e; + auto sourceNodeIndex = nodeIdToIndex[edge.source->stateId]; + if (selectedNodes[sourceNodeIndex] != 0) { + selectedNodes[i] = 1; + modules[i] = modules[sourceNodeIndex]; + break; + } + } + } + if (selectedNodes[i] == 0) { + // No connected node with a module index, fall back to create new module + selectedNodes[i] = 1; + modules[i] = moduleIndex; + ++moduleIndex; + } + } + } + } else { + Log() << "\n -> " << numNodesWithoutClusterInfo << " nodes not found in cluster file are put into separate modules. "; + // Put non-selected nodes in its own module + for (unsigned int i = 0; i < numNodes; ++i) { + if (selectedNodes[i] == 0) { + modules[i] = moduleIndex; + ++moduleIndex; + } + } + } + + return initPartition(modules); +} + +InfomapBase& InfomapBase::initPartition(std::vector>& clusters, bool hard) +{ + Log(3) << "\n -> Init " << (hard ? "hard" : "soft") << " partition... " << std::flush; + unsigned int numNodes = numLeafNodes(); + // Get module indices from the merge structure + std::vector modules(numNodes); + std::vector selectedNodes(numNodes, 0); + unsigned int moduleIndex = 0; + + for (auto& cluster : clusters) { + if (cluster.empty()) + continue; + for (auto id : cluster) { + ++selectedNodes[id]; + modules[id] = moduleIndex; + } + ++moduleIndex; + } + + // Put non-selected nodes in its own module + unsigned int numNodesWithoutClusterInfo = 0; + for (unsigned int i = 0; i < numNodes; ++i) { + if (selectedNodes[i] == 0) { + modules[i] = moduleIndex; + ++moduleIndex; + ++numNodesWithoutClusterInfo; + } + } + if (numNodesWithoutClusterInfo > 0) + Log() << "\n -> " << numNodesWithoutClusterInfo << " nodes not found in cluster file are put into separate modules. "; + + return initPartition(modules, hard); +} + +InfomapBase& InfomapBase::initPartition(std::vector& modules, bool hard) +{ + removeModules(); + setActiveNetworkFromLeafs(); + initPartition(); // TODO: confusing same name, should be able to init default without arguments here too + moveActiveNodesToPredefinedModules(modules); + consolidateModules(false); + + if (hard) { + // Save the original network + m_originalLeafNodes.swap(m_leafNodes); + + // Use the pre-partitioned network as the new leaf network + unsigned int numNodesInNewNetwork = numTopModules(); + m_leafNodes.resize(numNodesInNewNetwork); + unsigned int nodeIndex = 0; + unsigned int numLinksInNewNetwork = 0; + for (InfoNode& node : m_root) { + m_leafNodes[nodeIndex] = &node; + // Collapse children + node.collapseChildren(); + numLinksInNewNetwork += node.outDegree(); + ++nodeIndex; + } + + Log(1) << "\n -> Hard-partitioned the network to " << numNodesInNewNetwork << " nodes and " << numLinksInNewNetwork << " links with codelength " << *this << '\n'; + } else { + Log(1) << "\n -> Initiated to codelength " << *this << " in " << numTopModules() << " top modules.\n"; + } + m_hierarchicalCodelength = getCodelength(); + + return *this; +} + +void InfomapBase::generateSubNetwork(Network& network) +{ + unsigned int numNodes = network.numNodes(); + auto& metaData = network.metaData(); + numMetaDataDimensions = network.numMetaDataColumns(); + + Log() << "Build internal network with " << numNodes << " nodes and " << network.numLinks() << " links...\n"; + if (!metaData.empty()) { + Log() << "and " << metaData.size() << " meta-data records in " << numMetaDataDimensions << " dimensions\n"; + } + + m_leafNodes.reserve(numNodes); + double sumNodeFlow = 0.0; + double sumTeleFlow = 0.0; + std::map nodeIndexMap; + for (auto& nodeIt : network.nodes()) { + auto& networkNode = nodeIt.second; + auto* node = new InfoNode(networkNode.flow, networkNode.id, networkNode.physicalId, networkNode.layerId); + node->data.teleportWeight = networkNode.weight; + node->data.teleportFlow = networkNode.teleFlow; + node->data.exitFlow = networkNode.exitFlow; + node->data.enterFlow = networkNode.enterFlow; + if (haveMetaData()) { + auto meta = metaData.find(networkNode.id); + if (meta != metaData.end()) { + node->metaData = meta->second; + } else { + node->metaData = std::vector(numMetaDataDimensions, -1); + } + } + sumNodeFlow += networkNode.flow; + sumTeleFlow += networkNode.teleFlow; + m_root.addChild(node); + nodeIndexMap[networkNode.id] = m_leafNodes.size(); + m_leafNodes.push_back(node); + } + m_root.data.flow = sumNodeFlow; + m_root.data.teleportFlow = sumTeleFlow; + // m_calculateEnterExitFlow = true; //TODO: Implement always in flow calculation + if (!this->regularized) { + m_calculateEnterExitFlow = true; + } + BiasedMapEquation::setNetworkProperties(network); + + if (std::abs(sumNodeFlow - 1.0) > 1e-10) + Log() << "Warning, total flow on nodes differs from 1.0 by " << sumNodeFlow - 1.0 << ".\n"; + + bool changeMarkovTime = std::abs(markovTime - 1) > 1e-3; + if (changeMarkovTime) { + Log() << " -> Rescale link flow with global Markov time " << markovTime << "\n"; + } + + for (auto& linkIt : network.nodeLinkMap()) { + unsigned int linkSourceId = linkIt.first.id; + unsigned int sourceIndex = nodeIndexMap[linkSourceId]; + const auto& subLinks = linkIt.second; + for (auto& subIt : subLinks) { + unsigned int linkTargetId = subIt.first.id; + unsigned int targetIndex = nodeIndexMap[linkTargetId]; + // Ignore self-links in optimization as it doesn't change enter/exit flow on modular level + if (sourceIndex != targetIndex) { + auto& linkData = subIt.second; + m_leafNodes[sourceIndex]->addOutEdge(*m_leafNodes[targetIndex], linkData.weight, linkData.flow * markovTime); + } + } + } + + if (variableMarkovTime) { + Log() << " -> Rescale link flow with variable Markov time\n"; + if (std::abs(variableMarkovTimeDamping - 1) > 1e-9) { + Log() << " -> Use variable Markov time strength " << variableMarkovTimeDamping << "\n"; + } + } + + double maxEntropy = 0.0; + double maxFlow = 0.0; + double entropyRate = 0.0; + unsigned int maxDegree = 0; + unsigned int maxOutDegree = 0; + unsigned int maxInDegree = 0; + double totDegree = network.sumDegree(); + std::vector entropies(numNodes, 0); + + for (unsigned i = 0; i < numNodes; ++i) { + InfoNode& node = *m_leafNodes[i]; + maxDegree = std::max(maxDegree, node.degree()); + maxOutDegree = std::max(maxOutDegree, node.outDegree()); + maxInDegree = std::max(maxInDegree, node.inDegree()); + double entropy = 0; + double sumOut = 0; + for (InfoEdge* e : node.outEdges()) { + entropy -= infomath::plogp(e->data.weight); + sumOut += e->data.weight; + } + if (isUndirectedFlow()) { + for (InfoEdge* e : node.inEdges()) { + entropy -= infomath::plogp(e->data.weight); + sumOut += e->data.weight; + } + } + entropy = sumOut > 1e-9 ? (entropy + infomath::plogp(sumOut)) / sumOut : 0; + maxEntropy = std::max(maxEntropy, entropy); + entropyRate += m_leafNodes[i]->data.flow * entropy; + maxFlow = std::max(maxFlow, node.data.flow); + entropies[i] = entropy; // Store for undirected networks + } + + m_entropyRate = entropyRate; + m_maxEntropy = maxEntropy; + m_maxFlow = maxFlow; + + double minLocalScale = variableMarkovTimeMinLocalScale; + double damping = variableMarkovTimeDamping; + + double maxScale = infomath::linlog(maxFlow * totDegree, damping); + + if (variableMarkovTime) { + if (damping < 0) { + maxScale = infomath::linlog(pow(2.0, maxEntropy), -damping); + } + for (unsigned i = 0; i < numNodes; ++i) { + InfoNode& node = *m_leafNodes[i]; + double localScale = damping < 0 ? infomath::linlog(pow(2.0, entropies[i]), -damping) : infomath::linlog(std::max(minLocalScale, node.data.flow * totDegree), damping); + for (InfoEdge* e : node.outEdges()) { + if (isUndirectedFlow()) { + double oppositeLocalScale = damping < 0 ? infomath::linlog(pow(2.0, entropies[nodeIndexMap[e->target->stateId]]), -damping) : infomath::linlog(std::max(minLocalScale, e->target->data.flow * totDegree), damping); + localScale = std::max(localScale, oppositeLocalScale); + } + double localMarkovTimeScale = maxScale / std::max(minLocalScale, localScale); + e->data.flow *= localMarkovTimeScale; + network.nodeLinkMap()[e->source->stateId][e->target->stateId].flow = e->data.flow; + } + } + } +} + +void InfomapBase::generateSubNetwork(InfoNode& parent) +{ + // Store parent module + m_root.owner = &parent; + m_root.data = parent.data; + + unsigned int numNodes = parent.childDegree(); + m_leafNodes.resize(numNodes); + + Log(1) << "Generate sub network with " << numNodes << " nodes...\n"; + + unsigned int childIndex = 0; + for (InfoNode& node : parent) { + auto* clonedNode = new InfoNode(node); + clonedNode->initClean(); + m_root.addChild(clonedNode); + node.index = childIndex; // Set index to its place in this subnetwork to be able to find edge target below + m_leafNodes[childIndex] = clonedNode; + ++childIndex; + } + + InfoNode* parentPtr = &parent; + // Clone edges + for (InfoNode& node : parent) { + for (InfoEdge* e : node.outEdges()) { + InfoEdge& edge = *e; + // If neighbour node is within the same module, add the link to this subnetwork. + if (edge.target->parent == parentPtr) { + m_leafNodes[edge.source->index]->addOutEdge(*m_leafNodes[edge.target->index], edge.data.weight, edge.data.flow); + } + } + } +} + +void InfomapBase::init() +{ + Log(3) << "InfomapBase::init()...\n"; + + if (m_calculateEnterExitFlow && isMainInfomap()) + initEnterExitFlow(); + + initNetwork(); + + m_oneLevelCodelength = calcCodelength(m_root); + Log() << " -> One-level codelength: " << m_oneLevelCodelength << '\n'; +} + +// =================================================== +// Run: * +// =================================================== + +void InfomapBase::hierarchicalPartition() +{ + Log(1) << "Hierarchical partition...\n"; + + const auto depth = maxTreeDepth(); + if (depth > 2) { + Log(1) << "Continuing from a tree with " << depth << " levels...\n"; + + if (fastHierarchicalSolution == 0) { + Log(1) << "Removing sub modules...\n"; + removeSubModules(true); + m_hierarchicalCodelength = calcCodelengthOnTree(root(), true); + } + + else if (fastHierarchicalSolution == 1) { + Log(1) << "Fine-tune bottom modules... "; + bool isSilent = isMainInfomap() && Log::isSilent(); + + double codelengthBefore = 0.0; + double codelengthAfter = 0.0; + + for (InfoNode& module : m_root.infomapTree()) { + if (!module.isLeaf() && module.firstChild->isLeafModule()) { + codelengthBefore += module.codelength; + auto numLeafs = 0; + for (auto& leafModule : module) { + numLeafs += leafModule.childDegree(); + } + + std::vector modules(numLeafs); + std::vector leafs(numLeafs); + + auto i = 0; + for (auto it = module.begin_tree(); !it.isEnd(); ++it) { + if (it->isLeaf()) { + modules[i] = it.moduleIndex(); + leafs[i] = it.current(); + ++i; + } + } + + module.replaceChildrenWithGrandChildren(); + + auto& subInfomap = getSubInfomap(module).initNetwork(module); + + subInfomap.initPartition(modules); + + // Run two-level partition + find hierarchically super modules (skip recursion) + subInfomap.setOnlySuperModules(true).run(); + + // Collect sub Infomap modules + i = 0; + for (auto& subLeafPtr : subInfomap.leafNodes()) { + modules[i] = subLeafPtr->index; + ++i; + } + + // Create new sub modules + std::vector subModules(numLeafs, nullptr); + module.releaseChildren(); + + for (auto j = 0; j < numLeafs; ++j) { + InfoNode* leaf = leafs[j]; + unsigned int moduleIndex = modules[j]; + if (subModules[moduleIndex] == nullptr) { + subModules[moduleIndex] = new InfoNode(subInfomap.leafNodes()[j]->parent->data); + subModules[moduleIndex]->index = moduleIndex; + module.addChild(subModules[moduleIndex]); + } + subModules[moduleIndex]->addChild(leaf); + } + module.disposeInfomap(); + module.codelength = calcCodelength(module); + codelengthAfter += module.codelength; + } + } + + if (isMainInfomap()) + Log::setSilent(isSilent); + + const double diffCodelength = codelengthBefore - codelengthAfter; + Log() << "done! Codelength improvement " << (diffCodelength / codelengthBefore) * 100 << "% to codelength " << codelengthAfter << "\n"; + } + + recursivePartition(); + return; + } + + partition(); + + if (numTopModules() == 1 || numTopModules() == numLeafNodes()) { + Log(1) << "Trivial partition, skip search for hierarchical solution.\n"; + return; + } + + if (numTopModules() > preferredNumberOfModules) { + findHierarchicalSuperModules(); + } + + if (onlySuperModules) { + removeSubModules(true); + m_hierarchicalCodelength = calcCodelengthOnTree(root(), true); + return; + } + + if (fastHierarchicalSolution >= 2) { + // FIXME Calculate individual module codelengths and store on the modules? + return; + } + + if (fastHierarchicalSolution == 0) { + removeSubModules(true); + m_hierarchicalCodelength = calcCodelengthOnTree(root(), true); + } + + recursivePartition(); +} + +void InfomapBase::partition() +{ + auto oldPrecision = Log::precision(); + Log(0, 0) << "Two-level compression: " << std::setprecision(2) << std::flush; + Log(1) << "Trying to find modular structure... \n"; + double initialCodelength = m_oneLevelCodelength; + double oldCodelength = initialCodelength; + + m_tuneIterationIndex = 0; + findTopModulesRepeatedly(levelAggregationLimit); + + double newCodelength = getCodelength(); + double compression = oldCodelength < 1e-16 ? 0.0 : (oldCodelength - newCodelength) / oldCodelength; + Log(0, 0) << (compression * 100) << "% " << std::flush; + oldCodelength = newCodelength; + + bool doFineTune = true; + bool coarseTuned = false; + while (numTopModules() > 1 && (m_tuneIterationIndex + 1) != tuneIterationLimit) { + ++m_tuneIterationIndex; + if (doFineTune) { + Log(3) << "\n"; + Log(1, 3) << "Fine tune... " << std::flush; + unsigned int numEffectiveLoops = fineTune(); + if (numEffectiveLoops > 0) { + Log(1, 3) << " -> done in " << numEffectiveLoops << " effective loops to codelength " << *this << " in " << numTopModules() << " modules.\n"; + // Continue to merge fine-tuned modules + findTopModulesRepeatedly(levelAggregationLimit); + } else { + Log(1, 3) << "no improvement.\n"; + } + } else { + coarseTuned = true; + if (!noCoarseTune) { + Log(3) << "\n"; + Log(1, 3) << "Coarse tune... " << std::flush; + unsigned int numEffectiveLoops = coarseTune(); + if (numEffectiveLoops > 0) { + Log(1, 3) << "done in " << numEffectiveLoops << " effective loops to codelength " << *this << " in " << numTopModules() << " modules.\n"; + // Continue to merge fine-tuned modules + findTopModulesRepeatedly(levelAggregationLimit); + } else { + Log(1, 3) << "no improvement.\n"; + } + } + } + newCodelength = getCodelength(); + compression = oldCodelength < 1e-16 ? 0.0 : (oldCodelength - newCodelength) / oldCodelength; + bool isImprovement = newCodelength <= oldCodelength - minimumCodelengthImprovement && newCodelength < oldCodelength - initialCodelength * minimumRelativeTuneIterationImprovement; + if (!isImprovement) { + // Make sure coarse-tuning have been tried + if (coarseTuned) + break; + } else { + oldCodelength = newCodelength; + } + Log(0, 0) << (compression * 100) << "% " << std::flush; + doFineTune = !doFineTune; + } + + Log(0, 0) << std::setprecision(oldPrecision) << '\n'; + Log() << "Partitioned to codelength " << *this << " in " << numTopModules(); + if (m_numNonTrivialTopModules != numTopModules()) + Log() << " (" << m_numNonTrivialTopModules << " non-trivial)"; + Log() << " modules.\n"; + + if (!preferModularSolution && preferredNumberOfModules == 0 && haveNonTrivialModules() && getCodelength() > getOneLevelCodelength()) { + Log() << "Worse codelength than one-level codelength, putting all nodes in one module... "; + + // Create new single module between modules and root + auto& module = root().replaceChildrenWithOneNode(); + module.data = m_root.data; + module.index = 0; + for (auto& node : module) { + node.index = 0; + } + module.codelength = getOneLevelCodelength(); + m_hierarchicalCodelength = getOneLevelCodelength(); + + } else { + // Set consolidated cluster index on nodes and modules + for (auto clusterIt = m_root.begin_tree(); !clusterIt.isEnd(); ++clusterIt) { + clusterIt->index = clusterIt.moduleIndex(); + } + + // Calculate individual module codelengths and store on the modules + calcCodelengthOnTree(root(), false); + m_root.codelength = getIndexCodelength(); + m_hierarchicalCodelength = getCodelength(); + } + m_hierarchicalCodelength = calcCodelengthOnTree(root(), true); +} + +void InfomapBase::restoreHardPartition() +{ + // Collect all leaf nodes in a separate sequence to be able to iterate independent of tree structure + std::vector leafNodes(numLeafNodes()); + unsigned int leafIndex = 0; + for (InfoNode& node : m_root.infomapTree()) { + if (node.isLeaf()) { + leafNodes[leafIndex] = &node; + ++leafIndex; + } + } + // Expand all children + unsigned int numExpandedChildren = 0; + unsigned int numExpandedNodes = 0; + for (InfoNode* node : leafNodes) { + ++numExpandedNodes; + numExpandedChildren += node->expandChildren(); + node->replaceWithChildren(); + } + + // Swap back original leaf nodes + m_originalLeafNodes.swap(m_leafNodes); + + Log(1) << "Expanded " << numExpandedNodes << " hard modules to " << numExpandedChildren << " original nodes.\n"; +} + +// =================================================== +// Run: Init: * +// =================================================== + +void InfomapBase::initEnterExitFlow() +{ + // Not done in Bayesian + // TODO: Skip this, always add enter/exit/tele flow from flow calculator + // Calculate enter/exit + double alpha = teleportationProbability; + double beta = 1.0 - alpha; + + for (auto* n : m_leafNodes) { + n->data.enterFlow = n->data.exitFlow = 0.0; + } + if (!isUndirectedClustering()) { + for (auto* n : m_leafNodes) { + auto& node = *n; + node.data.teleportFlow = alpha * node.data.flow; + node.data.teleportSourceFlow = node.data.flow; + if (node.isDangling()) { + node.data.teleportFlow = node.data.flow; + node.data.danglingFlow = node.data.flow; + m_sumDanglingFlow += node.data.flow; + } + } + for (auto* n : m_leafNodes) { + auto& node = *n; + for (InfoEdge* e : node.outEdges()) { + InfoEdge& edge = *e; + // Self-links not included here, should not add to enter and exit flow in its enclosing module + edge.source->data.exitFlow += edge.data.flow; + edge.target->data.enterFlow += edge.data.flow; + } + if (recordedTeleportation) { + // Don't let self-teleportation add to the enter/exit flow (i.e. multiply with (1.0 - node.data.teleportWeight)) + node.data.exitFlow += (alpha * node.data.flow + beta * node.data.danglingFlow) * (1.0 - node.data.teleportWeight); + node.data.enterFlow += (alpha * (1.0 - node.data.flow) + beta * (m_sumDanglingFlow - node.data.danglingFlow)) * node.data.teleportWeight; + } + } + } else { + for (auto* n : m_leafNodes) { + auto& node = *n; + node.data.teleportFlow = alpha * node.data.flow; + node.data.teleportSourceFlow = node.data.flow; + if (node.isDangling()) { + node.data.teleportFlow = node.data.flow; + node.data.danglingFlow = node.data.flow; + } + for (InfoEdge* e : node.outEdges()) { + InfoEdge& edge = *e; + // Self-links not included here, should not add to enter and exit flow in its enclosing module + double halfFlow = edge.data.flow / 2; + edge.source->data.exitFlow += halfFlow; + edge.target->data.exitFlow += halfFlow; + edge.source->data.enterFlow += halfFlow; + edge.target->data.enterFlow += halfFlow; + } + } + } +} + +// Aggregate node and enter/exit flow to all tree nodes +void InfomapBase::aggregateFlowValuesFromLeafToRoot() +{ + // Aggregate flow from leaf nodes to root node + unsigned int numLevels = 0; + root().data.flow = 0.0; + for (auto it = root().begin_post_depth_first(); !it.isEnd(); ++it) { + auto& node = *it; + if (!node.isRoot()) + node.parent->data += node.data; + // Don't aggregate enter and exit flow + if (!node.isLeaf()) { + node.index = it.depth(); // Use index to store the depth on modules + node.data.enterFlow = 0.0; + node.data.exitFlow = 0.0; + } else + numLevels = std::max(numLevels, it.depth()); + } + + if (std::abs(root().data.flow - 1.0) > 1e-10) { + Log() << "Warning, aggregated flow is not exactly 1.0, but " << std::setprecision(10) << root().data.flow << std::setprecision(9) << ".\n"; + } + + // Aggregate enter and exit flow between modules + for (auto& leafNode : m_leafNodes) { + auto& leafNodeSource = *leafNode; + for (InfoEdge* e : leafNodeSource.outEdges()) { + auto& edge = *e; + auto& leafNodeTarget = edge.target; + double linkFlow = edge.data.flow; + double halfFlow = linkFlow / 2; + + InfoNode* node1 = leafNodeSource.parent; + InfoNode* node2 = leafNodeTarget->parent; + + if (node1 == node2) + continue; + + // First aggregate link flow until equal depth + while (node1->index > node2->index) { + if (isUndirectedClustering()) { + node1->data.exitFlow += halfFlow; + node1->data.enterFlow += halfFlow; + } else { + node1->data.exitFlow += linkFlow; + } + node1 = node1->parent; + } + while (node2->index > node1->index) { + if (isUndirectedClustering()) { + node2->data.enterFlow += halfFlow; + node2->data.exitFlow += halfFlow; + } else { + node2->data.enterFlow += linkFlow; + } + node2 = node2->parent; + } + + // Then aggregate link flow until equal parent + while (node1 != node2) { + if (isUndirectedClustering()) { + node1->data.exitFlow += halfFlow; + node1->data.enterFlow += halfFlow; + node2->data.enterFlow += halfFlow; + node2->data.exitFlow += halfFlow; + } else { + node1->data.exitFlow += linkFlow; + node2->data.enterFlow += linkFlow; + } + node1 = node1->parent; + node2 = node2->parent; + } + } + } + if (recordedTeleportation) { + Log() << "\n\nAggregating enter/exit flow for recorded teleportation, sum teleFlow: " << m_root.data.teleportFlow << "\n"; + + for (auto& node : m_root.infomapTree()) { + if (!node.isLeaf()) { + // Don't code self-teleportation + + node.data.enterFlow += (m_root.data.teleportFlow - node.data.teleportFlow) * node.data.teleportWeight; + node.data.exitFlow += node.data.teleportFlow * (1.0 - node.data.teleportWeight); + } + } + } +} + +double InfomapBase::calcCodelengthOnTree(InfoNode& root, bool includeRoot) const +{ + double totalCodelength = 0.0; + // Calculate enter/exit flow (assuming 0 by default) + for (auto& node : root.infomapTree()) { + if (node.isLeaf() || (!includeRoot && node.isRoot())) + continue; + node.codelength = calcCodelength(node); + totalCodelength += node.codelength; + } + return totalCodelength; +} + +// =================================================== +// Run: Partition: * +// =================================================== + +void InfomapBase::setActiveNetworkFromChildrenOfRoot() +{ + m_moduleNodes.resize(m_root.childDegree()); + unsigned int i = 0; + for (auto& node : m_root) + m_moduleNodes[i++] = &node; + m_activeNetwork = &m_moduleNodes; +} + +void InfomapBase::findTopModulesRepeatedly(unsigned int maxLevels) +{ + Log(1, 2) << "Iteration " << (m_tuneIterationIndex + 1) << ", moving "; + Log(3) << "\nIteration " << (m_tuneIterationIndex + 1) << ":\n"; + m_aggregationLevel = 0; + unsigned int numLevelsConsolidated = numLevels() - 1; + if (maxLevels == 0) + maxLevels = std::numeric_limits::max(); + + std::string initialCodelength; + + // Reapply core algorithm on modular network, replacing modules with super modules + while (numTopModules() > 1 && numLevelsConsolidated != maxLevels) { + if (haveModules()) + setActiveNetworkFromChildrenOfRoot(); + else + setActiveNetworkFromLeafs(); + initPartition(); + if (m_aggregationLevel == 0) { + initialCodelength = io::Str() << "" << *this; + } + + Log(1, 2) << activeNetwork().size() << "*" << std::flush; + Log(3) << "Level " << (numLevelsConsolidated + 1) << " (codelength: " << *this << "): Moving " << activeNetwork().size() << " nodes... " << std::flush; + // Core loop, merging modules + unsigned int numOptimizationLoops = optimizeActiveNetwork(); + + Log(1, 2) << numOptimizationLoops << ", " << std::flush; + Log(3) << "done! -> codelength " << *this << " in " << numActiveModules() << " modules.\n"; + + // If no improvement, revert codelength terms to the last consolidated state + if (haveModules() && restoreConsolidatedOptimizationPointIfNoImprovement()) { + Log(3) << "-> Restored to codelength " << *this << " in " << numTopModules() << " modules.\n"; + break; + } + + // Consolidate modules + bool replaceExistingModules = haveModules(); + consolidateModules(replaceExistingModules); + ++numLevelsConsolidated; + ++m_aggregationLevel; + } + m_aggregationLevel = 0; + + m_numNonTrivialTopModules = calculateNumNonTrivialTopModules(); + + Log(1, 2) << (m_isCoarseTune ? "modules" : "nodes") << "*loops from codelength " << initialCodelength << " to codelength " << *this << " in " << numTopModules() << " modules. (" << m_numNonTrivialTopModules << " non-trivial modules)\n"; +} + +unsigned int InfomapBase::fineTune() +{ + if (numLevels() != 2) + throw std::logic_error("InfomapBase::fineTune() called but numLevels != 2"); + + setActiveNetworkFromLeafs(); + initPartition(); + + // Make sure module nodes have correct index //TODO: Assume always correct here? + unsigned int moduleIndex = 0; + for (auto& module : m_root) { + module.index = moduleIndex++; + } + + // Put leaf modules in existing modules + std::vector modules(numLeafNodes()); + for (unsigned int i = 0; i < numLeafNodes(); ++i) { + modules[i] = m_leafNodes[i]->parent->index; + } + moveActiveNodesToPredefinedModules(modules); + + Log(3) << " -> moved to codelength " << *this << " in " << numActiveModules() << " existing modules. Try tuning...\n"; + + // Continue to optimize from there to tune leaf nodes + unsigned int numEffectiveLoops = optimizeActiveNetwork(); + if (numEffectiveLoops == 0) { + restoreConsolidatedOptimizationPointIfNoImprovement(); + Log(4) << "Fine-tune didn't improve solution, restoring last.\n"; + } else { + // Delete existing modules and consolidate fine-tuned modules + root().replaceChildrenWithGrandChildren(); + consolidateModules(false); + Log(4) << "Fine-tune done in " << numEffectiveLoops << " effective loops to codelength " << *this << " in " << numTopModules() << " modules.\n"; + } + + return numEffectiveLoops; +} + +unsigned int InfomapBase::coarseTune() +{ + if (numLevels() != 2) + throw std::logic_error("InfomapBase::coarseTune() called but numLevels != 2"); + + Log(4) << "Coarse-tune...\nPartition each module in sub-modules for coarse tune...\n"; + + bool isSilent = false; + if (isMainInfomap()) { + isSilent = Log::isSilent(); + Log::setSilent(true); + } + + unsigned int moduleIndexOffset = 0; + for (auto& node : m_root) { + // Don't search for sub-modules in too small modules + if (node.childDegree() < 2) { + for (auto& child : node) { + child.index = moduleIndexOffset; + } + moduleIndexOffset += 1; + continue; + } else { + InfomapBase& subInfomap = getSubInfomap(node) + .setTwoLevel(true) + .setTuneIterationLimit(1); + subInfomap.initNetwork(node).run(); + + auto originalLeafIt = node.begin_child(); + for (auto& subLeafPtr : subInfomap.leafNodes()) { + InfoNode& subLeaf = *subLeafPtr; + originalLeafIt->index = subLeaf.index + moduleIndexOffset; + ++originalLeafIt; + } + moduleIndexOffset += subInfomap.numTopModules(); + + node.disposeInfomap(); + } + } + + if (isMainInfomap()) + Log::setSilent(isSilent); + + Log(4) << "Move leaf nodes to " << moduleIndexOffset << " sub-modules... \n"; + // Put leaf modules in the calculated sub-modules + std::vector subModules(numLeafNodes()); + for (unsigned int i = 0; i < numLeafNodes(); ++i) { + subModules[i] = m_leafNodes[i]->index; + } + + setActiveNetworkFromLeafs(); + initPartition(); + moveActiveNodesToPredefinedModules(subModules); + + Log(4) << "Moved to " << numActiveModules() << " modules...\n"; + + // Replace existing modules but store that structure on the sub-modules + consolidateModules(true); + + Log(4) << "Consolidated " << numTopModules() << " sub-modules to codelength " << *this << '\n'; + + Log(4) << "Move sub-modules to former modular structure... \n"; + // Put sub-modules in the former modular structure + std::vector modules(numTopModules()); + unsigned int iModule = 0; + for (auto& subModule : m_root) { + modules[iModule++] = subModule.index; + } + + setActiveNetworkFromChildrenOfRoot(); + initPartition(); + // Move sub-modules to former modular structure + moveActiveNodesToPredefinedModules(modules); + + Log(4) << "Tune sub-modules from codelength " << *this << " in " << numActiveModules() << " modules... \n"; + // Continue to optimize from there to tune sub-modules + unsigned int numEffectiveLoops = optimizeActiveNetwork(); + Log(4) << "Tuned sub-modules in " << numEffectiveLoops << " effective loops to codelength " << *this << " in " << numActiveModules() << " modules.\n"; + consolidateModules(true); + Log(4) << "Consolidated tuned sub-modules to codelength " << *this << " in " << numTopModules() << " modules.\n"; + return numEffectiveLoops; +} + +unsigned int InfomapBase::calculateNumNonTrivialTopModules() const +{ + if (root().childDegree() == 1) + return 0; + unsigned int numNonTrivialTopModules = 0; + for (auto& module : m_root) { + if (module.childDegree() > 1) + ++numNonTrivialTopModules; + } + return numNonTrivialTopModules; +} + +unsigned int InfomapBase::calculateMaxDepth() const +{ + unsigned int maxDepth = 0; + for (auto it(m_root.begin_tree()); !it.isEnd(); ++it) { + if (it->isLeaf()) { + maxDepth = std::max(maxDepth, it.depth()); + } + } + return maxDepth; +} + +unsigned int InfomapBase::findHierarchicalSuperModulesFast(unsigned int superLevelLimit) +{ + if (superLevelLimit == 0) + return 0; + + unsigned int numLevelsCreated = 0; + double oldIndexLength = getIndexCodelength(); + double hierarchicalCodelength = getCodelength(); + double workingHierarchicalCodelength = hierarchicalCodelength; + + Log(1) << "\nFind hierarchical super modules iteratively...\n"; + Log(0, 0) << "Fast super-level compression: " << std::setprecision(2) << std::flush; + + // Add index codebooks as long as the code gets shorter + do { + Log(1) << "Iteration " << numLevelsCreated + 1 << ", finding super modules fast to " << numTopModules() << (haveModules() ? " modules" : " nodes") << "... \n"; + + if (haveModules()) { + setActiveNetworkFromChildrenOfRoot(); + transformNodeFlowToEnterFlow(m_root); + initSuperNetwork(); + } else { + setActiveNetworkFromLeafs(); + } + + initPartition(); + + unsigned int numEffectiveLoops = optimizeActiveNetwork(); + + double codelength = getCodelength(); + double indexCodelength = getIndexCodelength(); + unsigned int numSuperModules = numActiveModules(); + bool trivialSolution = numSuperModules == 1 || numSuperModules == activeNetwork().size(); + + bool acceptSolution = !trivialSolution && codelength < oldIndexLength - minimumCodelengthImprovement; + // Force at least one modular level! + bool acceptByForce = !acceptSolution && !haveModules(); + if (acceptByForce) + acceptSolution = true; + + workingHierarchicalCodelength += codelength - oldIndexLength; + + Log(0, 0) << hideIf(!acceptSolution) << ((hierarchicalCodelength - workingHierarchicalCodelength) / hierarchicalCodelength * 100) << "% " << std::flush; + Log(1) << " -> Found " << numActiveModules() << " super modules in " << numEffectiveLoops << " effective loops with hierarchical codelength " << indexCodelength << " + " << (workingHierarchicalCodelength - indexCodelength) << " = " << workingHierarchicalCodelength << (acceptSolution ? "\n" : ", discarding the solution.\n") << std::flush; + Log(1) << oldIndexLength << " -> " << *this << "\n"; + + if (!acceptSolution) { + restoreConsolidatedOptimizationPointIfNoImprovement(true); + break; + } + + // Consolidate the dynamic modules without replacing any existing ones. + consolidateModules(false); + + hierarchicalCodelength = workingHierarchicalCodelength; + oldIndexLength = indexCodelength; + + ++numLevelsCreated; + + m_numNonTrivialTopModules = calculateNumNonTrivialTopModules(); + + } while (m_numNonTrivialTopModules > 1 && numLevelsCreated != superLevelLimit); + + // Restore the temporary transformation of flow to enter flow on super modules + resetFlowOnModules(); + + Log(0, 0) << "to codelength " << io::toPrecision(hierarchicalCodelength) << " in " << numTopModules() << " top modules.\n"; + Log(1) << "Finding super modules done! Added " << numLevelsCreated << " levels with hierarchical codelength " << io::toPrecision(hierarchicalCodelength) << " in " << numTopModules() << " top modules.\n"; + + // Calculate and store hierarchical codelengths + m_hierarchicalCodelength = calcCodelengthOnTree(root(), true); + + return numLevelsCreated; +} + +unsigned int InfomapBase::findHierarchicalSuperModules(unsigned int superLevelLimit) +{ + if (superLevelLimit == 0) + return 0; + + unsigned int numLevelsCreated = 0; + double oldIndexLength = getIndexCodelength(); + double hierarchicalCodelength = getCodelength(); + double workingHierarchicalCodelength = hierarchicalCodelength; + + if (!haveModules()) + throw std::logic_error("Trying to find hierarchical super modules without any modules"); + + Log(1) << "\nFind hierarchical super modules iteratively...\n"; + Log(0, 0) << "Super-level compression: " << std::setprecision(2) << std::flush; + + // Add index codebooks as long as the code gets shorter + do { + Log(1) << "Iteration " << numLevelsCreated + 1 << ", finding super modules to " << numTopModules() << " modules... \n"; + bool isSilent = false; + if (isMainInfomap()) { + isSilent = Log::isSilent(); + Log::setSilent(true); + } + InfoNode tmp(m_root.data); // Temporary owner for the super Infomap instance + auto& superInfomap = getSuperInfomap(tmp) + .setTwoLevel(true); + superInfomap.initNetwork(m_root, true); //.initSuperNetwork(); + superInfomap.run(); + if (isMainInfomap()) { + Log::setSilent(isSilent); + } + double superCodelength = superInfomap.getCodelength(); + double superIndexCodelength = superInfomap.getIndexCodelength(); + + unsigned int numSuperModules = superInfomap.numTopModules(); + bool trivialSolution = numSuperModules == 1 || numSuperModules == numTopModules(); + + if (trivialSolution) { + Log(1) << "failed to find non-trivial super modules.\n"; + break; + } + + bool improvedCodelength = superCodelength < oldIndexLength - minimumCodelengthImprovement; + if (!improvedCodelength) { + Log(1) << "two-level index codebook not improved over one-level.\n"; + break; + } + + workingHierarchicalCodelength += superCodelength - oldIndexLength; + + Log(0, 0) << ((hierarchicalCodelength - workingHierarchicalCodelength) + / hierarchicalCodelength * 100) + << "% " << std::flush; + Log(1) << " -> Found " << numSuperModules << " super modules in with hierarchical codelength " << superIndexCodelength << " + " << (superCodelength - superIndexCodelength) << " + " << (workingHierarchicalCodelength - superCodelength) << " = " << workingHierarchicalCodelength << '\n'; + + // Merge current top modules to two-level solution found in the super Infomap instance. + std::vector modules(numTopModules()); + unsigned int iModule = 0; + for (InfoNode* n : superInfomap.leafNodes()) { + modules[iModule++] = n->index; + } + + setActiveNetworkFromChildrenOfRoot(); + initPartition(); + // Move top modules to super modules + moveActiveNodesToPredefinedModules(modules); + + // Consolidate the dynamic modules without replacing any existing ones. + consolidateModules(false); + + Log(1) << "Consolidated " << numTopModules() << " super modules. Index codelength: " << oldIndexLength << " -> " << *this << "\n"; + + hierarchicalCodelength = workingHierarchicalCodelength; + oldIndexLength = superIndexCodelength; + + ++numLevelsCreated; + + m_numNonTrivialTopModules = calculateNumNonTrivialTopModules(); + + } while (m_numNonTrivialTopModules > 1 && numLevelsCreated != superLevelLimit); + + // Restore the temporary transformation of flow to enter flow on super modules + resetFlowOnModules(); + + Log(0, 0) << "to codelength " << io::toPrecision(hierarchicalCodelength) << " in " << numTopModules() << " top modules.\n"; + Log(1) << "Finding super modules done! Added " << numLevelsCreated << " levels with hierarchical codelength " << io::toPrecision(hierarchicalCodelength) << " in " << numTopModules() << " top modules.\n"; + + // Calculate and store hierarchical codelengths + m_hierarchicalCodelength = calcCodelengthOnTree(root(), true); + + return numLevelsCreated; +} + +void InfomapBase::transformNodeFlowToEnterFlow(InfoNode& parent) +{ + double sumFlow = 0.0; + for (auto& module : m_root) { + module.data.flow = module.data.enterFlow; + sumFlow += module.data.flow; + } + parent.data.flow = sumFlow; +} + +void InfomapBase::resetFlowOnModules() +{ + // Reset flow on all modules + for (auto& module : m_root.infomapTree()) { + if (!module.isLeaf()) + module.data.flow = 0.0; + } + // Aggregate flow from leaf nodes up in the tree + for (InfoNode* n : m_leafNodes) { + double leafNodeFlow = n->data.flow; + InfoNode* module = n->parent; + do { + module->data.flow += leafNodeFlow; + module = module->parent; + } while (module != nullptr); + } +} + +unsigned int InfomapBase::removeModules() +{ + unsigned int numLevelsDeleted = 0; + while (numLevels() > 1) { + m_root.replaceChildrenWithGrandChildren(); + ++numLevelsDeleted; + } + if (numLevelsDeleted > 0) { + Log(2) << "Removed " << numLevelsDeleted << " levels of modules.\n"; + } + return numLevelsDeleted; +} + +unsigned int InfomapBase::removeSubModules(bool recalculateCodelengthOnTree) +{ + unsigned int numLevelsDeleted = 0; + while (numLevels() > 2) { + for (InfoNode& module : m_root) + module.replaceChildrenWithGrandChildren(); + ++numLevelsDeleted; + } + if (numLevelsDeleted > 0) { + Log(2) << "Removed " << numLevelsDeleted << " levels of sub-modules.\n"; + if (recalculateCodelengthOnTree) + calcCodelengthOnTree(root(), false); + } + return numLevelsDeleted; +} + +unsigned int InfomapBase::recursivePartition() +{ + double indexCodelength = getIndexCodelength(); + double hierarchicalCodelength = m_hierarchicalCodelength; + + Log(0, 0) << "\nRecursive sub-structure compression: " << std::flush; + + PartitionQueue partitionQueue; + if (fastHierarchicalSolution > 0) { + queueLeafModules(partitionQueue); + Log(1) << "\nFind sub modules recursively from " << partitionQueue.size() << " sub modules on level " << numLevels() - 2; + } else { + queueTopModules(partitionQueue); + Log(1) << "\nFind sub modules recursively from " << partitionQueue.size() << " top modules"; + double moduleCodelength = 0.0; + for (auto& module : m_root) + moduleCodelength += module.codelength; + hierarchicalCodelength = indexCodelength + moduleCodelength; + } + Log(1) << " with codelength: " << indexCodelength << " + " << (hierarchicalCodelength - indexCodelength) << " = " << io::toPrecision(hierarchicalCodelength) << '\n'; + + double sumConsolidatedCodelength = hierarchicalCodelength - partitionQueue.moduleCodelength; + + bool isSilent = false; + if (isMainInfomap()) { + isSilent = Log::isSilent(); + } + + while (partitionQueue.size() > 0) { + Log(1) << "Level " << partitionQueue.level << ": " << (partitionQueue.flow * 100) << "% of the flow in " << partitionQueue.size() << " modules. Partitioning... " << std::setprecision(6) << std::flush; + + if (isMainInfomap()) + Log::setSilent(true); + + // Partition all modules in the queue and fill up the next level queue + PartitionQueue nextLevelQueue; + processPartitionQueue(partitionQueue, nextLevelQueue); + + if (isMainInfomap()) + Log::setSilent(isSilent); + + double leftToImprove = partitionQueue.moduleCodelength; + sumConsolidatedCodelength += partitionQueue.indexCodelength + partitionQueue.leafCodelength; + double limitCodelength = sumConsolidatedCodelength + leftToImprove; + + Log(0, 0) << ((hierarchicalCodelength - limitCodelength) / hierarchicalCodelength) * 100 << "% " << std::flush; + Log(1) << "done! Codelength: " << partitionQueue.indexCodelength << " + " << partitionQueue.leafCodelength << " (+ " << leftToImprove << " left to improve)" + << " -> limit: " << io::toPrecision(limitCodelength) << " bits.\n"; + + hierarchicalCodelength = limitCodelength; + + partitionQueue.swap(nextLevelQueue); + } + + // Store resulting hierarchical codelength + m_hierarchicalCodelength = hierarchicalCodelength; + + Log(0, 0) << ". Found " << partitionQueue.level << " levels with codelength " << io::toPrecision(hierarchicalCodelength) << "\n"; + Log(1) << " -> Found " << partitionQueue.level << " levels with codelength " << io::toPrecision(hierarchicalCodelength) << "\n"; + + return partitionQueue.level; +} + +void InfomapBase::queueTopModules(PartitionQueue& partitionQueue) +{ + // Add modules to partition queue + unsigned int numNonTrivialModules = 0; + partitionQueue.resize(numTopModules()); + double sumFlow = 0.0; + double sumNonTrivialFlow = 0.0; + double sumModuleCodelength = 0.0; + unsigned int moduleIndex = 0; + for (auto& module : m_root) { + partitionQueue[moduleIndex] = &module; + sumFlow += module.data.flow; + sumModuleCodelength += module.codelength; + if (module.childDegree() > 1) { + ++numNonTrivialModules; + sumNonTrivialFlow += module.data.flow; + } + ++moduleIndex; + } + partitionQueue.flow = sumFlow; + partitionQueue.numNonTrivialModules = numNonTrivialModules; + partitionQueue.nonTrivialFlow = sumNonTrivialFlow; + partitionQueue.indexCodelength = getIndexCodelength(); + partitionQueue.moduleCodelength = sumModuleCodelength; + partitionQueue.level = 1; +} + +void InfomapBase::queueLeafModules(PartitionQueue& partitionQueue) +{ + unsigned int numLeafModules = 0; + for (auto& node : m_root.infomapTree()) { + if (node.isLeafModule()) + ++numLeafModules; + } + + // Add modules to partition queue + partitionQueue.resize(numLeafModules); + unsigned int numNonTrivialModules = 0; + double sumFlow = 0.0; + double sumNonTrivialFlow = 0.0; + double sumModuleCodelength = 0.0; + unsigned int moduleIndex = 0; + unsigned int maxDepth = 0; + for (auto it = m_root.begin_tree(); !it.isEnd(); ++it) { + if (it->isLeafModule()) { + auto& module = *it; + partitionQueue[moduleIndex] = it.current(); + sumFlow += module.data.flow; + sumModuleCodelength += module.codelength; + if (module.childDegree() > 1) { + ++numNonTrivialModules; + sumNonTrivialFlow += module.data.flow; + } + maxDepth = std::max(maxDepth, it.depth()); + ++moduleIndex; + } + } + partitionQueue.flow = sumFlow; + partitionQueue.numNonTrivialModules = numNonTrivialModules; + partitionQueue.nonTrivialFlow = sumNonTrivialFlow; + partitionQueue.indexCodelength = getIndexCodelength(); + partitionQueue.moduleCodelength = sumModuleCodelength; + partitionQueue.level = maxDepth; +} + +bool InfomapBase::processPartitionQueue(PartitionQueue& queue, PartitionQueue& nextLevelQueue) const +{ + PartitionQueue::size_t numModules = queue.size(); + std::vector indexCodelengths(numModules, 0.0); + std::vector moduleCodelengths(numModules, 0.0); + std::vector leafCodelengths(numModules, 0.0); + std::vector subQueues(numModules); + +#pragma omp parallel for schedule(dynamic) + for (PartitionQueue::size_t moduleIndex = 0; moduleIndex < numModules; ++moduleIndex) { + InfoNode& module = *queue[moduleIndex]; + + module.codelength = calcCodelength(module); + // Delete former sub-structure if exists + if (module.disposeInfomap()) + module.codelength = calcCodelength(module); + + // If only trivial substructure is to be found, no need to create infomap instance to find sub-module structures. + if (module.childDegree() <= 2) { + module.codelength = calcCodelength(module); + leafCodelengths[moduleIndex] = module.codelength; + continue; + } + + double oldModuleCodelength = module.codelength; + PartitionQueue& subQueue = subQueues[moduleIndex]; + subQueue.level = queue.level + 1; + + auto& subInfomap = getSubInfomap(module) + .initNetwork(module); + // Run two-level partition + find hierarchically super modules (skip recursion) + subInfomap.setOnlySuperModules(true).run(); + + double subCodelength = subInfomap.getHierarchicalCodelength(); + double subIndexCodelength = subInfomap.root().codelength; + double subModuleCodelength = subCodelength - subIndexCodelength; + InfoNode& subRoot = *module.getInfomapRoot(); + unsigned int numSubModules = subRoot.childDegree(); + bool trivialSubPartition = numSubModules == 1 || numSubModules == module.childDegree(); + bool improvedCodelength = subCodelength < oldModuleCodelength - minimumCodelengthImprovement; + + if (trivialSubPartition || !improvedCodelength) { + Log(1) << "Disposing unaccepted sub Infomap instance.\n"; + module.disposeInfomap(); + module.codelength = oldModuleCodelength; + subQueue.skip = true; + leafCodelengths[moduleIndex] = module.codelength; + } else { + // Improvement + subInfomap.queueTopModules(subQueue); + indexCodelengths[moduleIndex] = subIndexCodelength; + moduleCodelengths[moduleIndex] = subModuleCodelength; + } + } + + double sumLeafCodelength = 0.0; + double sumIndexCodelength = 0.0; + double sumModuleCodelengths = 0.0; + PartitionQueue::size_t nextLevelSize = 0; + for (PartitionQueue::size_t moduleIndex = 0; moduleIndex < numModules; ++moduleIndex) { + nextLevelSize += subQueues[moduleIndex].skip ? 0 : subQueues[moduleIndex].size(); + sumLeafCodelength += leafCodelengths[moduleIndex]; + sumIndexCodelength += indexCodelengths[moduleIndex]; + sumModuleCodelengths += moduleCodelengths[moduleIndex]; + } + + queue.indexCodelength = sumIndexCodelength; + queue.leafCodelength = sumLeafCodelength; + queue.moduleCodelength = sumModuleCodelengths; + + // Collect the sub-queues and build the next-level queue + nextLevelQueue.level = queue.level + 1; + nextLevelQueue.resize(nextLevelSize); + PartitionQueue::size_t nextLevelIndex = 0; + for (PartitionQueue::size_t moduleIndex = 0; moduleIndex < numModules; ++moduleIndex) { + PartitionQueue& subQueue = subQueues[moduleIndex]; + if (!subQueue.skip) { + for (PartitionQueue::size_t subIndex = 0; subIndex < subQueue.size(); ++subIndex) { + nextLevelQueue[nextLevelIndex++] = subQueue[subIndex]; + } + nextLevelQueue.flow += subQueue.flow; + nextLevelQueue.nonTrivialFlow += subQueue.nonTrivialFlow; + nextLevelQueue.numNonTrivialModules += subQueue.numNonTrivialModules; + } + } + + return nextLevelSize > 0; +} + +// =================================================== +// Write output +// =================================================== + +void InfomapBase::writeResult(int trial) +{ + if (noFileOutput) + return; + + io::Str s; + s << outDirectory + outName; + + if (printAllTrials && trial != -1 && numTrials > 1) { + s << "_trial_" << trial; + } + + std::string basename = s; + + if (printTree) { + std::string filename = basename + ".tree"; + + if (!printStates()) { + Log() << "Write tree to " << filename << "... "; + writeTree(filename); + Log() << "done!\n"; + } else { + // Write both physical and state level + Log() << "Write physical tree to " << filename << "... "; + writeTree(filename); + Log() << "done!\n"; + std::string filenameStates = basename + "_states.tree"; + Log() << "Write state tree to " << filenameStates << "... "; + writeTree(filenameStates, true); + Log() << "done!\n"; + } + } + + if (printFlowTree) { + std::string filename = basename + ".ftree"; + + if (!printStates()) { + Log() << "Write flow tree to " << filename << "... "; + writeFlowTree(filename); + Log() << "done!\n"; + } else { + // Write both physical and state level + Log() << "Write physical flow tree to " << filename << "... "; + writeFlowTree(filename, false); + Log() << "done!\n"; + std::string filenameStates = basename + "_states.ftree"; + Log() << "Write state flow tree to " << filenameStates << "... "; + writeFlowTree(filenameStates, true); + Log() << "done!\n"; + } + } + + if (printNewick) { + std::string filename = basename + ".nwk"; + + if (!printStates()) { + Log() << "Write Newick tree to " << filename << "... "; + writeNewickTree(filename); + Log() << "done!\n"; + } else { + // Write both physical and state level + Log() << "Write physical Newick tree to " << filename << "... "; + writeNewickTree(filename, false); + Log() << "done!\n"; + std::string filenameStates = basename + "_states.nwk"; + Log() << "Write state Newick tree to " << filenameStates << "... "; + writeNewickTree(filenameStates, true); + Log() << "done!\n"; + } + } + + if (printJson) { + std::string filename = basename + ".json"; + const bool writeLinks = false; + + if (!printStates()) { + Log() << "Write JSON tree to " << filename << "... "; + writeJsonTree(filename, false, writeLinks); + Log() << "done!\n"; + } else { + // Write both physical and state level + Log() << "Write physical JSON tree to " << filename << "... "; + writeJsonTree(filename, false, writeLinks); + Log() << "done!\n"; + std::string filenameStates = basename + "_states.json"; + Log() << "Write state JSON tree to " << filenameStates << "... "; + writeJsonTree(filenameStates, true, writeLinks); + Log() << "done!\n"; + } + } + + if (printCsv) { + std::string filename = basename + ".csv"; + + if (!printStates()) { + Log() << "Write CSV tree to " << filename << "... "; + writeCsvTree(filename); + Log() << "done!\n"; + } else { + // Write both physical and state level + Log() << "Write physical CSV tree to " << filename << "... "; + writeCsvTree(filename, false); + Log() << "done!\n"; + std::string filenameStates = basename + "_states.csv"; + Log() << "Write state CSV tree to " << filenameStates << "... "; + writeCsvTree(filenameStates, true); + Log() << "done!\n"; + } + } + + if (printClu) { + std::string filename = basename + ".clu"; + if (!printStates()) { + Log() << "Write node modules to " << filename << "... "; + writeClu(filename, false, cluLevel); + Log() << "done!\n"; + } else { + // Write both physical and state level + Log() << "Write physical node modules to " << filename << "... "; + writeClu(filename, false, cluLevel); + Log() << "done!\n"; + std::string filenameStates = basename + "_states.clu"; + Log() << "Write state node modules to " << filenameStates << "... "; + writeClu(filenameStates, true, cluLevel); + Log() << "done!\n"; + } + } +} + +unsigned int printPerLevelCodelength(const InfoNode& parent, std::ostream& out) +{ + std::vector perLevelStats; + aggregatePerLevelCodelength(parent, perLevelStats); + + unsigned int numLevels = perLevelStats.size(); + + out << "Per level number of modules: ["; + for (unsigned int i = 0; i < numLevels - 1; ++i) { + out << io::padValue(perLevelStats[i].numModules, 11) << ", "; + } + out << io::padValue(perLevelStats[numLevels - 1].numModules, 11) << "]"; + unsigned int sumNumModules = 0; + for (unsigned int i = 0; i < numLevels; ++i) + sumNumModules += perLevelStats[i].numModules; + out << " (sum: " << sumNumModules << ")\n"; + + out << "Per level number of leaf nodes: ["; + for (unsigned int i = 0; i < numLevels - 1; ++i) { + out << io::padValue(perLevelStats[i].numLeafNodes, 11) << ", "; + } + out << io::padValue(perLevelStats[numLevels - 1].numLeafNodes, 11) << "]"; + unsigned int sumNumLeafNodes = 0; + for (unsigned int i = 0; i < numLevels; ++i) + sumNumLeafNodes += perLevelStats[i].numLeafNodes; + out << " (sum: " << sumNumLeafNodes << ")\n"; + + out << "Per level average child degree: ["; + double childDegree = perLevelStats[0].numNodes(); + double sumAverageChildDegree = childDegree * childDegree; + if (numLevels > 1) { + out << io::padValue(perLevelStats[0].numModules, 11) << ", "; + } + for (unsigned int i = 1; i < numLevels - 1; ++i) { + childDegree = perLevelStats[i].numNodes() * 1.0 / perLevelStats[i - 1].numModules; + sumAverageChildDegree += childDegree * perLevelStats[i].numNodes(); + out << io::padValue(childDegree, 11) << ", "; + } + if (numLevels > 1) { + childDegree = perLevelStats[numLevels - 1].numNodes() * 1.0 / perLevelStats[numLevels - 2].numModules; + sumAverageChildDegree += childDegree * perLevelStats[numLevels - 1].numNodes(); + } + out << io::padValue(childDegree, 11) << "]"; + out << " (average: " << sumAverageChildDegree / (sumNumModules + sumNumLeafNodes) << ")\n"; + + out << std::fixed << std::setprecision(9); + out << "Per level codelength for modules: ["; + for (unsigned int i = 0; i < numLevels - 1; ++i) { + out << perLevelStats[i].indexLength << ", "; + } + out << perLevelStats[numLevels - 1].indexLength << "]"; + double sumIndexLengths = 0.0; + for (unsigned int i = 0; i < numLevels; ++i) + sumIndexLengths += perLevelStats[i].indexLength; + out << " (sum: " << sumIndexLengths << ")\n"; + + out << "Per level codelength for leaf nodes: ["; + for (unsigned int i = 0; i < numLevels - 1; ++i) { + out << perLevelStats[i].leafLength << ", "; + } + out << perLevelStats[numLevels - 1].leafLength << "]"; + + double sumLeafLengths = 0.0; + for (unsigned int i = 0; i < numLevels; ++i) + sumLeafLengths += perLevelStats[i].leafLength; + out << " (sum: " << sumLeafLengths << ")\n"; + + out << "Per level codelength total: ["; + for (unsigned int i = 0; i < numLevels - 1; ++i) { + out << perLevelStats[i].codelength() << ", "; + } + out << perLevelStats[numLevels - 1].codelength() << "]"; + + double sumCodelengths = 0.0; + for (unsigned int i = 0; i < numLevels; ++i) + sumCodelengths += perLevelStats[i].codelength(); + out << " (sum: " << sumCodelengths << ")\n"; + + return numLevels; +} + +void aggregatePerLevelCodelength(const InfoNode& parent, std::vector& perLevelStat, unsigned int level) +{ + if (perLevelStat.size() < level + 1) + perLevelStat.resize(level + 1); + + if (parent.firstChild->isLeaf()) { + perLevelStat[level].numLeafNodes += parent.childDegree(); + perLevelStat[level].leafLength += parent.codelength; + return; + } + + perLevelStat[level].numModules += parent.childDegree(); + perLevelStat[level].indexLength += parent.codelength; + + for (auto& module : parent) { + if (module.getInfomapRoot() != nullptr) + aggregatePerLevelCodelength(*module.getInfomapRoot(), perLevelStat, level + 1); + else + aggregatePerLevelCodelength(module, perLevelStat, level + 1); + } +} + +void InfomapBase::initOptimizer(bool forceNoMemory) +{ + if (haveMetaData()) { + m_optimizer = std::make_unique>(); + } else if (haveMemory() && !forceNoMemory) { + m_optimizer = std::make_unique>(); + } else { + m_optimizer = std::make_unique>(); + } + m_optimizer->init(this); +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/core/InfomapBase.h b/src/vendor/cigraph/vendor/infomap/src/core/InfomapBase.h new file mode 100644 index 00000000000..4c8a13293e7 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/InfomapBase.h @@ -0,0 +1,586 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef INFOMAP_BASE_H_ +#define INFOMAP_BASE_H_ + +#include "InfomapConfig.h" +#include "InfoEdge.h" +#include "InfoNode.h" +#include "InfomapOptimizerBase.h" +#include "iterators/InfomapIterator.h" +#include "../io/ClusterMap.h" +#include "../io/Network.h" +#include "../io/Output.h" +#include "../utils/Log.h" +#include "../utils/Date.h" +#include "../utils/Stopwatch.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace infomap { + +namespace detail { + class PartitionQueue; + struct PerLevelStat; +} // namespace detail + +class InfomapBase : public InfomapConfig { + template + friend class InfomapOptimizer; + + void initOptimizer(bool forceNoMemory = false); + +public: + using PartitionQueue = detail::PartitionQueue; + + InfomapBase() : InfomapConfig() { initOptimizer(); } + + explicit InfomapBase(const Config& conf) : InfomapConfig(conf), m_network(conf) { initOptimizer(); } + + explicit InfomapBase(const std::string& flags, bool isCli = false) : InfomapConfig(flags, isCli) + { + initOptimizer(); + m_network.setConfig(*this); + m_initialParameters = m_currentParameters = flags; + } + + virtual ~InfomapBase() = default; + + // =================================================== + // Iterators + // =================================================== + + InfomapIterator iterTree(int maxClusterLevel = 1) { return { &root(), maxClusterLevel }; } + + InfomapIteratorPhysical iterTreePhysical(int maxClusterLevel = 1) { return { &root(), maxClusterLevel }; } + + InfomapModuleIterator iterModules(int maxClusterLevel = 1) { return { &root(), maxClusterLevel }; } + + InfomapLeafModuleIterator iterLeafModules(int maxClusterLevel = 1) { return { &root(), maxClusterLevel }; } + + InfomapLeafIterator iterLeafNodes(int maxClusterLevel = 1) { return { &root(), maxClusterLevel }; } + + InfomapLeafIteratorPhysical iterLeafNodesPhysical(int maxClusterLevel = 1) { return { &root(), maxClusterLevel }; } + + InfomapIterator begin(int maxClusterLevel = 1) { return { &root(), maxClusterLevel }; } + + InfomapIterator end() const { return InfomapIterator(nullptr); } + + // =================================================== + // Getters + // =================================================== + + Network& network() { return m_network; } + const Network& network() const { return m_network; } + + InfoNode& root() { return m_root; } + const InfoNode& root() const { return m_root; } + + unsigned int numLeafNodes() const { return m_leafNodes.size(); } + + const std::vector& leafNodes() const { return m_leafNodes; } + + unsigned int numTopModules() const { return m_root.childDegree(); } + + unsigned int numActiveModules() const { return m_optimizer->numActiveModules(); } + + unsigned int numNonTrivialTopModules() const { return m_numNonTrivialTopModules; } + + bool haveModules() const { return !m_root.isLeaf() && !m_root.firstChild->isLeaf(); } + + bool haveNonTrivialModules() const { return numNonTrivialTopModules() > 0; } + + /** + * Number of node levels below the root in current Infomap instance, 1 if no modules + */ + unsigned int numLevels() const; + + /** + * Get maximum depth of any child in the tree, following possible sub Infomap instances + */ + unsigned int maxTreeDepth() const; + + double getCodelength() const { return m_optimizer->getCodelength(); } + + double getMetaCodelength(bool unweighted = false) const { return m_optimizer->getMetaCodelength(unweighted); } + + double codelength() const { return m_hierarchicalCodelength; } + + const std::vector& codelengths() const { return m_codelengths; } + + double getIndexCodelength() const { return m_optimizer->getIndexCodelength(); } + + double getModuleCodelength() const { return m_hierarchicalCodelength - m_optimizer->getIndexCodelength(); } + + double getHierarchicalCodelength() const { return m_hierarchicalCodelength; } + + double getOneLevelCodelength() const { return m_oneLevelCodelength; } + + double getRelativeCodelengthSavings() const + { + auto oneLevelCodelength = getOneLevelCodelength(); + return oneLevelCodelength < 1e-16 ? 0 : 1.0 - codelength() / oneLevelCodelength; + } + + double getEntropyRate() { return m_entropyRate; } + double getMaxEntropy() { return m_maxEntropy; } + double getMaxFlow() { return m_maxFlow; } + + const Date& getStartDate() const { return m_startDate; } + const Stopwatch& getElapsedTime() const { return m_elapsedTime; } + + std::vector& activeNetwork() const { return *m_activeNetwork; } + + std::map> getMultilevelModules(bool states = false); + + // =================================================== + // IO + // =================================================== + + std::ostream& toString(std::ostream& out) const { return m_optimizer->toString(out); } + + // =================================================== + // Run + // =================================================== + + using InitialPartition = std::map; + + const InitialPartition& getInitialPartition() const { return m_initialPartition; } + + InfomapBase& setInitialPartition(const InitialPartition& moduleIds) + { + m_initialPartition = moduleIds; + return *this; + } + + void run(const std::string& parameters = ""); + + void run(Network& network); + +private: + bool isFullNetwork() const { return m_isMain && m_aggregationLevel == 0; } + bool isFirstLoop() const { return m_tuneIterationIndex == 0 && isFullNetwork(); } + + InfomapBase* getNewInfomapInstance() const { return new InfomapBase(getConfig()); } + InfomapBase* getNewInfomapInstanceWithoutMemory() const + { + auto im = new InfomapBase(); + im->initOptimizer(true); + return im; + } + + InfomapBase& getSubInfomap(InfoNode& node) const + { + return node.setInfomap(getNewInfomapInstance()) + .setIsMain(false) + .setSubLevel(m_subLevel + 1) + .setNonMainConfig(*this); + } + + InfomapBase& getSuperInfomap(InfoNode& node) const + { + return node.setInfomap(getNewInfomapInstanceWithoutMemory()) + .setIsMain(false) + .setSubLevel(m_subLevel + SUPER_LEVEL_ADDITION) + .setNonMainConfig(*this); + } + + /** + * Only the main infomap reads an external cluster file if exist + */ + InfomapBase& setIsMain(bool isMain) + { + m_isMain = isMain; + return *this; + } + + InfomapBase& setSubLevel(unsigned int level) + { + m_subLevel = level; + return *this; + } + + bool isTopLevel() const { return (m_subLevel & (SUPER_LEVEL_ADDITION - 1)) == 0; } + + bool isSuperLevelOnTopLevel() const { return m_subLevel == SUPER_LEVEL_ADDITION; } + + bool isMainInfomap() const { return m_isMain; } + + bool haveHardPartition() const { return !m_originalLeafNodes.empty(); } + + // =================================================== + // Run: * + // =================================================== + + InfomapBase& initNetwork(Network& network); + InfomapBase& initNetwork(InfoNode& parent, bool asSuperNetwork = false); + + void generateSubNetwork(Network& network); + void generateSubNetwork(InfoNode& parent); + + /** + * Init categorical meta data on all nodes from a file with the following format: + * # nodeId metaData + * 1 1 + * 2 1 + * 3 2 + * 4 2 + * 5 3 + * + */ + InfomapBase& initMetaData(const std::string& metaDataFile); + + /** + * Provide an initial partition of the network. + * + * @param clusterDataFile A .clu file containing cluster data. + * @param hard If true, the provided clusters will not be splitted. This reduces the + * effective network size during the optimization phase but the hard partitions are + * after that replaced by the original nodes. + */ + InfomapBase& initPartition(const std::string& clusterDataFile, bool hard = false, const Network* network = nullptr); + + /** + * Provide an initial partition of the network. + * + * @param clusterIds map from nodeId to clusterId, doesn't have to be complete + * @param hard If true, the provided clusters will not be splitted. This reduces the + * effective network size during the optimization phase but the hard partitions are + * after that replaced by the original nodes. + */ + InfomapBase& initPartition(const std::map& clusterIds, bool hard = false); + + /** + * Provide an initial partition of the network. + * + * @param clusters Each sub-vector contain node IDs for all nodes that should be merged. + * @param hard If true, the provided clusters will not be splitted. This reduces the + * effective network size during the optimization phase but the hard partitions are + * after that replaced by the original nodes. + */ + InfomapBase& initPartition(std::vector>& clusters, bool hard = false); + + /** + * Provide an initial partition of the network. + * + * @param modules Module indices for each node + */ + InfomapBase& initPartition(std::vector& modules, bool hard = false); + + /** + * Provide an initial hierarchical partition of the network + * + * @param tree A tree path for each node + */ + InfomapBase& initTree(const NodePaths& tree); + + void init(); + + void runPartition() + { + if (twoLevel) + partition(); + else + hierarchicalPartition(); + } + + void restoreHardPartition(); + + void writeResult(int trial = -1); + + // =================================================== + // runPartition: * + // =================================================== + + void hierarchicalPartition(); + + void partition(); + + // =================================================== + // runPartition: init: * + // =================================================== + + /** + * Done in network? + */ + void initEnterExitFlow(); + + void aggregateFlowValuesFromLeafToRoot(); + + // Init terms that is constant for the whole network + void initTree() { return m_optimizer->initTree(); } + + void initNetwork() { return m_optimizer->initNetwork(); } + + void initSuperNetwork() { return m_optimizer->initSuperNetwork(); } + + double calcCodelength(const InfoNode& parent) const { return m_optimizer->calcCodelength(parent); } + + /** + * Calculate and store codelength on all modules in the tree + * @param includeRoot Also calculate the codelength on the root node + * @return the hierarchical codelength + */ + double calcCodelengthOnTree(InfoNode& root, bool includeRoot = true) const; + + // =================================================== + // Run: Partition: * + // =================================================== + + void setActiveNetworkFromLeafs() { m_activeNetwork = &m_leafNodes; } + + void setActiveNetworkFromChildrenOfRoot(); + + void initPartition() { return m_optimizer->initPartition(); } + + void findTopModulesRepeatedly(unsigned int maxLevels); + + unsigned int fineTune(); + + unsigned int coarseTune(); + + /** + * Return the number of effective core loops, i.e. not the last if not at coreLoopLimit + */ + unsigned int optimizeActiveNetwork() { return m_optimizer->optimizeActiveNetwork(); } + + void moveActiveNodesToPredefinedModules(std::vector& modules) + { + return m_optimizer->moveActiveNodesToPredefinedModules(modules); + } + + void consolidateModules(bool replaceExistingModules = true) + { + return m_optimizer->consolidateModules(replaceExistingModules); + } + + unsigned int calculateNumNonTrivialTopModules() const; + + unsigned int calculateMaxDepth() const; + + // =================================================== + // Partition: findTopModulesRepeatedly: * + // =================================================== + + /** + * Return true if restored to consolidated optimization state + */ + bool restoreConsolidatedOptimizationPointIfNoImprovement(bool forceRestore = false) + { + return m_optimizer->restoreConsolidatedOptimizationPointIfNoImprovement(forceRestore); + } + + // =================================================== + // Run: Hierarchical Partition: * + // =================================================== + + /** + * Find super modules applying the whole two-level algorithm on the + * top modules iteratively + * @param levelLimit The maximum number of super module levels allowed + * @return number of levels created + */ + unsigned int findHierarchicalSuperModules(unsigned int superLevelLimit = std::numeric_limits::max()); + + /** + * Find super modules fast by merge and consolidate top modules iteratively + * @param levelLimit The maximum number of super module levels allowed + * @return number of levels created + */ + unsigned int findHierarchicalSuperModulesFast(unsigned int superLevelLimit = std::numeric_limits::max()); + + void transformNodeFlowToEnterFlow(InfoNode& parent); + + void resetFlowOnModules(); + + unsigned int removeModules(); + + unsigned int removeSubModules(bool recalculateCodelengthOnTree); + + unsigned int recursivePartition(); + + void queueTopModules(PartitionQueue& partitionQueue); + + void queueLeafModules(PartitionQueue& partitionQueue); + + bool processPartitionQueue(PartitionQueue& queue, PartitionQueue& nextLevel) const; + +public: + // =================================================== + // Output: * + // =================================================== + + /** + * Write tree to a .tree file. + * @param filename the filename for the output file. If empty, use default + * based on output directory and input file name + * @param states if memory network, print the state-level network without merging physical nodes within modules + * @return the filename written to + */ + std::string writeTree(const std::string& filename = "", bool states = false) { return infomap::writeTree(*this, m_network, filename, states); } + + /** + * Write flow tree to a .ftree file. + * This is the same as a .tree file but appended with links aggregated + * within modules on all levels in the tree + * @param filename the filename for the output file. If empty, use default + * based on output directory and input file name + * @param states if memory network, print the state-level network without merging physical nodes within modules + * @return the filename written to + */ + std::string writeFlowTree(const std::string& filename = "", bool states = false) { return infomap::writeFlowTree(*this, m_network, filename, states); } + + /** + * Write Newick tree to a .tre file. + * @param filename the filename for the output file. If empty, use default + * based on output directory and input file name + * @param states if memory network, print the state-level network without merging physical nodes within modules + * @return the filename written to + */ + std::string writeNewickTree(const std::string& filename = "", bool states = false) { return infomap::writeNewickTree(*this, filename, states); } + + std::string writeJsonTree(const std::string& filename = "", bool states = false, bool writeLinks = false) { return infomap::writeJsonTree(*this, m_network, filename, states, writeLinks); } + + std::string writeCsvTree(const std::string& filename = "", bool states = false) { return infomap::writeCsvTree(*this, m_network, filename, states); } + + /** + * Write tree to a .clu file. + * @param filename the filename for the output file. If empty, use default + * based on output directory and input file name + * @param states if memory network, print the state-level network without merging physical nodes within modules + * @param moduleIndexLevel the depth from the root on which to advance module index. + * Value 1 (default) will give the module index on the coarsest level, 2 the level below and so on. + * Value -1 will give the module index for the lowest level, i.e. the finest modular structure. + * @return the filename written to + */ + std::string writeClu(const std::string& filename = "", bool states = false, int moduleIndexLevel = 1) { return infomap::writeClu(*this, m_network, filename, states, moduleIndexLevel); } + +private: + +#if 0 + // =================================================== + // Debug: * + // =================================================== + + void printDebug() const { return m_optimizer->printDebug(); } +#endif + + // =================================================== + // Members + // =================================================== + +protected: + InfoNode m_root; + std::vector m_leafNodes; + std::vector m_moduleNodes; + std::vector* m_activeNetwork = nullptr; + + std::vector m_originalLeafNodes; + + Network m_network; + InitialPartition m_initialPartition = {}; // nodeId -> moduleId + + const unsigned int SUPER_LEVEL_ADDITION = 1 << 20; + bool m_isMain = true; + unsigned int m_subLevel = 0; + + bool m_calculateEnterExitFlow = false; + + double m_oneLevelCodelength = 0.0; + unsigned int m_numNonTrivialTopModules = 0; + unsigned int m_tuneIterationIndex = 0; + bool m_isCoarseTune = false; + unsigned int m_aggregationLevel = 0; + + double m_hierarchicalCodelength = 0.0; + std::vector m_codelengths; + double m_entropyRate = 0.0; + double m_maxEntropy = 0.0; + double m_maxFlow = 0.0; + + double m_sumDanglingFlow = 0.0; + + Date m_startDate; + Date m_endDate; + Stopwatch m_elapsedTime = Stopwatch(false); + std::string m_initialParameters; + std::string m_currentParameters; + + std::unique_ptr m_optimizer; +}; + +/** + * Print per level statistics + */ +unsigned int printPerLevelCodelength(const InfoNode& parent, std::ostream& out); + +void aggregatePerLevelCodelength(const InfoNode& parent, std::vector& perLevelStat, unsigned int level = 0); + +namespace detail { + + struct PerLevelStat { + double codelength() const { return indexLength + leafLength; } + + unsigned int numNodes() const { return numModules + numLeafNodes; } + + unsigned int numModules = 0; + unsigned int numLeafNodes = 0; + double indexLength = 0.0; + double leafLength = 0.0; + }; + + class PartitionQueue { + using PendingModule = InfoNode*; + + std::deque m_queue; + + public: + unsigned int level = 1; + unsigned int numNonTrivialModules = 0; + double flow = 0.0; + double nonTrivialFlow = 0.0; + bool skip = false; + double indexCodelength = 0.0; // Consolidated + double leafCodelength = 0.0; // Consolidated + double moduleCodelength = 0.0; // Left to improve on next level + + using size_t = std::deque::size_type; + + void swap(PartitionQueue& other) noexcept + { + std::swap(level, other.level); + std::swap(numNonTrivialModules, other.numNonTrivialModules); + std::swap(flow, other.flow); + std::swap(nonTrivialFlow, other.nonTrivialFlow); + std::swap(skip, other.skip); + std::swap(indexCodelength, other.indexCodelength); + std::swap(leafCodelength, other.leafCodelength); + std::swap(moduleCodelength, other.moduleCodelength); + m_queue.swap(other.m_queue); + } + + size_t size() const { return m_queue.size(); } + + void resize(size_t size) { m_queue.resize(size); } + + PendingModule& operator[](size_t i) { return m_queue[i]; } + }; + +} // namespace detail + +} // namespace infomap + +#endif // INFOMAP_BASE_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/InfomapConfig.h b/src/vendor/cigraph/vendor/infomap/src/core/InfomapConfig.h new file mode 100644 index 00000000000..e6ff0b898b8 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/InfomapConfig.h @@ -0,0 +1,137 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef INFOMAP_CONFIG_H_ +#define INFOMAP_CONFIG_H_ + +#include "../io/Config.h" +#include "../utils/Random.h" +#include "../utils/Log.h" +#include + +namespace infomap { + +template +class InfomapConfig : public Config { +public: + InfomapConfig() = default; + + InfomapConfig(const std::string& flags, bool isCli = false) : InfomapConfig(Config(flags, isCli)) { } + + InfomapConfig(const Config& conf) : Config(conf), m_rand(/* conf.seedToRandomNumberGenerator */) + { + Log::precision(conf.verboseNumberPrecision); + } + + virtual ~InfomapConfig() = default; + + InfomapConfig(const InfomapConfig&) = default; + InfomapConfig& operator=(const InfomapConfig&) = default; + InfomapConfig(InfomapConfig&&) noexcept = default; + InfomapConfig& operator=(InfomapConfig&&) noexcept = default; + +private: + Infomap& get() + { + return static_cast(*this); + } + +protected: + Random m_rand; + +public: + Config& getConfig() + { + return *this; + } + + const Config& getConfig() const + { + return *this; + } + + Infomap& setConfig(const Config& conf) + { + *this = conf; + /* m_rand.seed(conf.seedToRandomNumberGenerator); */ + Log::precision(conf.verboseNumberPrecision); + return get(); + } + + Infomap& setNonMainConfig(const Config& conf) + { + cloneAsNonMain(conf); + return get(); + } + + Infomap& setNumTrials(unsigned int N) + { + numTrials = N; + return get(); + } + + Infomap& setVerbosity(unsigned int level) + { + verbosity = level; + return get(); + } + + Infomap& setTwoLevel(bool value) + { + twoLevel = value; + return get(); + } + + Infomap& setTuneIterationLimit(unsigned int value) + { + tuneIterationLimit = value; + return get(); + } + + Infomap& setFastHierarchicalSolution(unsigned int level) + { + fastHierarchicalSolution = level; + return get(); + } + + Infomap& setOnlySuperModules(bool value) + { + onlySuperModules = value; + return get(); + } + + Infomap& setNoCoarseTune(bool value) + { + noCoarseTune = value; + return get(); + } + + Infomap& setNoInfomap(bool value = true) + { + noInfomap = value; + return get(); + } + + Infomap& setMarkovTime(double codeRate) + { + markovTime = codeRate; + return get(); + } + + Infomap& setDirected(bool value) + { + directed = value; + flowModel = directed ? FlowModel::directed : FlowModel::undirected; + return get(); + } +}; + +} // namespace infomap + +#endif // INFOMAP_CONFIG_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/InfomapOptimizer.h b/src/vendor/cigraph/vendor/infomap/src/core/InfomapOptimizer.h new file mode 100644 index 00000000000..29c683fc200 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/InfomapOptimizer.h @@ -0,0 +1,766 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef INFOMAP_OPTIMIZER_H_ +#define INFOMAP_OPTIMIZER_H_ + +#include "InfomapOptimizerBase.h" +#include "InfomapBase.h" +#include "../utils/VectorMap.h" +#include "../utils/infomath.h" +#include "InfoNode.h" +#include "FlowData.h" + +#include +#include + +namespace infomap { + +template +class InfomapOptimizer : public InfomapOptimizerBase { + using FlowDataType = FlowData; + using DeltaFlowDataType = typename Objective::DeltaFlowDataType; + +public: + void init(InfomapBase* infomap) override + { + m_infomap = infomap; + m_objective.init(infomap->getConfig()); + this->setInterruptionHandler(infomap->getConfig().interruptionHandler); + } + + // =================================================== + // IO + // =================================================== + + std::ostream& toString(std::ostream& out) const override { return out << m_objective; } + + // =================================================== + // Getters + // =================================================== + + double getCodelength() const override { return m_objective.getCodelength(); } + + double getIndexCodelength() const override { return m_objective.getIndexCodelength(); } + + double getModuleCodelength() const override { return m_objective.getModuleCodelength(); } + + double getMetaCodelength(bool unweighted = false) const override; + +protected: + unsigned int numActiveModules() const override { return m_infomap->activeNetwork().size() - m_emptyModules.size(); } + + // =================================================== + // Run: Init: * + // =================================================== + + // Init terms that is constant for the whole network + void initTree() override; + + void initNetwork() override; + + void initSuperNetwork() override; + + double calcCodelength(const InfoNode& parent) const override { return m_objective.calcCodelength(parent); } + + // =================================================== + // Run: Partition: * + // =================================================== + + void initPartition() override; + + void moveActiveNodesToPredefinedModules(std::vector& modules) override; + + bool moveNodeToPredefinedModule(InfoNode& current, unsigned int module); + + unsigned int optimizeActiveNetwork() override; + + unsigned int tryMoveEachNodeIntoBestModule() override; + + unsigned int tryMoveEachNodeIntoBestModuleInParallel() override; + + void consolidateModules(bool replaceExistingModules = true) override; + + bool restoreConsolidatedOptimizationPointIfNoImprovement(bool forceRestore = false) override; + +#if 0 + // =================================================== + // Debug: * + // =================================================== + + void printDebug() override { m_objective.printDebug(); } +#endif + + // =================================================== + // Protected members + // =================================================== + + InfomapBase* m_infomap = nullptr; + Objective m_objective; + Objective m_consolidatedObjective; + std::vector m_moduleFlowData; + std::vector m_moduleMembers; + std::vector m_emptyModules; +}; + +// =================================================== +// Getters +// =================================================== + +template <> +inline double InfomapOptimizer::getMetaCodelength(bool unweighted) const +{ + return m_objective.getMetaCodelength(unweighted); +} + +template +inline double InfomapOptimizer::getMetaCodelength(bool /*unweighted*/) const +{ + return 0.0; +} + +// =================================================== +// Run: Init: * +// =================================================== + +template +inline void InfomapOptimizer::initTree() +{ + Log(4) << "InfomapOptimizer::initTree()...\n"; + m_objective.initTree(m_infomap->root()); +} + +template +inline void InfomapOptimizer::initNetwork() +{ + Log(4) << "InfomapOptimizer::initNetwork()...\n"; + m_objective.initNetwork(m_infomap->root()); + + if (!m_infomap->isMainInfomap()) + m_objective.initSubNetwork(m_infomap->root()); // TODO: Already called in initNetwork? +} + +template +inline void InfomapOptimizer::initSuperNetwork() +{ + Log(4) << "InfomapOptimizer::initSuperNetwork()...\n"; + m_objective.initSuperNetwork(m_infomap->root()); +} + +// =================================================== +// Run: Partition: * +// =================================================== + +template +void InfomapOptimizer::initPartition() +{ + auto& network = m_infomap->activeNetwork(); + Log(4) << "InfomapOptimizer::initPartition() with " << network.size() << " nodes...\n"; + + // Init one module for each node + auto numNodes = network.size(); + m_moduleFlowData.resize(numNodes); + m_moduleMembers.assign(numNodes, 1); + m_emptyModules.clear(); + m_emptyModules.reserve(numNodes); + + unsigned int i = 0; + for (auto& nodePtr : network) { + InfoNode& node = *nodePtr; + node.index = i; // Unique module index for each node + m_moduleFlowData[i] = node.data; + node.dirty = true; + ++i; + } + + m_objective.initPartition(network); +} + +template +void InfomapOptimizer::moveActiveNodesToPredefinedModules(std::vector& modules) +{ + auto& network = m_infomap->activeNetwork(); + auto numNodes = network.size(); + if (modules.size() != numNodes) + throw std::length_error("Size of predefined modules differ from size of active network."); + + for (unsigned int i = 0; i < numNodes; ++i) { + moveNodeToPredefinedModule(*network[i], modules[i]); + } +} + +template +bool InfomapOptimizer::moveNodeToPredefinedModule(InfoNode& current, unsigned int newModule) +{ + unsigned int oldM = current.index; + unsigned int newM = newModule; + + if (newM == oldM) { + return false; + } + + DeltaFlowDataType oldModuleDelta(oldM, 0.0, 0.0); + DeltaFlowDataType newModuleDelta(newM, 0.0, 0.0); + + // For all outlinks + for (auto& e : current.outEdges()) { + auto& edge = *e; + unsigned int otherModule = edge.target->index; + if (otherModule == oldM) { + oldModuleDelta.deltaExit += edge.data.flow; + } else if (otherModule == newM) { + newModuleDelta.deltaExit += edge.data.flow; + } + } + // For all inlinks + for (auto& e : current.inEdges()) { + auto& edge = *e; + unsigned int otherModule = edge.source->index; + if (otherModule == oldM) { + oldModuleDelta.deltaEnter += edge.data.flow; + } else if (otherModule == newM) { + newModuleDelta.deltaEnter += edge.data.flow; + } + } + + // For recorded teleportation + if (m_infomap->recordedTeleportation) { + auto& oldModuleFlowData = m_moduleFlowData[oldM]; + double deltaEnterOld = (oldModuleFlowData.teleportFlow - current.data.teleportFlow) * current.data.teleportWeight; + double deltaExitOld = current.data.teleportFlow * (oldModuleFlowData.teleportWeight - current.data.teleportWeight); + oldModuleDelta.deltaEnter += deltaEnterOld; + oldModuleDelta.deltaExit += deltaExitOld; + + auto& newModuleFlowData = m_moduleFlowData[newM]; + double deltaEnterNew = current.data.teleportFlow * newModuleFlowData.teleportWeight; + double deltaExitNew = newModuleFlowData.teleportFlow * current.data.teleportWeight; + newModuleDelta.deltaEnter += deltaEnterNew; + newModuleDelta.deltaExit += deltaExitNew; + } + // Update empty module vector + if (m_moduleMembers[newM] == 0) { + m_emptyModules.pop_back(); + } + if (m_moduleMembers[current.index] == 1) { + m_emptyModules.push_back(oldM); + } + + m_objective.updateCodelengthOnMovingNode(current, oldModuleDelta, newModuleDelta, m_moduleFlowData, m_moduleMembers); + + m_moduleMembers[oldM] -= 1; + m_moduleMembers[newM] += 1; + + current.index = newM; + return true; +} + +template +inline unsigned int InfomapOptimizer::optimizeActiveNetwork() +{ + unsigned int coreLoopCount = 0; + unsigned int numEffectiveLoops = 0; + double oldCodelength = m_objective.getCodelength(); + unsigned int loopLimit = m_infomap->coreLoopLimit; + unsigned int minRandLoop = 2; + if (loopLimit >= minRandLoop && m_infomap->randomizeCoreLoopLimit) + loopLimit = m_infomap->m_rand.randInt(minRandLoop, loopLimit); + if (m_infomap->m_aggregationLevel > 0 || m_infomap->m_isCoarseTune) { + loopLimit = 20; + } + + do { + ++coreLoopCount; + unsigned int numNodesMoved = m_infomap->innerParallelization + ? tryMoveEachNodeIntoBestModuleInParallel() + : tryMoveEachNodeIntoBestModule(); + // Break if not enough improvement + if (numNodesMoved == 0 || m_objective.getCodelength() >= oldCodelength - m_infomap->minimumCodelengthImprovement) + break; + ++numEffectiveLoops; + oldCodelength = m_objective.getCodelength(); + } while (coreLoopCount != loopLimit); + + return numEffectiveLoops; +} + +template +unsigned int InfomapOptimizer::tryMoveEachNodeIntoBestModule() +{ + // Get random enumeration of nodes + auto& network = m_infomap->activeNetwork(); + std::vector nodeEnumeration(network.size()); + m_infomap->m_rand.getRandomizedIndexVector(nodeEnumeration); + + auto numNodes = nodeEnumeration.size(); + unsigned int numMoved = 0; + + // Create map with module links + VectorMap deltaFlow(numNodes); + + for (unsigned int i = 0; i < numNodes; ++i) { + InfoNode& current = *network[nodeEnumeration[i]]; + + this->checkInterruption(); + + if (!current.dirty) + continue; + + // If other nodes have moved here, don't move away on first loop + if (m_moduleMembers[current.index] > 1 && m_infomap->isFirstLoop() && m_infomap->tuneIterationLimit != 1) + continue; + + // If no links connecting this node with other nodes, it won't move into others, + // and others won't move into this. TODO: Always best leave it alone? + // For memory networks, don't skip try move to same physical node! + + deltaFlow.startRound(); + + // For all outlinks + for (auto& e : current.outEdges()) { + auto& edge = *e; + InfoNode* neighbour = edge.target; + deltaFlow.add(neighbour->index, DeltaFlowDataType(neighbour->index, edge.data.flow, 0.0)); + } + // For all inlinks + for (auto& e : current.inEdges()) { + auto& edge = *e; + InfoNode* neighbour = edge.source; + deltaFlow.add(neighbour->index, DeltaFlowDataType(neighbour->index, 0.0, edge.data.flow)); + } + + // For not moving + deltaFlow.add(current.index, DeltaFlowDataType(current.index, 0.0, 0.0)); + DeltaFlowDataType& oldModuleDelta = deltaFlow[current.index]; + oldModuleDelta.module = current.index; // Make sure index is correct if created new + + // Option to move to empty module (if node not already alone) + if (m_moduleMembers[current.index] > 1 && !m_emptyModules.empty()) { + deltaFlow.add(m_emptyModules.back(), DeltaFlowDataType(m_emptyModules.back(), 0.0, 0.0)); + } + + // For memory networks + m_objective.addMemoryContributions(current, oldModuleDelta, deltaFlow); + + auto& moduleDeltaEnterExit = deltaFlow.values(); + unsigned int numModuleLinks = deltaFlow.size(); + + // For recorded teleportation + if (m_infomap->recordedTeleportation) { + for (unsigned int j = 0; j < numModuleLinks; ++j) { + auto& deltaEnterExit = moduleDeltaEnterExit[j]; + auto moduleIndex = deltaEnterExit.module; + if (moduleIndex == current.index) { + auto& oldModuleFlowData = m_moduleFlowData[moduleIndex]; + double deltaEnterOld = (oldModuleFlowData.teleportFlow - current.data.teleportFlow) * current.data.teleportWeight; + double deltaExitOld = current.data.teleportFlow * (oldModuleFlowData.teleportWeight - current.data.teleportWeight); + deltaFlow.add(moduleIndex, DeltaFlowDataType(moduleIndex, deltaExitOld, deltaEnterOld)); + } else { + auto& newModuleFlowData = m_moduleFlowData[moduleIndex]; + double deltaEnterNew = newModuleFlowData.teleportFlow * current.data.teleportWeight; + double deltaExitNew = current.data.teleportFlow * newModuleFlowData.teleportWeight; + deltaFlow.add(moduleIndex, DeltaFlowDataType(moduleIndex, deltaExitNew, deltaEnterNew)); + } + } + } + + // Randomize link order for optimized search + std::vector moduleEnumeration(numModuleLinks); + m_infomap->m_rand.getRandomizedIndexVector(moduleEnumeration); + + DeltaFlowDataType bestDeltaModule(oldModuleDelta); + double bestDeltaCodelength = 0.0; + DeltaFlowDataType strongestConnectedModule(oldModuleDelta); + double deltaCodelengthOnStrongestConnectedModule = 0.0; + + // Find the move that minimizes the description length + for (unsigned int k = 0; k < numModuleLinks; ++k) { + auto j = moduleEnumeration[k]; + unsigned int otherModule = moduleDeltaEnterExit[j].module; + if (otherModule != current.index) { + double deltaCodelength = m_objective.getDeltaCodelengthOnMovingNode(current, + oldModuleDelta, + moduleDeltaEnterExit[j], + m_moduleFlowData, + m_moduleMembers); + + if (deltaCodelength < bestDeltaCodelength - m_infomap->minimumSingleNodeCodelengthImprovement) { + bestDeltaModule = moduleDeltaEnterExit[j]; + bestDeltaCodelength = deltaCodelength; + } + + // Save strongest connected module to prefer if codelength improvement equal + if (moduleDeltaEnterExit[j].deltaExit > strongestConnectedModule.deltaExit) { + strongestConnectedModule = moduleDeltaEnterExit[j]; + deltaCodelengthOnStrongestConnectedModule = deltaCodelength; + } + } + } + + // Prefer strongest connected module if equal delta codelength + if (strongestConnectedModule.module != bestDeltaModule.module && deltaCodelengthOnStrongestConnectedModule <= bestDeltaCodelength + m_infomap->minimumSingleNodeCodelengthImprovement) { + bestDeltaModule = strongestConnectedModule; + } + + // Make best possible move + if (bestDeltaModule.module != current.index) { + unsigned int bestModuleIndex = bestDeltaModule.module; + // Update empty module vector + if (m_moduleMembers[bestModuleIndex] == 0) { + m_emptyModules.pop_back(); + } + if (m_moduleMembers[current.index] == 1) { + m_emptyModules.push_back(current.index); + } + + m_objective.updateCodelengthOnMovingNode(current, oldModuleDelta, bestDeltaModule, m_moduleFlowData, m_moduleMembers); + + m_moduleMembers[current.index] -= 1; + m_moduleMembers[bestModuleIndex] += 1; + + unsigned int oldModuleIndex = current.index; + current.index = bestModuleIndex; + + ++numMoved; + + InfoNode* nodeInOldModule = ¤t; + unsigned int numLinkedNodesInOldModule = 0; + // Mark neighbours as dirty + for (auto& e : current.outEdges()) { + e->target->dirty = true; + if (e->target->index == oldModuleIndex) { + nodeInOldModule = e->target; + ++numLinkedNodesInOldModule; + } + } + for (auto& e : current.inEdges()) { + e->source->dirty = true; + if (e->source->index == oldModuleIndex) { + nodeInOldModule = e->source; + ++numLinkedNodesInOldModule; + } + } + + // Move single connected nodes to same module + if (numLinkedNodesInOldModule == 1 && m_moduleMembers[oldModuleIndex] == 1) { + moveNodeToPredefinedModule(*nodeInOldModule, bestModuleIndex); + ++numMoved; + // Mark neighbours as dirty + if (nodeInOldModule->degree() > 1) { + for (auto& e : nodeInOldModule->outEdges()) + e->target->dirty = true; + for (auto& e : nodeInOldModule->inEdges()) + e->source->dirty = true; + } + } + } else { + current.dirty = false; + } + } + + return numMoved; +} + +/** + * Minimize the codelength by trying to move each node into best module, in parallel. + * + * For each node: + * 1. Calculate the change in codelength for a move to each of its neighbouring modules or to an empty module + * 2. Move to the one that reduces the codelength the most, if any. + * + * @return The number of nodes moved. + */ +template +unsigned int InfomapOptimizer::tryMoveEachNodeIntoBestModuleInParallel() +{ + // Get random enumeration of nodes + auto& network = m_infomap->activeNetwork(); + std::vector nodeEnumeration(network.size()); + m_infomap->m_rand.getRandomizedIndexVector(nodeEnumeration); + + auto numNodes = nodeEnumeration.size(); + unsigned int numMoved = 0; + unsigned int numInvalidMoves = 0; + +#pragma omp parallel for schedule(dynamic) // Use dynamic scheduling as some threads could end early + for (unsigned int i = 0; i < numNodes; ++i) { + // Pick nodes in random order + InfoNode& current = *network[nodeEnumeration[i]]; + + if (!current.dirty) + continue; + + // If other nodes have moved here, don't move away on first loop + if (m_moduleMembers[current.index] > 1 && m_infomap->isFirstLoop() && m_infomap->tuneIterationLimit != 1) + continue; + + // If no links connecting this node with other nodes, it won't move into others, + // and others won't move into this. TODO: Always best leave it alone? + // For memory networks, don't skip try move to same physical node! + + // Create map with module links + VectorMap deltaFlow(numNodes); + + // For all outlinks + for (auto& e : current.outEdges()) { + auto& edge = *e; + InfoNode* neighbour = edge.target; + deltaFlow.add(neighbour->index, DeltaFlowDataType(neighbour->index, edge.data.flow, 0.0)); + } + // For all inlinks + for (auto& e : current.inEdges()) { + auto& edge = *e; + InfoNode* neighbour = edge.source; + deltaFlow.add(neighbour->index, DeltaFlowDataType(neighbour->index, 0.0, edge.data.flow)); + } + + // For not moving + deltaFlow.add(current.index, DeltaFlowDataType(current.index, 0.0, 0.0)); + DeltaFlowDataType& oldModuleDelta = deltaFlow[current.index]; + oldModuleDelta.module = current.index; // Make sure index is correct if created new + + // Option to move to empty module (if node not already alone) + if (m_moduleMembers[current.index] > 1 && !m_emptyModules.empty()) { + // deltaFlow[m_emptyModules.back()] += DeltaFlowDataType(m_emptyModules.back(), 0.0, 0.0); + deltaFlow.add(m_emptyModules.back(), DeltaFlowDataType(m_emptyModules.back(), 0.0, 0.0)); + } + + // For memory networks + m_objective.addMemoryContributions(current, oldModuleDelta, deltaFlow); + + auto& moduleDeltaEnterExit = deltaFlow.values(); + unsigned int numModuleLinks = deltaFlow.size(); + + // Randomize link order for optimized search + if (numModuleLinks > 2) { + for (unsigned int j = 0; j < numModuleLinks - 2; ++j) { + unsigned int randPos = m_infomap->m_rand.randInt(j + 1, numModuleLinks - 1); + swap(moduleDeltaEnterExit[j], moduleDeltaEnterExit[randPos]); + } + } + + DeltaFlowDataType bestDeltaModule(oldModuleDelta); + double bestDeltaCodelength = 0.0; + DeltaFlowDataType strongestConnectedModule(oldModuleDelta); + double deltaCodelengthOnStrongestConnectedModule = 0.0; + + // Find the move that minimizes the description length + for (unsigned int j = 0; j < deltaFlow.size(); ++j) { + unsigned int otherModule = moduleDeltaEnterExit[j].module; + if (otherModule != current.index) { + double deltaCodelength = m_objective.getDeltaCodelengthOnMovingNode(current, + oldModuleDelta, + moduleDeltaEnterExit[j], + m_moduleFlowData, + m_moduleMembers); + + if (deltaCodelength < bestDeltaCodelength - m_infomap->minimumSingleNodeCodelengthImprovement) { + bestDeltaModule = moduleDeltaEnterExit[j]; + bestDeltaCodelength = deltaCodelength; + } + + // Save strongest connected module to prefer if codelength improvement equal + if (moduleDeltaEnterExit[j].deltaExit > strongestConnectedModule.deltaExit) { + strongestConnectedModule = moduleDeltaEnterExit[j]; + deltaCodelengthOnStrongestConnectedModule = deltaCodelength; + } + } + } + + // Prefer strongest connected module if equal delta codelength + if (strongestConnectedModule.module != bestDeltaModule.module && deltaCodelengthOnStrongestConnectedModule <= bestDeltaCodelength + m_infomap->minimumSingleNodeCodelengthImprovement) { + bestDeltaModule = strongestConnectedModule; + } + + // Make best possible move + if (bestDeltaModule.module == current.index) { + current.dirty = false; + continue; + } else { +#pragma omp critical(moveUpdate) + { + unsigned int bestModuleIndex = bestDeltaModule.module; + unsigned int oldModuleIndex = current.index; + + bool validMove = bestModuleIndex == m_emptyModules.back() + // Check validity of move to empty target + ? m_moduleMembers[oldModuleIndex] > 1 && !m_emptyModules.empty() + // Not valid if the best module is empty now but not when decided + : m_moduleMembers[bestModuleIndex] > 0; + + if (validMove) { + // Recalculate delta codelength for proposed move to see if still an improvement + oldModuleDelta = DeltaFlowDataType(oldModuleIndex, 0.0, 0.0); + DeltaFlowDataType newModuleDelta(bestModuleIndex, 0.0, 0.0); + + // For all outlinks + for (auto& e : current.outEdges()) { + auto& edge = *e; + unsigned int otherModule = edge.target->index; + if (otherModule == oldModuleIndex) + oldModuleDelta.deltaExit += edge.data.flow; + else if (otherModule == bestModuleIndex) + newModuleDelta.deltaExit += edge.data.flow; + } + // For all inlinks + for (auto& e : current.inEdges()) { + auto& edge = *e; + unsigned int otherModule = edge.source->index; + if (otherModule == oldModuleIndex) + oldModuleDelta.deltaEnter += edge.data.flow; + else if (otherModule == bestModuleIndex) + newModuleDelta.deltaEnter += edge.data.flow; + } + + // For memory networks + m_objective.addMemoryContributions(current, oldModuleDelta, deltaFlow); + + double deltaCodelength = m_objective.getDeltaCodelengthOnMovingNode(current, + oldModuleDelta, + newModuleDelta, + m_moduleFlowData, + m_moduleMembers); + + if (deltaCodelength < 0.0 - m_infomap->minimumSingleNodeCodelengthImprovement) { + // Update empty module vector + if (m_moduleMembers[bestModuleIndex] == 0) { + m_emptyModules.pop_back(); + } + if (m_moduleMembers[oldModuleIndex] == 1) { + m_emptyModules.push_back(oldModuleIndex); + } + + m_objective.updateCodelengthOnMovingNode(current, oldModuleDelta, bestDeltaModule, m_moduleFlowData, m_moduleMembers); + + m_moduleMembers[oldModuleIndex] -= 1; + m_moduleMembers[bestModuleIndex] += 1; + + current.index = bestModuleIndex; + + ++numMoved; + + // Mark neighbours as dirty + for (auto& e : current.outEdges()) + e->target->dirty = true; + for (auto& e : current.inEdges()) + e->source->dirty = true; + } else { + ++numInvalidMoves; + } + } else { + ++numInvalidMoves; + } + } + } + } + + return numMoved + numInvalidMoves; +} + +template +inline void InfomapOptimizer::consolidateModules(bool replaceExistingModules) +{ + auto& network = m_infomap->activeNetwork(); + auto numNodes = network.size(); + std::vector modules(numNodes, nullptr); + + InfoNode& firstActiveNode = *network[0]; + auto level = firstActiveNode.depth(); + auto leafLevel = m_infomap->numLevels(); + + if (leafLevel == 1) + replaceExistingModules = false; + + // Release children pointers on current parent(s) to put new modules between + for (auto& n : network) { + n->parent->releaseChildren(); // Safe to call multiple times + } + + // Create the new module nodes and re-parent the active network from its common parent to the new module level + for (unsigned int i = 0; i < numNodes; ++i) { + InfoNode* node = network[i]; + unsigned int moduleIndex = node->index; + if (modules[moduleIndex] == nullptr) { + modules[moduleIndex] = new InfoNode(m_moduleFlowData[moduleIndex]); + modules[moduleIndex]->index = moduleIndex; + node->parent->addChild(modules[moduleIndex]); + } + modules[moduleIndex]->addChild(node); + } + + using NodePair = std::pair; + using EdgeMap = std::map; + EdgeMap moduleLinks; + + for (auto& node : network) { + unsigned int module1 = node->index; + for (auto& e : node->outEdges()) { + InfoEdge& edge = *e; + unsigned int module2 = edge.target->index; + if (module1 != module2) { + // Use new variables to not swap module1 + unsigned int m1 = module1, m2 = module2; + // If undirected, the order may be swapped to aggregate the edge on an opposite one + if (m_infomap->isUndirectedClustering() && m1 > m2) + std::swap(m1, m2); + auto ret = moduleLinks.insert(std::make_pair(NodePair(m1, m2), edge.data.flow)); + if (!ret.second) { + ret.first->second += edge.data.flow; + } + } + } + } + + // Add the aggregated edge flow structure to the new modules + for (auto& e : moduleLinks) { + const auto& nodePair = e.first; + modules[nodePair.first]->addOutEdge(*modules[nodePair.second], 0.0, e.second); + } + + if (replaceExistingModules) { + if (level == 1) { + Log(4) << "Consolidated super modules, removing old modules...\n"; + for (auto& node : network) + node->replaceWithChildren(); + } else if (level == 2) { + Log(4) << "Consolidated sub-modules, removing modules...\n"; + unsigned int moduleIndex = 0; + for (InfoNode& module : m_infomap->root()) { + // Store current modular structure on the sub-modules + for (auto& subModule : module) + subModule.index = moduleIndex; + ++moduleIndex; + } + m_infomap->root().replaceChildrenWithGrandChildren(); + } + } + + // Calculate the number of non-trivial modules + m_infomap->m_numNonTrivialTopModules = 0; + for (auto& module : m_infomap->root()) { + if (module.childDegree() != 1) + ++m_infomap->m_numNonTrivialTopModules; + } + + m_objective.consolidateModules(modules); + m_consolidatedObjective = m_objective; +} + +template +inline bool InfomapOptimizer::restoreConsolidatedOptimizationPointIfNoImprovement(bool forceRestore) +{ + if (forceRestore || m_objective.getCodelength() >= m_consolidatedObjective.getCodelength() - m_infomap->minimumSingleNodeCodelengthImprovement) { + m_objective = m_consolidatedObjective; + return true; + } + return false; +} + +} /* namespace infomap */ + +#endif // INFOMAP_OPTIMIZER_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/InfomapOptimizerBase.h b/src/vendor/cigraph/vendor/infomap/src/core/InfomapOptimizerBase.h new file mode 100644 index 00000000000..75ba8ff8b42 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/InfomapOptimizerBase.h @@ -0,0 +1,113 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef INFOMAP_OPTIMIZER_BASE_H_ +#define INFOMAP_OPTIMIZER_BASE_H_ + +#include "InfomapBase.h" +#include "InfoNode.h" +#include "FlowData.h" +#include + +namespace infomap { + +class InfomapOptimizerBase { + friend class InfomapBase; + using FlowDataType = FlowData; + +public: + InfomapOptimizerBase() = default; + + virtual ~InfomapOptimizerBase() = default; + + virtual void init(InfomapBase* infomap) = 0; + + // =================================================== + // IO + // =================================================== + + virtual std::ostream& toString(std::ostream& out) const = 0; + + // =================================================== + // Getters + // =================================================== + + virtual double getCodelength() const = 0; + + virtual double getIndexCodelength() const = 0; + + virtual double getModuleCodelength() const = 0; + + virtual double getMetaCodelength(bool /*unweighted*/ = false) const { return 0.0; } + + void setInterruptionHandler(interruptionHandlerFn *interruptionHandler) { + this->interruptionHandler = interruptionHandler; + } + +protected: + virtual unsigned int numActiveModules() const = 0; + + void checkInterruption() { + if (interruptionHandler) { + if (interruptionHandler()) { + throw infomap::InterruptException(); + } + } + } + + // =================================================== + // Run: Init: * + // =================================================== + + // Init terms that is constant for the whole network + virtual void initTree() = 0; + + virtual void initNetwork() = 0; + + virtual void initSuperNetwork() = 0; + + virtual double calcCodelength(const InfoNode& parent) const = 0; + + // =================================================== + // Run: Partition: * + // =================================================== + + virtual void initPartition() = 0; + + virtual void moveActiveNodesToPredefinedModules(std::vector& modules) = 0; + + virtual unsigned int optimizeActiveNetwork() = 0; + + virtual unsigned int tryMoveEachNodeIntoBestModule() = 0; + + // virtual unsigned int tryMoveEachNodeIntoBestModuleLocal() = 0; + + virtual unsigned int tryMoveEachNodeIntoBestModuleInParallel() = 0; + + virtual void consolidateModules(bool replaceExistingModules = true) = 0; + + virtual bool restoreConsolidatedOptimizationPointIfNoImprovement(bool forceRestore = false) = 0; + +#if 0 + // =================================================== + // Debug: * + // =================================================== + + virtual void printDebug() = 0; +#endif + +private: + + interruptionHandlerFn *interruptionHandler = NULL; + +}; + +} /* namespace infomap */ + +#endif // INFOMAP_OPTIMIZER_BASE_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/MapEquation.h b/src/vendor/cigraph/vendor/infomap/src/core/MapEquation.h new file mode 100644 index 00000000000..b9913f87394 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/MapEquation.h @@ -0,0 +1,339 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef MAPEQUATION_H_ +#define MAPEQUATION_H_ + +#include "../utils/infomath.h" +#include "../utils/convert.h" +#include "../io/Config.h" +#include "../utils/Log.h" +#include "../utils/VectorMap.h" +#include "InfoNode.h" +#include "FlowData.h" +#include +#include +#include + +namespace infomap { + +class InfoNode; + +template +class MapEquation { + using ME = MapEquation; + +public: + MapEquation() = default; + + MapEquation(const MapEquation& other) = default; + + MapEquation& operator=(const MapEquation& other) = default; + + MapEquation(MapEquation&& other) noexcept = default; + + MapEquation& operator=(MapEquation&& other) noexcept = default; + + virtual ~MapEquation() = default; + + // =================================================== + // Getters + // =================================================== + + virtual double getIndexCodelength() const { return indexCodelength; } + + virtual double getModuleCodelength() const { return moduleCodelength; } + + virtual double getCodelength() const { return codelength; } + + // =================================================== + // IO + // =================================================== + + virtual std::ostream& print(std::ostream& out) const + { + return out << indexCodelength << " + " << moduleCodelength << " = " << io::toPrecision(codelength); + } + + // =================================================== + // Init + // =================================================== + + virtual void init(const Config&) + { + Log(3) << "MapEquation::init()...\n"; + } + + virtual void initTree(InfoNode& /*root*/) = 0; + + virtual void initNetwork(InfoNode& root) + { + Log(3) << "MapEquation::initNetwork()...\n"; + + nodeFlow_log_nodeFlow = 0.0; + for (InfoNode& node : root) { + nodeFlow_log_nodeFlow += infomath::plogp(node.data.flow); + } + ME::initSubNetwork(root); + } + + virtual void initSuperNetwork(InfoNode& root) + { + Log(3) << "MapEquation::initSuperNetwork()...\n"; + + nodeFlow_log_nodeFlow = 0.0; + for (InfoNode& node : root) { + nodeFlow_log_nodeFlow += infomath::plogp(node.data.enterFlow); + } + } + + virtual void initSubNetwork(InfoNode& root) + { + exitNetworkFlow = root.data.exitFlow; + exitNetworkFlow_log_exitNetworkFlow = infomath::plogp(exitNetworkFlow); + } + + virtual void initPartition(std::vector& nodes) { ME::calculateCodelength(nodes); } + + // =================================================== + // Codelength + // =================================================== + + virtual double calcCodelength(const InfoNode& parent) const + { + return parent.isLeafModule() ? ME::calcCodelengthOnModuleOfLeafNodes(parent) : ME::calcCodelengthOnModuleOfModules(parent); + } + + virtual void addMemoryContributions(InfoNode& /*current*/, DeltaFlowDataType& /*oldModuleDelta*/, DeltaFlowDataType& /*newModuleDelta*/) { } + + virtual void addMemoryContributions(InfoNode& /*current*/, DeltaFlowDataType& /*oldModuleDelta*/, VectorMap& /*moduleDeltaFlow*/) { } + + virtual double getDeltaCodelengthOnMovingNode(InfoNode& current, + DeltaFlowDataType& oldModuleDelta, + DeltaFlowDataType& newModuleDelta, + std::vector& moduleFlowData, + std::vector& /*moduleMembers*/); + + // =================================================== + // Consolidation + // =================================================== + + virtual void updateCodelengthOnMovingNode(InfoNode& current, + DeltaFlowDataType& oldModuleDelta, + DeltaFlowDataType& newModuleDelta, + std::vector& moduleFlowData, + std::vector& /*moduleMembers*/); + + virtual void consolidateModules(std::vector& /*modules*/) = 0; + + // =================================================== + // Debug + // =================================================== + +#if 0 + virtual void printDebug() const + { + std::cout << "(enterFlow_log_enterFlow: " << enterFlow_log_enterFlow << ", " + << "enter_log_enter: " << enter_log_enter << ", " + << "exitNetworkFlow_log_exitNetworkFlow: " << exitNetworkFlow_log_exitNetworkFlow << ") "; + } +#endif + +protected: + // =================================================== + // Protected member functions + // =================================================== + + virtual double calcCodelengthOnModuleOfLeafNodes(const InfoNode& parent) const; + + virtual double calcCodelengthOnModuleOfModules(const InfoNode& parent) const; + + virtual void calculateCodelength(std::vector& nodes) + { + ME::calculateCodelengthTerms(nodes); + ME::calculateCodelengthFromCodelengthTerms(); + } + + virtual void calculateCodelengthTerms(std::vector& nodes); + + virtual void calculateCodelengthFromCodelengthTerms() + { + indexCodelength = enterFlow_log_enterFlow - enter_log_enter - exitNetworkFlow_log_exitNetworkFlow; + moduleCodelength = -exit_log_exit + flow_log_flow - nodeFlow_log_nodeFlow; + codelength = indexCodelength + moduleCodelength; + } + +public: + // =================================================== + // Public member variables + // =================================================== + + double codelength = 0.0; + double indexCodelength = 0.0; + double moduleCodelength = 0.0; + +protected: + // =================================================== + // Protected member variables + // =================================================== + + double nodeFlow_log_nodeFlow = 0.0; // constant while the leaf network is the same + double flow_log_flow = 0.0; // node.(flow + exitFlow) + double exit_log_exit = 0.0; + double enter_log_enter = 0.0; + double enterFlow = 0.0; + double enterFlow_log_enterFlow = 0.0; + + // For hierarchical + double exitNetworkFlow = 0.0; + double exitNetworkFlow_log_exitNetworkFlow = 0.0; +}; + +template +double MapEquation::getDeltaCodelengthOnMovingNode(InfoNode& current, DeltaFlowDataType& oldModuleDelta, DeltaFlowDataType& newModuleDelta, std::vector& moduleFlowData, std::vector&) +{ + using infomath::plogp; + unsigned int oldModule = oldModuleDelta.module; + unsigned int newModule = newModuleDelta.module; + double deltaEnterExitOldModule = oldModuleDelta.deltaEnter + oldModuleDelta.deltaExit; + double deltaEnterExitNewModule = newModuleDelta.deltaEnter + newModuleDelta.deltaExit; + + double delta_enter = plogp(enterFlow + deltaEnterExitOldModule - deltaEnterExitNewModule) - enterFlow_log_enterFlow; + + double delta_enter_log_enter = -plogp(moduleFlowData[oldModule].enterFlow) + - plogp(moduleFlowData[newModule].enterFlow) + + plogp(moduleFlowData[oldModule].enterFlow - current.data.enterFlow + deltaEnterExitOldModule) + + plogp(moduleFlowData[newModule].enterFlow + current.data.enterFlow - deltaEnterExitNewModule); + + double delta_exit_log_exit = -plogp(moduleFlowData[oldModule].exitFlow) + - plogp(moduleFlowData[newModule].exitFlow) + + plogp(moduleFlowData[oldModule].exitFlow - current.data.exitFlow + deltaEnterExitOldModule) + + plogp(moduleFlowData[newModule].exitFlow + current.data.exitFlow - deltaEnterExitNewModule); + + double delta_flow_log_flow = -plogp(moduleFlowData[oldModule].exitFlow + moduleFlowData[oldModule].flow) + - plogp(moduleFlowData[newModule].exitFlow + moduleFlowData[newModule].flow) + + plogp(moduleFlowData[oldModule].exitFlow + moduleFlowData[oldModule].flow + - current.data.exitFlow - current.data.flow + deltaEnterExitOldModule) + + plogp(moduleFlowData[newModule].exitFlow + moduleFlowData[newModule].flow + + current.data.exitFlow + current.data.flow - deltaEnterExitNewModule); + + double deltaL = delta_enter - delta_enter_log_enter - delta_exit_log_exit + delta_flow_log_flow; + return deltaL; +} + +template +void MapEquation::updateCodelengthOnMovingNode(InfoNode& current, DeltaFlowDataType& oldModuleDelta, DeltaFlowDataType& newModuleDelta, std::vector& moduleFlowData, std::vector&) +{ + using infomath::plogp; + unsigned int oldModule = oldModuleDelta.module; + unsigned int newModule = newModuleDelta.module; + double deltaEnterExitOldModule = oldModuleDelta.deltaEnter + oldModuleDelta.deltaExit; + double deltaEnterExitNewModule = newModuleDelta.deltaEnter + newModuleDelta.deltaExit; + + enterFlow -= moduleFlowData[oldModule].enterFlow + moduleFlowData[newModule].enterFlow; + enter_log_enter -= plogp(moduleFlowData[oldModule].enterFlow) + plogp(moduleFlowData[newModule].enterFlow); + exit_log_exit -= plogp(moduleFlowData[oldModule].exitFlow) + plogp(moduleFlowData[newModule].exitFlow); + flow_log_flow -= plogp(moduleFlowData[oldModule].exitFlow + moduleFlowData[oldModule].flow) + plogp(moduleFlowData[newModule].exitFlow + moduleFlowData[newModule].flow); + + moduleFlowData[oldModule] -= current.data; + moduleFlowData[newModule] += current.data; + + moduleFlowData[oldModule].enterFlow += deltaEnterExitOldModule; + moduleFlowData[oldModule].exitFlow += deltaEnterExitOldModule; + moduleFlowData[newModule].enterFlow -= deltaEnterExitNewModule; + moduleFlowData[newModule].exitFlow -= deltaEnterExitNewModule; + + enterFlow += moduleFlowData[oldModule].enterFlow + moduleFlowData[newModule].enterFlow; + enter_log_enter += plogp(moduleFlowData[oldModule].enterFlow) + plogp(moduleFlowData[newModule].enterFlow); + exit_log_exit += plogp(moduleFlowData[oldModule].exitFlow) + plogp(moduleFlowData[newModule].exitFlow); + flow_log_flow += plogp(moduleFlowData[oldModule].exitFlow + moduleFlowData[oldModule].flow) + plogp(moduleFlowData[newModule].exitFlow + moduleFlowData[newModule].flow); + + enterFlow_log_enterFlow = plogp(enterFlow); + + indexCodelength = enterFlow_log_enterFlow - enter_log_enter - exitNetworkFlow_log_exitNetworkFlow; + moduleCodelength = -exit_log_exit + flow_log_flow - nodeFlow_log_nodeFlow; + codelength = indexCodelength + moduleCodelength; +} + +template +double MapEquation::calcCodelengthOnModuleOfLeafNodes(const InfoNode& parent) const +{ + double parentFlow = parent.data.flow; + double parentExit = parent.data.exitFlow; + double totalParentFlow = parentFlow + parentExit; + if (totalParentFlow < 1e-16) + return 0.0; + + double indexLength = 0.0; + for (const auto& node : parent) { + indexLength -= infomath::plogp(node.data.flow / totalParentFlow); + } + indexLength -= infomath::plogp(parentExit / totalParentFlow); + + indexLength *= totalParentFlow; + + return indexLength; +} + +template +double MapEquation::calcCodelengthOnModuleOfModules(const InfoNode& parent) const +{ + double parentFlow = parent.data.flow; + double parentExit = parent.data.exitFlow; + if (parentFlow < 1e-16) + return 0.0; + + // H(x) = -xlog(x), T = q + SUM(p), q = exitFlow, p = enterFlow + // Normal format + // L = q * -log(q/T) + SUM(p * -log(p/T)) + // Compact format + // L = T * ( H(q/T) + SUM( H(p/T) ) ) + // Expanded format + // L = q * -log(q) - q * -log(T) + SUM( p * -log(p) - p * -log(T) ) + // = T * log(T) - q*log(q) - SUM( p*log(p) ) + // = -H(T) + H(q) + SUM(H(p)) + // As T is not known, use expanded format to avoid two loops + double sumEnter = 0.0; + double sumEnterLogEnter = 0.0; + for (const auto& node : parent) { + sumEnter += node.data.enterFlow; // rate of enter to finer level + sumEnterLogEnter += infomath::plogp(node.data.enterFlow); + } + // The possibilities from this module: Either exit to coarser level or enter one of its children + double totalCodewordUse = parentExit + sumEnter; + + return infomath::plogp(totalCodewordUse) - sumEnterLogEnter - infomath::plogp(parentExit); +} + +template +void MapEquation::calculateCodelengthTerms(std::vector& nodes) +{ + enter_log_enter = 0.0; + flow_log_flow = 0.0; + exit_log_exit = 0.0; + enterFlow = 0.0; + + // For each module + for (InfoNode* n : nodes) { + InfoNode& node = *n; + // own node/module codebook + flow_log_flow += infomath::plogp(node.data.flow + node.data.exitFlow); + + // use of index codebook + enter_log_enter += infomath::plogp(node.data.enterFlow); + exit_log_exit += infomath::plogp(node.data.exitFlow); + enterFlow += node.data.enterFlow; + } + enterFlow += exitNetworkFlow; + enterFlow_log_enterFlow = infomath::plogp(enterFlow); +} + +} // namespace infomap + +#endif // MAPEQUATION_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/MemMapEquation.cpp b/src/vendor/cigraph/vendor/infomap/src/core/MemMapEquation.cpp new file mode 100644 index 00000000000..1c25d4b99c3 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/MemMapEquation.cpp @@ -0,0 +1,451 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "MemMapEquation.h" +#include "FlowData.h" +#include "InfoNode.h" + +#include +#include +#include +#include +#include + +namespace infomap { + +// =================================================== +// IO +// =================================================== + +std::ostream& MemMapEquation::print(std::ostream& out) const +{ + return out << indexCodelength << " + " << moduleCodelength << " = " << io::toPrecision(codelength); +} + +std::ostream& operator<<(std::ostream& out, const MemMapEquation& mapEq) +{ + return mapEq.print(out); +} + +// =================================================== +// Init +// =================================================== + +void MemMapEquation::init(const Config& /*config*/) +{ + Log(3) << "MemMapEquation::init()...\n"; +} + +void MemMapEquation::initNetwork(InfoNode& root) +{ + initPhysicalNodes(root); +} + +void MemMapEquation::initSuperNetwork(InfoNode& /*root*/) +{ + // TODO: How use enterFlow instead of flow +} + +void MemMapEquation::initSubNetwork(InfoNode& /*root*/) +{ + // Base::initSubNetwork(root); +} + +void MemMapEquation::initPartition(std::vector& nodes) +{ + initPartitionOfPhysicalNodes(nodes); + + calculateCodelength(nodes); +} + +void MemMapEquation::initPhysicalNodes(InfoNode& root) +{ + bool notInitiatedOnRoot = root.physicalNodes.empty(); + if (notInitiatedOnRoot) { + // Assume leaf nodes directly under the root node + std::unordered_map physicalNodes; + unsigned int maxPhysicalId = 0; + unsigned int minPhysicalId = std::numeric_limits::max(); + for (auto it(root.begin_leaf_nodes()); !it.isEnd(); ++it) { + InfoNode& node = *it; + physicalNodes[node.physicalId] += node.data.flow; + minPhysicalId = std::min(minPhysicalId, node.physicalId); + maxPhysicalId = std::max(maxPhysicalId, node.physicalId); + } + + // Re-index physical nodes if necessary + std::map toZeroBasedIndex; + if (maxPhysicalId - minPhysicalId + 1 > m_numPhysicalNodes) { + unsigned int zeroBasedPhysicalId = 0; + for (const auto& physNode : physicalNodes) { + toZeroBasedIndex.insert(std::make_pair(physNode.first, zeroBasedPhysicalId++)); + } + } + + for (const auto& physNode : physicalNodes) { + unsigned int zeroBasedIndex = !toZeroBasedIndex.empty() ? toZeroBasedIndex[physNode.first] : (physNode.first - minPhysicalId); + root.physicalNodes.emplace_back(zeroBasedIndex, physNode.second); + } + } + auto firstLeafIt = root.begin_leaf_nodes(); + auto depth = firstLeafIt.depth(); + bool notInitiatedOnLeafNodes = firstLeafIt->physicalNodes.empty(); + if (notInitiatedOnLeafNodes) { + Log(3) << "MemMapEquation::initPhysicalNodesOnOriginalNetwork()...\n"; + std::set setOfPhysicalNodes; + unsigned int maxPhysicalId = 0; + unsigned int minPhysicalId = std::numeric_limits::max(); + for (auto it(root.begin_leaf_nodes()); !it.isEnd(); ++it) { + InfoNode& node = *it; + setOfPhysicalNodes.insert(node.physicalId); + maxPhysicalId = std::max(maxPhysicalId, node.physicalId); + minPhysicalId = std::min(minPhysicalId, node.physicalId); + } + + m_numPhysicalNodes = setOfPhysicalNodes.size(); + + // Re-index physical nodes if necessary + std::map toZeroBasedIndex; + if (maxPhysicalId - minPhysicalId + 1 > m_numPhysicalNodes) { + unsigned int zeroBasedPhysicalId = 0; + for (unsigned int physIndex : setOfPhysicalNodes) { + toZeroBasedIndex.insert(std::make_pair(physIndex, zeroBasedPhysicalId++)); + } + } + + for (auto it(root.begin_leaf_nodes()); !it.isEnd(); ++it) { + InfoNode& node = *it; + unsigned int zeroBasedIndex = !toZeroBasedIndex.empty() ? toZeroBasedIndex[node.physicalId] : (node.physicalId - minPhysicalId); + node.physicalNodes.emplace_back(zeroBasedIndex, node.data.flow); + } + + // If leaf nodes was not directly under root, make sure leaf modules have + // physical nodes defined also + if (depth > 1) { + for (auto it(root.begin_leaf_modules()); !it.isEnd(); ++it) { + InfoNode& module = *it; + std::map physToFlow; + for (auto& node : module) { + for (PhysData& physData : node.physicalNodes) { + physToFlow[physData.physNodeIndex] += physData.sumFlowFromM2Node; + } + } + for (auto& physFlow : physToFlow) { + module.physicalNodes.emplace_back(physFlow.first, physFlow.second); + } + } + } + } else { + // Either a sub-network (without modules) or the whole network with reconstructed tree + if (depth == 1) { + // new sub-network + Log(3) << "MemMapEquation::initPhysicalNodesOnSubNetwork()...\n"; + std::set setOfPhysicalNodes; + unsigned int maxPhysNodeIndex = 0; + unsigned int minPhysNodeIndex = std::numeric_limits::max(); + + // Collect all physical nodes in this sub network + for (InfoNode& node : root) { + for (PhysData& physData : node.physicalNodes) { + setOfPhysicalNodes.insert(physData.physNodeIndex); + maxPhysNodeIndex = std::max(maxPhysNodeIndex, physData.physNodeIndex); + minPhysNodeIndex = std::min(minPhysNodeIndex, physData.physNodeIndex); + } + } + + m_numPhysicalNodes = setOfPhysicalNodes.size(); + + // Re-index physical nodes if needed (not required when reconstructing tree) + if (maxPhysNodeIndex >= m_numPhysicalNodes) { + std::map toZeroBasedIndex; + if (maxPhysNodeIndex - minPhysNodeIndex + 1 > m_numPhysicalNodes) { + unsigned int zeroBasedPhysicalId = 0; + for (unsigned int physIndex : setOfPhysicalNodes) { + toZeroBasedIndex.insert(std::make_pair(physIndex, zeroBasedPhysicalId++)); + } + } + + for (InfoNode& node : root) { + for (PhysData& physData : node.physicalNodes) { + unsigned int zeroBasedIndex = !toZeroBasedIndex.empty() ? toZeroBasedIndex[physData.physNodeIndex] : (physData.physNodeIndex - minPhysNodeIndex); + physData.physNodeIndex = zeroBasedIndex; + } + } + } + } else { + // whole network with reconstructed tree + for (auto it(root.begin_leaf_modules()); !it.isEnd(); ++it) { + InfoNode& module = *it; + std::map physToFlow; + for (auto& node : module) { + for (PhysData& physData : node.physicalNodes) { + physToFlow[physData.physNodeIndex] += physData.sumFlowFromM2Node; + } + } + for (auto& physFlow : physToFlow) { + module.physicalNodes.emplace_back(physFlow.first, physFlow.second); + } + } + } + } +} + +void MemMapEquation::initPartitionOfPhysicalNodes(std::vector& nodes) +{ + Log(4) << "MemMapEquation::initPartitionOfPhysicalNodes()...\n"; + m_physToModuleToMemNodes.clear(); + m_physToModuleToMemNodes.resize(m_numPhysicalNodes); + + for (auto& n : nodes) { + InfoNode& node = *n; + unsigned int moduleIndex = node.index; // Assume unique module index for all nodes in this initiation phase + + for (PhysData& physData : node.physicalNodes) { + m_physToModuleToMemNodes[physData.physNodeIndex].insert(m_physToModuleToMemNodes[physData.physNodeIndex].end(), + std::make_pair(moduleIndex, MemNodeSet(1, physData.sumFlowFromM2Node))); + } + } + + m_memoryContributionsAdded = false; +} + +// =================================================== +// Codelength +// =================================================== + +void MemMapEquation::calculateCodelength(std::vector& nodes) +{ + calculateCodelengthTerms(nodes); + + calculateNodeFlow_log_nodeFlow(); + + calculateCodelengthFromCodelengthTerms(); +} + +void MemMapEquation::calculateNodeFlow_log_nodeFlow() +{ + nodeFlow_log_nodeFlow = 0.0; + for (unsigned int i = 0; i < m_numPhysicalNodes; ++i) { + const ModuleToMemNodes& moduleToMemNodes = m_physToModuleToMemNodes[i]; + for (const auto& moduleToMemNode : moduleToMemNodes) + nodeFlow_log_nodeFlow += infomath::plogp(moduleToMemNode.second.sumFlow); + } +} + +double MemMapEquation::calcCodelength(const InfoNode& parent) const +{ + if (parent.isLeafModule()) { + return calcCodelengthOnModuleOfLeafNodes(parent); + } + // Use first-order model on index codebook + return Base::calcCodelengthOnModuleOfModules(parent); +} + +double MemMapEquation::calcCodelengthOnModuleOfLeafNodes(const InfoNode& parent) const +{ + if (parent.numPhysicalNodes() == 0) { + return Base::calcCodelength(parent); // Infomap root node + } + + // TODO: For ordinary networks, flow should be used instead of enter flow + // for leaf nodes, what about memory networks? sumFlowFromM2Node vs sumEnterFlowFromM2Node? + double parentFlow = parent.data.flow; + double parentExit = parent.data.exitFlow; + double totalParentFlow = parentFlow + parentExit; + if (totalParentFlow < 1e-16) + return 0.0; + + double indexLength = 0.0; + + for (const PhysData& physData : parent.physicalNodes) { + indexLength -= infomath::plogp(physData.sumFlowFromM2Node / totalParentFlow); + } + indexLength -= infomath::plogp(parentExit / totalParentFlow); + + indexLength *= totalParentFlow; + + return indexLength; +} + +void MemMapEquation::addMemoryContributions(InfoNode& current, + MemDeltaFlow& oldModuleDelta, + VectorMap& moduleDeltaFlow) +{ + // Overlapping modules + /* + * delta = old.first + new.first + old.second - new.second. + * Two cases: (p(x) = plogp(x)) + * Moving to a module that already have that physical node: (old: p1, p2, new p3, moving p2 -> old:p1, new p2,p3) + * Then old.second = new.second = plogp(physicalNodeSize) -> cancelation -> delta = p(p1) - p(p1+p2) + p(p2+p3) - p(p3) + * Moving to a module that not have that physical node: (old: p1, p2, new -, moving p2 -> old: p1, new: p2) + * Then new.first = new.second = 0 -> delta = p(p1) - p(p1+p2) + p(p2). + */ + auto& physicalNodes = current.physicalNodes; + unsigned int numPhysicalNodes = physicalNodes.size(); + for (unsigned int i = 0; i < numPhysicalNodes; ++i) { + PhysData& physData = physicalNodes[i]; + ModuleToMemNodes& moduleToMemNodes = m_physToModuleToMemNodes[physData.physNodeIndex]; + for (const auto& moduleToMemNode : moduleToMemNodes) { + unsigned int moduleIndex = moduleToMemNode.first; + auto& memNodeSet = moduleToMemNode.second; + if (moduleIndex == current.index) // From where the multiple assigned node is moved + { + double oldPhysFlow = memNodeSet.sumFlow; + double newPhysFlow = memNodeSet.sumFlow - physData.sumFlowFromM2Node; + oldModuleDelta.sumDeltaPlogpPhysFlow += infomath::plogp(newPhysFlow) - infomath::plogp(oldPhysFlow); + oldModuleDelta.sumPlogpPhysFlow += infomath::plogp(physData.sumFlowFromM2Node); + } else // To where the multiple assigned node is moved + { + double oldPhysFlow = memNodeSet.sumFlow; + double newPhysFlow = memNodeSet.sumFlow + physData.sumFlowFromM2Node; + + double sumDeltaPlogpPhysFlow = infomath::plogp(newPhysFlow) - infomath::plogp(oldPhysFlow); + double sumPlogpPhysFlow = infomath::plogp(physData.sumFlowFromM2Node); + moduleDeltaFlow.add(moduleIndex, MemDeltaFlow(moduleIndex, 0.0, 0.0, sumDeltaPlogpPhysFlow, sumPlogpPhysFlow)); + } + } + } + m_memoryContributionsAdded = true; +} + +double MemMapEquation::getDeltaCodelengthOnMovingNode(InfoNode& current, + MemDeltaFlow& oldModuleDelta, + MemDeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) +{ + double deltaL = Base::getDeltaCodelengthOnMovingNode(current, oldModuleDelta, newModuleDelta, moduleFlowData, moduleMembers); + + double delta_nodeFlow_log_nodeFlow = oldModuleDelta.sumDeltaPlogpPhysFlow + newModuleDelta.sumDeltaPlogpPhysFlow + oldModuleDelta.sumPlogpPhysFlow - newModuleDelta.sumPlogpPhysFlow; + + return deltaL - delta_nodeFlow_log_nodeFlow; +} + +// =================================================== +// Consolidation +// =================================================== + +void MemMapEquation::updateCodelengthOnMovingNode(InfoNode& current, + MemDeltaFlow& oldModuleDelta, + MemDeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) +{ + Base::updateCodelengthOnMovingNode(current, oldModuleDelta, newModuleDelta, moduleFlowData, moduleMembers); + if (m_memoryContributionsAdded) + updatePhysicalNodes(current, oldModuleDelta.module, newModuleDelta.module); + else + addMemoryContributionsAndUpdatePhysicalNodes(current, oldModuleDelta, newModuleDelta); + + double delta_nodeFlow_log_nodeFlow = oldModuleDelta.sumDeltaPlogpPhysFlow + newModuleDelta.sumDeltaPlogpPhysFlow + oldModuleDelta.sumPlogpPhysFlow - newModuleDelta.sumPlogpPhysFlow; + + nodeFlow_log_nodeFlow += delta_nodeFlow_log_nodeFlow; + moduleCodelength -= delta_nodeFlow_log_nodeFlow; + codelength -= delta_nodeFlow_log_nodeFlow; +} + +void MemMapEquation::updatePhysicalNodes(InfoNode& current, unsigned int oldModuleIndex, unsigned int bestModuleIndex) +{ + // For all multiple assigned nodes + for (const auto& physData : current.physicalNodes) { + ModuleToMemNodes& moduleToMemNodes = m_physToModuleToMemNodes[physData.physNodeIndex]; + + // Remove contribution to old module + auto overlapIt = moduleToMemNodes.find(oldModuleIndex); + if (overlapIt == moduleToMemNodes.end()) + throw std::length_error(io::Str() << "Couldn't find old module " << oldModuleIndex << " in physical node " << physData.physNodeIndex); + + MemNodeSet& oldMemNodeSet = overlapIt->second; + oldMemNodeSet.sumFlow -= physData.sumFlowFromM2Node; + if (--oldMemNodeSet.numMemNodes == 0) + moduleToMemNodes.erase(overlapIt); + + // Add contribution to new module + overlapIt = moduleToMemNodes.find(bestModuleIndex); + if (overlapIt == moduleToMemNodes.end()) { + moduleToMemNodes.insert(std::make_pair(bestModuleIndex, MemNodeSet(1, physData.sumFlowFromM2Node))); + } else { + MemNodeSet& newMemNodeSet = overlapIt->second; + ++newMemNodeSet.numMemNodes; + newMemNodeSet.sumFlow += physData.sumFlowFromM2Node; + } + } +} + +void MemMapEquation::addMemoryContributionsAndUpdatePhysicalNodes(InfoNode& current, MemDeltaFlow& oldModuleDelta, MemDeltaFlow& newModuleDelta) +{ + unsigned int oldModuleIndex = oldModuleDelta.module; + unsigned int bestModuleIndex = newModuleDelta.module; + + // For all multiple assigned nodes + for (const auto& physData : current.physicalNodes) { + ModuleToMemNodes& moduleToMemNodes = m_physToModuleToMemNodes[physData.physNodeIndex]; + + // Remove contribution to old module + auto overlapIt = moduleToMemNodes.find(oldModuleIndex); + if (overlapIt == moduleToMemNodes.end()) + throw std::length_error("Couldn't find old module among physical node assignments."); + + MemNodeSet& oldMemNodeSet = overlapIt->second; + double oldPhysFlow = oldMemNodeSet.sumFlow; + double newPhysFlow = oldMemNodeSet.sumFlow - physData.sumFlowFromM2Node; + oldModuleDelta.sumDeltaPlogpPhysFlow += infomath::plogp(newPhysFlow) - infomath::plogp(oldPhysFlow); + oldModuleDelta.sumPlogpPhysFlow += infomath::plogp(physData.sumFlowFromM2Node); + oldMemNodeSet.sumFlow -= physData.sumFlowFromM2Node; + if (--oldMemNodeSet.numMemNodes == 0) + moduleToMemNodes.erase(overlapIt); + + // Add contribution to new module + overlapIt = moduleToMemNodes.find(bestModuleIndex); + if (overlapIt == moduleToMemNodes.end()) { + moduleToMemNodes.insert(std::make_pair(bestModuleIndex, MemNodeSet(1, physData.sumFlowFromM2Node))); + oldPhysFlow = 0.0; + newPhysFlow = physData.sumFlowFromM2Node; + newModuleDelta.sumDeltaPlogpPhysFlow += infomath::plogp(newPhysFlow) - infomath::plogp(oldPhysFlow); + newModuleDelta.sumPlogpPhysFlow += infomath::plogp(physData.sumFlowFromM2Node); + } else { + MemNodeSet& newMemNodeSet = overlapIt->second; + oldPhysFlow = newMemNodeSet.sumFlow; + newPhysFlow = newMemNodeSet.sumFlow + physData.sumFlowFromM2Node; + newModuleDelta.sumDeltaPlogpPhysFlow += infomath::plogp(newPhysFlow) - infomath::plogp(oldPhysFlow); + newModuleDelta.sumPlogpPhysFlow += infomath::plogp(physData.sumFlowFromM2Node); + ++newMemNodeSet.numMemNodes; + newMemNodeSet.sumFlow += physData.sumFlowFromM2Node; + } + } +} + +void MemMapEquation::consolidateModules(std::vector& modules) +{ + std::map> validate; + + for (unsigned int i = 0; i < m_numPhysicalNodes; ++i) { + ModuleToMemNodes& modToMemNodes = m_physToModuleToMemNodes[i]; + for (const auto& modToMemNode : modToMemNodes) { + if (++validate[modToMemNode.first][i] > 1) + throw std::domain_error("[InfomapGreedy::consolidateModules] Error updating physical nodes: duplication error"); + + modules[modToMemNode.first]->physicalNodes.emplace_back(i, modToMemNode.second.sumFlow); + } + } +} + +#if 0 +// =================================================== +// Debug +// =================================================== + +void MemMapEquation::printDebug() const +{ + std::cout << "MemMapEquation::m_numPhysicalNodes: " << m_numPhysicalNodes << "\n"; + Base::printDebug(); +} +#endif + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/core/MemMapEquation.h b/src/vendor/cigraph/vendor/infomap/src/core/MemMapEquation.h new file mode 100644 index 00000000000..e4d7410d242 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/MemMapEquation.h @@ -0,0 +1,174 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef MEM_MAPEQUATION_H_ +#define MEM_MAPEQUATION_H_ + +#include "MapEquation.h" +#include "FlowData.h" +#include "../utils/Log.h" +#include +#include +#include +#include + +namespace infomap { + +class InfoNode; +struct MemNodeSet; + +class MemMapEquation : private MapEquation { + using Base = MapEquation; + +public: + using FlowDataType = FlowData; + using DeltaFlowDataType = MemDeltaFlow; + + // =================================================== + // Getters + // =================================================== + + using Base::getIndexCodelength; + + using Base::getModuleCodelength; + + using Base::getCodelength; + + // =================================================== + // IO + // =================================================== + + std::ostream& print(std::ostream& out) const override; + friend std::ostream& operator<<(std::ostream&, const MemMapEquation&); + + // =================================================== + // Init + // =================================================== + + void init(const Config& config) override; + + void initTree(InfoNode& /*root*/) override { } + + void initNetwork(InfoNode& root) override; + + void initSuperNetwork(InfoNode& root) override; + + void initSubNetwork(InfoNode& root) override; + + void initPartition(std::vector& nodes) override; + + // =================================================== + // Codelength + // =================================================== + + double calcCodelength(const InfoNode& parent) const override; + + void addMemoryContributions(InfoNode& current, MemDeltaFlow& oldModuleDelta, VectorMap& moduleDeltaFlow) override; + + double getDeltaCodelengthOnMovingNode(InfoNode& current, + MemDeltaFlow& oldModuleDelta, + MemDeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) override; + + // =================================================== + // Consolidation + // =================================================== + + void updateCodelengthOnMovingNode(InfoNode& current, + MemDeltaFlow& oldModuleDelta, + MemDeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) override; + + void consolidateModules(std::vector& modules) override; + +#if 0 + // =================================================== + // Debug + // =================================================== + + void printDebug() const override; +#endif + +private: + // =================================================== + // Private member functions + // =================================================== + double calcCodelengthOnModuleOfLeafNodes(const InfoNode& parent) const override; + + // =================================================== + // Init + // =================================================== + + void initPhysicalNodes(InfoNode& root); + + void initPartitionOfPhysicalNodes(std::vector& nodes); + + // =================================================== + // Codelength + // =================================================== + + void calculateCodelength(std::vector& nodes) override; + + using Base::calculateCodelengthTerms; + + using Base::calculateCodelengthFromCodelengthTerms; + + void calculateNodeFlow_log_nodeFlow(); + + // =================================================== + // Consolidation + // =================================================== + + void updatePhysicalNodes(InfoNode& current, unsigned int oldModuleIndex, unsigned int bestModuleIndex); + + void addMemoryContributionsAndUpdatePhysicalNodes(InfoNode& current, MemDeltaFlow& oldModuleDelta, MemDeltaFlow& newModuleDelta); + +public: + // =================================================== + // Public member variables + // =================================================== + + using Base::codelength; + using Base::indexCodelength; + using Base::moduleCodelength; + +private: + // =================================================== + // Private member variables + // =================================================== + + using Base::enter_log_enter; + using Base::enterFlow; + using Base::enterFlow_log_enterFlow; + using Base::exit_log_exit; + using Base::flow_log_flow; // node.(flow + exitFlow) + using Base::nodeFlow_log_nodeFlow; // constant while the leaf network is the same + + // For hierarchical + using Base::exitNetworkFlow; + using Base::exitNetworkFlow_log_exitNetworkFlow; + + using ModuleToMemNodes = std::map; + + std::vector m_physToModuleToMemNodes; // vector[physicalNodeID] map + unsigned int m_numPhysicalNodes = 0; + bool m_memoryContributionsAdded = false; +}; + +struct MemNodeSet { + MemNodeSet(unsigned int numMemNodes, double sumFlow) : numMemNodes(numMemNodes), sumFlow(sumFlow) { } + unsigned int numMemNodes; // use counter to check for zero to avoid round-off errors in sumFlow + double sumFlow; +}; + +} // namespace infomap + +#endif // MEM_MAPEQUATION_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/MetaMapEquation.cpp b/src/vendor/cigraph/vendor/infomap/src/core/MetaMapEquation.cpp new file mode 100644 index 00000000000..48685fb601f --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/MetaMapEquation.cpp @@ -0,0 +1,271 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "MetaMapEquation.h" +#include "FlowData.h" +#include "InfoNode.h" + +#include +#include + +namespace infomap { + +double MetaMapEquation::getModuleCodelength() const +{ + return moduleCodelength + metaCodelength * metaDataRate; +} + +double MetaMapEquation::getCodelength() const +{ + return codelength + metaCodelength * metaDataRate; +} + +// =================================================== +// IO +// =================================================== + +std::ostream& MetaMapEquation::print(std::ostream& out) const +{ + return out << indexCodelength << " + " << moduleCodelength << " + " << metaCodelength << " = " << io::toPrecision(getCodelength()); +} + +std::ostream& operator<<(std::ostream& out, const MetaMapEquation& mapEq) +{ + return mapEq.print(out); +} + +// =================================================== +// Init +// =================================================== + +void MetaMapEquation::init(const Config& config) +{ + Log(3) << "MetaMapEquation::init()...\n"; + numMetaDataDimensions = config.numMetaDataDimensions; + metaDataRate = config.metaDataRate; + weightByFlow = !config.unweightedMetaData; +} + +void MetaMapEquation::initTree(InfoNode& root) +{ + Log(3) << "MetaMapEquation::initTree()...\n"; + initMetaNodes(root); +} + +void MetaMapEquation::initNetwork(InfoNode& root) +{ + Log(3) << "MetaMapEquation::initNetwork()...\n"; + Base::initNetwork(root); + m_unweightedNodeFlow = 1.0 / root.childDegree(); +} + +void MetaMapEquation::initPartition(std::vector& nodes) +{ + initPartitionOfMetaNodes(nodes); + calculateCodelength(nodes); +} + +void MetaMapEquation::initMetaNodes(InfoNode& root) +{ + bool notInitiated = root.firstChild->metaCollection.empty(); + if (notInitiated) { + Log(3) << "MetaMapEquation::initMetaNodes()...\n"; + + for (auto it = root.begin_post_depth_first(); !it.isEnd(); ++it) { + auto& node = *it; + if (node.isRoot()) { + break; + } + if (node.isLeaf()) { + if (!node.metaData.empty()) { + // TODO: Use flow here and move weightByFlow choice to metaCollection, using flowCount? + double flow = weightByFlow ? node.data.flow : m_unweightedNodeFlow; + node.parent->metaCollection.add(node.metaData[0], flow); + } else { + throw std::length_error("A node is missing meta data using MetaMapEquation"); + } + } else { + node.parent->metaCollection.add(node.metaCollection); + } + } + } +} + +void MetaMapEquation::initPartitionOfMetaNodes(std::vector& nodes) +{ + Log(4) << "MetaMapEquation::initPartitionOfMetaNodes()...\n"; + m_moduleToMetaCollection.clear(); + + for (auto& n : nodes) { + InfoNode& node = *n; + unsigned int moduleIndex = node.index; // Assume unique module index for all nodes in this initiation phase + if (node.metaCollection.empty()) { + if (!node.metaData.empty()) { + double flow = weightByFlow ? node.data.flow : m_unweightedNodeFlow; + node.metaCollection.add(node.metaData[0], flow); + } else + throw std::length_error("A node is missing meta data using MetaMapEquation"); + } + m_moduleToMetaCollection[moduleIndex] = node.metaCollection; + } +} + +// =================================================== +// Codelength +// =================================================== + +void MetaMapEquation::calculateCodelength(std::vector& nodes) +{ + calculateCodelengthTerms(nodes); + + calculateCodelengthFromCodelengthTerms(); + + metaCodelength = 0.0; + + // Treat each node as a single module + for (InfoNode* n : nodes) { + InfoNode& node = *n; + metaCodelength += node.metaCollection.calculateEntropy(); + } +} + +double MetaMapEquation::calcCodelength(const InfoNode& parent) const +{ + return parent.isLeafModule() ? calcCodelengthOnModuleOfLeafNodes(parent) : Base::calcCodelengthOnModuleOfModules(parent); +} + +double MetaMapEquation::calcCodelengthOnModuleOfLeafNodes(const InfoNode& parent) const +{ + double indexLength = Base::calcCodelength(parent); + + // Meta addition + MetaCollection metaCollection; + for (const InfoNode& node : parent) { + if (!node.metaCollection.empty()) + metaCollection.add(node.metaCollection); + else + metaCollection.add(node.metaData[0], weightByFlow ? node.data.flow : m_unweightedNodeFlow); // TODO: Initiate to collection and use all dimensions + } + + double _metaCodelength = metaCollection.calculateEntropy(); + + return indexLength + metaDataRate * _metaCodelength; +} + +double MetaMapEquation::getDeltaCodelengthOnMovingNode(InfoNode& current, + DeltaFlow& oldModuleDelta, + DeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) +{ + double deltaL = Base::getDeltaCodelengthOnMovingNode(current, oldModuleDelta, newModuleDelta, moduleFlowData, moduleMembers); + + double deltaMetaL = 0.0; + + unsigned int oldModuleIndex = oldModuleDelta.module; + unsigned int newModuleIndex = newModuleDelta.module; + + // Remove codelength of old and new module before changes + deltaMetaL -= getCurrentModuleMetaCodelength(oldModuleIndex, current, 0); + deltaMetaL -= getCurrentModuleMetaCodelength(newModuleIndex, current, 0); + // Add codelength of old module with current node removed + deltaMetaL += getCurrentModuleMetaCodelength(oldModuleIndex, current, -1); + // Add codelength of old module with current node added + deltaMetaL += getCurrentModuleMetaCodelength(newModuleIndex, current, 1); + + return deltaL + deltaMetaL * metaDataRate; +} + +double MetaMapEquation::getCurrentModuleMetaCodelength(unsigned int module, InfoNode& current, int addRemoveOrNothing) +{ + auto& currentMetaCollection = m_moduleToMetaCollection[module]; + + double moduleMetaCodelength = 0.0; + + if (addRemoveOrNothing == 0) { + moduleMetaCodelength = currentMetaCollection.calculateEntropy(); + } + // If add or remove, do the change, calculate new codelength and then undo the change + else if (addRemoveOrNothing == 1) { + currentMetaCollection.add(current.metaCollection); + moduleMetaCodelength = currentMetaCollection.calculateEntropy(); + currentMetaCollection.remove(current.metaCollection); + } else { + currentMetaCollection.remove(current.metaCollection); + moduleMetaCodelength = currentMetaCollection.calculateEntropy(); + currentMetaCollection.add(current.metaCollection); + } + + return moduleMetaCodelength; +} + +// =================================================== +// Consolidation +// =================================================== + +void MetaMapEquation::updateCodelengthOnMovingNode(InfoNode& current, + DeltaFlow& oldModuleDelta, + DeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) +{ + Base::updateCodelengthOnMovingNode(current, oldModuleDelta, newModuleDelta, moduleFlowData, moduleMembers); + + double deltaMetaL = 0.0; + + unsigned int oldModuleIndex = oldModuleDelta.module; + unsigned int newModuleIndex = newModuleDelta.module; + + // Remove codelength of old and new module before changes + deltaMetaL -= getCurrentModuleMetaCodelength(oldModuleIndex, current, 0); + deltaMetaL -= getCurrentModuleMetaCodelength(newModuleIndex, current, 0); + + // Update meta data from moving node + updateMetaData(current, oldModuleIndex, newModuleIndex); + + // Add codelength of old and new module after changes + deltaMetaL += getCurrentModuleMetaCodelength(oldModuleIndex, current, 0); + deltaMetaL += getCurrentModuleMetaCodelength(newModuleIndex, current, 0); + + metaCodelength += deltaMetaL; +} + +void MetaMapEquation::updateMetaData(InfoNode& current, unsigned int oldModuleIndex, unsigned int bestModuleIndex) +{ + // Remove meta id from old module (can be a set of meta ids when moving submodules in coarse tune) + auto& oldMetaCollection = m_moduleToMetaCollection[oldModuleIndex]; + oldMetaCollection.remove(current.metaCollection); + + // Add meta id to new module + auto& newMetaCollection = m_moduleToMetaCollection[bestModuleIndex]; + newMetaCollection.add(current.metaCollection); +} + +void MetaMapEquation::consolidateModules(std::vector& modules) +{ + for (auto& module : modules) { + if (module == nullptr) + continue; + module->metaCollection = m_moduleToMetaCollection[module->index]; + } +} + +#if 0 +// =================================================== +// Debug +// =================================================== + +void MetaMapEquation::printDebug() const +{ + std::cout << "MetaMapEquation\n"; + Base::printDebug(); +} +#endif + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/core/MetaMapEquation.h b/src/vendor/cigraph/vendor/infomap/src/core/MetaMapEquation.h new file mode 100644 index 00000000000..29b780c6114 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/MetaMapEquation.h @@ -0,0 +1,185 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef META_MAPEQUATION_H_ +#define META_MAPEQUATION_H_ + +#include "MapEquation.h" +#include "FlowData.h" +#include "../utils/Log.h" +#include "../utils/MetaCollection.h" +#include +#include +#include +#include + +namespace infomap { + +class InfoNode; + +class MetaMapEquation : private MapEquation<> { + using Base = MapEquation<>; + +public: + using FlowDataType = FlowData; + using DeltaFlowDataType = DeltaFlow; + + // =================================================== + // Getters + // =================================================== + + using Base::getIndexCodelength; + + double getModuleCodelength() const override; + + double getCodelength() const override; + + double getMetaCodelength(bool unweighted = false) const + { + return unweighted ? metaCodelength : metaDataRate * metaCodelength; + }; + + // =================================================== + // IO + // =================================================== + + std::ostream& print(std::ostream& out) const override; + friend std::ostream& operator<<(std::ostream&, const MetaMapEquation&); + + // =================================================== + // Init + // =================================================== + + void init(const Config& config) override; + + void initTree(InfoNode& root) override; + + void initNetwork(InfoNode& root) override; + + using Base::initSuperNetwork; + + using Base::initSubNetwork; + + void initPartition(std::vector& nodes) override; + + // =================================================== + // Codelength + // =================================================== + + double calcCodelength(const InfoNode& parent) const override; + + using Base::addMemoryContributions; + + double getDeltaCodelengthOnMovingNode(InfoNode& current, + DeltaFlow& oldModuleDelta, + DeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) override; + + // =================================================== + // Consolidation + // =================================================== + + void updateCodelengthOnMovingNode(InfoNode& current, + DeltaFlow& oldModuleDelta, + DeltaFlow& newModuleDelta, + std::vector& moduleFlowData, + std::vector& moduleMembers) override; + + void consolidateModules(std::vector& modules) override; + +#if 0 + // =================================================== + // Debug + // =================================================== + + void printDebug() const override; +#endif + +private: + // =================================================== + // Private member functions + // =================================================== + double calcCodelengthOnModuleOfLeafNodes(const InfoNode& parent) const override; + + // =================================================== + // Init + // =================================================== + + void initMetaNodes(InfoNode& root); + + void initPartitionOfMetaNodes(std::vector& nodes); + + // =================================================== + // Codelength + // =================================================== + + void calculateCodelength(std::vector& nodes) override; + + using Base::calculateCodelengthTerms; + + using Base::calculateCodelengthFromCodelengthTerms; + + // =================================================== + // Consolidation + // =================================================== + + void updateMetaData(InfoNode& current, unsigned int oldModuleIndex, unsigned int bestModuleIndex); + +public: + // =================================================== + // Public member variables + // =================================================== + + using Base::codelength; + using Base::indexCodelength; + using Base::moduleCodelength; + +private: + // =================================================== + // Private member functions + // =================================================== + + /** + * Get meta codelength of module of current node + * @param addRemoveOrNothing +1, -1 or 0 to calculate codelength + * as if current node was added, removed or untouched in current module + */ + double getCurrentModuleMetaCodelength(unsigned int module, InfoNode& current, int addRemoveOrNothing); + + // =================================================== + // Private member variables + // =================================================== + + using Base::enter_log_enter; + using Base::enterFlow; + using Base::enterFlow_log_enterFlow; + using Base::exit_log_exit; + using Base::flow_log_flow; // node.(flow + exitFlow) + using Base::nodeFlow_log_nodeFlow; // constant while the leaf network is the same + + // For hierarchical + using Base::exitNetworkFlow; + using Base::exitNetworkFlow_log_exitNetworkFlow; + + // For meta data + using ModuleMetaMap = std::map; // moduleId -> (metaId -> count) + + ModuleMetaMap m_moduleToMetaCollection; + + unsigned int numMetaDataDimensions = 0; + double metaDataRate = 1.0; + bool weightByFlow = true; + double metaCodelength = 0.0; + double m_unweightedNodeFlow = 0.0; +}; + +} // namespace infomap + +#endif // META_MAPEQUATION_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/StateNetwork.cpp b/src/vendor/cigraph/vendor/infomap/src/core/StateNetwork.cpp new file mode 100644 index 00000000000..464428c1e16 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/StateNetwork.cpp @@ -0,0 +1,329 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "StateNetwork.h" +#include "../utils/FlowCalculator.h" +#include "../utils/Log.h" +#include "../io/SafeFile.h" +#include +#include + +namespace infomap { + +std::pair StateNetwork::addStateNode(const StateNode& node) +{ + auto ret = m_nodes.insert(StateNetwork::NodeMap::value_type(node.id, node)); + if (ret.second) { + // If state node didn't exist, also create the associated physical node + addPhysicalNode(node.physicalId); + if (node.id != node.physicalId) { + m_haveMemoryInput = true; + } + } + return ret; +} + +std::pair StateNetwork::addStateNode(unsigned int id, unsigned int physId) +{ + m_higherOrderInputMethodCalled = true; + return addStateNode(StateNode(id, physId)); +} + +std::pair StateNetwork::addNode(unsigned int id) +{ + return addStateNode(StateNode(id)); +} + +std::pair StateNetwork::addNode(unsigned int id, double weight) +{ + auto ret = addNode(id); + auto& node = ret.first->second; + node.weight = weight; + return ret; +} + +std::pair StateNetwork::addNode(unsigned int id, std::string name) +{ + m_names[id] = std::move(name); + return addNode(id); +} + +std::pair StateNetwork::addNode(unsigned int id, std::string name, double weight) +{ + m_names[id] = std::move(name); + return addNode(id, weight); +} + +StateNetwork::PhysNode& StateNetwork::addPhysicalNode(unsigned int physId) +{ + auto& physNode = m_physNodes[physId]; + physNode.physId = physId; + m_sumNodeWeight += 1.0; + return physNode; +} + +StateNetwork::PhysNode& StateNetwork::addPhysicalNode(unsigned int physId, double weight) +{ + auto& physNode = addPhysicalNode(physId); + physNode.weight = weight; + m_sumNodeWeight += weight; + return physNode; +} + +StateNetwork::PhysNode& StateNetwork::addPhysicalNode(unsigned int physId, const std::string& name) +{ + auto& physNode = addPhysicalNode(physId); + m_names[physId] = name; + m_sumNodeWeight += 1.0; + return physNode; +} + +StateNetwork::PhysNode& StateNetwork::addPhysicalNode(unsigned int physId, double weight, const std::string& name) +{ + auto& physNode = addPhysicalNode(physId); + physNode.weight = weight; + m_sumNodeWeight += weight; + m_names[physId] = name; + return physNode; +} + +std::pair::iterator, bool> StateNetwork::addName(unsigned int id, const std::string& name) +{ + return m_names.insert(std::make_pair(id, name)); +} + +bool StateNetwork::addLink(unsigned int sourceId, unsigned int targetId, double weight) +{ + if (weight < m_config.weightThreshold || weight <= 0) { + ++m_numLinksIgnoredByWeightThreshold; + m_totalLinkWeightIgnored += weight; + return false; + } + m_totalLinkWeightAdded += weight; + + if (sourceId == targetId) { + ++m_numSelfLinksFound; + if (m_config.noSelfLinks) { + return false; + } + ++m_numSelfLinks; + m_sumSelfLinkWeight += weight; + } + + addNode(sourceId); + addNode(targetId); + + ++m_numLinks; + m_sumLinkWeight += weight; + + bool addedNewLink = true; + + // Aggregate link weights if they are defined more than once + auto& outLinks = m_nodeLinkMap[sourceId]; + if (outLinks.empty()) { + outLinks[targetId] = weight; + } else { + auto ret = outLinks.insert(std::make_pair(StateNode(targetId), LinkData(weight))); + auto& linkData = ret.first->second; + if (!ret.second) { + linkData.weight += weight; + ++m_numAggregatedLinks; + --m_numLinks; + addedNewLink = false; + } else { + linkData.weight = weight; + } + } + m_outWeights[sourceId] += weight; + return addedNewLink; +} + +bool StateNetwork::addLink(unsigned int sourceId, unsigned int targetId, unsigned long weight) +{ + return addLink(sourceId, targetId, static_cast(weight)); +} + +bool StateNetwork::removeLink(unsigned int sourceId, unsigned int targetId) +{ + auto itSource = m_nodeLinkMap.find(sourceId); + if (itSource == m_nodeLinkMap.end()) { + return false; + } + + auto& targetMap = itSource->second; + auto itTarget = targetMap.find(targetId); + + if (itTarget == targetMap.end()) { + return false; + } + + double weight = itTarget->second.weight; + + targetMap.erase(itTarget); + if (targetMap.empty()) { + m_nodeLinkMap.erase(itSource); + } else { + --m_numAggregatedLinks; + } + + --m_numLinks; + m_sumLinkWeight -= weight; + m_totalLinkWeightAdded -= weight; + + if (sourceId == targetId) { + --m_numSelfLinksFound; + --m_numSelfLinks; + m_sumSelfLinkWeight -= weight; + } + + m_outWeights[sourceId] -= weight; + + return true; +} + +bool StateNetwork::undirectedToDirected() +{ + // Collect links in separate data structure to not risk iterating newly added links + if (!m_config.isUndirectedFlow()) { + return false; + } + std::deque oppositeLinks; + for (auto& linkIt : m_nodeLinkMap) { + unsigned int sourceId = linkIt.first.id; + const auto& subLinks = linkIt.second; + for (auto& subIt : subLinks) { + unsigned int targetId = subIt.first.id; + if (targetId == sourceId) { + continue; // Self-links are treated as directed on undirected networks + } + double weight = subIt.second.weight; + oppositeLinks.emplace_back(targetId, sourceId, weight); + } + } + for (auto& link : oppositeLinks) { + addLink(link.source, link.target, link.weight); + } + return true; +} + +void StateNetwork::clearLinks() +{ + m_nodeLinkMap.clear(); +} + +void StateNetwork::clear() +{ + m_nodes.clear(); + m_nodeLinkMap.clear(); + m_physNodes.clear(); + m_outWeights.clear(); + m_names.clear(); + + m_haveDirectedInput = false; + m_haveMemoryInput = false; + m_numStateNodesFound = 0; + m_numLinks = 0; + m_numSelfLinksFound = 0; + m_sumLinkWeight = 0.0; + m_numSelfLinks = 0; + m_sumSelfLinkWeight = 0.0; + m_numAggregatedLinks = 0; + m_totalLinkWeightAdded = 0.0; + m_numLinksIgnoredByWeightThreshold = 0; + m_totalLinkWeightIgnored = 0.0; +} + +void StateNetwork::writeStateNetwork(const std::string& filename) const +{ + if (filename.empty()) + throw std::runtime_error("writeStateNetwork called with empty filename"); + + SafeOutFile outFile(filename); + + outFile << "# v" << INFOMAP_VERSION << "\n" + << "# ./Infomap " << m_config.parsedString << "\n"; + + if (!m_names.empty()) { + outFile << "*Vertices\n"; + for (auto& nameIt : m_names) { + auto& physId = nameIt.first; + auto& name = nameIt.second; + outFile << physId << " \"" << name << "\"\n"; + } + } + + outFile << "*States\n"; + outFile << "# stateId physicalId\n"; + for (const auto& nodeIt : nodes()) { + const auto& node = nodeIt.second; + outFile << node.id << " " << node.physicalId; + // Optional name + if (!node.name.empty()) + outFile << " \"" << node.name << "\""; + outFile << "\n"; + } + + outFile << "*Links\n"; + for (auto& linkIt : m_nodeLinkMap) { + for (auto& subIt : linkIt.second) { + outFile << linkIt.first.id << " " << subIt.first.id << " " << subIt.second.weight << "\n"; + } + } +} + +void StateNetwork::writePajekNetwork(const std::string& filename, bool printFlow) const +{ + if (filename.empty()) + throw std::runtime_error("writePajekNetwork called with empty filename"); + + SafeOutFile outFile(filename); + + outFile << "# v" << INFOMAP_VERSION << "\n" + << "# ./Infomap " << m_config.parsedString << "\n"; + if (haveMemoryInput()) + outFile << "# State network as physical network\n"; + + outFile << "*Vertices\n"; + outFile << "#id name " << (printFlow ? "flow" : "weight") << "\n"; + for (const auto& nodeIt : nodes()) { + const auto& node = nodeIt.second; + outFile << node.id << " \""; + // Name, default to id + const auto& nameIt = haveMemoryInput() ? m_names.end() : m_names.find(node.id); + if (nameIt != m_names.end()) + outFile << nameIt->second; + else + outFile << node.id; + outFile << "\" " << (printFlow ? node.flow : node.weight) << "\n"; + } + + outFile << (m_config.printAsUndirected() ? "*Edges" : "*Arcs") << "\n"; + outFile << "#source target " << (printFlow ? "flow" : "weight") << "\n"; + for (auto& linkIt : m_nodeLinkMap) { + for (auto& subIt : linkIt.second) { + auto& linkData = subIt.second; + outFile << linkIt.first.id << " " << subIt.first.id << " " << (printFlow ? linkData.flow : linkData.weight) << "\n"; + } + } +} + +std::pair StateNetwork::addStateNodeWithAutogeneratedId(unsigned int physId) +{ + // Keys sorted with std::less comparator, so last key is the largest + unsigned int stateId = m_nodes.empty() ? 0 : m_nodes.crbegin()->first + 1; + return addStateNode(stateId, physId); +} + +std::pair StateNetwork::addStateNodeWithDeterministicId(unsigned int physId, unsigned int layerId, unsigned int numLayersLog2) +{ + unsigned int stateId = physId << (numLayersLog2 + 1) | layerId; + return addStateNode(stateId, physId); +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/core/StateNetwork.h b/src/vendor/cigraph/vendor/infomap/src/core/StateNetwork.h new file mode 100644 index 00000000000..97b43084228 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/StateNetwork.h @@ -0,0 +1,216 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef STATE_NETWORK_H_ +#define STATE_NETWORK_H_ + +#include "../io/Config.h" +#include +#include +#include +#include +#include + +namespace infomap { + +class StateNetwork { +public: + struct StateNode { + unsigned int id = 0; + unsigned int physicalId = 0; + std::string name; + unsigned int layerId = 0; + double weight = 1.0; + double flow = 0.0; + double enterFlow = 0.0; + double exitFlow = 0.0; + double teleFlow = 0.0; + + StateNode(unsigned int id = 0) : id(id), physicalId(id) { } + + StateNode(unsigned int id, unsigned int physicalId) : id(id), physicalId(physicalId) { } + + StateNode(unsigned int id, unsigned int physicalId, std::string name) : id(id), physicalId(physicalId), name(std::move(name)) { } + + bool operator==(const StateNode& rhs) const { return id == rhs.id; } + bool operator!=(const StateNode& rhs) const { return id != rhs.id; } + bool operator<(const StateNode& rhs) const { return id < rhs.id; } + }; + + struct PhysNode { + unsigned int physId = 0; + double weight = 1.0; + PhysNode(unsigned int physId) : physId(physId) { } + PhysNode(unsigned int physId, double weight) : physId(physId), weight(weight) { } + PhysNode(double weight = 1.0) : weight(weight) { } + }; + + struct LinkData { + double weight = 1.0; + double flow = 0.0; + + LinkData(double weight = 1.0) : weight(weight) { } + + LinkData& operator+=(double w) + { + weight += w; + return *this; + } + }; + + struct StateLink { + StateLink(unsigned int sourceIndex = 0, unsigned int targetIndex = 0, double weight = 0.0) + : source(sourceIndex), + target(targetIndex), + weight(weight), + flow(weight) { } + + unsigned int source; + unsigned int target; + double weight; + double flow; + }; + + // Unique state id to state node + using NodeMap = std::map; + using OutLinkMap = std::map; + using NodeLinkMap = std::map; + +protected: + friend class FlowCalculator; + // Config + Config m_config; + // Network + bool m_haveDirectedInput = false; + bool m_haveMemoryInput = false; + bool m_higherOrderInputMethodCalled = false; + NodeMap m_nodes; // Nodes indexed by state id (equal physical id for first-order networks) + NodeLinkMap m_nodeLinkMap; + unsigned int m_numStateNodesFound = 0; + double m_sumNodeWeight = 0.0; + unsigned int m_numLinks = 0; + double m_sumLinkWeight = 0.0; + unsigned int m_numSelfLinksFound = 0; + unsigned int m_numSelfLinks = 0; + double m_sumSelfLinkWeight = 0.0; + unsigned int m_numAggregatedLinks = 0; + double m_totalLinkWeightAdded = 0.0; + unsigned int m_numLinksIgnoredByWeightThreshold = 0; + double m_totalLinkWeightIgnored = 0.0; + std::map m_outWeights; + bool m_haveNodeWeights = false; + bool m_haveStateNodeWeights = false; + bool m_haveFileInput = false; + // Attributes + std::map m_names; + std::map m_physNodes; + + // Bipartite + unsigned int m_bipartiteStartId = 0; + +public: + StateNetwork() : m_config(Config()) { } + StateNetwork(Config config) : m_config(std::move(config)) { } + virtual ~StateNetwork() = default; + + StateNetwork(const StateNetwork&) = delete; + StateNetwork& operator=(const StateNetwork&) = delete; + StateNetwork(StateNetwork&&) = delete; + StateNetwork& operator=(StateNetwork&&) = delete; + + // Config + void setConfig(const Config& config) { m_config = config; } + + // Mutators + std::pair addStateNode(const StateNode& node); + std::pair addStateNode(unsigned int id, unsigned int physId); + std::pair addNode(unsigned int id); + std::pair addNode(unsigned int id, std::string name); + std::pair addNode(unsigned int id, double weight); + std::pair addNode(unsigned int id, std::string, double weight); + PhysNode& addPhysicalNode(unsigned int physId); + PhysNode& addPhysicalNode(unsigned int physId, double weight); + PhysNode& addPhysicalNode(unsigned int physId, const std::string& name); + PhysNode& addPhysicalNode(unsigned int physId, double weight, const std::string& name); + std::pair::iterator, bool> addName(unsigned int id, const std::string&); + bool addLink(unsigned int sourceId, unsigned int targetId, double weight = 1.0); + bool addLink(unsigned int sourceId, unsigned int targetId, unsigned long weight); + + /** + * Remove link + * Note: It will not remove nodes if they become dangling + */ + bool removeLink(unsigned int sourceId, unsigned int targetId); + + // Expand each undirected link to two opposite directed links + bool undirectedToDirected(); + + /** + * Clear all network data and reset to default state. + */ + virtual void clear(); + + /** + * Clear link data but keep node data. + */ + virtual void clearLinks(); + + // Getters + const NodeMap& nodes() const { return m_nodes; } + unsigned int numNodes() const { return m_nodes.size(); } + unsigned int numPhysicalNodes() const { return m_physNodes.size(); } + double sumNodeWeight() const { return m_sumNodeWeight; } + const NodeLinkMap& nodeLinkMap() const { return m_nodeLinkMap; } + NodeLinkMap& nodeLinkMap() { return m_nodeLinkMap; } + unsigned int numLinks() const { return m_numLinks; } + double sumLinkWeight() const { return m_sumLinkWeight; } + unsigned int numSelfLinks() const { return m_numSelfLinks; } + double sumSelfLinkWeight() const { return m_sumSelfLinkWeight; } + // Use convention of counting self-links only once, treating them as directed + double sumWeightedDegree() const { return 2 * sumLinkWeight() - (m_config.isUndirectedFlow() ? sumSelfLinkWeight() : 0); } + unsigned int sumDegree() const { return 2 * numLinks() - (m_config.isUndirectedFlow() ? numSelfLinks() : 0); } + std::map& outWeights() { return m_outWeights; } + std::map& names() { return m_names; } + const std::map& names() const { return m_names; } + bool haveNodeWeights() const { return m_haveNodeWeights; } + bool haveStateNodeWeights() const { return m_haveStateNodeWeights; } + bool haveFileInput() const { return m_haveFileInput; } + + virtual const std::map>& metaData() const = 0; + + bool haveDirectedInput() const { return m_haveDirectedInput; } + bool haveMemoryInput() const { return m_haveMemoryInput; } + bool higherOrderInputMethodCalled() const { return m_higherOrderInputMethodCalled; } + // Bipartite + bool isBipartite() const { return m_bipartiteStartId > 0; } + unsigned int bipartiteStartId() const { return m_bipartiteStartId; } + void setBipartiteStartId(unsigned int value) { m_bipartiteStartId = value; } + + /** + * Write state network to file. + */ + void writeStateNetwork(const std::string& filename) const; + + /** + * Write state network as first-order Pajek network, where + * state nodes are treated as physical nodes. + * For a non-memory input, the state nodes are equivalent to + * physical nodes. + */ + void writePajekNetwork(const std::string& filename, bool printFlow = false) const; + +protected: + std::pair addStateNodeWithAutogeneratedId(unsigned int physId); + + std::pair addStateNodeWithDeterministicId(unsigned int physId, unsigned int layerId, unsigned int numLayersLog2); +}; + +} // namespace infomap + +#endif // STATE_NETWORK_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/iterators/InfomapIterator.cpp b/src/vendor/cigraph/vendor/infomap/src/core/iterators/InfomapIterator.cpp new file mode 100644 index 00000000000..433d9edd242 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/iterators/InfomapIterator.cpp @@ -0,0 +1,238 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "InfomapIterator.h" +#include "../InfoNode.h" +#include +#include // std::pair + +namespace infomap { + +InfomapIterator& InfomapIterator::operator++() noexcept +{ + const auto root = m_current->getInfomapRoot(); + auto current = root ? root : m_current; + + if (current->firstChild) { + current = current->firstChild; + ++m_depth; + m_path.push_back(1); + } else { + // Current node is a leaf + // Presupposes that the next pointer can't reach out from the current parent. + + bool tryNext = true; + + while (tryNext) { + tryNext = false; + + while (!current->next) { + if (current->owner) { + current = current->owner; + + if (current == m_root) { // Check if back to beginning + m_current = nullptr; + return *this; + } + + tryNext = true; + break; + } + if (current->parent) { + current = current->parent; + --m_depth; + m_path.pop_back(); + + if (current == m_root) { // Check if back to beginning + m_current = nullptr; + return *this; + } + } else { // null also if no children in first place + m_current = nullptr; + return *this; + } + } + } + + current = current->next; + + if (!current->isLeaf() && (static_cast(m_moduleIndexLevel) >= m_depth)) { + ++m_moduleIndex; + } + + ++m_path.back(); + } + + m_current = current; + return *this; +} + +double InfomapIterator::modularCentrality() const noexcept +{ + if (m_current->parent == nullptr) { + // The root node has no modular centrality + return 0.0; + } + + const auto p_m = m_current->parent->data.flow; + const auto p_u = m_current->data.flow; + const auto p_diff = p_m - p_u; + + if (p_diff > 0.0) { + return -p_diff * std::log2(p_diff / p_m); + } + + return 0.0; +} + +// ------------------------------------- +// InfomapModuleIterator +// ------------------------------------- + +InfomapIterator& InfomapModuleIterator::operator++() noexcept +{ + InfomapIterator::operator++(); + while (!isEnd() && m_current->isLeaf()) { + InfomapIterator::operator++(); + } + return *this; +} + +// ------------------------------------- +// InfomapLeafModuleIterator +// ------------------------------------- + +void InfomapLeafModuleIterator::init() noexcept +{ + while (!isEnd() && !m_current->isLeafModule()) { + InfomapIterator::operator++(); + } +} + +InfomapIterator& InfomapLeafModuleIterator::operator++() noexcept +{ + InfomapIterator::operator++(); + while (!isEnd() && !m_current->isLeafModule()) { + InfomapIterator::operator++(); + } + return *this; +} + +// ------------------------------------- +// InfomapLeafIterator +// ------------------------------------- + +void InfomapLeafIterator::init() noexcept +{ + while (!isEnd() && !m_current->isLeaf()) { + InfomapIterator::operator++(); + } +} + +InfomapIterator& InfomapLeafIterator::operator++() noexcept +{ + InfomapIterator::operator++(); + while (!isEnd() && !m_current->isLeaf()) { + InfomapIterator::operator++(); + } + return *this; +} + +// ------------------------------------- +// InfomapIteratorPhysical +// ------------------------------------- + +InfomapIterator& InfomapIteratorPhysical::operator++() noexcept +{ + if (m_physNodes.empty()) { + // Iterate modules + InfomapIterator::operator++(); + if (isEnd()) { + return *this; + } + if (m_current->isLeaf()) { + // Copy current iterator to restart after iterating through the leaf nodes + auto firstLeafIt = *this; + // If on a leaf node, loop through and aggregate to physical nodes + while (!isEnd() && m_current->isLeaf()) { + auto ret = m_physNodes.insert(std::make_pair(m_current->physicalId, InfoNode(*m_current))); + auto& physNode = ret.first->second; + if (ret.second) { + // New physical node, use same parent as the state leaf node + physNode.parent = m_current->parent; + } else { + // Not inserted, add flow to existing physical node + // TODO: If exitFlow should be correct, flow between memory nodes within same physical node should be subtracted. + physNode.data += m_current->data; + } + physNode.stateNodes.push_back(m_current->stateId); + InfomapIterator::operator++(); + } + // Store current iterator to continue with after iterating physical leaf nodes + m_oldIter = *this; + // Reset path/depth/moduleIndex to values for first leaf node + m_path = firstLeafIt.m_path; + m_depth = firstLeafIt.m_depth; + m_moduleIndex = firstLeafIt.m_moduleIndex; + // Set current node to the first physical node + m_physIter = m_physNodes.begin(); + m_current = &m_physIter->second; + } + } else { + // Iterate physical nodes instead of leaf state nodes + ++m_physIter; + ++m_path.back(); + if (m_physIter == m_physNodes.end()) { + // End of leaf nodes + m_physNodes.clear(); + m_path.pop_back(); + // reset iterator to the one after the leaf nodes + *this = m_oldIter; + } else { + // Set iterator node to the currently iterated physical node + m_current = &m_physIter->second; + } + } + return *this; +} + +// ------------------------------------- +// InfomapLeafIteratorPhysical +// ------------------------------------- + +void InfomapLeafIteratorPhysical::init() noexcept +{ + while (!isEnd() && !m_current->isLeaf()) { + InfomapIteratorPhysical::operator++(); + } +} + +InfomapIterator& InfomapLeafIteratorPhysical::operator++() noexcept +{ + InfomapIteratorPhysical::operator++(); + while (!isEnd() && !m_current->isLeaf()) { + InfomapIteratorPhysical::operator++(); + } + return *this; +} + +// ------------------------------------- +// InfomapParentIterator +// ------------------------------------- + +InfomapParentIterator& InfomapParentIterator::operator++() noexcept +{ + m_current = m_current->parent; + if (m_current != nullptr && m_current->owner != nullptr) { + m_current = m_current->owner; + } + return *this; +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/core/iterators/InfomapIterator.h b/src/vendor/cigraph/vendor/infomap/src/core/iterators/InfomapIterator.h new file mode 100644 index 00000000000..ac7f6d136db --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/iterators/InfomapIterator.h @@ -0,0 +1,341 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef INFOMAP_ITERATOR_H_ +#define INFOMAP_ITERATOR_H_ + +#include +#include +#include + +namespace infomap { + +class InfoNode; + +/** + * Pre processing depth first iterator that explores sub-Infomap instances + * Note: + * This iterator presupposes that the next pointer of a node can't reach a node with a different parent. + */ +struct InfomapIterator { +protected: + InfoNode* m_root = nullptr; + InfoNode* m_current = nullptr; + int m_moduleIndexLevel = -1; + unsigned int m_moduleIndex = 0; + std::deque m_path; // The tree path to current node (indexing starting from one!) + unsigned int m_depth = 0; + +public: + InfomapIterator() = default; + + InfomapIterator(InfoNode* nodePointer, int moduleIndexLevel = -1) + : m_root(nodePointer), m_current(nodePointer), m_moduleIndexLevel(moduleIndexLevel) { } + + virtual ~InfomapIterator() = default; + InfomapIterator(const InfomapIterator&) = default; + InfomapIterator& operator=(const InfomapIterator&) = default; + InfomapIterator(InfomapIterator&&) noexcept = default; + InfomapIterator& operator=(InfomapIterator&&) noexcept = default; + + InfoNode* current() noexcept { return m_current; } + + const InfoNode* current() const noexcept { return m_current; } + + InfoNode& operator*() noexcept { return *m_current; } + + const InfoNode& operator*() const noexcept { return *m_current; } + + InfoNode* operator->() noexcept { return m_current; } + + const InfoNode* operator->() const noexcept { return m_current; } + + bool operator==(const InfomapIterator& other) const noexcept { return m_current == other.m_current; } + + bool operator!=(const InfomapIterator& other) const noexcept { return m_current != other.m_current; } + + virtual InfomapIterator& operator++() noexcept; + + virtual InfomapIterator operator++(int) noexcept + { + InfomapIterator copy(*this); + ++(*this); + return copy; + } + + virtual InfomapIterator& stepForward() noexcept + { + ++(*this); + return *this; + } + + const std::deque& path() const noexcept { return m_path; } + + unsigned int moduleIndex() const noexcept { return m_moduleIndex; } + + unsigned int moduleId() const noexcept { return m_moduleIndex + 1; } + + unsigned int childIndex() const noexcept { return m_path.empty() ? 0 : m_path.back() - 1; } + + unsigned int depth() const noexcept { return m_depth; } + + double modularCentrality() const noexcept; + + bool isEnd() const noexcept { return m_current == nullptr; } +}; + +struct InfomapModuleIterator : public InfomapIterator { +public: + InfomapModuleIterator() : InfomapIterator() { } + + InfomapModuleIterator(InfoNode* nodePointer, int moduleIndexLevel = -1) : InfomapIterator(nodePointer, moduleIndexLevel) { } + + ~InfomapModuleIterator() override = default; + InfomapModuleIterator(const InfomapModuleIterator&) = default; + InfomapModuleIterator& operator=(const InfomapModuleIterator&) = default; + InfomapModuleIterator(InfomapModuleIterator&&) = default; + InfomapModuleIterator& operator=(InfomapModuleIterator&&) = default; + + InfomapIterator& operator++() noexcept override; + + InfomapIterator operator++(int) noexcept override + { + InfomapModuleIterator copy(*this); + ++(*this); + return std::move(copy); + } + + using InfomapIterator::childIndex; + using InfomapIterator::current; + using InfomapIterator::depth; + using InfomapIterator::modularCentrality; + using InfomapIterator::path; +}; + +struct InfomapLeafModuleIterator : public InfomapIterator { +public: + InfomapLeafModuleIterator() : InfomapIterator() { } + + InfomapLeafModuleIterator(InfoNode* nodePointer, int moduleIndexLevel = -1) + : InfomapIterator(nodePointer, moduleIndexLevel) { init(); } + + ~InfomapLeafModuleIterator() override = default; + InfomapLeafModuleIterator(const InfomapLeafModuleIterator& other) : InfomapIterator(other) { init(); } + InfomapLeafModuleIterator& operator=(const InfomapLeafModuleIterator&) = default; + InfomapLeafModuleIterator(InfomapLeafModuleIterator&&) = default; + InfomapLeafModuleIterator& operator=(InfomapLeafModuleIterator&&) = default; + + /** + * Iterate to first leaf module + */ + void init() noexcept; + + InfomapIterator& operator++() noexcept override; + + InfomapIterator operator++(int) noexcept override + { + InfomapLeafModuleIterator copy(*this); + ++(*this); + return std::move(copy); + } + + using InfomapIterator::childIndex; + using InfomapIterator::current; + using InfomapIterator::depth; + using InfomapIterator::modularCentrality; + using InfomapIterator::path; +}; + +struct InfomapLeafIterator : public InfomapIterator { +public: + InfomapLeafIterator() : InfomapIterator() { } + + InfomapLeafIterator(InfoNode* nodePointer, int moduleIndexLevel = -1) + : InfomapIterator(nodePointer, moduleIndexLevel) { init(); } + + ~InfomapLeafIterator() override = default; + InfomapLeafIterator(const InfomapLeafIterator& other) : InfomapIterator(other) { init(); } + InfomapLeafIterator& operator=(const InfomapLeafIterator&) = default; + InfomapLeafIterator(InfomapLeafIterator&&) = default; + InfomapLeafIterator& operator=(InfomapLeafIterator&&) = default; + + /** + * Iterate to first leaf node + */ + void init() noexcept; + + InfomapIterator& operator++() noexcept override; + + InfomapIterator operator++(int) noexcept override + { + InfomapLeafIterator copy(*this); + ++(*this); + return std::move(copy); + } + + using InfomapIterator::childIndex; + using InfomapIterator::current; + using InfomapIterator::depth; + using InfomapIterator::modularCentrality; + using InfomapIterator::path; +}; + +/** + * Iterate over the whole tree, collecting physical nodes within same leaf modules + * Note: The physical nodes are created when entering the parent module and removed + * when leaving the module. The tree will not be modified. + */ +struct InfomapIteratorPhysical : public InfomapIterator { +protected: + std::map m_physNodes; + std::map::iterator m_physIter; + InfomapIterator m_oldIter; + +public: + InfomapIteratorPhysical() : InfomapIterator() { } + + InfomapIteratorPhysical(InfoNode* nodePointer, int moduleIndexLevel = -1) + : InfomapIterator(nodePointer, moduleIndexLevel) { } + + ~InfomapIteratorPhysical() override = default; + InfomapIteratorPhysical(const InfomapIteratorPhysical&) = default; + InfomapIteratorPhysical(const InfomapIterator& other) : InfomapIterator(other) { } + + InfomapIteratorPhysical(InfomapIteratorPhysical&&) = default; + InfomapIteratorPhysical& operator=(const InfomapIteratorPhysical&) = default; + + // Don't allow moving from this iterator as we use the old iterator in operator++ + InfomapIteratorPhysical& operator=(InfomapIteratorPhysical&&) = delete; + + InfomapIteratorPhysical& operator=(const InfomapIterator& other) + { + InfomapIterator::operator=(other); + return *this; + } + + InfomapIterator& operator++() noexcept override; + + InfomapIterator operator++(int) noexcept override + { + InfomapIteratorPhysical copy(*this); + ++(*this); + return std::move(copy); + } + + using InfomapIterator::childIndex; + using InfomapIterator::current; + using InfomapIterator::depth; + using InfomapIterator::modularCentrality; + using InfomapIterator::path; +}; + +/** + * Iterate over all physical leaf nodes, joining physical nodes within same leaf modules + * Note: The physical nodes are created when entering the parent module and removed + * when leaving the module. The tree will not be modified. + */ +struct InfomapLeafIteratorPhysical : public InfomapIteratorPhysical { +public: + InfomapLeafIteratorPhysical() : InfomapIteratorPhysical() { } + + InfomapLeafIteratorPhysical(InfoNode* nodePointer, int moduleIndexLevel = -1) + : InfomapIteratorPhysical(nodePointer, moduleIndexLevel) { init(); } + + InfomapLeafIteratorPhysical(const InfomapLeafIteratorPhysical& other) + : InfomapIteratorPhysical(other) { init(); } + + ~InfomapLeafIteratorPhysical() override = default; + InfomapLeafIteratorPhysical(InfomapLeafIteratorPhysical&&) = default; + InfomapLeafIteratorPhysical& operator=(const InfomapLeafIteratorPhysical&) = default; + + // Don't allow moving from this iterator as we use the old iterator in operator++ + InfomapLeafIteratorPhysical& operator=(InfomapLeafIteratorPhysical&&) = delete; + + /** + * Iterate to first leaf node + */ + void init() noexcept; + + InfomapIterator& operator++() noexcept override; + + InfomapIterator operator++(int) noexcept override + { + InfomapLeafIteratorPhysical copy(*this); + ++(*this); + return std::move(copy); + } + + using InfomapIteratorPhysical::childIndex; + using InfomapIteratorPhysical::current; + using InfomapIteratorPhysical::depth; + using InfomapIteratorPhysical::modularCentrality; + using InfomapIteratorPhysical::path; +}; + +/** + * Iterate parent by parent until it is nullptr, + * moving up through possible sub infomap instances + * on the way + */ +struct InfomapParentIterator { +protected: + InfoNode* m_current = nullptr; + +public: + InfomapParentIterator() = default; + + InfomapParentIterator(InfoNode* nodePointer) : m_current(nodePointer) { } + + ~InfomapParentIterator() = default; + + InfomapParentIterator(const InfomapParentIterator&) = default; + + InfomapParentIterator& operator=(const InfomapParentIterator&) = default; + + InfomapParentIterator(InfomapParentIterator&&) = default; + + InfomapParentIterator& operator=(InfomapParentIterator&&) = default; + + InfoNode* current() noexcept { return m_current; } + + const InfoNode* current() const noexcept { return m_current; } + + InfoNode& operator*() noexcept { return *m_current; } + + const InfoNode& operator*() const noexcept { return *m_current; } + + InfoNode* operator->() noexcept { return m_current; } + + const InfoNode* operator->() const noexcept { return m_current; } + + bool operator==(const InfomapParentIterator& other) const noexcept { return m_current == other.m_current; } + + bool operator!=(const InfomapParentIterator& other) const noexcept { return m_current != other.m_current; } + + InfomapParentIterator& operator++() noexcept; + + InfomapParentIterator operator++(int) noexcept + { + InfomapParentIterator copy(*this); + ++(*this); + return copy; + } + + InfomapParentIterator& stepForward() noexcept + { + ++(*this); + return *this; + } + + bool isEnd() const noexcept { return m_current == nullptr; } +}; + +} // namespace infomap + +#endif // INFOMAP_ITERATOR_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/iterators/IterWrapper.h b/src/vendor/cigraph/vendor/infomap/src/core/iterators/IterWrapper.h new file mode 100644 index 00000000000..f043eb6dd23 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/iterators/IterWrapper.h @@ -0,0 +1,32 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef ITER_WRAPPER_H_ +#define ITER_WRAPPER_H_ + +namespace infomap { + +template +class IterWrapper { + Iter m_begin, m_end; + +public: + IterWrapper(Iter begin, Iter end) : m_begin(begin), m_end(end) { } + + template + IterWrapper(Container& container) : m_begin(container.begin()), m_end(container.end()) { } + + Iter begin() noexcept { return m_begin; }; + + Iter end() noexcept { return m_end; }; +}; + +} // namespace infomap + +#endif // ITER_WRAPPER_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/iterators/infomapIterators.h b/src/vendor/cigraph/vendor/infomap/src/core/iterators/infomapIterators.h new file mode 100644 index 00000000000..2d13ffe1a84 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/iterators/infomapIterators.h @@ -0,0 +1,369 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef INFOMAP_ITERATORS_H_ +#define INFOMAP_ITERATORS_H_ + +#include "treeIterators.h" +#include +#include + +namespace infomap { + +/** + * Child iterator. + */ +template // pointer or const pointer +class InfomapChildIterator { + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename iterator_traits::value_type; + using difference_type = typename iterator_traits::difference_type; + using reference = typename iterator_traits::reference; + using pointer = typename iterator_traits::pointer; + +protected: + NodePointerType m_root = nullptr; + NodePointerType m_current = nullptr; + +public: + InfomapChildIterator() = default; + + InfomapChildIterator(const NodePointerType& nodePointer) + : m_root(nodePointer), m_current(nodePointer) { init(); } + + InfomapChildIterator(const InfomapChildIterator& other) + : m_root(other.m_root), m_current(other.m_current) { } + + InfomapChildIterator& operator=(const InfomapChildIterator& other) + { + m_root = other.m_root; + m_current = other.m_current; + return *this; + } + + void init() + { + if (m_root != nullptr) { + NodePointerType infomapRoot = m_root->getInfomapRoot(); + if (infomapRoot != nullptr) { + m_root = infomapRoot; + } + } + m_current = m_root == nullptr ? nullptr : m_root->firstChild; + } + + pointer current() const { return m_current; } + + reference operator*() const { return *m_current; } + + pointer operator->() const { return m_current; } + + bool operator==(const InfomapChildIterator& rhs) const { return m_current == rhs.m_current; } + + bool operator!=(const InfomapChildIterator& rhs) const { return m_current != rhs.m_current; } + + bool isEnd() const { return m_current == nullptr; } + + InfomapChildIterator& operator++() + { + m_current = m_current->next; + if (m_current != nullptr && m_current->parent != m_root) { + m_current = nullptr; + } + return *this; + } + + InfomapChildIterator operator++(int) + { + InfomapChildIterator copy(*this); + ++(*this); + return copy; + } + + InfomapChildIterator& operator--() + { + m_current = m_current->previous; + if (m_current != nullptr && m_current->parent != m_root) { + m_current = nullptr; + } + return *this; + } + + InfomapChildIterator operator--(int) + { + InfomapChildIterator copy(*this); + --(*this); + return copy; + } +}; + +/** + * Pre processing depth first iterator that explores sub-Infomap instances + * Note: This iterator presupposes that the next pointer of a node can't reach a node with a different parent. + */ +template +class InfomapClusterIterator : public DepthFirstIteratorBase { +protected: + using Base = DepthFirstIteratorBase; + + unsigned int m_moduleIndex = 0; + int m_moduleIndexLevel = -1; + + using Base::m_current; + using Base::m_depth; + +public: + InfomapClusterIterator() : Base() { } + + InfomapClusterIterator(const NodePointerType& nodePointer, int moduleIndexLevel = -1) + : Base(nodePointer), m_moduleIndexLevel(moduleIndexLevel) + { + init(); + } + + InfomapClusterIterator(const InfomapClusterIterator& other) + : Base(other), m_moduleIndex(other.m_moduleIndex), m_moduleIndexLevel(other.m_moduleIndexLevel) { } + + virtual void init() { moveToInfomapRootIfExist(); } + + void moveToInfomapRootIfExist() + { + if (m_current != nullptr) { + NodePointerType infomapRoot = m_current->getInfomapRoot(); + if (infomapRoot != nullptr) { + m_current = infomapRoot; + } + } + } + + InfomapClusterIterator& operator=(const InfomapClusterIterator& other) + { + Base::operator=(other); + m_moduleIndex = other.m_moduleIndex; + m_moduleIndexLevel = other.m_moduleIndexLevel; + return *this; + } + + InfomapClusterIterator& operator++() + { + NodePointerType curr = Base::m_current; + + if (curr->firstChild != nullptr) { + curr = curr->firstChild; + ++m_depth; + } else { + // Current node is a leaf + // Presupposes that the next pointer can't reach out from the current parent. + tryNext: + while (curr->next == nullptr) { + if (curr->parent != nullptr) { + curr = curr->parent; + --m_depth; + if (curr == Base::m_root) // Check if back to beginning + { + m_current = nullptr; + return *this; + } + if (m_moduleIndexLevel < 0) { + if (curr->isLeafModule()) // TODO: Generalize to -2 for second level to bottom + ++m_moduleIndex; + } else if (static_cast(m_moduleIndexLevel) == m_depth) + ++m_moduleIndex; + } else { + NodePointerType infomapOwner = curr->owner; + if (infomapOwner != nullptr) { + curr = infomapOwner; + if (curr == Base::m_root) // Check if back to beginning + { + m_current = nullptr; + return *this; + } + goto tryNext; + } else // null also if no children in first place + { + m_current = nullptr; + return *this; + } + } + } + curr = curr->next; + } + m_current = curr; + moveToInfomapRootIfExist(); + return *this; + } + + InfomapClusterIterator operator++(int) + { + InfomapClusterIterator copy(*this); + ++(*this); + return copy; + } + + InfomapClusterIterator next() + { + InfomapClusterIterator copy(*this); + return ++copy; + } + + InfomapClusterIterator& stepForward() + { + ++(*this); + return *this; + } + + unsigned int moduleIndex() const + { + return m_moduleIndex; + } +}; + +/** + * Pre processing depth first iterator that explores sub-Infomap instances + * Note: This iterator presupposes that the next pointer of a node can't reach a node with a different parent. + */ +template +class InfomapDepthFirstIterator : public DepthFirstIteratorBase { +protected: + using Base = DepthFirstIteratorBase; + + std::deque m_path; // The child index path to current node + unsigned int m_moduleIndex = 0; + int m_moduleIndexLevel = -1; + + using Base::m_current; + using Base::m_depth; + +public: + InfomapDepthFirstIterator() : Base() { } + + InfomapDepthFirstIterator(const NodePointerType& nodePointer, int moduleIndexLevel = -1) + : Base(nodePointer), + m_moduleIndexLevel(moduleIndexLevel) + { + init(); + } + + InfomapDepthFirstIterator(const InfomapDepthFirstIterator& other) + : Base(other), + m_path(other.m_path), + m_moduleIndex(other.m_moduleIndex), + m_moduleIndexLevel(other.m_moduleIndexLevel) + { + } + + InfomapDepthFirstIterator& operator=(const InfomapDepthFirstIterator& other) + { + Base::operator=(other); + m_path = other.m_path; + m_moduleIndex = other.m_moduleIndex; + m_moduleIndexLevel = other.m_moduleIndexLevel; + return *this; + } + + virtual void init() + { + moveToInfomapRootIfExist(); + } + + void moveToInfomapRootIfExist() + { + if (m_current != nullptr) { + NodePointerType infomapRoot = m_current->getInfomapRoot(); + if (infomapRoot != nullptr) { + m_current = infomapRoot; + } + } + } + + InfomapDepthFirstIterator& operator++() + { + NodePointerType curr = Base::m_current; + + if (curr->firstChild != nullptr) { + curr = curr->firstChild; + ++m_depth; + m_path.push_back(0); + } else { + // Current node is a leaf + // Presupposes that the next pointer can't reach out from the current parent. + tryNext: + while (curr->next == nullptr) { + if (curr->parent != nullptr) { + curr = curr->parent; + --m_depth; + m_path.pop_back(); + if (curr == Base::m_root) // Check if back to beginning + { + m_current = nullptr; + return *this; + } + if (m_moduleIndexLevel < 0) { + if (curr->isLeafModule()) // TODO: Generalize to -2 for second level to bottom + ++m_moduleIndex; + } else if (static_cast(m_moduleIndexLevel) == m_depth) + ++m_moduleIndex; + } else { + NodePointerType infomapOwner = curr->owner; + if (infomapOwner != nullptr) { + curr = infomapOwner; + if (curr == Base::m_root) // Check if back to beginning + { + m_current = nullptr; + return *this; + } + goto tryNext; + } else // null also if no children in first place + { + m_current = nullptr; + return *this; + } + } + } + curr = curr->next; + ++m_path.back(); + } + m_current = curr; + moveToInfomapRootIfExist(); + return *this; + } + + InfomapDepthFirstIterator operator++(int) + { + InfomapDepthFirstIterator copy(*this); + ++(*this); + return copy; + } + + InfomapDepthFirstIterator next() + { + InfomapDepthFirstIterator copy(*this); + return ++copy; + } + + InfomapDepthFirstIterator& stepForward() + { + ++(*this); + return *this; + } + + const std::deque& path() const + { + return m_path; + } + + unsigned int moduleIndex() const + { + return m_moduleIndex; + } +}; + +} // namespace infomap + +#endif // INFOMAP_ITERATORS_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/core/iterators/treeIterators.h b/src/vendor/cigraph/vendor/infomap/src/core/iterators/treeIterators.h new file mode 100644 index 00000000000..7717e208f79 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/core/iterators/treeIterators.h @@ -0,0 +1,628 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef TREE_ITERATORS_H_ +#define TREE_ITERATORS_H_ + +#include +#include +#include + +namespace infomap { + +#ifndef ASSERT +#include +#define ASSERT(x) assert(x) +#endif + +using std::iterator_traits; + +/** + * Child iterator. + */ +template // pointer or const pointer +class ChildIterator { + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename iterator_traits::value_type; + using difference_type = typename iterator_traits::difference_type; + using reference = typename iterator_traits::reference; + using pointer = typename iterator_traits::pointer; + +protected: + NodePointerType m_root = nullptr; + NodePointerType m_current = nullptr; + +public: + ChildIterator() = default; + + ChildIterator(const NodePointerType& nodePointer) + : m_root(nodePointer), m_current(nodePointer == nullptr ? nullptr : nodePointer->firstChild) { } + + ChildIterator(const ChildIterator& other) + : m_root(other.m_root), m_current(other.m_current) { } + + ChildIterator& operator=(const ChildIterator& other) + { + m_root = other.m_root; + m_current = other.m_current; + return *this; + } + + pointer current() const { return m_current; } + + reference operator*() const { return *m_current; } + + pointer operator->() const { return m_current; } + + bool operator==(const ChildIterator& rhs) const { return m_current == rhs.m_current; } + + bool operator!=(const ChildIterator& rhs) const { return !(m_current == rhs.m_current); } + + bool isEnd() const { return m_current == nullptr; } + + ChildIterator& operator++() + { + m_current = m_current->next; + if (m_current != nullptr && m_current->parent != m_root) { + m_current = nullptr; + } + return *this; + } + + ChildIterator operator++(int) + { + ChildIterator copy(*this); + ++(*this); + return copy; + } + + ChildIterator& operator--() + { + m_current = m_current->previous; + if (m_current != nullptr && m_current->parent != m_root) { + m_current = nullptr; + } + return *this; + } + + ChildIterator operator--(int) + { + ChildIterator copy(*this); + --(*this); + return copy; + } +}; + +/** + * Tree iterator. + */ +template // pointer or const pointer +class TreeIterator { + using iterator_category = std::forward_iterator_tag; + using value_type = typename iterator_traits::value_type; + using difference_type = typename iterator_traits::difference_type; + using reference = typename iterator_traits::reference; + using pointer = typename iterator_traits::pointer; + +protected: + NodePointerType m_root = nullptr; + NodePointerType m_current = nullptr; + int m_moduleIndexLevel = -1; + unsigned int m_moduleIndex = 0; + std::deque m_path; // The child index path to current node + unsigned int m_depth = 0; + +public: + TreeIterator() = default; + + TreeIterator(NodePointerType nodePointer, int moduleIndexLevel = -1) + : m_root(nodePointer), + m_current(nodePointer), + m_moduleIndexLevel(moduleIndexLevel) { } + + TreeIterator(const TreeIterator& other) + : m_root(other.m_root), + m_current(other.m_current), + m_moduleIndexLevel(other.m_moduleIndexLevel), + m_moduleIndex(other.m_moduleIndex), + m_path(other.m_path), + m_depth(other.m_depth) { } + + virtual ~TreeIterator() = default; + + TreeIterator& operator=(const TreeIterator& other) + { + m_root = other.m_root; + m_current = other.m_current; + m_moduleIndexLevel = other.m_moduleIndexLevel; + m_moduleIndex = other.m_moduleIndex; + m_path = other.m_path; + m_depth = other.m_depth; + return *this; + } + + pointer current() const { return m_current; } + + reference operator*() const { return *m_current; } + + pointer operator->() const { return m_current; } + + bool operator==(const TreeIterator& rhs) const { return m_current == rhs.m_current; } + + bool operator!=(const TreeIterator& rhs) const { return !(m_current == rhs.m_current); } + + const std::deque& path() const { return m_path; } + + unsigned int moduleIndex() const { return m_moduleIndex; } + + unsigned int depth() const { return m_depth; } + + bool isEnd() const { return m_current == nullptr; } + + TreeIterator& operator++() + { + NodePointerType curr = m_current; + NodePointerType infomapRoot = curr->getInfomapRoot(); + if (infomapRoot != nullptr) { + curr = infomapRoot; + } + + if (curr->firstChild != nullptr) { + curr = curr->firstChild; + ++m_depth; + m_path.push_back(0); + } else { + // Current node is a leaf + // Presupposes that the next pointer can't reach out from the current parent. + tryNext: + while (curr->next == nullptr) { + if (curr->parent != nullptr) { + curr = curr->parent; + --m_depth; + m_path.pop_back(); + if (curr == m_root) // Check if back to beginning + { + m_current = nullptr; + return *this; + } + if (m_moduleIndexLevel < 0) { + if (curr->isLeafModule()) // TODO: Generalize to -2 for second level to bottom + ++m_moduleIndex; + } else if (static_cast(m_moduleIndexLevel) == m_depth) + ++m_moduleIndex; + } else { + NodePointerType infomapOwner = curr->owner; + if (infomapOwner != nullptr) { + curr = infomapOwner; + if (curr == m_root) // Check if back to beginning + { + m_current = nullptr; + return *this; + } + goto tryNext; + } else // null also if no children in first place + { + m_current = nullptr; + return *this; + } + } + } + curr = curr->next; + ++m_path.back(); + } + m_current = curr; + return *this; + } + + TreeIterator operator++(int) + { + TreeIterator copy(*this); + ++(*this); + return copy; + } + + TreeIterator& stepForward() + { + ++(*this); + return *this; + } +}; + +/** + * Base node iterator. + */ +template +struct node_iterator_base { + using iterator_category = iterator_tag; + using value_type = typename iterator_traits::value_type; + using difference_type = typename iterator_traits::difference_type; + using reference = typename iterator_traits::reference; + using pointer = typename iterator_traits::pointer; + + node_iterator_base() : m_current(nullptr) { } + + node_iterator_base(const NodePointerType& nodePointer) : m_current(nodePointer) { } + + node_iterator_base(const node_iterator_base& other) : m_current(other.m_current) { } + + node_iterator_base& operator=(const node_iterator_base& other) + { + m_current = other.m_current; + return *this; + } + + virtual ~node_iterator_base() = default; + + pointer base() const { return m_current; } + + reference operator*() const { return *m_current; } + + pointer operator->() const { return m_current; } + + bool operator==(const node_iterator_base& rhs) const { return m_current == rhs.m_current; } + + bool operator!=(const node_iterator_base& rhs) const { return !(m_current == rhs.m_current); } + + bool isEnd() const { return m_current == nullptr; } + +protected: + NodePointerType m_current; +}; + +template +class DepthFirstIteratorBase : public node_iterator_base { + using Base = node_iterator_base; + +public: + DepthFirstIteratorBase() : Base(), m_root(nullptr), m_depth(0) { } + + DepthFirstIteratorBase(const NodePointerType& nodePointer) : Base(nodePointer), m_root(nodePointer), m_depth(0) { } + + DepthFirstIteratorBase(const DepthFirstIteratorBase& other) : Base(other), m_root(other.m_root), m_depth(other.m_depth) { } + + DepthFirstIteratorBase& operator=(const DepthFirstIteratorBase& other) + { + Base::operator=(other); + m_root = other.m_root; + m_depth = other.m_depth; + return *this; + } + + unsigned int depth() const { return m_depth; } + +protected: + NodePointerType m_root; + unsigned int m_depth; + using Base::m_current; +}; + +/** + * Pre processing depth first iterator + * Note: + * This iterator presupposes that the next pointer of a node can't reach a node with a different parent. + */ +template +class DepthFirstIterator : public DepthFirstIteratorBase { + using Base = DepthFirstIteratorBase; + +public: + DepthFirstIterator() : Base() { } + + DepthFirstIterator(const NodePointerType& nodePointer) : Base(nodePointer) { } + + DepthFirstIterator(const DepthFirstIterator& other) : Base(other) { } + + DepthFirstIterator& operator=(const DepthFirstIterator& other) + { + Base::operator=(other); + return *this; + } + + DepthFirstIterator& operator++() + { + NodePointerType curr = Base::m_current; + if (curr->firstChild != nullptr) { + curr = curr->firstChild; + ++Base::m_depth; + } else { + // Presupposes that the next pointer can't reach out from the current parent. + while (curr->next == nullptr) { + curr = curr->parent; + --Base::m_depth; + if (curr == Base::m_root || curr == nullptr) // 0 if no children in first place + { + Base::m_current = nullptr; + return *this; + } + } + curr = curr->next; + } + Base::m_current = curr; + return *this; + } + + DepthFirstIterator operator++(int) + { + auto copy(*this); + ++(*this); + return copy; + } + + DepthFirstIterator next() + { + auto copy(*this); + return ++copy; + } +}; + +/** + * Post processing depth first iterator + * Note: + * This iterator presupposes that the next pointer of a node can't reach a node with a different parent. + */ +template +class DepthFirstIterator : public DepthFirstIteratorBase { + using Base = DepthFirstIteratorBase; + +public: + DepthFirstIterator() : Base() { } + + DepthFirstIterator(const NodePointerType& nodePointer) : Base(nodePointer) { init(); } + + DepthFirstIterator(const DepthFirstIterator& other) : Base(other) { } + + DepthFirstIterator& operator=(const DepthFirstIterator& other) + { + Base::operator=(other); + return *this; + } + + void init() + { + if (Base::m_current != nullptr) { + while (Base::m_current->firstChild != nullptr) { + Base::m_current = Base::m_current->firstChild; + ++Base::m_depth; + } + } + } + + DepthFirstIterator& operator++() + { + // The root should be the last node + if (Base::m_current == Base::m_root) { + Base::m_current = nullptr; + return *this; + } + + NodePointerType curr = Base::m_current; + if (curr->next != nullptr) { + curr = curr->next; + while (curr->firstChild != nullptr) { + curr = curr->firstChild; + ++Base::m_depth; + } + } else { + curr = curr->parent; + --Base::m_depth; + } + + Base::m_current = curr; + + return *this; + } + + DepthFirstIterator operator++(int) + { + DepthFirstIterator copy(*this); + ++(*this); + return copy; + } + + DepthFirstIterator + next() + { + DepthFirstIterator copy(*this); + return ++copy; + } +}; + +/** + * Leaf node iterator + */ +template +class LeafNodeIterator : public DepthFirstIteratorBase { + using Base = DepthFirstIteratorBase; + +public: + LeafNodeIterator() : Base() { } + + LeafNodeIterator(const NodePointerType& nodePointer) : Base(nodePointer) { init(); } + + LeafNodeIterator(const LeafNodeIterator& other) : Base(other) { } + + LeafNodeIterator& operator=(const LeafNodeIterator& other) + { + Base::operator=(other); + return *this; + } + + void init() + { + if (Base::m_current != nullptr) { + while (Base::m_current->firstChild != nullptr) { + Base::m_current = Base::m_current->firstChild; + ++Base::m_depth; + } + } + } + + LeafNodeIterator& operator++() + { + ASSERT(Base::m_current != nullptr); + while (Base::m_current->next == nullptr || Base::m_current->next->parent != Base::m_current->parent) { + Base::m_current = Base::m_current->parent; + --Base::m_depth; + if (Base::m_current == nullptr) + return *this; + } + + Base::m_current = Base::m_current->next; + + if (Base::m_current != nullptr) { + while (Base::m_current->firstChild != nullptr) { + Base::m_current = Base::m_current->firstChild; + ++Base::m_depth; + } + } + return *this; + } + + LeafNodeIterator operator++(int) + { + LeafNodeIterator copy(*this); + ++(*this); + return copy; + } + + LeafNodeIterator next() + { + LeafNodeIterator copy(*this); + return ++copy; + } +}; + +/** + * Leaf module iterator + */ +template +class LeafModuleIterator : public DepthFirstIteratorBase { + using Base = DepthFirstIteratorBase; + +public: + LeafModuleIterator() : Base() { } + + LeafModuleIterator(const NodePointerType& nodePointer) : Base(nodePointer) { init(); } + + LeafModuleIterator(const LeafModuleIterator& other) : Base(other) { } + + LeafModuleIterator& operator=(const LeafModuleIterator& other) + { + Base::operator=(other); + init(); + return *this; + } + + void init() + { + if (Base::m_current != nullptr) { + if (Base::m_current->firstChild == nullptr) { + Base::m_current = nullptr; // End directly if no module + } else { + while (Base::m_current->firstChild->firstChild != nullptr) { + Base::m_current = Base::m_current->firstChild; + ++Base::m_depth; + } + } + } + } + + LeafModuleIterator& operator++() + { + ASSERT(Base::m_current != nullptr); + while (Base::m_current->next == nullptr || Base::m_current->next->parent != Base::m_current->parent) { + Base::m_current = Base::m_current->parent; + --Base::m_depth; + if (Base::m_current == nullptr) + return *this; + } + + Base::m_current = Base::m_current->next; + + if (Base::m_current != nullptr) { + if (Base::m_current->firstChild == nullptr) { + Base::m_current = Base::m_current->parent; + } else { + while (Base::m_current->firstChild->firstChild != nullptr) { + Base::m_current = Base::m_current->firstChild; + ++Base::m_depth; + } + } + } + return *this; + } + + LeafModuleIterator operator++(int) + { + LeafModuleIterator copy(*this); + ++(*this); + return copy; + } + + LeafModuleIterator next() + { + LeafModuleIterator copy(*this); + return ++copy; + } +}; + +/** + * Sibling iterator. + */ +template // pointer or const pointer +class SiblingIterator : public node_iterator_base { + using Base = node_iterator_base; + +public: + using self_type = SiblingIterator; + + SiblingIterator() : Base() { } + + SiblingIterator(const NodePointerType& nodePointer) : Base(nodePointer) { } + + SiblingIterator(const SiblingIterator& other) : Base(other) { } + + SiblingIterator& operator=(const SiblingIterator& other) + { + Base::operator=(other); + return *this; + } + + SiblingIterator& operator++() + { + ASSERT(Base::m_current != nullptr); + Base::m_current = Base::m_current->next; + return *this; + } + + SiblingIterator operator++(int) + { + SiblingIterator copy(*this); + ++(*this); + return copy; + } + + SiblingIterator& operator--() + { + ASSERT(Base::m_current != nullptr); + Base::m_current = Base::m_current->previous; + return *this; + } + + SiblingIterator operator--(int) + { + SiblingIterator copy(*this); + --(*this); + return copy; + } +}; + +} // namespace infomap + +#endif // TREE_ITERATORS_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/io/ClusterMap.cpp b/src/vendor/cigraph/vendor/infomap/src/io/ClusterMap.cpp new file mode 100644 index 00000000000..1de468c739c --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/ClusterMap.cpp @@ -0,0 +1,189 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "ClusterMap.h" +#include "SafeFile.h" +#include "../utils/Log.h" +#include "../utils/FileURI.h" +#include + +namespace infomap { + +void ClusterMap::readClusterData(const std::string& filename, bool includeFlow, const std::map>* layerNodeToStateId) +{ + FileURI file(filename); + m_extension = file.getExtension(); + if (m_extension == "tree" || m_extension == "ftree") { + return readTree(filename, includeFlow, layerNodeToStateId); + } + if (m_extension == "clu") { + return readClu(filename, includeFlow, layerNodeToStateId); + } + throw std::runtime_error(io::Str() << "Input cluster data from file '" << filename << "' is of unknown extension '" << m_extension << "'. Must be 'clu' or 'tree'."); +} + +/** + * Sample from .tree file +# Codelength = 3.46227314 bits. +# path flow name physicalId +1:1:1 0.0384615 "1" 1 +1:1:2 0.025641 "2" 2 +1:1:3 0.0384615 "3" 3 +1:2:1 0.0384615 "4" 4 + */ +void ClusterMap::readTree(const std::string& filename, bool includeFlow, const std::map>* layerNodeToStateId) +{ + bool isMultilayer = layerNodeToStateId != nullptr; + + SafeInFile input(filename); + std::string line; + std::istringstream lineStream; + std::istringstream pathStream; + m_nodePaths.clear(); + + unsigned int lineNr = 0; + + while (!std::getline(input, line).fail()) { + ++lineNr; + if (line.length() == 0) + continue; + if (line[0] == '#') { + continue; + } + if (line[0] == '*') { + break; + } + + lineStream.clear(); + lineStream.str(line); + + std::string pathString; + double flow; + std::string name; + unsigned int stateId; + unsigned int nodeId; + unsigned int layerId; + if (!(lineStream >> pathString)) + throw std::runtime_error(io::Str() << "Couldn't parse tree path from line '" << line << "'"); + if (!(lineStream >> flow)) + throw std::runtime_error(io::Str() << "Couldn't parse node flow from line '" << line << "'"); + // Get the name by extracting the rest of the stream until the first quotation mark and then the last. + if (!getline(lineStream, name, '"')) + throw std::runtime_error(io::Str() << "Can't parse node name from line " << lineNr << " ('" << line << "')."); + if (!getline(lineStream, name, '"')) + throw std::runtime_error(io::Str() << "Can't parse node name from line " << lineNr << " ('" << line << "')."); + if (!(lineStream >> stateId)) + throw std::runtime_error(io::Str() << "Couldn't parse node id from line '" << line << "'"); + if (lineStream >> nodeId) { + m_isHigherOrder = true; + } else if (m_isHigherOrder) { + throw std::runtime_error(io::Str() << "Missing state id for node on line '" << line << "'."); + } + if (isMultilayer && !(lineStream >> layerId)) + throw std::runtime_error(io::Str() << "Couldn't parse layer id from line '" << line << "'"); + + bool multilayerNodeFound = false; + + if (isMultilayer) { + // get new state id from map + auto it = layerNodeToStateId->find(layerId); + + if (it != layerNodeToStateId->end()) { + auto nodeIdToStateId = it->second.find(nodeId); + if (nodeIdToStateId != it->second.end()) { + stateId = nodeIdToStateId->second; + multilayerNodeFound = true; + } + } + } + + if (isMultilayer && !multilayerNodeFound) { + continue; + } + + pathStream.clear(); + pathStream.str(pathString); + unsigned int childNumber; + + Path path; + while (pathStream >> childNumber) { + pathStream.get(); // Extract the delimiting character also + if (childNumber == 0) + throw std::runtime_error("There is a '0' in the tree path, lowest allowed integer is 1."); + path.push_back(childNumber); // Keep 1-based indexing in path + } + + m_nodePaths.emplace_back(stateId, path); + + if (includeFlow) + m_flowData[stateId] = flow; + } +} + +void ClusterMap::readClu(const std::string& filename, bool includeFlow, const std::map>* layerNodeToStateId) +{ + auto isMultilayer = layerNodeToStateId != nullptr; + + Log() << "Read initial partition from '" << filename << "'... " << std::flush; + SafeInFile input(filename); + std::string line; + std::istringstream lineStream; + std::map clusterData; + + while (!std::getline(input, line).fail()) { + if (line.length() == 0 || line[0] == '#' || line[0] == '*') + continue; + + lineStream.clear(); + lineStream.str(line); + // # state_id module flow node_id layer_id + + unsigned int stateId; + unsigned int nodeId; + unsigned int moduleId; + unsigned int layerId; + + if (!(lineStream >> stateId >> moduleId)) + throw std::runtime_error(io::Str() << "Couldn't parse node key and cluster id from line '" << line << "'"); + + auto flow = 0.0; + if (lineStream >> flow) { + if (includeFlow) + m_flowData[stateId] = flow; + } + + auto multilayerNodeFound = false; + if (isMultilayer) { + if (!(lineStream >> nodeId)) + throw std::runtime_error(io::Str() << "Couldn't parse node key from line '" << line << "'"); + + if (!(lineStream >> layerId)) + throw std::runtime_error(io::Str() << "Couldn't parse layer id from line '" << line << "'"); + + // get new state id from map + auto it = layerNodeToStateId->find(layerId); + + if (it != layerNodeToStateId->end()) { + auto nodeIdToStateId = it->second.find(nodeId); + if (nodeIdToStateId != it->second.end()) { + stateId = nodeIdToStateId->second; + multilayerNodeFound = true; + } + } + } + + if (isMultilayer && !multilayerNodeFound) { + continue; + } + + m_clusterIds[stateId] = moduleId; + } +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/io/ClusterMap.h b/src/vendor/cigraph/vendor/infomap/src/io/ClusterMap.h new file mode 100644 index 00000000000..5526663c334 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/ClusterMap.h @@ -0,0 +1,52 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef CLUSTER_MAP_H_ +#define CLUSTER_MAP_H_ + +#include +#include +#include +#include + +namespace infomap { + +using Path = std::deque; // 1-based indexing + +using NodePath = std::pair; + +using NodePaths = std::vector; + +class ClusterMap { +public: + void readClusterData(const std::string& filename, bool includeFlow = false, const std::map>* layerNodeToStateId = nullptr); + + const std::map& clusterIds() const noexcept + { + return m_clusterIds; + } + + const NodePaths& nodePaths() const noexcept { return m_nodePaths; } + + const std::string& extension() const noexcept { return m_extension; } + +private: + void readTree(const std::string& filename, bool includeFlow, const std::map>* layerNodeToStateId = nullptr); + void readClu(const std::string& filename, bool includeFlow, const std::map>* layerNodeToStateId = nullptr); + + std::map m_clusterIds; + std::map m_flowData; + NodePaths m_nodePaths; + std::string m_extension; + bool m_isHigherOrder = false; +}; + +} // namespace infomap + +#endif // CLUSTER_MAP_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/io/Config.cpp b/src/vendor/cigraph/vendor/infomap/src/io/Config.cpp new file mode 100644 index 00000000000..ce6a80fc4eb --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/Config.cpp @@ -0,0 +1,264 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "Config.h" +#include "ProgramInterface.h" +#include "SafeFile.h" +#include "../utils/FileURI.h" +#include "../utils/Log.h" +#include +#include + +namespace infomap { + +constexpr int FlowModel::undirected; +constexpr int FlowModel::directed; +constexpr int FlowModel::undirdir; +constexpr int FlowModel::outdirdir; +constexpr int FlowModel::rawdir; +constexpr int FlowModel::precomputed; + +Config::Config(const std::string& flags, bool isCLI) : isCLI(isCLI) +{ + ProgramInterface api("Infomap", + "Implementation of the Infomap clustering algorithm based on the Map Equation (see www.mapequation.org)", + INFOMAP_VERSION); + + api.setGroups({ "Input", "Algorithm", "Accuracy", "Output" }); + + std::vector optionalOutputDir; // Used if !isCLI + // --------------------- Input options --------------------- + if (isCLI) { + api.addNonOptionArgument(networkFile, "network_file", "File containing the network data. Assumes a link list format if no Pajek formatted heading.", "Input"); + } else { + api.addOptionArgument(networkFile, "input", "File containing the network data. Assumes a link list format if no Pajek formatted heading.", ArgType::path, "Input"); + } + + api.addOptionArgument(skipAdjustBipartiteFlow, "skip-adjust-bipartite-flow", "Skip distributing all flow from the bipartite nodes to the primary nodes.", "Input", true); + + api.addOptionArgument(bipartiteTeleportation, "bipartite-teleportation", "Teleport like the bipartite flow instead of two-step (unipartite) teleportation.", "Input", true); + + api.addOptionArgument(weightThreshold, "weight-threshold", "Limit the number of links to read from the network. Ignore links with less weight than the threshold.", ArgType::number, "Input", 0.0, true); + + bool deprecated_includeSelfLinks = false; + api.addOptionArgument(deprecated_includeSelfLinks, 'k', "include-self-links", "DEPRECATED. Include self links by default now, exclude with --no-self-links.", "Input", true).setHidden(true); + + api.addOptionArgument(noSelfLinks, "no-self-links", "Exclude self links in the input network.", "Input", true); + + api.addOptionArgument(nodeLimit, "node-limit", "Limit the number of nodes to read from the network. Ignore links connected to ignored nodes.", ArgType::integer, "Input", 1u, true); + + api.addOptionArgument(matchableMultilayerIds, "matchable-multilayer-ids", "Construct state ids from node and layer ids that are consistent across networks for the same max number of layers. Set to at least the largest layer id among networks to match.", ArgType::integer, "Input", 1u, true); + + api.addOptionArgument(clusterDataFile, 'c', "cluster-data", "Provide an initial two-level (clu format) or multi-layer (tree format) solution.", ArgType::path, "Input"); + + api.addOptionArgument(assignToNeighbouringModule, "assign-to-neighbouring-module", "Assign nodes without module assignments (from --cluster-data) to the module assignment of a neighbouring node if possible.", "Input", true); + + api.addOptionArgument(metaDataFile, "meta-data", "Provide meta data (clu format) that should be encoded.", ArgType::path, "Input", true); + + api.addOptionArgument(metaDataRate, "meta-data-rate", "Metadata encoding rate. Default is to encode each step.", ArgType::number, "Input", 0.0, true); + + api.addOptionArgument(unweightedMetaData, "meta-data-unweighted", "Don't weight meta data by node flow.", "Input", true); + + api.addOptionArgument(noInfomap, "no-infomap", "Don't run the optimizer. Useful to calculate codelength of provided cluster data or to print non-modular statistics.", "Input"); + + // --------------------- Output options --------------------- + + api.addOptionArgument(outName, "out-name", "Name for the output files, e.g. [output_directory]/[out-name].tree", ArgType::string, "Output", true); + + api.addOptionArgument(noFileOutput, '0', "no-file-output", "Don't write output to file.", "Output", true); + + api.addOptionArgument(printTree, "tree", "Write a tree file with the modular hierarchy. Automatically enabled if no other output is specified.", "Output"); + + api.addOptionArgument(printFlowTree, "ftree", "Write a ftree file with the modular hierarchy including aggregated links between (nested) modules. (Used by Network Navigator)", "Output"); + + api.addOptionArgument(printClu, "clu", "Write a clu file with the top cluster ids for each node.", "Output"); + + api.addOptionArgument(cluLevel, "clu-level", "For clu output, print modules at specified depth from root. Use -1 for bottom level modules.", ArgType::integer, "Output", -1, true); + + api.addOptionArgument(outputFormats, 'o', "output", "Comma-separated output formats without spaces, e.g. -o clu,tree,ftree. Options: clu, tree, ftree, newick, json, csv, network, states, flow.", ArgType::list, "Output", true); + + api.addOptionArgument(hideBipartiteNodes, "hide-bipartite-nodes", "Project bipartite solution to unipartite.", "Output", true); + + api.addOptionArgument(printAllTrials, "print-all-trials", "Print all trials to separate files.", "Output", true); + + // --------------------- Core algorithm options --------------------- + api.addOptionArgument(twoLevel, '2', "two-level", "Optimize a two-level partition of the network. Default is multi-level.", "Algorithm"); + + std::string flowModelArg; + + api.addOptionArgument(flowModelArg, 'f', "flow-model", "Specify flow model. Options: undirected, directed, undirdir, outdirdir, rawdir, precomputed.", ArgType::option, "Algorithm"); + + api.addOptionArgument(directed, 'd', "directed", "Assume directed links. Shorthand for '--flow-model directed'.", "Algorithm"); + + api.addOptionArgument(recordedTeleportation, 'e', "recorded-teleportation", "If teleportation is used to calculate the flow, also record it when minimizing codelength.", "Algorithm", true); + + api.addOptionArgument(useNodeWeightsAsFlow, "use-node-weights-as-flow", "Use node weights (from api or after names in Pajek format) as flow, normalized to sum to 1", "Algorithm", true); + + api.addOptionArgument(teleportToNodes, "to-nodes", "Teleport to nodes instead of to links, assuming uniform node weights if no such input data.", "Algorithm", true); + + api.addOptionArgument(teleportationProbability, 'p', "teleportation-probability", "Probability of teleporting to a random node or link.", ArgType::probability, "Algorithm", 0.0, 1.0, true); + + api.addOptionArgument(regularized, "regularized", "Effectively add a fully connected Bayesian prior network to not overfit due to missing links. Implies recorded teleportation", "Algorithm", true); + + api.addOptionArgument(regularizationStrength, "regularization-strength", "Adjust relative strength of Bayesian prior network with this multiplier.", ArgType::number, "Algorithm", 0.0, true); + + api.addOptionArgument(entropyBiasCorrection, "entropy-corrected", "Correct for negative entropy bias in small samples (many modules).", "Algorithm", true); + + api.addOptionArgument(entropyBiasCorrectionMultiplier, "entropy-correction-strength", "Increase or decrease the default entropy correction with this factor.", ArgType::number, "Algorithm", true); + + api.addOptionArgument(markovTime, "markov-time", "Scale link flow to change the cost of moving between modules. Higher values results in fewer modules.", ArgType::number, "Algorithm", 0.0, true); + + api.addOptionArgument(variableMarkovTime, "variable-markov-time", "Increase Markov time locally to level out link flow. Reduces risk of overpartitioning sparse areas while keeping high resolution in dense areas.", "Algorithm", true); + + api.addOptionArgument(variableMarkovTimeDamping, "variable-markov-damping", "Damping parameter for variable Markov time, to scale with local effective degree (0) or local entropy (1).", ArgType::number, "Algorithm", true); + + api.addOptionArgument(variableMarkovTimeMinLocalScale, "variable-markov-min-scale", "Minimum local scale for nodes with zero entropy to avoid division by zero. Local Markov time is max scale divided by local scale.", ArgType::number, "Algorithm", true); + + // api.addOptionArgument(markovTimeNoSelfLinks, "markov-time-no-self-links", "For testing.", "Algorithm", true); + + api.addOptionArgument(preferredNumberOfModules, "preferred-number-of-modules", "Penalize solutions the more they differ from this number.", ArgType::integer, "Algorithm", 1u, true); + + api.addOptionArgument(multilayerRelaxRate, "multilayer-relax-rate", "Probability to relax the constraint to move only in the current layer.", ArgType::probability, "Algorithm", 0.0, 1.0, true); + + api.addOptionArgument(multilayerRelaxLimit, "multilayer-relax-limit", "Number of neighboring layers in each direction to relax to. If negative, relax to any layer.", ArgType::integer, "Algorithm", -1, true); + + api.addOptionArgument(multilayerRelaxLimitUp, "multilayer-relax-limit-up", "Number of neighboring layers with higher id to relax to. If negative, relax to any layer.", ArgType::integer, "Algorithm", -1, true); + + api.addOptionArgument(multilayerRelaxLimitDown, "multilayer-relax-limit-down", "Number of neighboring layers with lower id to relax to. If negative, relax to any layer.", ArgType::integer, "Algorithm", -1, true); + + api.addOptionArgument(multilayerRelaxByJensenShannonDivergence, "multilayer-relax-by-jsd", "Relax proportional to the out-link similarity measured by the Jensen-Shannon divergence.", "Algorithm", true); + + // --------------------- Performance and accuracy options --------------------- + // api.addOptionArgument(seedToRandomNumberGenerator, 's', "seed", "A seed (integer) to the random number generator for reproducible results.", ArgType::integer, "Accuracy", 1ul); + + api.addOptionArgument(numTrials, 'N', "num-trials", "Number of outer-most loops to run before picking the best solution.", ArgType::integer, "Accuracy", 1u); + + api.addOptionArgument(coreLoopLimit, 'M', "core-loop-limit", "Limit the number of loops that tries to move each node into the best possible module.", ArgType::integer, "Accuracy", 1u, true); + + api.addOptionArgument(levelAggregationLimit, 'L', "core-level-limit", "Limit the number of times the core loops are reapplied on existing modular network to search bigger structures.", ArgType::integer, "Accuracy", 1u, true); + + api.addOptionArgument(tuneIterationLimit, 'T', "tune-iteration-limit", "Limit the number of main iterations in the two-level partition algorithm. 0 means no limit.", ArgType::integer, "Accuracy", 1u, true); + + api.addOptionArgument(minimumCodelengthImprovement, "core-loop-codelength-threshold", "Minimum codelength threshold for accepting a new solution in core loop.", ArgType::number, "Accuracy", 0.0, true); + + api.addOptionArgument(minimumRelativeTuneIterationImprovement, "tune-iteration-relative-threshold", "Set codelength improvement threshold of each new tune iteration to 'f' times the initial two-level codelength.", ArgType::number, "Accuracy", 0.0, true); + + api.addIncrementalOptionArgument(fastHierarchicalSolution, 'F', "fast-hierarchical-solution", "Find top modules fast. Use -FF to keep all fast levels. Use -FFF to skip recursive part.", "Accuracy", true); + + api.addOptionArgument(preferModularSolution, "prefer-modular-solution", "Prefer modular solutions even if they are worse than putting all nodes in one module.", "Accuracy", true); + + api.addOptionArgument(innerParallelization, "inner-parallelization", "Parallelize the inner-most loop for greater speed. This may give some accuracy tradeoff.", "Accuracy", true); + + api.addOptionalNonOptionArguments(optionalOutputDir, "out_directory", "Directory to write the results to.", "Output"); + + api.addIncrementalOptionArgument(verbosity, 'v', "verbose", "Verbose output on the console. Add additional 'v' flags to increase verbosity up to -vvv.", "Output"); + + api.addOptionArgument(silent, "silent", "No output on the console.", "Output"); + + api.parseArgs(flags); + + if (deprecated_includeSelfLinks) { + throw std::runtime_error("The --include-self-links flag is deprecated to include self links by default. Use --no-self-links to exclude."); + } + + if (!optionalOutputDir.empty()) + outDirectory = optionalOutputDir[0]; + + if (!isCLI && outDirectory.empty()) + noFileOutput = true; + + if (!noFileOutput && outDirectory.empty() && isCLI) { + throw std::runtime_error("Missing out_directory"); + } + + if (flowModelArg == "directed" || directed) { + setFlowModel(FlowModel::directed); + } else if (flowModelArg == "undirected") { + setFlowModel(FlowModel::undirected); + } else if (flowModelArg == "undirdir") { + setFlowModel(FlowModel::undirdir); + } else if (flowModelArg == "outdirdir") { + setFlowModel(FlowModel::outdirdir); + } else if (flowModelArg == "rawdir") { + setFlowModel(FlowModel::rawdir); + } else if (flowModelArg == "precomputed") { + setFlowModel(FlowModel::precomputed); + } else if (!flowModelArg.empty()) { + throw std::runtime_error(io::Str() << "Unrecognized flow model: '" << flowModelArg << "'"); + } + + if (regularized) { + recordedTeleportation = true; + } + + if (*--outDirectory.end() != '/') + outDirectory.append("/"); + + if (haveOutput() && !isDirectoryWritable(outDirectory)) + throw std::runtime_error(io::Str() << "Can't write to directory '" << outDirectory << "'. Check that the directory exists and that you have write permissions."); + + if (outName.empty()) { + outName = !networkFile.empty() ? FileURI(networkFile).getName() : "no-name"; + } + + if (noInfomap) { + numTrials = 1; + } + + parsedString = flags; + parsedOptions = api.getUsedOptionArguments(); + + if (printAllTrials && numTrials < 2) { + printAllTrials = false; + } + + adaptDefaults(); + + Log::init(verbosity, silent, verboseNumberPrecision); +} + +void Config::adaptDefaults() +{ + auto outputs = io::split(outputFormats, ','); + for (std::string& o : outputs) { + if (o == "clu") { + printClu = true; + } else if (o == "tree") { + printTree = true; + } else if (o == "ftree") { + printFlowTree = true; + } else if (o == "newick") { + printNewick = true; + } else if (o == "json") { + printJson = true; + } else if (o == "csv") { + printCsv = true; + } else if (o == "network") { + printPajekNetwork = true; + } else if (o == "flow") { + printFlowNetwork = true; + } else if (o == "states") { + printStateNetwork = true; + } else { + throw std::runtime_error(io::Str() << "Unrecognized output format: '" << o << "'."); + } + } + + // Of no output format specified, use tree as default (if not used as a library). + if (isCLI && !haveModularResultOutput()) { + printTree = true; + } +} + +std::ostream& operator<<(std::ostream& out, FlowModel f) +{ + return out << flowModelToString(f); +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/io/Config.h b/src/vendor/cigraph/vendor/infomap/src/io/Config.h new file mode 100644 index 00000000000..c7ce6112c04 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/Config.h @@ -0,0 +1,268 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef CONFIG_H_ +#define CONFIG_H_ + +#include "../utils/Date.h" +#include "../version.h" +#include "ProgramInterface.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace infomap { + +struct FlowModel { + static constexpr int undirected = 0; + static constexpr int directed = 1; + static constexpr int undirdir = 2; + static constexpr int outdirdir = 3; + static constexpr int rawdir = 4; + static constexpr int precomputed = 5; + + int value = 0; + + FlowModel(int val) : value(val) { } + FlowModel& operator=(int val) + { + value = val; + return *this; + } + + operator int&() { return value; } + operator int() const { return value; } +}; + +std::ostream& operator<<(std::ostream& out, FlowModel f); + +inline const char* flowModelToString(const FlowModel& flowModel) +{ + switch (flowModel) { + case FlowModel::directed: + return "directed"; + case FlowModel::undirdir: + return "undirdir"; + case FlowModel::outdirdir: + return "outdirdir"; + case FlowModel::rawdir: + return "rawdir"; + case FlowModel::precomputed: + return "precomputed"; + case FlowModel::undirected: + default: + return "undirected"; + } +} + +struct Config { + // Input + bool isCLI = false; + std::string networkFile; + std::vector additionalInput; + bool stateInput = false; + bool stateOutput = false; + bool multilayerInput = false; + double weightThreshold = 0.0; + bool bipartite = false; + bool skipAdjustBipartiteFlow = false; + bool bipartiteTeleportation = false; + bool noSelfLinks = false; // Replaces includeSelfLinks + unsigned int nodeLimit = 0; + unsigned int matchableMultilayerIds = 0; + std::string clusterDataFile; + std::string metaDataFile; + double metaDataRate = 1.0; + bool unweightedMetaData = false; + unsigned int numMetaDataDimensions = 0; + bool clusterDataIsHard = false; // FIXME Not used + bool assignToNeighbouringModule = false; + bool noInfomap = false; + + FlowModel flowModel = FlowModel::undirected; + bool flowModelIsSet = false; + bool directed = false; + bool useNodeWeightsAsFlow = false; + bool teleportToNodes = false; + double markovTime = 1.0; + bool variableMarkovTime = false; + double variableMarkovTimeDamping = 1.0; // 0 for linear scaling, 1 for log scaled. + double variableMarkovTimeMinLocalScale = 1; // Correspond to two links in undirected unweighted networks. Avoids division by zero. + bool markovTimeNoSelfLinks = false; + double multilayerRelaxRate = 0.15; + int multilayerRelaxLimit = -1; // Amount of layers allowed to jump up or down + int multilayerRelaxLimitUp = -1; // One-sided limit to higher layers + int multilayerRelaxLimitDown = -1; // One-sided limit to lower layers + double multilayerJSRelaxRate = 0.15; + bool multilayerRelaxByJensenShannonDivergence = false; + int multilayerJSRelaxLimit = -1; + + // Clustering + bool twoLevel = false; + bool noCoarseTune = false; + bool recordedTeleportation = false; + bool regularized = false; // Add a Bayesian prior network with recorded teleportation (sets recordedTeleportation and teleportToNodes to true) + double regularizationStrength = 1.0; // Scale Bayesian prior constant ln(N)/N with this factor + double teleportationProbability = 0.15; + unsigned int preferredNumberOfModules = 0; + bool entropyBiasCorrection = false; + double entropyBiasCorrectionMultiplier = 1; + /* unsigned long seedToRandomNumberGenerator = 123; */ + + // Performance and accuracy + unsigned int numTrials = 1; + double minimumCodelengthImprovement = 1e-10; + double minimumSingleNodeCodelengthImprovement = 1e-16; + bool randomizeCoreLoopLimit = false; + unsigned int coreLoopLimit = 10; + unsigned int levelAggregationLimit = 0; + unsigned int tuneIterationLimit = 0; // Iterations of fine-tune/coarse-tune in two-level partition + double minimumRelativeTuneIterationImprovement = 1e-5; + bool onlySuperModules = false; + unsigned int fastHierarchicalSolution = 0; + bool preferModularSolution = false; + bool innerParallelization = false; + + // Output + std::string outDirectory; + std::string outName; + std::string outputFormats; + bool printTree = false; + bool printFlowTree = false; + bool printNewick = false; + bool printJson = false; + bool printCsv = false; + bool printClu = false; + bool printAllTrials = false; + int cluLevel = 1; // Write modules at specified depth from root. 1, 2, ... or -1 for bottom level + bool printFlowNetwork = false; + bool printPajekNetwork = false; + bool printStateNetwork = false; + bool noFileOutput = false; + unsigned int verbosity = 0; + unsigned int verboseNumberPrecision = 9; + bool silent = false; + bool hideBipartiteNodes = false; + + // Other + Date startDate; + std::string version = INFOMAP_VERSION; + std::string parsedString; + std::vector parsedOptions; + infomap::interruptionHandlerFn *interruptionHandler = NULL; + + Config() = default; + + explicit Config(const std::string& flags, bool isCLI = false); + + Config& cloneAsNonMain(const Config& other) + { + isCLI = other.isCLI; + networkFile = other.networkFile; + additionalInput = other.additionalInput; + stateInput = other.stateInput; + stateOutput = other.stateOutput; + multilayerInput = other.multilayerInput; + weightThreshold = other.weightThreshold; + bipartite = other.bipartite; + skipAdjustBipartiteFlow = other.skipAdjustBipartiteFlow; + bipartiteTeleportation = other.bipartiteTeleportation; + noSelfLinks = other.noSelfLinks; + nodeLimit = other.nodeLimit; + matchableMultilayerIds = other.matchableMultilayerIds; + metaDataRate = other.metaDataRate; + unweightedMetaData = other.unweightedMetaData; + numMetaDataDimensions = other.numMetaDataDimensions; + assignToNeighbouringModule = other.assignToNeighbouringModule; + noInfomap = other.noInfomap; + flowModel = other.flowModel; + flowModelIsSet = other.flowModelIsSet; + directed = other.directed; + useNodeWeightsAsFlow = other.useNodeWeightsAsFlow; + teleportToNodes = other.teleportToNodes; + markovTime = other.markovTime; + variableMarkovTime = other.variableMarkovTime; + variableMarkovTimeDamping = other.variableMarkovTimeDamping; + markovTimeNoSelfLinks = other.markovTimeNoSelfLinks; + multilayerRelaxRate = other.multilayerRelaxRate; + multilayerRelaxLimit = other.multilayerRelaxLimit; + multilayerRelaxLimitUp = other.multilayerRelaxLimitUp; + multilayerRelaxLimitDown = other.multilayerRelaxLimitDown; + multilayerJSRelaxRate = other.multilayerJSRelaxRate; + multilayerRelaxByJensenShannonDivergence = other.multilayerRelaxByJensenShannonDivergence; + multilayerJSRelaxLimit = other.multilayerJSRelaxLimit; + twoLevel = other.twoLevel; + noCoarseTune = other.noCoarseTune; + recordedTeleportation = other.recordedTeleportation; + regularized = other.regularized; + regularizationStrength = other.regularizationStrength; + teleportationProbability = other.teleportationProbability; + entropyBiasCorrection = other.entropyBiasCorrection; + entropyBiasCorrectionMultiplier = other.entropyBiasCorrectionMultiplier; + // seedToRandomNumberGenerator = other.seedToRandomNumberGenerator; + minimumCodelengthImprovement = other.minimumCodelengthImprovement; + minimumSingleNodeCodelengthImprovement = other.minimumSingleNodeCodelengthImprovement; + randomizeCoreLoopLimit = other.randomizeCoreLoopLimit; + minimumRelativeTuneIterationImprovement = other.minimumRelativeTuneIterationImprovement; + preferModularSolution = other.preferModularSolution; + innerParallelization = other.innerParallelization; + outDirectory = other.outDirectory; + outName = other.outName; + outputFormats = other.outputFormats; + verbosity = other.verbosity; + verboseNumberPrecision = other.verboseNumberPrecision; + startDate = other.startDate; + version = other.version; + return *this; + } + + void adaptDefaults(); + + void setStateInput() { stateInput = true; } + + void setStateOutput() { stateOutput = true; } + + void setMultilayerInput() { multilayerInput = true; } + + void setFlowModel(FlowModel value) + { + flowModel = value; + flowModelIsSet = true; + } + + bool isUndirectedClustering() const { return flowModel == FlowModel::undirected; } + + bool isUndirectedFlow() const { return flowModel == FlowModel::undirected || flowModel == FlowModel::undirdir; } + + bool printAsUndirected() const { return isUndirectedClustering(); } + + bool isMultilayerNetwork() const { return multilayerInput || !additionalInput.empty(); } + bool isBipartite() const { return bipartite; } + + bool haveMemory() const { return stateInput; } + bool printStates() const { return stateOutput; } + + bool haveMetaData() const { return !metaDataFile.empty() || numMetaDataDimensions != 0; } + + bool haveOutput() const { return !noFileOutput; } + + bool haveModularResultOutput() const + { + return printTree || printFlowTree || printNewick || printJson || printCsv || printClu; + } +}; + +} // namespace infomap + +#endif // CONFIG_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/io/Network.cpp b/src/vendor/cigraph/vendor/infomap/src/io/Network.cpp new file mode 100644 index 00000000000..b405fd7a676 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/Network.cpp @@ -0,0 +1,990 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "Network.h" +#include "../io/SafeFile.h" +#include "../utils/FileURI.h" +#include "../utils/Log.h" + +#include +#include +#include + +namespace infomap { + +using std::make_pair; + +void Network::init() +{ + initValidHeadings(); + m_multilayerStateIdBitShift = static_cast(std::ceil(std::log2(m_config.matchableMultilayerIds))); +} + +void Network::initValidHeadings() +{ + auto& headingsPajek = m_validHeadings["pajek"]; + headingsPajek.insert("*vertices"); + headingsPajek.insert("*edges"); + headingsPajek.insert("*arcs"); + + auto& headingsLinklist = m_validHeadings["link-list"]; + headingsLinklist.insert("*links"); + headingsLinklist.insert("*edges"); + headingsLinklist.insert("*arcs"); + + auto& headingsBipartite = m_validHeadings["bipartite"]; + headingsBipartite.insert("*vertices"); + headingsBipartite.insert("*bipartite"); + + auto& headingsStates = m_validHeadings["states"]; + headingsStates.insert("*vertices"); + headingsStates.insert("*states"); + headingsStates.insert("*edges"); + headingsStates.insert("*arcs"); + headingsStates.insert("*links"); + headingsStates.insert("*contexts"); + auto& ignoreHeadingsStates = m_ignoreHeadings["states"]; + ignoreHeadingsStates.insert("*edges"); + ignoreHeadingsStates.insert("*contexts"); + + auto& headingsMultilayer = m_validHeadings["multilayer"]; + headingsMultilayer.insert("*vertices"); + headingsMultilayer.insert("*multiplex"); + headingsMultilayer.insert("*multilayer"); + headingsMultilayer.insert("*intra"); + headingsMultilayer.insert("*inter"); + + auto& headingsGeneral = m_validHeadings["general"]; + headingsGeneral.insert("*vertices"); + headingsGeneral.insert("*states"); + headingsGeneral.insert("*multilayer"); + headingsGeneral.insert("*intra"); + headingsGeneral.insert("*inter"); + headingsGeneral.insert("*paths"); + headingsGeneral.insert("*edges"); + headingsGeneral.insert("*arcs"); + headingsGeneral.insert("*links"); + headingsGeneral.insert("*contexts"); + headingsGeneral.insert("*bipartite"); + auto& ignoreHeadingsGeneral = m_ignoreHeadings["general"]; + ignoreHeadingsGeneral.insert("*contexts"); +} + +void Network::clear() +{ + StateNetwork::clear(); + m_networks.clear(); + m_interLinks.clear(); + m_layerNodeToStateId.clear(); + m_sumIntraOutWeight.clear(); + m_layers.clear(); + m_numInterLayerLinks = 0; + m_numIntraLayerLinks = 0; + + // Bipartite + m_bipartiteStartId = 0; + + // Meta data + m_metaData.clear(); + m_numMetaDataColumns = 0; +} + +void Network::readInputData(std::string filename, bool accumulate) +{ + if (!accumulate) { + clear(); + } + if (filename.empty()) + filename = m_config.networkFile; + if (filename.empty()) { + throw std::runtime_error("No input file to read network"); + } + FileURI networkFilename(filename, false); + + parseNetwork(filename); + printSummary(); +} + +void Network::parseNetwork(const std::string& filename) +{ + Log() << "Parsing " << (m_config.isUndirectedFlow() ? "undirected" : "directed") << " network from file '" << filename << "'...\n"; + + parseNetwork(filename, m_validHeadings["general"], m_ignoreHeadings["general"]); +} + +void Network::parseNetwork(const std::string& filename, const InsensitiveStringSet& validHeadings, const InsensitiveStringSet& ignoreHeadings, const std::string& startHeading) +{ + m_haveFileInput = true; + SafeInFile input(filename); + + // Parse standard links by default until possible heading is reached + std::string heading = startHeading.length() > 0 ? startHeading : parseLinks(input); + + while (heading.length() > 0 && heading[0] == '*') { + std::string headingLowerCase = io::tolower(io::firstWord(heading)); + if (validHeadings.count(headingLowerCase) == 0) { + throw std::runtime_error(io::Str() << "Unrecognized heading in network file: '" << headingLowerCase << "'."); + } + if (ignoreHeadings.count(headingLowerCase) > 0) { + heading = ignoreSection(input, headingLowerCase); + } else if (headingLowerCase == "*vertices") { + heading = parseVertices(input, heading); + } else if (headingLowerCase == "*states") { + heading = parseStateNodes(input, heading); + } else if (headingLowerCase == "*edges") { + if (!m_config.isUndirectedFlow()) + Log() << "\n --> Notice: Links marked as undirected but parsed as directed.\n"; + heading = parseLinks(input); + } else if (headingLowerCase == "*arcs") { + if (m_config.isUndirectedFlow()) + Log() << "\n --> Notice: Links marked as directed but parsed as undirected.\n"; + heading = parseLinks(input); + } else if (headingLowerCase == "*links") { + heading = parseLinks(input); + } else if (headingLowerCase == "*multilayer" || headingLowerCase == "*multiplex") { + heading = parseMultilayerLinks(input); + } else if (headingLowerCase == "*intra") { + heading = parseMultilayerIntraLinks(input); + } else if (headingLowerCase == "*inter") { + heading = parseMultilayerInterLinks(input); + } else if (headingLowerCase == "*bipartite") { + heading = parseBipartiteLinks(input, heading); + } else { + heading = ignoreSection(input, headingLowerCase); + } + } + + postProcessInputData(); + Log() << "Done!\n"; +} + +void Network::postProcessInputData() +{ + if (!m_networks.empty()) { + generateStateNetworkFromMultilayer(); + } + + if (!haveMemoryInput()) { + // If no memory input, add physical nodes as state nodes to not miss unconnected nodes + for (auto& it : m_physNodes) { + addNode(it.second.physId, it.second.weight); + } + } +} + +void Network::readMetaData(const std::string& filename) +{ + Log() << "Parsing meta data from '" << filename << "'...\n"; + SafeInFile input(filename); + std::string line; + while (!std::getline(input, line).fail()) { + if (line.length() == 0 || line[0] == '#') + continue; + + if (line[0] == '*') + break; + + m_extractor.clear(); + m_extractor.str(line); + + unsigned int nodeId; + if (!(m_extractor >> nodeId)) + throw std::runtime_error(io::Str() << "Can't parse node id from line '" << line << "'"); + + std::vector metaData; + unsigned int metaId; + while (m_extractor >> metaId) { + metaData.push_back(metaId); + } + if (metaData.empty()) + throw std::runtime_error(io::Str() << "Can't parse any meta data from line '" << line << "'"); + + addMetaData(nodeId, metaData); + } + Log() << " -> Parsed " << m_numMetaDataColumns << " columns of meta data for " << m_metaData.size() << " nodes.\n"; +} +////////////////////////////////////////////////////////////////////////////////////////// +// +// HELPER METHODS +// +////////////////////////////////////////////////////////////////////////////////////////// + +std::string Network::parseVertices(std::ifstream& file, const std::string& /*heading*/) +{ + Log() << " Parsing vertices...\n" + << std::flush; + std::string line; + while (!std::getline(file, line).fail()) { + if (line.length() == 0 || line[0] == '#') + continue; + + if (line[0] == '*') + break; + + m_extractor.clear(); + m_extractor.str(line); + + unsigned int id = 0; + if (!(m_extractor >> id)) + throw std::runtime_error(io::Str() << "Can't parse node id from line '" << line << "'"); + + auto nameStart = line.find_first_of('\"'); + auto nameEnd = line.find_last_of('\"'); + std::string name; + if (nameStart < nameEnd) { + name = std::string(line.begin() + nameStart + 1, line.begin() + nameEnd); + line = line.substr(nameEnd + 1); + m_extractor.clear(); + m_extractor.str(line); + } else { + if (!(m_extractor >> name)) + throw std::runtime_error(io::Str() << "Can't parse node name from line '" << line << "'"); + } + double weight = 1.0; + if ((m_extractor >> weight)) { + m_haveNodeWeights = true; + if (weight < 0) + throw std::runtime_error(io::Str() << "Negative node weight (" << weight << ") from line '" << line << "'"); + } + + addPhysicalNode(id, weight, name); + } + Log() << " -> " << m_physNodes.size() << " physical nodes added\n"; + return line; +} + +std::string Network::parseStateNodes(std::ifstream& file, const std::string& /*heading*/) +{ + m_higherOrderInputMethodCalled = true; + Log() << " Parsing state nodes...\n" + << std::flush; + std::string line; + while (!std::getline(file, line).fail()) { + if (line.length() == 0 || line[0] == '#') + continue; + + if (line[0] == '*') + break; + + StateNode stateNode; + parseStateNode(line, stateNode); + + addStateNode(stateNode); + addPhysicalNode(stateNode.physicalId); + + ++m_numStateNodesFound; + } + Log() << " -> " << m_numStateNodesFound << " state nodes added\n"; + return line; +} + +std::string Network::parseLinks(std::ifstream& file) +{ + // This is the default action, so check for links before printing + bool parsingLinks = false; + std::string line; + while (!std::getline(file, line).fail()) { + if (line.length() == 0 || line[0] == '#') + continue; + + if (line[0] == '*') + break; + + if (!parsingLinks) { + parsingLinks = true; + Log() << " Parsing links...\n" + << std::flush; + } + + unsigned int n1, n2; + double weight; + parseLink(line, n1, n2, weight); + + addLink(n1, n2, weight); + } + if (parsingLinks) + Log() << " -> " << m_numLinks << " links\n"; + return line; +} + +std::string Network::parseMultilayerLinks(std::ifstream& file) +{ + Log() << " Parsing multilayer links...\n" + << std::flush; + + if (m_config.matchableMultilayerIds > 0) { + Log() << " Creating matchable state ids using: nodeId << (log2(" << m_config.matchableMultilayerIds << ") + 1) | layerId\n"; + } + + std::string line; + while (!std::getline(file, line).fail()) { + if (line.length() == 0 || line[0] == '#') + continue; + + if (line[0] == '*') + break; + + unsigned int layer1, n1, layer2, n2; + double weight; + parseMultilayerLink(line, layer1, n1, layer2, n2, weight); + + // TODO: This explicit multilayer format can allow undirected but not the inter/intra format, clear? + addMultilayerLink(layer1, n1, layer2, n2, weight); + } + Log() << " -> " << (m_numIntraLayerLinks + m_numInterLayerLinks) << " links in " << m_layers.size() << " layers\n"; + Log() << " -> " << m_numIntraLayerLinks << " intra-layer links\n"; + Log() << " -> " << m_numInterLayerLinks << " inter-layer links\n"; + return line; +} + +std::string Network::parseMultilayerIntraLinks(std::ifstream& file) +{ + Log() << " Parsing intra-layer links...\n" + << std::flush; + + if (m_config.matchableMultilayerIds > 0) { + Log() << " Creating matchable state ids using: nodeId << (log2(" << m_config.matchableMultilayerIds << ") + 1) | layerId\n"; + } + + std::string line; + while (!std::getline(file, line).fail()) { + if (line.length() == 0 || line[0] == '#') + continue; + + if (line[0] == '*') + break; + + unsigned int layer, n1, n2; + double weight; + parseMultilayerIntraLink(line, layer, n1, n2, weight); + + addMultilayerIntraLink(layer, n1, n2, weight); + } + Log() << " -> " << m_numIntraLayerLinks << " intra-layer links\n"; + return line; +} + +std::string Network::parseMultilayerInterLinks(std::ifstream& file) +{ + Log() << " Parsing inter-layer links...\n" + << std::flush; + std::string line; + while (!std::getline(file, line).fail()) { + if (line.length() == 0 || line[0] == '#') + continue; + + if (line[0] == '*') + break; + + unsigned int layer1, n, layer2; + double weight; + parseMultilayerInterLink(line, layer1, n, layer2, weight); + + addMultilayerInterLink(layer1, n, layer2, weight); + } + Log() << " -> " << m_numInterLayerLinks << " inter-layer links\n"; + return line; +} + +std::string Network::parseBipartiteLinks(std::ifstream& file, const std::string& heading) +{ + Log() << " Parsing bipartite links...\n"; + // Extract break point for bipartite links + m_extractor.clear(); + m_extractor.str(heading); + std::string tmp; + if (!(m_extractor >> tmp >> m_bipartiteStartId)) + throw std::runtime_error(io::Str() << "Can't parse bipartite start id from line '" << heading << "'"); + + Log() << " -> Using bipartite start id " << m_bipartiteStartId << "\n"; + m_config.bipartite = true; + std::string line; + while (!std::getline(file, line).fail()) { + if (line.length() == 0 || line[0] == '#') + continue; + + if (line[0] == '*') + break; + + unsigned int n1, n2; + double weight; + parseLink(line, n1, n2, weight); + bool sourceIsFeature = n1 >= m_bipartiteStartId; + bool targetIsFeature = n2 >= m_bipartiteStartId; + if (sourceIsFeature == targetIsFeature) { + throw std::runtime_error(io::Str() << "Bipartite link '" << line << "' must cross bipartite start id " << m_bipartiteStartId << "."); + } + addLink(n1, n2, weight); + } + return line; +} + +std::string Network::ignoreSection(std::ifstream& file, const std::string& heading) +{ + Log() << "(Ignoring section " << heading << ") "; + std::string line; + while (!std::getline(file, line).fail()) { + if (line[0] == '*') + break; + } + return line; +} + +void Network::parseStateNode(const std::string& line, StateNetwork::StateNode& stateNode) +{ + m_extractor.clear(); + m_extractor.str(line); + if (!(m_extractor >> stateNode.id >> stateNode.physicalId)) + throw std::runtime_error(io::Str() << "Can't parse any state node from line '" << line << "'"); + + // Optional name enclosed in double quotes + auto nameStart = line.find_first_of('\"', m_extractor.tellg()); + auto nameEnd = line.find_last_of('\"'); + if (nameStart < nameEnd) { + stateNode.name = std::string(line.begin() + nameStart + 1, line.begin() + nameEnd); + m_extractor.seekg(nameEnd + 1); + } + // Optional weight, default to 1.0 + if ((m_extractor >> stateNode.weight)) { + m_haveStateNodeWeights = true; + if (stateNode.weight < 0) + throw std::runtime_error(io::Str() << "Negative state node weight (" << stateNode.weight << ") from line '" << line << "'"); + } +} + +void Network::parseLink(const std::string& line, unsigned int& n1, unsigned int& n2, double& weight) +{ + m_extractor.clear(); + m_extractor.str(line); + if (!(m_extractor >> n1 >> n2)) + throw std::runtime_error(io::Str() << "Can't parse link data from line '" << line << "'"); + (m_extractor >> weight) || (weight = 1.0); +} + +void Network::parseMultilayerLink(const std::string& line, unsigned int& layer1, unsigned int& n1, unsigned int& layer2, unsigned int& n2, double& weight) +{ + m_extractor.clear(); + m_extractor.str(line); + if (!(m_extractor >> layer1 >> n1 >> layer2 >> n2)) + throw std::runtime_error(io::Str() << "Can't parse multilayer link data from line '" << line << "'"); + (m_extractor >> weight) || (weight = 1.0); +} + +void Network::parseMultilayerIntraLink(const std::string& line, unsigned int& layer, unsigned int& n1, unsigned int& n2, double& weight) +{ + m_extractor.clear(); + m_extractor.str(line); + if (!(m_extractor >> layer >> n1 >> n2)) + throw std::runtime_error(io::Str() << "Can't parse intra-multilayer link data from line '" << line << "'"); + (m_extractor >> weight) || (weight = 1.0); +} + +void Network::parseMultilayerInterLink(const std::string& line, unsigned int& layer1, unsigned int& n, unsigned int& layer2, double& weight) +{ + m_extractor.clear(); + m_extractor.str(line); + if (!(m_extractor >> layer1 >> n >> layer2)) + throw std::runtime_error(io::Str() << "Can't parse inter-multilayer link data from line '" << line << "'"); + (m_extractor >> weight) || (weight = 1.0); + if (layer1 == layer2) + throw std::runtime_error(io::Str() << "Inter-layer link from line '" << line << "' doesn't go between different layers."); + // TODO: Same as intra-layer self-link? +} + +void Network::printSummary() +{ + Log() << "-------------------------------------\n"; + if (haveMemoryInput()) { + Log() << " -> " << numNodes() << " state nodes\n"; + Log() << " -> " << numPhysicalNodes() << " physical nodes\n"; + } else { + if (m_bipartiteStartId > 0) + Log() << " -> " << numNodes() << " bipartite nodes\n"; + else + Log() << " -> " << numNodes() << " nodes\n"; + } + Log() << " -> " << numLinks() << " links with total weight " << m_totalLinkWeightAdded << "\n"; + if (m_numLinksIgnoredByWeightThreshold > 0) { + Log() << " -> " << m_numLinksIgnoredByWeightThreshold << " links ignored by weight threshold with total weight " << m_totalLinkWeightIgnored << " (" << io::toPrecision(m_totalLinkWeightIgnored / (m_totalLinkWeightIgnored + m_totalLinkWeightAdded) * 100, 1, true) << "%)\n"; + } +} + +void Network::addMultilayerLink(unsigned int layer1, unsigned int n1, unsigned int layer2, unsigned int n2, double weight) +{ + m_higherOrderInputMethodCalled = true; + if (weight < m_config.weightThreshold) { + ++m_numLinksIgnoredByWeightThreshold; + m_totalLinkWeightIgnored += weight; + return; + } + unsigned int stateId1 = addMultilayerNode(layer1, n1); + unsigned int stateId2 = addMultilayerNode(layer2, n2); + + if (stateId1 == stateId2) { + // TODO: Handle self-links? + } + + if (layer1 == layer2) { + ++m_numIntraLayerLinks; + m_sumIntraOutWeight[layer1][n1] += weight; // TODO: Not used? Add on target also if undirected (not inter/intra format)? + } else { + ++m_numInterLayerLinks; + } + + addLink(stateId1, stateId2, weight); +} + +void Network::generateStateNetworkFromMultilayer() +{ + // As inter-layer links is directed to neighbouring nodes in target layer, + // the symmetry is broken so we need directed links for inter-layer flow + m_haveDirectedInput = true; + if (m_config.isUndirectedFlow()) { + // TODO: Don't allow undirdir/outdirdir/rawdir? + // Expand each undirected intra-layer link to two opposite directed links + Log() << " -> Expanding undirected links to directed...\n"; + for (auto& layerIt : m_networks) { + auto& network = layerIt.second; + network.undirectedToDirected(); + } + } + + if (!m_interLinks.empty()) { + generateStateNetworkFromMultilayerWithInterLinks(); + } else { + generateStateNetworkFromMultilayerWithSimulatedInterLinks(); + } + m_networks.clear(); + m_interLinks.clear(); +} + +void Network::generateStateNetworkFromMultilayerWithInterLinks() +{ + Log() << "Generating state network from multilayer networks with inter-layer links...\n" + << std::flush; + // First add intra-layer links + for (auto& layerIt : m_networks) { + unsigned int layer1 = layerIt.first; + auto& network = layerIt.second; + for (auto& linkIt : network.nodeLinkMap()) { + auto& source = linkIt.first; + const auto& subLinks = linkIt.second; + for (auto& subIt : subLinks) { + auto& target = subIt.first; + double linkWeight = subIt.second.weight; + addMultilayerLink(layer1, source.physicalId, layer1, target.physicalId, linkWeight); + } + } + } + + Log() << "Connecting layers...\n"; + // Connect layers with inter-layer links spread out in target layer + for (auto& it : m_interLinks) { + auto& layerNode = it.first; + unsigned int layer1 = layerNode.layer; + unsigned int physId = layerNode.node; + unsigned int stateId1 = addMultilayerNode(layer1, physId); + for (auto& it2 : it.second) { + unsigned int layer2 = it2.first; + double interWeight = it2.second; + auto& targetNetwork = m_networks[layer2]; + + std::map>& targetLinks = targetNetwork.nodeLinkMap(); + auto& outlinks = targetLinks[StateNode(physId)]; + if (outlinks.empty()) { + continue; + } + auto& targetOutWeights = targetNetwork.outWeights(); + double sumIntraOutWeightTargetLayer = targetOutWeights[physId]; + + for (auto& outLink : outlinks) { + auto& targetPhysId = outLink.first.physicalId; + auto& linkData = outLink.second; + double intraWeight = linkData.weight; + unsigned int stateId2i = addMultilayerNode(layer2, targetPhysId); + + double weight = sumIntraOutWeightTargetLayer == 0.0 ? 0.0 : interWeight * intraWeight / sumIntraOutWeightTargetLayer; + + addLink(stateId1, stateId2i, weight); + ++m_numInterLayerLinks; // TODO: Count all as one? + } + } + } + if (m_config.isUndirectedFlow()) { + // For undirected inter-layer links, expand and add in other direction too + for (auto& it : m_interLinks) { + auto& layerNode = it.first; + unsigned int layer2 = layerNode.layer; + unsigned int physId = layerNode.node; + auto& targetNetwork = m_networks[layer2]; + std::map>& targetLinks = targetNetwork.nodeLinkMap(); + auto& outlinks = targetLinks[StateNode(physId)]; + if (outlinks.empty()) { + continue; + } + auto& targetOutWeights = targetNetwork.outWeights(); + double sumIntraOutWeightTargetLayer = targetOutWeights[physId]; + for (auto& it2 : it.second) { + unsigned int layer1 = it2.first; + double interWeight = it2.second; + unsigned int stateId1 = addMultilayerNode(layer1, physId); + + for (auto& outLink : outlinks) { + auto& targetPhysId = outLink.first.physicalId; + auto& linkData = outLink.second; + double intraWeight = linkData.weight; + unsigned int stateId2i = addMultilayerNode(layer2, targetPhysId); + + double weight = sumIntraOutWeightTargetLayer == 0.0 ? 0.0 : interWeight * intraWeight / sumIntraOutWeightTargetLayer; + + addLink(stateId1, stateId2i, weight); + ++m_numInterLayerLinks; // TODO: Count all as one? + } + } + } + } +} + +void Network::generateStateNetworkFromMultilayerWithSimulatedInterLinks() +{ + Log() << "Generating state network from multilayer networks with simulated inter-layer links...\n" + << std::flush; + double relaxRate = m_config.multilayerRelaxRate; + + int maxRelaxLimit = m_networks.size(); + int relaxLimitSymmetric = m_config.multilayerRelaxLimit < 0 ? maxRelaxLimit : m_config.multilayerRelaxLimit; + int relaxLimitDown = m_config.multilayerRelaxLimitDown < 0 ? relaxLimitSymmetric : std::min(relaxLimitSymmetric, m_config.multilayerRelaxLimitDown); + int relaxLimitUp = m_config.multilayerRelaxLimitUp < 0 ? relaxLimitSymmetric : std::min(relaxLimitSymmetric, m_config.multilayerRelaxLimitUp); + auto haveUpOrDownLimit = m_config.multilayerRelaxLimitDown >= 0 || m_config.multilayerRelaxLimitUp >= 0; + + Log() << "-> " << m_networks.size() << " networks\n"; + Log() << "-> Relax rate: " << relaxRate << "\n"; + if (haveUpOrDownLimit) { + Log() << "-> Relax limit up: " << relaxLimitUp << (relaxLimitUp == maxRelaxLimit ? " (no limit)\n" : "\n"); + Log() << "-> Relax limit down: " << relaxLimitDown << (relaxLimitDown == maxRelaxLimit ? " (no limit)\n" : "\n"); + } else if (m_config.multilayerRelaxLimit >= 0) { + Log() << "-> Relax limit: " << m_config.multilayerRelaxLimit << "\n"; + } + + auto withinRelaxLimit = [relaxLimitDown, relaxLimitUp](auto& layer1, auto& layer2) { + int diff = layer1 - layer2; + return layer1 >= layer2 ? diff <= relaxLimitDown : -diff <= relaxLimitUp; + }; + + if (m_config.multilayerRelaxByJensenShannonDivergence) { + Log() << "-> Using Jensen-Shannon Divergence\n"; + + for (unsigned int nodeId = 0; nodeId <= m_maxNodeIdInIntraLayerNetworks; ++nodeId) { + unsigned int layer2from = 0; + + // Calculate Jensen-Shannon similarity between all layers such that layer1 >= layer2, + // and then use its symmetry for layer2 > layer1 + std::map> jsRelaxWeights; + std::map jsTotWeight; + + for (unsigned int layer1 = 0; layer1 < m_networks.size(); ++layer1) { + unsigned int layer2to = layer1 + 1; + // Limit possible jumps to close by layers + if (m_config.multilayerRelaxLimit >= 0) { + layer2from = ((int)layer1 - m_config.multilayerRelaxLimit) < 0 ? 0 : layer1 - m_config.multilayerRelaxLimit; + } + + auto& layer1LinkMap = m_networks[layer1].nodeLinkMap(); + auto& layer1OutLinks = layer1LinkMap[StateNode(nodeId)]; + // Skip dangling nodes, because they have no information to calculate similarity + if (layer1OutLinks.empty()) + continue; + + double sumOutLinkWeightLayer1 = m_networks[layer1].outWeights()[nodeId]; + + for (unsigned int layer2 = layer2from; layer2 < layer2to; ++layer2) { + auto& layer2LinkMap = m_networks[layer2].nodeLinkMap(); + auto& layer2OutLinks = layer2LinkMap[StateNode(nodeId)]; + if (layer2OutLinks.empty()) + continue; + + double sumOutLinkWeightLayer2 = m_networks[layer2].outWeights()[nodeId]; + + bool intersect; + double div = calculateJensenShannonDivergence(intersect, layer1OutLinks, sumOutLinkWeightLayer1, layer2OutLinks, sumOutLinkWeightLayer2); + double jsWeight = 1.0 - div; + if (intersect && (jsWeight >= m_config.multilayerJSRelaxLimit)) { + jsTotWeight[layer1] += jsWeight; + jsRelaxWeights[layer1][layer2] = jsWeight; + if (layer1 != layer2) { + jsTotWeight[layer2] += jsWeight; + jsRelaxWeights[layer2][layer1] = jsWeight; + } + } + } + } + + // Second loop over all pairs of layers + unsigned int layer2to = m_networks.size(); + + for (unsigned int layer1 = 0; layer1 < m_networks.size(); ++layer1) { + // Limit possible jumps to close by layers + if (m_config.multilayerRelaxLimit >= 0) { + layer2from = ((int)layer1 - m_config.multilayerRelaxLimit) < 0 ? 0 : layer1 - m_config.multilayerRelaxLimit; + layer2to = (layer1 + m_config.multilayerRelaxLimit) > m_networks.size() ? m_networks.size() : layer1 + m_config.multilayerRelaxLimit; + } + + double sumOutLinkWeightLayer1 = m_networks[layer1].outWeights()[nodeId]; + + auto jsRelaxWeightsLayer1It = jsRelaxWeights.find(layer1); + auto jsTotWeightIt = jsTotWeight.find(layer1); + + // Create inter-links to the intra-connected nodes in other layers + for (unsigned int layer2 = layer2from; layer2 < layer2to; ++layer2) { + if (jsRelaxWeightsLayer1It != jsRelaxWeights.end()) { + auto jsRelaxWeightsIt = jsRelaxWeightsLayer1It->second.find(layer2); + if (jsRelaxWeightsIt != jsRelaxWeightsLayer1It->second.end()) { + bool isIntra = layer2 == layer1; + + // Create inter-links to the outgoing nodes in the target layer + double linkWeightNormalizationFactor; + if (isIntra) { + linkWeightNormalizationFactor = 1; + } else { + linkWeightNormalizationFactor = jsRelaxWeightsIt->second * relaxRate / (1.0 - relaxRate) * sumOutLinkWeightLayer1 / jsTotWeightIt->second; + } + + auto& targetLinks = m_networks[layer2].nodeLinkMap(); + auto& targetOutlinks = targetLinks[StateNode(nodeId)]; + if (targetOutlinks.empty()) { + continue; + } + for (auto& outLink : targetOutlinks) { + auto& n2 = outLink.first.physicalId; + auto& linkData = outLink.second; + double intraWeight = linkData.weight; + // Add intra link weight as teleport weight to source node + unsigned int stateId1 = addMultilayerNode(layer1, nodeId, intraWeight); + unsigned int stateId2i = addMultilayerNode(layer2, n2, 0.0); + + double weight = intraWeight == 0.0 ? 0.0 : linkWeightNormalizationFactor * intraWeight; + addLink(stateId1, stateId2i, weight); + ++m_numInterLayerLinks; + } + } + } + } + } + } + + return; + } + + for (auto& it1 : m_networks) { + auto layer1 = it1.first; + auto& network1 = it1.second; + + for (auto& n1It : network1.nodes()) { + auto& n1 = n1It.first; + unsigned int stateId1 = addMultilayerNode(layer1, n1); + + double sumOutLinkWeightLayer1 = network1.outWeights()[n1]; + double sumOutWeightAllLayers = 0.0; + + for (auto& it2 : m_networks) { + auto layer2 = it2.first; + if (!withinRelaxLimit(layer1, layer2)) { + continue; + } + auto& network2 = it2.second; + sumOutWeightAllLayers += network2.outWeights()[n1]; + } + + if (sumOutWeightAllLayers <= 0) { + continue; + } + for (auto& it2 : m_networks) { + auto layer2 = it2.first; + if (!withinRelaxLimit(layer1, layer2)) { + continue; + } + auto& network2 = it2.second; + bool isIntra = layer2 == layer1; + + double linkWeightNormalizationFactor = relaxRate / sumOutWeightAllLayers; + if (isIntra) { + linkWeightNormalizationFactor += (1.0 - relaxRate) / sumOutLinkWeightLayer1; + } + + auto& targetLinks = network2.nodeLinkMap(); + auto& targetOutlinks = targetLinks[StateNode(n1)]; + if (targetOutlinks.empty()) { + continue; + } + for (auto& outLink : targetOutlinks) { + auto& n2 = outLink.first.physicalId; + auto& linkData = outLink.second; + double intraWeight = linkData.weight; + unsigned int stateId2i = addMultilayerNode(layer2, n2); + + double weight = intraWeight == 0.0 ? 0.0 : linkWeightNormalizationFactor * intraWeight; + addLink(stateId1, stateId2i, weight); + ++m_numInterLayerLinks; // TODO: Count all as one? + } + } + } + } +} + +double Network::calculateJensenShannonDivergence(bool& intersect, const OutLinkMap& layer1OutLinks, double sumOutLinkWeightLayer1, const OutLinkMap& layer2OutLinks, double sumOutLinkWeightLayer2) +{ + intersect = false; + double h1 = 0.0; // The entropy rate of the node in the first layer + double h2 = 0.0; // The entropy rate of the node in the second layer + double h12 = 0.0; // The entropy rate of the lumped node + // The out-link weights of the nodes + double ow1 = sumOutLinkWeightLayer1; + double ow2 = sumOutLinkWeightLayer2; + // Normalized weights over node in layer 1 and 2 + double pi1 = ow1 / (ow1 + ow2); + double pi2 = ow2 / (ow1 + ow2); + + auto layer1OutLinkIt = layer1OutLinks.begin(); + auto layer2OutLinkIt = layer2OutLinks.begin(); + auto layer1OutLinkItEnd = layer1OutLinks.end(); + auto layer2OutLinkItEnd = layer2OutLinks.end(); + while (layer1OutLinkIt != layer1OutLinkItEnd && layer2OutLinkIt != layer2OutLinkItEnd) { + int diff = layer1OutLinkIt->first.id - layer2OutLinkIt->first.id; + if (diff < 0) { + // If the first state node has a link that the second has not + double p1 = layer1OutLinkIt->second.weight / ow1; + h1 -= p1 * log2(p1); + double p12 = pi1 * layer1OutLinkIt->second.weight / ow1; + h12 -= p12 * log2(p12); + layer1OutLinkIt++; + } else if (diff > 0) { + // If the second state node has a link that the second has not + double p2 = layer2OutLinkIt->second.weight / ow2; + h2 -= p2 * log2(p2); + double p12 = pi2 * layer2OutLinkIt->second.weight / ow2; + h12 -= p12 * log2(p12); + layer2OutLinkIt++; + } else { // If both state nodes have the link + intersect = true; + double p1 = layer1OutLinkIt->second.weight / ow1; + h1 -= p1 * log2(p1); + double p2 = layer2OutLinkIt->second.weight / ow2; + h2 -= p2 * log2(p2); + double p12 = pi1 * layer1OutLinkIt->second.weight / ow1 + pi2 * layer2OutLinkIt->second.weight / ow2; + h12 -= p12 * log2(p12); + layer1OutLinkIt++; + layer2OutLinkIt++; + } + } + + while (layer1OutLinkIt != layer1OutLinkItEnd) { + // If the first state node has a link that the second has not + double p1 = layer1OutLinkIt->second.weight / ow1; + h1 -= p1 * log2(p1); + double p12 = pi1 * layer1OutLinkIt->second.weight / ow1; + h12 -= p12 * log2(p12); + layer1OutLinkIt++; + } + + while (layer2OutLinkIt != layer2OutLinkItEnd) { + // If the second state node has a link that the second has not + double p2 = layer2OutLinkIt->second.weight / ow2; + h2 -= p2 * log2(p2); + double p12 = pi2 * layer2OutLinkIt->second.weight / ow2; + h12 -= p12 * log2(p12); + layer2OutLinkIt++; + } + + double div = (pi1 + pi2) * h12 - pi1 * h1 - pi2 * h2; + + // Fix precision problems + if (div < 0.0) + div = 0.0; + else if (div > 1.0) + div = 1.0; + + return div; +} + +void Network::simulateInterLayerLinks() +{ +} + +void Network::addMultilayerIntraLink(unsigned int layer, unsigned int n1, unsigned int n2, double weight) +{ + m_higherOrderInputMethodCalled = true; + bool added = m_networks[layer].addLink(n1, n2, weight); + if (added) { + ++m_numIntraLayerLinks; + m_maxNodeIdInIntraLayerNetworks = std::max(m_maxNodeIdInIntraLayerNetworks, std::max(n1, n2)); + } +} + +void Network::addMultilayerInterLink(unsigned int layer1, unsigned int n, unsigned int layer2, double interWeight) +{ + if (layer1 == layer2) { + throw std::runtime_error(io::Str() << "Inter-layer link (layer1, node, layer2): " << layer1 << ", " << n << ", " << layer2 << " must have layer1 != layer2"); + } + m_higherOrderInputMethodCalled = true; + + auto& interLinks = m_interLinks[LayerNode(layer1, n)]; + auto it = interLinks.find(layer2); + + if (it == interLinks.end()) { + ++m_numInterLayerLinks; + } + interLinks[layer2] += interWeight; +} + +unsigned int Network::addMultilayerNode(unsigned int layerId, unsigned int physicalId, double weight) +{ + m_higherOrderInputMethodCalled = true; + + // Create state node if not already exist, return state node id + auto& layerIt = m_layerNodeToStateId[layerId]; + auto it = layerIt.find(physicalId); + + if (it != layerIt.end()) { + return it->second; + } + + bool matchableMultilayerIds = m_config.matchableMultilayerIds != 0; + + if (matchableMultilayerIds && layerId > m_config.matchableMultilayerIds) { + throw std::runtime_error(io::Str() << "Cannot add node with layer " << layerId << " to network with matchable multilayer ids using largest layer id " << m_config.matchableMultilayerIds); + } + + auto ret = matchableMultilayerIds + ? addStateNodeWithDeterministicId(physicalId, layerId, m_multilayerStateIdBitShift) + : addStateNodeWithAutogeneratedId(physicalId); + auto& stateNode = ret.first->second; + stateNode.layerId = layerId; + stateNode.weight = weight; + m_layerNodeToStateId[layerId][physicalId] = stateNode.id; + m_layers.insert(layerId); + return stateNode.id; +} + +void Network::addMetaData(unsigned int nodeId, int meta) +{ + std::vector metaData(1, meta); + addMetaData(nodeId, metaData); +} + +void Network::addMetaData(unsigned int nodeId, const std::vector& metaData) +{ + m_metaData[nodeId] = metaData; + if (m_numMetaDataColumns == 0) { + m_numMetaDataColumns = metaData.size(); + } else if (metaData.size() != m_numMetaDataColumns) { + throw std::runtime_error(io::Str() << "Must have same number of dimensions in meta data, error trying to add meta data '" << io::stringify(metaData, ",") << "' on node " << nodeId << "."); + } +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/io/Network.h b/src/vendor/cigraph/vendor/infomap/src/io/Network.h new file mode 100644 index 00000000000..a801db6927c --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/Network.h @@ -0,0 +1,214 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef NETWORK_H_ +#define NETWORK_H_ + +#include "Config.h" +#include "../core/StateNetwork.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace infomap { + +struct LayerNode; + +class Network : public StateNetwork { +private: + // Helpers + std::istringstream m_extractor; + + // Multilayer + std::map m_networks; // intra-layer links + std::map> m_interLinks; + // { layer -> { physId -> stateId }} + std::map> m_layerNodeToStateId; + std::map> m_sumIntraOutWeight; + std::set m_layers; + unsigned int m_numInterLayerLinks = 0; + unsigned int m_numIntraLayerLinks = 0; + unsigned int m_maxNodeIdInIntraLayerNetworks = 0; + + unsigned int m_multilayerStateIdBitShift = 0; + + // Meta data + std::map> m_metaData; + unsigned int m_numMetaDataColumns = 0; + + using InsensitiveStringSet = std::set; + + std::map m_ignoreHeadings; + std::map m_validHeadings; // { + // { "pajek", {"*Vertices", "*Edges", "*Arcs"} }, + // { "link-list", {"*Links"} }, + // { "bipartite", {"*Vertices", "*Bipartite"} }, + // { "general", {"*Vertices", "*States", "*Edges", "*Arcs", "*Links", "*Context"} } + // }; + +public: + Network() : StateNetwork() { init(); } + explicit Network(const Config& config) : StateNetwork(config) { init(); } + explicit Network(const std::string& flags) : StateNetwork(Config(flags)) { init(); } + ~Network() override = default; + + Network(const Network&) = delete; + Network& operator=(const Network&) = delete; + Network(Network&&) = delete; + Network& operator=(Network&&) = delete; + + void clear() override; + + /** + * Parse network data from file and generate network + * @param filename input network + * @param accumulate add to possibly existing network data (default), else clear before. + */ + virtual void readInputData(std::string filename = "", bool accumulate = true); + + /** + * Init categorical meta data on all nodes from a file with the following format: + * # nodeId metaData + * 1 1 + * 2 1 + * 3 2 + * 4 2 + * 5 3 + * @param filename input filename for metadata + */ + virtual void readMetaData(const std::string& filename); + + unsigned int numMetaDataColumns() const { return m_numMetaDataColumns; } + const std::map>& metaData() const override { return m_metaData; } + + bool isMultilayerNetwork() const { return !m_layerNodeToStateId.empty(); } + const std::map>& layerNodeToStateId() const { return m_layerNodeToStateId; } + + void postProcessInputData(); + void generateStateNetworkFromMultilayer(); + void generateStateNetworkFromMultilayerWithInterLinks(); + void generateStateNetworkFromMultilayerWithSimulatedInterLinks(); + void simulateInterLayerLinks(); + + /** + * Create state node corresponding to this multilayer node if not already exist + * @return state node id + */ + unsigned int addMultilayerNode(unsigned int layerId, unsigned int physicalId, double weight = 1.0); + + void addMultilayerLink(unsigned int layer1, unsigned int n1, unsigned int layer2, unsigned int n2, double weight); + + /** + * Create an intra-layer link + */ + void addMultilayerIntraLink(unsigned int layer, unsigned int n1, unsigned int n2, double weight); + + /** + * Create links between (layer1,n) and (layer2,m) for all m connected to n in layer 2. + * The weight is distributed proportionally. + * TODO: This is done later.. + */ + void addMultilayerInterLink(unsigned int layer1, unsigned int n, unsigned int layer2, double interWeight); + + void addMetaData(unsigned int nodeId, int meta); + + void addMetaData(unsigned int nodeId, const std::vector& metaData); + +private: + void init(); + void initValidHeadings(); + + void parseNetwork(const std::string& filename); + void parseNetwork(const std::string& filename, const InsensitiveStringSet& validHeadings, const InsensitiveStringSet& ignoreHeadings, const std::string& startHeading = ""); + + // Helper methods + + /** + * Parse vertices under the heading + * @return The line after the vertices + */ + std::string parseVertices(std::ifstream& file, const std::string& heading); + std::string parseStateNodes(std::ifstream& file, const std::string& heading); + + std::string parseLinks(std::ifstream& file); + + /** + * Parse multilayer links from a *multilayer section + */ + std::string parseMultilayerLinks(std::ifstream& file); + + /** + * Parse multilayer links from an *intra section + */ + std::string parseMultilayerIntraLinks(std::ifstream& file); + + /** + * Parse multilayer links from an *inter section + */ + std::string parseMultilayerInterLinks(std::ifstream& file); + + std::string parseBipartiteLinks(std::ifstream& file, const std::string& heading); + + static std::string ignoreSection(std::ifstream& file, const std::string& heading); + + void parseStateNode(const std::string& line, StateNetwork::StateNode& stateNode); + + /** + * Parse a string of link data. + * If no weight data can be extracted, the default value 1.0 will be used. + * @throws an error if not both node ids can be extracted. + */ + void parseLink(const std::string& line, unsigned int& n1, unsigned int& n2, double& weight); + + /** + * Parse a string of multilayer link data. + * If no weight data can be extracted, the default value 1.0 will be used. + * @throws an error if not both node and layer ids can be extracted. + */ + void parseMultilayerLink(const std::string& line, unsigned int& layer1, unsigned int& n1, unsigned int& layer2, unsigned int& n2, double& weight); + + /** + * Parse a string of intra-multilayer link data. + * If no weight data can be extracted, the default value 1.0 will be used. + * @throws an error if not both node and layer ids can be extracted. + */ + void parseMultilayerIntraLink(const std::string& line, unsigned int& layer, unsigned int& n1, unsigned int& n2, double& weight); + + /** + * Parse a string of inter-multilayer link data. + * If no weight data can be extracted, the default value 1.0 will be used. + * @throws an error if not both node and layer ids can be extracted. + */ + void parseMultilayerInterLink(const std::string& line, unsigned int& layer1, unsigned int& n, unsigned int& layer2, double& weight); + + static double calculateJensenShannonDivergence(bool& intersect, const OutLinkMap& layer1OutLinks, double sumOutLinkWeightLayer1, const OutLinkMap& layer2OutLinks, double sumOutLinkWeightLayer2); + + void printSummary(); +}; + +struct LayerNode { + unsigned int layer, node; + explicit LayerNode(unsigned int layer = 0, unsigned int node = 0) : layer(layer), node(node) { } + + bool operator<(const LayerNode other) const + { + return layer == other.layer ? node < other.node : layer < other.layer; + } +}; + +} // namespace infomap + +#endif // NETWORK_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/io/Output.cpp b/src/vendor/cigraph/vendor/infomap/src/io/Output.cpp new file mode 100644 index 00000000000..79f116ccbb0 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/Output.cpp @@ -0,0 +1,629 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "Output.h" +#include "../core/InfomapBase.h" +#include "../core/StateNetwork.h" +#include "../io/SafeFile.h" + +namespace infomap { + +std::string getOutputFilename(const InfomapBase& im, const std::string& filename, const std::string& ext, bool states) +{ + if (!filename.empty()) { + return filename; + } + + auto defaultFilename = im.outDirectory + im.outName; + + if (im.haveMemory() && states) { + defaultFilename += "_states"; + } + + return defaultFilename + ext; +} + +std::string getOutputFileHeader(const InfomapBase& im, const StateNetwork& network, bool states) +{ + std::string bipartiteInfo = io::Str() << "\n# bipartite start id " << network.bipartiteStartId(); + return io::Str() << "# v" << INFOMAP_VERSION << "\n" + << "# ./Infomap " << im.parsedString << "\n" + << "# started at " << im.getStartDate() << "\n" + << "# completed in " << im.getElapsedTime().getElapsedTimeInSec() << " s\n" + << "# partitioned into " << im.maxTreeDepth() << " levels with " << im.numTopModules() << " top modules\n" + << "# codelength " << im.codelength() << " bits\n" + << "# relative codelength savings " << im.getRelativeCodelengthSavings() * 100 << "%\n" + << "# flow model " << flowModelToString(im.flowModel) + << (im.haveMemory() ? "\n# higher order" : "") + << (im.haveMemory() ? states ? "\n# state level" : "\n# physical level" : "") + << (network.isBipartite() ? bipartiteInfo : ""); +} + +std::string getNodeName(const std::map& names, const InfoNode& node) +{ + try { + return names.at(node.physicalId); + } catch (...) { + return io::stringify(node.physicalId); + } +} + +std::string writeClu(InfomapBase& im, const StateNetwork& network, const std::string& filename, bool states, int moduleIndexLevel) +{ + auto outputFilename = getOutputFilename(im, filename, ".clu", states); + SafeOutFile outFile { outputFilename }; + + outFile << std::setprecision(9); + outFile << getOutputFileHeader(im, network, states) << "\n"; + outFile << "# module level " << moduleIndexLevel << "\n"; + outFile << std::resetiosflags(std::ios::floatfield) << std::setprecision(6); + + if (states) { + outFile << "# state_id module flow node_id"; + if (im.isMultilayerNetwork()) + outFile << " layer_id"; + outFile << '\n'; + } else { + outFile << "# node_id module flow\n"; + } + + const auto shouldHideBipartiteNodes = im.isBipartite() && im.hideBipartiteNodes; + const auto bipartiteStartId = shouldHideBipartiteNodes ? network.bipartiteStartId() : 0; + + if (im.haveMemory() && !states) { + for (auto it(im.iterTreePhysical(moduleIndexLevel)); !it.isEnd(); ++it) { + InfoNode& node = *it; + if (node.isLeaf()) { + if (shouldHideBipartiteNodes && node.physicalId >= bipartiteStartId) { + continue; + } + + outFile << node.physicalId << " " << it.moduleId() << " " << node.data.flow << "\n"; + } + } + } else { + for (auto it(im.iterTree(moduleIndexLevel)); !it.isEnd(); ++it) { + InfoNode& node = *it; + if (node.isLeaf()) { + if (shouldHideBipartiteNodes && node.physicalId >= bipartiteStartId) { + continue; + } + + if (states) { + outFile << node.stateId << " " << it.moduleId() << " " << node.data.flow << " " << node.physicalId; + if (im.isMultilayerNetwork()) + outFile << " " << node.layerId; + outFile << "\n"; + } else + outFile << node.physicalId << " " << it.moduleId() << " " << node.data.flow << "\n"; + } + } + } + return outputFilename; +} + +void writeTree(InfomapBase& im, const StateNetwork& network, std::ostream& outStream, bool states) +{ + auto oldPrecision = outStream.precision(); + outStream << std::setprecision(9); + outStream << getOutputFileHeader(im, network, states) << "\n"; + outStream << std::setprecision(6); + + if (states) { + outStream << "# path flow name state_id node_id"; + if (im.isMultilayerNetwork()) + outStream << " layer_id"; + outStream << '\n'; + } else { + outStream << "# path flow name node_id\n"; + } + + const auto shouldHideBipartiteNodes = !im.printFlowTree && im.isBipartite() && im.hideBipartiteNodes; + const auto bipartiteStartId = shouldHideBipartiteNodes ? network.bipartiteStartId() : 0; + + // TODO: Make a general iterator where merging physical nodes depend on a parameter rather than type to be able to DRY here + if (im.haveMemory() && !states) { + for (auto it(im.iterTreePhysical()); !it.isEnd(); ++it) { + InfoNode& node = *it; + if (node.isLeaf()) { + if (shouldHideBipartiteNodes && node.physicalId >= bipartiteStartId) { + continue; + } + + auto& path = it.path(); + + outStream << io::stringify(path, ":") << " " << node.data.flow << " \"" << getNodeName(network.names(), node) << "\" " << node.physicalId << '\n'; + } + } + } else { + for (auto it(im.iterTree()); !it.isEnd(); ++it) { + InfoNode& node = *it; + if (node.isLeaf()) { + if (shouldHideBipartiteNodes && node.physicalId >= bipartiteStartId) { + continue; + } + + auto& path = it.path(); + + outStream << io::stringify(path, ":") << " " << node.data.flow << " \"" << getNodeName(network.names(), node) << "\" "; + + if (states) { + outStream << node.stateId << " " << node.physicalId; + if (im.isMultilayerNetwork()) + outStream << " " << node.layerId; + outStream << '\n'; + } else { + outStream << node.physicalId << '\n'; + } + } + } + } + + outStream << std::setprecision(oldPrecision); +} + +using Link = std::pair; +using LinkMap = std::map; + +std::map aggregateModuleLinks(InfomapBase& im, bool states) +{ + // Aggregate links between each module. Rest is aggregated as exit flow + + // Links on nodes within sub infomap instances doesn't have links outside the root + // so iterate over links on main instance and map to infomap tree iterator + bool mergePhysicalNodes = im.haveMemory() && !states; + + // Map state id to parent in infomap tree iterator + std::map stateIdToParent; + std::map stateIdToChildIndex; + + if (mergePhysicalNodes) { + for (auto it(im.iterTreePhysical()); !it.isEnd(); ++it) { + if (it->isLeaf()) { + for (auto stateId : it->stateNodes) { + stateIdToParent[stateId] = it->parent; + stateIdToChildIndex[stateId] = it.childIndex(); + } + } else { + // Use stateId to store depth on modules to simplify link aggregation + it->stateId = it.depth(); + it->index = it.childIndex(); + } + } + } else { + for (auto it(im.iterTree()); !it.isEnd(); ++it) { + if (it->isLeaf()) { + stateIdToParent[it->stateId] = it->parent; + stateIdToChildIndex[it->stateId] = it.childIndex(); + } else { + // Use stateId to store depth on modules to simplify link aggregation + it->stateId = it.depth(); + it->index = it.childIndex(); + } + } + } + + std::map moduleLinks; + + for (auto& leaf : im.leafNodes()) { + for (auto& link : leaf->outEdges()) { + double flow = link->data.flow; + InfoNode* sourceParent = stateIdToParent[link->source->stateId]; + InfoNode* targetParent = stateIdToParent[link->target->stateId]; + + auto sourceDepth = sourceParent->calculatePath().size() + 1; + auto targetDepth = targetParent->calculatePath().size() + 1; + + auto sourceChildIndex = stateIdToChildIndex[link->source->stateId]; + auto targetChildIndex = stateIdToChildIndex[link->target->stateId]; + + auto sourceParentIt = InfomapParentIterator(sourceParent); + auto targetParentIt = InfomapParentIterator(targetParent); + + // Iterate to same depth + // First raise target + while (targetDepth > sourceDepth) { + ++targetParentIt; + --targetDepth; + } + + // Raise source to same depth + while (sourceDepth > targetDepth) { + ++sourceParentIt; + --sourceDepth; + } + + auto currentDepth = sourceDepth; + // Add link if same parent + + while (currentDepth > 0) { + if (sourceParentIt == targetParentIt) { + // Skip self-links + if (sourceChildIndex != targetChildIndex) { + auto parentId = io::stringify(sourceParentIt->calculatePath(), ":"); + auto& linkMap = moduleLinks[parentId]; + linkMap[std::make_pair(sourceChildIndex + 1, targetChildIndex + 1)] += flow; + } + } + + sourceChildIndex = sourceParentIt->index; + targetChildIndex = targetParentIt->index; + + ++sourceParentIt; + ++targetParentIt; + + --currentDepth; + } + } + } + + return moduleLinks; +} + +void writeTreeLinks(InfomapBase& im, std::ostream& outStream, bool states) +{ + auto oldPrecision = outStream.precision(); + outStream << std::setprecision(6); + + auto moduleLinks = aggregateModuleLinks(im, states); + + outStream << "*Links " << (im.isUndirectedFlow() ? "undirected" : "directed") << "\n"; + outStream << "#*Links path enterFlow exitFlow numEdges numChildren\n"; + + // Use stateId to store depth on modules to optimize link aggregation + for (auto it(im.iterModules()); !it.isEnd(); ++it) { + auto parentId = io::stringify(it.path(), ":"); + auto& module = *it; + auto& links = moduleLinks[parentId]; + + outStream << "*Links " << (parentId.empty() ? "root" : parentId) << " " << module.data.enterFlow << " " << module.data.exitFlow << " " << links.size() << " " << module.infomapChildDegree() << "\n"; + + for (auto itLink : links) { + unsigned int sourceId = itLink.first.first; + unsigned int targetId = itLink.first.second; + double flow = itLink.second; + outStream << sourceId << " " << targetId << " " << flow << "\n"; + } + } + + outStream << std::setprecision(oldPrecision); +} + +void writeNewickTree(InfomapBase& im, std::ostream& outStream, bool states) +{ + auto oldPrecision = outStream.precision(); + outStream << std::setprecision(6); + + auto isRoot = true; + unsigned int lastDepth = 0; + std::vector flowStack; + + auto writeNewickNode = [&](const InfoNode& node, unsigned int depth) { + if (depth > lastDepth || isRoot) { + outStream << "("; + flowStack.push_back(node.data.flow); + if (node.isLeaf()) + outStream << (states ? node.stateId : node.physicalId) << ":" << node.data.flow; + } else if (depth == lastDepth) { + outStream << ","; + flowStack[flowStack.size() - 1] = node.data.flow; + if (node.isLeaf()) { + outStream << (states ? node.stateId : node.physicalId) << ":" << node.data.flow; + } + } else { + // depth < lastDepth + while (flowStack.size() > depth + 1) { + flowStack.pop_back(); + outStream << "):" << flowStack.back(); + } + flowStack[flowStack.size() - 1] = node.data.flow; + outStream << ","; + } + lastDepth = depth; + isRoot = false; + }; + + // TODO: Make a general iterator where merging physical nodes depend on a parameter rather than type to be able to DRY here + if (im.haveMemory() && !states) { + for (auto it(im.iterTreePhysical()); !it.isEnd(); ++it) { + writeNewickNode(*it, it.depth()); + } + } else { + for (auto it(im.iterTree()); !it.isEnd(); ++it) { + writeNewickNode(*it, it.depth()); + } + } + while (flowStack.size() > 1) { + flowStack.pop_back(); + outStream << "):" << flowStack.back(); + } + outStream << ");\n"; + outStream << std::setprecision(oldPrecision); +} + +void writeJsonTree(InfomapBase& im, const StateNetwork& network, std::ostream& outStream, bool states, bool writeLinks) +{ + auto oldPrecision = outStream.precision(); + + outStream << "{"; + + outStream << "\"version\":\"v" << INFOMAP_VERSION << "\"," + << "\"args\":\"" << im.parsedString << "\"," + << "\"startedAt\":\"" << im.getStartDate() << "\"," + << "\"completedIn\":" << im.getElapsedTime().getElapsedTimeInSec() << "," + << "\"codelength\":" << im.codelength() << "," + << "\"numLevels\":" << im.maxTreeDepth() << "," + << "\"numTopModules\":" << im.numTopModules() << "," + << "\"relativeCodelengthSavings\":" << im.getRelativeCodelengthSavings() << "," + << "\"directed\":" << (im.isUndirectedFlow() ? "false" : "true") << "," + << "\"flowModel\": \"" << flowModelToString(im.flowModel) << "\"," + << "\"higherOrder\":" << (im.haveMemory() ? "true" : "false") << ","; + + if (im.haveMemory()) { + outStream << "\"stateLevel\":" << (states ? "true" : "false") << ","; + } + + if (im.isBipartite()) { + outStream << "\"bipartiteStartId\":" << network.bipartiteStartId() << ","; + } + + outStream << std::setprecision(6); + + outStream << "\"nodes\":["; + + const auto shouldHideBipartiteNodes = im.isBipartite() && im.hideBipartiteNodes; + const auto bipartiteStartId = shouldHideBipartiteNodes ? network.bipartiteStartId() : 0; + + auto metaData = network.metaData(); + auto writeMeta = [&metaData](auto& outStream, auto nodeId) { + outStream << "\"metadata\":{"; + auto meta = metaData[nodeId]; + for (unsigned int i = 0; i < meta.size(); ++i) { + outStream << '"' << i << "\":" + << '"' << meta[i] << '"'; // metadata class as string to highlight that this is a categorical variable + if (i < meta.size() - 1) + outStream << ','; + } + outStream << "},"; + }; + + // don't append a comma after the last entry + auto first = true; + + if (im.haveMemory() && !states) { + for (auto it(im.iterTreePhysical()); !it.isEnd(); ++it) { + InfoNode& node = *it; + if (node.isLeaf()) { + if (shouldHideBipartiteNodes && node.physicalId >= bipartiteStartId) { + continue; + } + + const auto path = io::stringify(it.path(), ","); + + if (first) { + first = false; + } else { + outStream << ","; + } + + outStream << "{" + << "\"path\":[" << path << "]," + << "\"name\":\"" << getNodeName(network.names(), node) << "\"," + << "\"flow\":" << node.data.flow << "," + << "\"mec\":" << it.modularCentrality() << "," + << "\"id\":" << node.physicalId << "}"; + } + } + } else { + const auto multilevelModules = im.getMultilevelModules(states); + + for (auto it(im.iterTree()); !it.isEnd(); ++it) { + InfoNode& node = *it; + if (node.isLeaf()) { + if (shouldHideBipartiteNodes && node.physicalId >= bipartiteStartId) { + continue; + } + + if (first) { + first = false; + } else { + outStream << ","; + } + + const auto path = io::stringify(it.path(), ", "); + const auto modules = im.haveModules() ? io::stringify(multilevelModules.at(states ? node.stateId : node.physicalId), ", ") : "1"; + + outStream << "{" + << "\"path\":[" << path << "]," + << "\"modules\":[" << modules << "]," + << "\"name\":\"" << getNodeName(network.names(), node) << "\"," + << "\"flow\":" << node.data.flow << "," + << "\"mec\":" << it.modularCentrality() << ","; + + // can't currently use both memory and meta map equation + if (im.haveMetaData() && !states) { + writeMeta(outStream, node.physicalId); + } + + if (states) { + outStream << "\"stateId\":" << node.stateId << ","; + if (im.isMultilayerNetwork()) + outStream << "\"layerId\":" << node.layerId << ","; + } + + outStream << "\"id\":" << node.physicalId << "}"; + } + } + } + + outStream << "],"; // tree + + // ------------- + // Write modules + // ------------- + + // Uses stateId to store depth on modules to optimize link aggregation + auto moduleLinks = aggregateModuleLinks(im, states); + + first = true; + + outStream << "\"modules\":["; + + for (auto it(im.iterModules()); !it.isEnd(); ++it) { + const auto parentId = io::stringify(it.path(), ":"); + const auto& module = *it; + const auto& links = moduleLinks[parentId]; + const auto path = io::stringify(it.path(), ","); + + if (first) { + first = false; + } else { + outStream << ","; + } + + outStream << "{"; + + outStream << "\"path\":[" << (parentId.empty() ? "0" : path) << "]," + << "\"enterFlow\":" << module.data.enterFlow << ',' + << "\"exitFlow\":" << module.data.exitFlow << ',' + << "\"numEdges\":" << links.size() << ',' + << "\"numChildren\":" << module.infomapChildDegree() << ',' + << "\"codelength\":" << module.codelength; + + if (writeLinks) { + outStream << "," + << "\"links\":["; + + auto firstLink = true; + + for (auto itLink : links) { + if (firstLink) { + firstLink = false; + } else { + outStream << ","; + } + + unsigned int sourceId = itLink.first.first; + unsigned int targetId = itLink.first.second; + double flow = itLink.second; + outStream << "{\"source\":" << sourceId << ",\"target\":" << targetId << ",\"flow\":" << flow << "}"; + } + outStream << "]"; // links + } + + outStream << "}"; + } + + outStream << "]"; // modules + + outStream << "}"; + + outStream << std::setprecision(oldPrecision); +} + +void writeCsvTree(InfomapBase& im, const StateNetwork& network, std::ostream& outStream, bool states) +{ + auto oldPrecision = outStream.precision(); + outStream << std::setprecision(6); + + outStream << "path,flow,name,"; + + if (im.haveMemory() && !states) { + outStream << "node_id\n"; + } else { + if (states) { + outStream << "state_id,"; + if (im.isMultilayerNetwork()) + outStream << "layer_id,"; + } + outStream << "node_id\n"; + } + + const auto shouldHideBipartiteNodes = im.isBipartite() && im.hideBipartiteNodes; + const auto bipartiteStartId = shouldHideBipartiteNodes ? network.bipartiteStartId() : 0; + + if (im.haveMemory() && !states) { + for (auto it(im.iterTreePhysical()); !it.isEnd(); ++it) { + InfoNode& node = *it; + if (node.isLeaf()) { + if (shouldHideBipartiteNodes && node.physicalId >= bipartiteStartId) { + continue; + } + + const auto path = io::stringify(it.path(), ":"); + outStream << path << ',' << node.data.flow << ",\"" << getNodeName(network.names(), node) << "\"," << node.physicalId << '\n'; + } + } + } else { + for (auto it(im.iterTree()); !it.isEnd(); ++it) { + InfoNode& node = *it; + if (node.isLeaf()) { + if (shouldHideBipartiteNodes && node.physicalId >= bipartiteStartId) { + continue; + } + + const auto path = io::stringify(it.path(), ":"); + outStream << path << ',' << node.data.flow << ",\"" << getNodeName(network.names(), node) << "\","; + + if (states) { + outStream << node.stateId << ','; + if (im.isMultilayerNetwork()) + outStream << node.layerId << ','; + } + + outStream << node.physicalId << '\n'; + } + } + } + + outStream << std::setprecision(oldPrecision); +} + +std::string writeTree(InfomapBase& im, const StateNetwork& network, const std::string& filename, bool states) +{ + auto outputFilename = getOutputFilename(im, filename, ".tree", states); + SafeOutFile outFile { outputFilename }; + writeTree(im, network, outFile, states); + return outputFilename; +} + +std::string writeFlowTree(InfomapBase& im, const StateNetwork& network, const std::string& filename, bool states) +{ + auto outputFilename = getOutputFilename(im, filename, ".ftree", states); + SafeOutFile outFile { outputFilename }; + writeTree(im, network, outFile, states); + writeTreeLinks(im, outFile, states); + return outputFilename; +} + +std::string writeNewickTree(InfomapBase& im, const std::string& filename, bool states) +{ + auto outputFilename = getOutputFilename(im, filename, ".nwk", states); + SafeOutFile outFile { outputFilename }; + writeNewickTree(im, outFile, states); + return outputFilename; +} + +std::string writeJsonTree(InfomapBase& im, const StateNetwork& network, const std::string& filename, bool states, bool writeLinks) +{ + auto outputFilename = getOutputFilename(im, filename, ".json", states); + SafeOutFile outFile { outputFilename }; + writeJsonTree(im, network, outFile, states, writeLinks); + return outputFilename; +} + +std::string writeCsvTree(InfomapBase& im, const StateNetwork& network, const std::string& filename, bool states) +{ + auto outputFilename = getOutputFilename(im, filename, ".csv", states); + SafeOutFile outFile { outputFilename }; + writeCsvTree(im, network, outFile, states); + return outputFilename; +} + +} // namespace infomap \ No newline at end of file diff --git a/src/vendor/cigraph/vendor/infomap/src/io/Output.h b/src/vendor/cigraph/vendor/infomap/src/io/Output.h new file mode 100644 index 00000000000..2b649835d93 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/Output.h @@ -0,0 +1,36 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef OUTPUT_H_ +#define OUTPUT_H_ + +#include +#include +#include + +namespace infomap { + +class InfomapBase; +class StateNetwork; + +std::string writeTree(InfomapBase&, const StateNetwork&, const std::string&, bool states); + +std::string writeFlowTree(InfomapBase&, const StateNetwork&, const std::string&, bool states); + +std::string writeNewickTree(InfomapBase&, const std::string&, bool states); + +std::string writeJsonTree(InfomapBase&, const StateNetwork&, const std::string&, bool states, bool writeLinks); + +std::string writeCsvTree(InfomapBase&, const StateNetwork&, const std::string&, bool states); + +std::string writeClu(InfomapBase&, const StateNetwork&, const std::string&, bool states, int moduleIndexLevel); + +} // namespace infomap + +#endif // OUTPUT_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/io/ProgramInterface.cpp b/src/vendor/cigraph/vendor/infomap/src/io/ProgramInterface.cpp new file mode 100644 index 00000000000..54d06248afc --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/ProgramInterface.cpp @@ -0,0 +1,362 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "ProgramInterface.h" +#include "../utils/Log.h" + +#include "igraph_error.h" + +#include +#include +#include +#include + +namespace infomap { + +const std::string ArgType::integer = "integer"; +const std::string ArgType::number = "number"; +const std::string ArgType::string = "string"; +const std::string ArgType::path = "path"; +const std::string ArgType::probability = "probability"; +const std::string ArgType::option = "option"; +const std::string ArgType::list = "list"; + +const std::unordered_map ArgType::toShort = { + { "integer", 'n' }, + { "number", 'f' }, + { "string", 's' }, + { "path", 'p' }, + { "probability", 'P' }, + { "option", 'o' }, + { "list", 'l' }, +}; + +ProgramInterface::ProgramInterface(std::string name, std::string shortDescription, std::string version) + : m_programName(std::move(name)), + m_shortProgramDescription(std::move(shortDescription)), + m_programVersion(std::move(version)) +{ + addIncrementalOptionArgument(m_displayHelp, 'h', "help", "Prints this help message. Use -hh to show advanced options.", "About"); + addOptionArgument(m_displayVersion, 'V', "version", "Display program version information.", "About"); + addOptionArgument(m_printJsonParameters, "print-json-parameters", "Print Infomap parameters in JSON.", "About").setHidden(true); +} + +/* Modification for igraph: Disable functions that call forbidden + * functions such as exit(). */ +#if 0 +void ProgramInterface::exitWithUsage(bool showAdvanced) const +{ + Log() << "Name:\n"; + Log() << " " << m_programName << " - " << m_shortProgramDescription << '\n'; + Log() << "\nUsage:\n"; + Log() << " " << m_executableName; + for (auto& nonOptionArgument : m_nonOptionArguments) + if (showAdvanced || !nonOptionArgument->isAdvanced) + Log() << " " << nonOptionArgument->variableName; + if (!m_optionArguments.empty()) + Log() << " [options]"; + Log() << '\n'; + + if (!m_programDescription.empty()) + Log() << "\nDescription:\n " << m_programDescription << '\n'; + + for (auto& nonOptionArgument : m_nonOptionArguments) + if (showAdvanced || !nonOptionArgument->isAdvanced) + Log() << "\n[" << nonOptionArgument->variableName << "]\n " << nonOptionArgument->description << '\n'; + + if (!m_optionArguments.empty()) + Log() << "\n[options]\n"; + + // First stringify the options part to get the maximum length + std::deque optionStrings(m_optionArguments.size()); + std::string::size_type maxLength = 0; + for (unsigned int i = 0; i < m_optionArguments.size(); ++i) { + auto& opt = *m_optionArguments[i]; + bool haveShort = opt.shortName != '\0'; + std::string optArgShort = opt.requireArgument ? (io::Str() << "<" << ArgType::toShort.at(opt.argumentName) << ">") : opt.incrementalArgument ? "[+]" + : std::string(3, ' '); + std::string optArgLong = opt.requireArgument ? (io::Str() << "<" << opt.argumentName << ">") : opt.incrementalArgument ? "[+]" + : std::string(3, ' '); + std::string shortOption = haveShort ? (io::Str() << " -" << opt.shortName << optArgShort) : std::string(7, ' '); + optionStrings[i] = io::Str() << shortOption << " --" << opt.longName << " " << optArgLong; + if (optionStrings[i].length() > maxLength) + maxLength = optionStrings[i].length(); + } + + std::vector groups { "About" }; + for (auto& group : m_groups) { + if (group != "About") + groups.push_back(group); + } + if (m_groups.empty()) + groups.emplace_back("All"); + + for (const auto& group : groups) { + if (group != "All") { + Log() << "\n" + << group << "\n"; + Log() << std::string(group.length(), '-') << "\n"; + } + for (unsigned int i = 0; i < m_optionArguments.size(); ++i) { + auto& opt = *m_optionArguments[i]; + if (group == "All" || opt.group == group) { + std::string::size_type numSpaces = maxLength + 3 - optionStrings[i].length(); + if (showAdvanced || !opt.isAdvanced) { + Log() << optionStrings[i] << std::string(numSpaces, ' ') << opt.description; + if (!opt.printNumericValue().empty()) + Log() << " (Default: " << opt.printNumericValue() << ")"; + Log() << "\n"; + } + } + } + } + Log() << '\n'; + std::exit(0); +} + +void ProgramInterface::exitWithVersionInformation() const +{ + Log() << m_programName << " version " << m_programVersion; +#ifdef _OPENMP + Log() << " compiled with OpenMP"; +#endif + Log() << '\n'; + Log() << "See www.mapequation.org for terms of use.\n"; + std::exit(0); +} +#endif + +void ProgramInterface::exitWithError(const std::string& message) const +{ + /* Modification for igraph: This function must never be called + * when using Infomap through igraph. The function is disabled + * to eliminate forbidden references to exit() and std::cerr. */ + IGRAPH_FATALF("Infomap called exitWithError() with message '%s'.", + message.c_str()); +#if 0 + Log() << m_programName << " version " << m_programVersion; +#ifdef _OPENMP + Log() << " compiled with OpenMP"; +#endif + Log() << std::endl; + std::cerr << message << std::endl; + Log() << "Usage: " << m_executableName; + for (auto& nonOptionArgument : m_nonOptionArguments) + if (!nonOptionArgument->isAdvanced) + Log() << " " << nonOptionArgument->variableName; + if (!m_optionArguments.empty()) + Log() << " [options]"; + Log() << ". Run with option '-h' for more information.\n"; + std::exit(1); +#endif +} + +std::string toJson(const std::string& key, const std::string& value) +{ + return io::Str() << '"' << key << "\": \"" << value << '"'; +} + +std::string toJson(const std::string& key, bool value) +{ + return io::Str() << '"' << key << "\": " << (value ? "true" : "false"); +} + +template +std::string toJson(const std::string& key, Value value) +{ + return io::Str() << '"' << key << "\": " << value; +} + +std::string toJson(const Option& opt) +{ + return io::Str() << "{ " + << toJson("long", std::string(io::Str() << "--" << opt.longName)) << ", " + << toJson("short", opt.shortName != '\0' ? std::string(io::Str() << "-" << opt.shortName) : "") << ", " + << toJson("description", opt.description) << ", " + << toJson("group", opt.group) << ", " + << toJson("required", opt.requireArgument) << ", " + << toJson("advanced", opt.isAdvanced) << ", " + << toJson("incremental", opt.incrementalArgument) << ", " + << (opt.requireArgument + ? (io::Str() << toJson("longType", opt.argumentName) << ", " + << toJson("shortType", std::string(1, ArgType::toShort.at(opt.argumentName))) << ", " + << toJson("default", opt.printValue())) + : toJson("default", false)) + << " }"; +} + +/* Modification for igraph: Disable functions that call forbidden + * functions such as exit(). */ +#if 0 +void ProgramInterface::exitWithJsonParameters() const +{ + Log() << "{\n \"parameters\": [\n"; + + for (unsigned int i = 0; i < m_optionArguments.size(); ++i) { + auto& opt = *m_optionArguments[i]; + if (opt.hidden) + continue; + Log() << " " << toJson(opt); + if (i < m_optionArguments.size() - 1) { + Log() << ",\n"; + } else { + Log() << "\n"; + } + } + Log() << " ]\n}"; + + std::exit(0); +} +#endif + +void ProgramInterface::parseArgs(const std::string& args) +{ + // Map the options on short and long name, and check for duplication + std::map shortOptionMap; + std::map longOptionMap; + for (auto& optionArgument : m_optionArguments) { + auto& opt = *optionArgument; + if (opt.shortName != '\0') { + auto it = shortOptionMap.find(opt.shortName); + if (it != shortOptionMap.end()) + throw std::runtime_error(io::Str() << "Duplication of option '" << opt.shortName << "'"); + shortOptionMap.insert(std::make_pair(opt.shortName, &opt)); + } + + auto it = longOptionMap.find(opt.longName); + if (it != longOptionMap.end()) + throw std::runtime_error(io::Str() << "Duplication of option \"" << opt.longName << "\""); + longOptionMap.insert(std::make_pair(opt.longName, &opt)); + } + + // Split the flags on whitespace + std::vector flags; + std::istringstream argStream(args); + + { + std::string arg; + while (!(argStream >> arg).fail()) + flags.push_back(arg); + } + + std::deque nonOpts; + try { + for (unsigned int i = 0; i < flags.size(); ++i) { + bool flagValue = true; + unsigned int numArgsLeft = flags.size() - i - 1; + + const std::string& arg = flags[i]; + if (arg.length() == 0) + throw std::runtime_error("Illegal argument ''"); + + if (arg[0] != '-') { + nonOpts.push_back(arg); + } else { + if (arg.length() < 2) + throw std::runtime_error("Illegal argument '-'"); + + if (arg[1] == '-') { + // Long option + if (arg.length() < 3) + throw std::runtime_error("Illegal argument '--'"); + std::string longOpt = arg.substr(2); + auto it = longOptionMap.find(longOpt); + if (it == longOptionMap.end()) { + // Unrecognized option, check if it negates a recognised option with the '--no-' prefix + if (longOpt.compare(0, 3, "no-") == 0 && longOptionMap.find(std::string(longOpt, 3)) != longOptionMap.end()) { + longOpt = std::string(longOpt, 3); + it = longOptionMap.find(longOpt); + flagValue = false; + } else { + throw std::runtime_error(io::Str() << "Unrecognized option: '--" << longOpt << "'"); + } + } + auto& opt = *it->second; + if (!opt.requireArgument || opt.incrementalArgument) + opt.set(flagValue); + else { + if (numArgsLeft == 0) + throw std::runtime_error(io::Str() << "Option '" << opt.longName << "' requires argument"); + ++i; + if (!opt.parse(flags[i])) + throw std::runtime_error(io::Str() << "Cannot parse '" << flags[i] << "' as argument to option '" << opt.longName << "'. "); + } + } else { + // Short option(s) + for (unsigned int j = 1; j < arg.length(); ++j) { + char o = arg[j]; + unsigned int numCharsLeft = arg.length() - j - 1; + auto it = shortOptionMap.find(o); + if (it == shortOptionMap.end()) + throw std::runtime_error(io::Str() << "Unrecognized option: '-" << o << "'"); + auto& opt = *it->second; + if (!opt.requireArgument || opt.incrementalArgument) + opt.set(flagValue); + else { + std::string optArg; + if (numCharsLeft > 0) { + optArg = arg.substr(j + 1); + j = arg.length() - 1; + } else if (numArgsLeft) { + ++i; + optArg = flags[i]; + } else + throw std::runtime_error(io::Str() << "Option '" << opt.longName << "' requires argument"); + + if (!opt.parse(optArg)) + throw std::runtime_error(io::Str() << "Cannot parse '" << optArg << "' as argument to option '" << opt.longName << "'. "); + } + } + } + } + /* Modification for igraph: Disable calls to functions that + * needed to be removed because they referenced exit(). */ +#if 0 + if (m_displayHelp > 0) + exitWithUsage(m_displayHelp > 1); + if (m_displayVersion) + exitWithVersionInformation(); + if (m_printJsonParameters) + exitWithJsonParameters(); +#endif + } + } catch (std::exception& e) { + exitWithError(e.what()); + } + + if (nonOpts.size() < numRequiredArguments()) + exitWithError("Missing required arguments."); + + unsigned int i = 0; + unsigned int numVectorArguments = nonOpts.size() - (m_nonOptionArguments.size() - 1); + while (!nonOpts.empty()) { + std::string arg = nonOpts.front(); + nonOpts.pop_front(); + if (m_nonOptionArguments[i]->isOptionalVector && numVectorArguments == 0) + ++i; + if (!m_nonOptionArguments[i]->parse(arg)) + exitWithError("Argument error."); + if (!m_nonOptionArguments[i]->isOptionalVector || --numVectorArguments == 0) + ++i; + } +} + +std::vector ProgramInterface::getUsedOptionArguments() const +{ + std::vector opts; + unsigned int numFlags = m_optionArguments.size(); + for (unsigned int i = 0; i < numFlags; ++i) { + auto& opt = *m_optionArguments[i]; + if (opt.used && opt.longName != "negate-next") + opts.emplace_back(opt); + } + return opts; +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/io/ProgramInterface.h b/src/vendor/cigraph/vendor/infomap/src/io/ProgramInterface.h new file mode 100644 index 00000000000..21841cbd9e3 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/ProgramInterface.h @@ -0,0 +1,423 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef PROGRAM_INTERFACE_H_ +#define PROGRAM_INTERFACE_H_ + +#include "../utils/convert.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace infomap { + +class InterruptException : public std::exception { +public: + InterruptException() {}; +}; + +typedef bool interruptionHandlerFn(void); + +struct ArgType { + static const std::string integer; + static const std::string number; + static const std::string string; + static const std::string path; + static const std::string probability; + static const std::string option; + static const std::string list; + static const std::unordered_map toShort; +}; + +struct Option { + Option(char shortName, std::string longName, std::string desc, std::string group, bool isAdvanced, bool requireArgument = false, std::string argName = "") + : shortName(shortName), + longName(std::move(longName)), + description(std::move(desc)), + group(std::move(group)), + isAdvanced(isAdvanced), + requireArgument(requireArgument), + incrementalArgument(false), + argumentName(std::move(argName)) { } + + virtual ~Option() = default; + + Option(const Option&) = default; + Option& operator=(const Option&) = default; + Option(Option&&) = default; + Option& operator=(Option&&) = default; + + virtual bool parse(std::string const&) + { + used = true; + return true; + } + + virtual void set(bool value) + { + used = true; + negated = !value; + }; + + Option& setHidden(bool value) + { + hidden = value; + return *this; + } + + virtual std::ostream& printValue(std::ostream& out) const { return out; } + virtual std::string printValue() const { return ""; } + virtual std::string printNumericValue() const { return ""; } + + friend std::ostream& operator<<(std::ostream& out, const Option& option) + { + out << option.longName; + if (option.requireArgument) { + out << " = "; + option.printValue(out); + } + return out; + } + + char shortName; + std::string longName; + std::string description; + std::string group; + bool isAdvanced; + bool requireArgument; + bool incrementalArgument; + std::string argumentName; + bool hidden = false; + bool used = false; + bool negated = false; +}; + +struct IncrementalOption : Option { + IncrementalOption(unsigned int& target, char shortName, std::string longName, std::string desc, std::string group, bool isAdvanced) + : Option(shortName, std::move(longName), std::move(desc), std::move(group), isAdvanced, false), target(target) + { + incrementalArgument = true; + } + + bool parse(std::string const& value) override + { + Option::parse(value); + return ++target; + } + + void set(bool value) override + { + Option::set(value); + if (value) { + ++target; + } else if (target > 0) { + --target; + } + } + + std::ostream& printValue(std::ostream& out) const override { return out << target; } + std::string printValue() const override { return io::Str() << target; } + + unsigned int& target; +}; + +template +struct ArgumentOption : Option { + ArgumentOption(T& target, char shortName, std::string longName, std::string desc, std::string group, bool isAdvanced, std::string argName) + : Option(shortName, std::move(longName), std::move(desc), std::move(group), isAdvanced, true, std::move(argName)), target(target) { } + + bool parse(std::string const& value) override + { + Option::parse(value); + return io::stringToValue(value, target); + } + + std::string printValue() const override { return io::Str() << target; } + std::ostream& printValue(std::ostream& out) const override { return out << target; } + std::string printNumericValue() const override { return TypeInfo::isNumeric() ? printValue() : ""; } + + T& target; +}; + +template +struct LowerBoundArgumentOption : ArgumentOption { + LowerBoundArgumentOption(T& target, char shortName, std::string longName, std::string desc, std::string group, bool isAdvanced, std::string argName, T minValue) + : ArgumentOption(target, shortName, std::move(longName), std::move(desc), std::move(group), isAdvanced, std::move(argName)), minValue(minValue) { } + + bool parse(std::string const& value) override + { + auto ok = ArgumentOption::parse(value); + if (ArgumentOption::target < minValue) return false; + return ok; + } + + T minValue; +}; + +template +struct LowerUpperBoundArgumentOption : LowerBoundArgumentOption { + LowerUpperBoundArgumentOption(T& target, char shortName, std::string longName, std::string desc, std::string group, bool isAdvanced, std::string argName, T minValue, T maxValue) + : LowerBoundArgumentOption(target, shortName, std::move(longName), std::move(desc), std::move(group), isAdvanced, std::move(argName), minValue), maxValue(maxValue) { } + + bool parse(std::string const& value) override + { + auto ok = LowerBoundArgumentOption::parse(value); + if (LowerBoundArgumentOption::target > maxValue) return false; + return ok; + } + + T maxValue; +}; + +template <> +struct ArgumentOption : Option { + ArgumentOption(bool& target, char shortName, std::string longName, std::string desc, std::string group, bool isAdvanced) + : Option(shortName, std::move(longName), std::move(desc), std::move(group), isAdvanced, false), target(target) { } + + bool parse(std::string const& value) override + { + Option::parse(value); + return target = true; + } + + void set(bool value) override + { + Option::set(value); + target = value; + } + + std::ostream& printValue(std::ostream& out) const override { return out << target; } + std::string printValue() const override { return io::Str() << target; } + std::string printNumericValue() const override { return ""; } + + bool& target; +}; + +struct ParsedOption { + explicit ParsedOption(const Option& opt) + : shortName(opt.shortName), + longName(opt.longName), + description(opt.description), + group(opt.group), + isAdvanced(opt.isAdvanced), + requireArgument(opt.requireArgument), + incrementalArgument(opt.incrementalArgument), + argumentName(opt.argumentName), + negated(opt.negated), + value(opt.printValue()) { } + + friend std::ostream& operator<<(std::ostream& out, const ParsedOption& option) + { + if (option.negated) + out << "no "; + out << option.longName; + if (option.requireArgument) + out << " = " << option.value; + return out; + } + + char shortName; + std::string longName; + std::string description; + std::string group; + bool isAdvanced; + bool requireArgument; + bool incrementalArgument; + std::string argumentName; + bool negated; + std::string value; +}; + +struct TargetBase { + TargetBase(std::string variableName, std::string desc, std::string group, bool isAdvanced) + : variableName(std::move(variableName)), description(std::move(desc)), group(std::move(group)), isOptionalVector(false), isAdvanced(isAdvanced) { } + + virtual ~TargetBase() = default; + + TargetBase(const TargetBase&) = default; + TargetBase& operator=(const TargetBase&) = default; + TargetBase(TargetBase&&) = default; + TargetBase& operator=(TargetBase&&) = default; + + virtual bool parse(std::string const& value) = 0; + + std::string variableName; + std::string description; + std::string group; + bool isOptionalVector = false; + bool isAdvanced; +}; + +template +struct Target : TargetBase { + Target(T& target, std::string variableName, std::string desc, std::string group, bool isAdvanced) + : TargetBase(std::move(variableName), std::move(desc), std::move(group), isAdvanced), target(target) { } + + bool parse(std::string const& value) override + { + return io::stringToValue(value, target); + } + + T& target; +}; + +template +struct OptionalTargets : TargetBase { + OptionalTargets(std::vector& target, std::string variableName, std::string desc, std::string group, bool isAdvanced) + : TargetBase(std::move(variableName), std::move(desc), std::move(group), isAdvanced), targets(target) + { + isOptionalVector = true; + } + + bool parse(std::string const& value) override + { + T target; + bool ok = io::stringToValue(value, target); + if (ok) + targets.push_back(target); + return ok; + } + + std::vector& targets; +}; + +class ProgramInterface { +public: + ProgramInterface(std::string name, std::string shortDescription, std::string version); + + void setGroups(std::vector groups) { m_groups = std::move(groups); } + + template + void addNonOptionArgument(T& target, std::string variableName, std::string desc, std::string group, bool isAdvanced = false) + { + m_nonOptionArguments.emplace_back(new Target(target, std::move(variableName), std::move(desc), std::move(group), isAdvanced)); + } + + template + void addOptionalNonOptionArguments(std::vector& target, std::string variableName, std::string desc, std::string group, bool isAdvanced = false) + { + if (m_numOptionalNonOptionArguments != 0) + throw std::runtime_error("Can't have two non-option vector arguments"); + ++m_numOptionalNonOptionArguments; + m_nonOptionArguments.emplace_back(new OptionalTargets(target, std::move(variableName), std::move(desc), std::move(group), isAdvanced)); + } + + Option& addOptionArgument(char shortName, std::string longName, std::string description, std::string group, bool isAdvanced = false) + { + auto* o = new Option(shortName, std::move(longName), std::move(description), std::move(group), isAdvanced); + m_optionArguments.emplace_back(o); + return *o; + } + + Option& addIncrementalOptionArgument(unsigned int& target, char shortName, std::string longName, std::string description, std::string group, bool isAdvanced = false) + { + auto* o = new IncrementalOption(target, shortName, std::move(longName), std::move(description), std::move(group), isAdvanced); + m_optionArguments.emplace_back(o); + return *o; + } + + Option& addOptionArgument(bool& target, char shortName, std::string longName, std::string description, std::string group, bool isAdvanced = false) + { + auto* o = new ArgumentOption(target, shortName, std::move(longName), std::move(description), std::move(group), isAdvanced); + m_optionArguments.emplace_back(o); + return *o; + } + + // Without shortName + Option& addOptionArgument(bool& target, std::string longName, std::string description, std::string group, bool isAdvanced = false) + { + return addOptionArgument(target, '\0', std::move(longName), std::move(description), std::move(group), isAdvanced); + } + + template + Option& addOptionArgument(T& target, char shortName, std::string longName, std::string description, std::string argumentName, std::string group, bool isAdvanced = false) + { + auto* o = new ArgumentOption(target, shortName, std::move(longName), std::move(description), std::move(group), isAdvanced, std::move(argumentName)); + m_optionArguments.emplace_back(o); + return *o; + } + + template + Option& addOptionArgument(T& target, char shortName, std::string longName, std::string description, std::string argumentName, std::string group, T minValue, bool isAdvanced = false) + { + auto* o = new LowerBoundArgumentOption(target, shortName, std::move(longName), std::move(description), std::move(group), isAdvanced, std::move(argumentName), minValue); + m_optionArguments.emplace_back(o); + return *o; + } + + template + Option& addOptionArgument(T& target, char shortName, std::string longName, std::string description, std::string argumentName, std::string group, T minValue, T maxValue, bool isAdvanced = false) + { + auto* o = new LowerUpperBoundArgumentOption(target, shortName, std::move(longName), std::move(description), std::move(group), isAdvanced, std::move(argumentName), minValue, maxValue); + m_optionArguments.emplace_back(o); + return *o; + } + + // Without shortName + template + Option& addOptionArgument(T& target, std::string longName, std::string description, std::string argumentName, std::string group, bool isAdvanced = false) + { + return addOptionArgument(target, '\0', std::move(longName), std::move(description), std::move(argumentName), std::move(group), isAdvanced); + } + + template + Option& addOptionArgument(T& target, std::string longName, std::string description, std::string argumentName, std::string group, T minValue, bool isAdvanced = false) + { + return addOptionArgument(target, '\0', std::move(longName), std::move(description), std::move(argumentName), std::move(group), minValue, isAdvanced); + } + + template + Option& addOptionArgument(T& target, std::string longName, std::string description, std::string argumentName, std::string group, T minValue, T maxValue, bool isAdvanced = false) + { + return addOptionArgument(target, '\0', std::move(longName), std::move(description), std::move(argumentName), std::move(group), minValue, maxValue, isAdvanced); + } + + void parseArgs(const std::string& args); + + std::vector getUsedOptionArguments() const; + + unsigned int numRequiredArguments() const { return m_nonOptionArguments.size() - m_numOptionalNonOptionArguments; } + +private: +/* Modification for igraph: Disable functions that call forbidden + * functions such as exit(). */ +#if 0 + void exitWithUsage(bool showAdvanced) const; + void exitWithVersionInformation() const; +#endif + void exitWithError(const std::string& message) const; +#if 0 + void exitWithJsonParameters() const; +#endif + + std::deque> m_optionArguments; + std::deque> m_nonOptionArguments; + std::string m_programName = "Infomap"; + std::string m_shortProgramDescription; + std::string m_programVersion; + std::string m_programDescription; + std::vector m_groups; + std::string m_executableName = "Infomap"; + unsigned int m_displayHelp = 0; + bool m_displayVersion = false; + bool m_printJsonParameters = false; + + unsigned int m_numOptionalNonOptionArguments = 0; +}; + +} // namespace infomap + +#endif // PROGRAM_INTERFACE_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/io/SafeFile.h b/src/vendor/cigraph/vendor/infomap/src/io/SafeFile.h new file mode 100644 index 00000000000..967cd09bd5c --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/io/SafeFile.h @@ -0,0 +1,87 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef SAFEFILE_H_ +#define SAFEFILE_H_ + +#include "../utils/convert.h" +#include +#include +#include +#include +#include + +namespace infomap { + +using std::ifstream; +using std::ofstream; + +/** + * A wrapper for the C++ file stream class that automatically closes + * the file stream when the destructor is called. Allocate it on the + * stack to have it automatically closed when going out of scope. + * + * Note: + * In C++, the only code that can be guaranteed to be executed after an + * exception is thrown are the destructors of objects residing on the stack. + * + * You can exploit that fact to avoid resource leaks by tying all resources + * to the lifespan of an object allocated on the stack. This technique is + * called Resource Acquisition Is Initialization (RAII). + * + */ +class SafeInFile : public ifstream { +public: + SafeInFile(const std::string& filename, ios_base::openmode mode = ios_base::in) + : ifstream(filename, mode) + { + if (fail()) + throw std::runtime_error(io::Str() << "Error opening file '" << filename << "'. Check that the path points to a file and that you have read permissions."); + } + + ~SafeInFile() override + { + if (is_open()) + close(); + } +}; + +class SafeOutFile : public ofstream { +public: + SafeOutFile(const std::string& filename, ios_base::openmode mode = ios_base::out) + : ofstream(filename, mode) + { + if (fail()) + throw std::runtime_error(io::Str() << "Error opening file '" << filename << "'. Check that the directory you are writing to exists and that you have write permissions."); + } + + ~SafeOutFile() override + { + if (is_open()) + close(); + } +}; + +inline bool isDirectoryWritable(const std::string& dir) +{ + std::string path = io::Str() << dir << "_1nf0m4p_.tmp"; + bool ok = true; + try { + SafeOutFile out(path); + } catch (const std::runtime_error&) { + ok = false; + } + if (ok) + std::remove(path.c_str()); + return ok; +} + +} // namespace infomap + +#endif // SAFEFILE_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/Date.h b/src/vendor/cigraph/vendor/infomap/src/utils/Date.h new file mode 100644 index 00000000000..98feced1e41 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/Date.h @@ -0,0 +1,69 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef DATE_H_ +#define DATE_H_ + +#include +#include +#include + +namespace infomap { + +class ElapsedTime { +public: + ElapsedTime(double elapsedTime = 0.0) : m_elapsedTime(elapsedTime) { } + + double getSeconds() const { return m_elapsedTime; } + + friend std::ostream& operator<<(std::ostream& out, const ElapsedTime& elapsedTime) + { + auto temp = static_cast(std::floor(elapsedTime.getSeconds())); + if (temp > 60) { + if (temp > 3600) { + if (temp > 86400) { + out << temp / 86400 << "d "; + temp %= 86400; + } + out << temp / 3600 << "h "; + temp %= 3600; + } + out << temp / 60 << "m "; + temp %= 60; + out << temp << "s"; + } else { + out << temp << "s"; + } + return out; + } + +private: + double m_elapsedTime; +}; + +class Date { +public: + friend std::ostream& operator<<(std::ostream& out, const Date& date) + { + struct std::tm t = *localtime(&date.m_timeOfCreation); + return out << "" << (t.tm_year + 1900) << (t.tm_mon < 9 ? "-0" : "-") << (t.tm_mon + 1) << (t.tm_mday < 10 ? "-0" : "-") << t.tm_mday << (t.tm_hour < 10 ? " 0" : " ") << t.tm_hour << (t.tm_min < 10 ? ":0" : ":") << t.tm_min << (t.tm_sec < 10 ? ":0" : ":") << t.tm_sec << ""; + } + + ElapsedTime operator-(const Date& date) const + { + return { difftime(m_timeOfCreation, date.m_timeOfCreation) }; + } + +private: + std::time_t m_timeOfCreation = time(nullptr); +}; + +} // namespace infomap + +#endif // DATE_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/FileURI.cpp b/src/vendor/cigraph/vendor/infomap/src/utils/FileURI.cpp new file mode 100644 index 00000000000..c466d5872e0 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/FileURI.cpp @@ -0,0 +1,50 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "FileURI.h" +#include "convert.h" +#include +#include + +using std::string; + +namespace infomap { + +FileURI::FileURI(string filename, bool requireExtension) + : m_filename(std::move(filename)), m_requireExtension(requireExtension) +{ + auto getErrorMessage = [](const auto& name, auto requireExt) { + string s = io::Str() << "Filename '" << name << "' must match the pattern \"[dir/]name" << (requireExt ? ".extension\"" : "[.extension]\""); + return s; + }; + + auto name = m_filename; + auto pos = m_filename.find_last_of('/'); + if (pos != string::npos) { + if (pos == m_filename.length()) // File could not end with slash + throw std::invalid_argument(getErrorMessage(m_filename, m_requireExtension)); + m_directory = m_filename.substr(0, pos + 1); // Include the last slash in the directory + name = m_filename.substr(pos + 1); // No slash in the name + } else { + m_directory = ""; + } + + pos = name.find_last_of('.'); + if (pos == string::npos || pos == 0 || pos == name.length() - 1) { + if (pos != string::npos || m_requireExtension) + throw std::invalid_argument(getErrorMessage(m_filename, m_requireExtension)); + m_name = name; + m_extension = ""; + } else { + m_name = name.substr(0, pos); + m_extension = name.substr(pos + 1); + } +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/FileURI.h b/src/vendor/cigraph/vendor/infomap/src/utils/FileURI.h new file mode 100644 index 00000000000..8dc1511e69b --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/FileURI.h @@ -0,0 +1,54 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef FILEURI_H_ +#define FILEURI_H_ + +#include +#include + +namespace infomap { + +/** + * Filename class to simplify handling of parts of a filename. + * If a path is path/to/file.ext, the member methods of this class give these parts: + * getFilename -> "path/to/file.ext" + * getName -> "file" + * getExtension -> "ext" + * Can throw std::invalid_argument on creation. + */ +class FileURI { +public: + FileURI() = default; + + explicit FileURI(std::string filename, bool requireExtension = false); + + const std::string& getFilename() const { return m_filename; } + + const std::string& getName() const { return m_name; } + + const std::string& getExtension() const { return m_extension; } + + friend std::ostream& operator<<(std::ostream& out, const FileURI& file) + { + return out << file.getFilename(); + } + +private: + std::string m_filename; + bool m_requireExtension = false; + + std::string m_directory; + std::string m_name; + std::string m_extension; +}; + +} // namespace infomap + +#endif // FILEURI_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/FlowCalculator.cpp b/src/vendor/cigraph/vendor/infomap/src/utils/FlowCalculator.cpp new file mode 100644 index 00000000000..723f1674e3a --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/FlowCalculator.cpp @@ -0,0 +1,898 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "FlowCalculator.h" +#include "../utils/Log.h" +#include "../utils/infomath.h" +#include "../core/StateNetwork.h" +#include +#include +#include +#include +#include +#include + +namespace infomap { + +template +inline void normalize(std::vector& v, const T sum) noexcept +{ + for (auto& numerator : v) { + numerator /= sum; + } +} + +template +inline void normalize(std::vector& v) noexcept +{ + const auto sum = std::accumulate(cbegin(v), cend(v), T {}); + normalize(v, sum); +} + +FlowCalculator::FlowCalculator(StateNetwork& network, const Config& config) + : numNodes(network.numNodes()) +{ + Log() << "Calculating global network flow using flow model '" << config.flowModel << "'... " << std::flush; + + // Prepare data in sequence containers for fast access of individual elements + // Map to zero-based dense indexing + nodeFlow.assign(numNodes, 0.0); + nodeTeleportWeights.assign(numNodes, 0.0); // Fraction of teleportation flow landing on node i + + nodeOutDegree.assign(numNodes, 0); + sumLinkOutWeight.assign(numNodes, 0.0); + + unsigned int nodeIndex = 0; + const auto& nodeLinkMap = network.nodeLinkMap(); + + if (network.isBipartite()) { + // Preserve node order + for (const auto& node : network.nodes()) { + const auto nodeId = node.second.id; + nodeIndexMap[nodeId] = nodeIndex++; + } + + auto bipartiteStartId = network.bipartiteStartId(); + bipartiteStartIndex = nodeIndexMap[bipartiteStartId]; + + } else { + if (config.flowModel != FlowModel::directed) { + // Preserve node order + for (const auto& node : network.nodes()) { + const auto nodeId = node.second.id; + nodeIndexMap[nodeId] = nodeIndex++; + } + } else { + // Store dangling nodes out-of-order, + // with dangling nodes first to optimize calculation of dangling rank + + for (const auto& node : network.nodes()) { + const auto isDangling = nodeLinkMap.find(node.second) == nodeLinkMap.end(); + if (!isDangling) continue; + + const auto& nodeId = node.second.id; + nodeIndexMap[nodeId] = nodeIndex++; + } + + nonDanglingStartIndex = nodeIndex; + + for (const auto& node : network.nodes()) { + const auto isDangling = nodeLinkMap.find(node.second) == nodeLinkMap.end(); + if (isDangling) continue; + + const auto& nodeId = node.second.id; + nodeIndexMap[nodeId] = nodeIndex++; + } + } + } + + flowLinks.resize(network.numLinks(), { 0, 0, 0.0 }); + sumLinkWeight = network.sumLinkWeight(); + sumWeightedDegree = network.sumWeightedDegree(); + + if (network.isBipartite()) { + const auto bipartiteStartId = network.bipartiteStartId(); + + for (const auto& node : nodeLinkMap) { + const auto sourceIsFeature = node.first.id >= bipartiteStartId; + if (sourceIsFeature) continue; + bipartiteLinkStartIndex += node.second.size(); + } + } + + unsigned int linkIndex = 0; + unsigned int featureLinkIndex = bipartiteLinkStartIndex; // bipartite case + + for (const auto& node : nodeLinkMap) { + const auto sourceId = node.first.id; + const auto sourceIndex = nodeIndexMap[sourceId]; + + for (const auto& link : node.second) { + const auto targetId = link.first.id; + const auto targetIndex = nodeIndexMap[targetId]; + const auto linkWeight = link.second.weight; + + ++nodeOutDegree[sourceIndex]; + sumLinkOutWeight[sourceIndex] += linkWeight; + nodeFlow[sourceIndex] += linkWeight / sumWeightedDegree; + + if (network.isBipartite() && sourceId >= network.bipartiteStartId()) { + // Link from feature node to ordinary node + flowLinks[featureLinkIndex].source = sourceIndex; + flowLinks[featureLinkIndex].target = targetIndex; + flowLinks[featureLinkIndex].flow = linkWeight; + ++featureLinkIndex; + } else { + // Ordinary link, or unipartite + flowLinks[linkIndex].source = sourceIndex; + flowLinks[linkIndex].target = targetIndex; + flowLinks[linkIndex].flow = linkWeight; + ++linkIndex; + } + + if (sourceIndex != targetIndex) { + if (config.isUndirectedFlow()) { + ++nodeOutDegree[targetIndex]; + sumLinkOutWeight[targetIndex] += linkWeight; + } + if (config.flowModel != FlowModel::outdirdir) { + nodeFlow[targetIndex] += linkWeight / sumWeightedDegree; + } + } + } + } + + bool normalizeNodeFlow = false; + + switch (config.flowModel) { + case FlowModel::undirected: + if (config.regularized) { + calcUndirectedRegularizedFlow(network, config); + } else { + calcUndirectedFlow(); + } + break; + case FlowModel::directed: + if (network.isBipartite() && config.bipartiteTeleportation) { + calcDirectedBipartiteFlow(network, config); + } else { + if (config.regularized) { + calcDirectedRegularizedFlow(network, config); + } else { + calcDirectedFlow(network, config); + } + } + break; + case FlowModel::undirdir: + case FlowModel::outdirdir: + calcDirdirFlow(config); + normalizeNodeFlow = true; + break; + case FlowModel::rawdir: + calcRawdirFlow(); + normalizeNodeFlow = true; + break; + case FlowModel::precomputed: + usePrecomputedFlow(network, config); + normalizeNodeFlow = true; + break; + } + + finalize(network, config, normalizeNodeFlow); +} + +void FlowCalculator::calcUndirectedFlow() noexcept +{ + Log() << "\n -> Using undirected links."; + + // Flow is outgoing transition probability times source node flow + // = w_ij / s_ij * s_ij / sum(s_ij) = w_ij / sum(s_ij) + // Count twice for non-loops to cover flow in both directions + // Assuming convention to treat self-links as directed + + for (auto& link : flowLinks) { + link.flow /= sumWeightedDegree; + if (link.source != link.target) { + link.flow *= 2; + } + } +} + +void FlowCalculator::calcDirdirFlow(const Config& config) noexcept +{ + if (config.flowModel == FlowModel::outdirdir) + Log() << "\n -> Counting only ingoing links."; + else + Log() << "\n -> Using undirected links, switching to directed after steady state."; + + // Take one last power iteration + const std::vector nodeFlowSteadyState(nodeFlow); + nodeFlow.assign(numNodes, 0.0); + + for (const auto& link : flowLinks) { + nodeFlow[link.target] += nodeFlowSteadyState[link.source] * link.flow / sumLinkOutWeight[link.source]; + } + + double sumNodeFlow = std::accumulate(cbegin(nodeFlow), cend(nodeFlow), 0.0); + + // Update link data to represent flow instead of weight + for (auto& link : flowLinks) { + link.flow *= nodeFlowSteadyState[link.source] / sumLinkOutWeight[link.source] / sumNodeFlow; + } +} + +void FlowCalculator::calcRawdirFlow() noexcept +{ + Log() << "\n -> Using directed links with raw flow."; + Log() << "\n -> Total link weight: " << sumLinkWeight << "."; + + // Treat the link weights as flow (after global normalization) and + // do one power iteration to set the node flow + nodeFlow.assign(numNodes, 0.0); + + for (auto& link : flowLinks) { + link.flow /= sumLinkWeight; + nodeFlow[link.target] += link.flow; + } +} + +void FlowCalculator::usePrecomputedFlow(const StateNetwork& network, const Config& config) +{ + Log() << "\n -> Using directed links with precomputed flow from input data."; + Log() << "\n -> Total link flow: " << sumLinkWeight << "."; + + if (network.haveFileInput()) { + if (network.haveMemoryInput() && !network.haveStateNodeWeights()) { + Log() << std::endl; + throw std::runtime_error("Missing node flow in input data. Should be passed as a third field under a *States section."); + } + if (!network.haveMemoryInput() && !network.haveNodeWeights()) { + Log() << std::endl; + throw std::runtime_error("Missing node flow in input data. Should be passed as a third field under a *Vertices section."); + } + } + + // Treat the link weights as flow + nodeFlow.assign(numNodes, 0.0); + double sumFlow = 0.0; + + for (const auto& nodeIt : network.nodes()) { + auto& node = nodeIt.second; + nodeFlow[nodeIndexMap[node.id]] = node.weight; + sumFlow += node.weight; + } + Log() << "\n -> Total node flow: " << sumFlow << "."; + + if (infomath::isEqual(sumFlow, 0)) { + throw std::runtime_error("Missing node flow. Set it on the node weight property."); + } + if (!infomath::isEqual(sumFlow, 1)) { + if (infomath::isEqual(sumFlow, numNodes) && infomath::isEqual(nodeFlow[0], 1)) { + Log() << "\n Warning: Node flow sums to the number of nodes, is node flow provided or is default node weights used? Normalizing."; + } else { + Log() << "\n Warning: Node flow sums to " << sumFlow << ", normalizing."; + } + for (unsigned int i = 0; i < numNodes; ++i) { + nodeFlow[i] /= sumFlow; + } + } +} + +struct IterationResult { + double alpha; + double beta; +}; + +template +IterationResult powerIterate(double alpha, Iteration&& iter) +{ + unsigned int iterations = 0; + double beta = 1.0 - alpha; + double err = 0.0; + + do { + double oldErr = err; + err = iter(iterations, alpha, beta); + + // Perturb the system if equilibrium + if (std::abs(err - oldErr) < 1e-17) { + alpha += 1.0e-12; + beta = 1.0 - alpha; + } + + ++iterations; + } while (iterations < 200 && (err > 1.0e-15 || iterations < 50)); + + Log() << "\n -> PageRank calculation done in " << iterations << " iterations.\n"; + + return { alpha, beta }; +} + +void FlowCalculator::calcDirectedFlow(const StateNetwork& network, const Config& config) noexcept +{ + Log() << "\n -> Using " << (config.recordedTeleportation ? "recorded" : "unrecorded") << " teleportation to " << (config.teleportToNodes ? "nodes" : "links") << ". " << std::flush; + + // Calculate the teleport rate distribution + if (config.teleportToNodes) { + double sumNodeWeights = 0.0; + + for (const auto& nodeIt : network.nodes()) { + auto& node = nodeIt.second; + nodeTeleportWeights[nodeIndexMap[node.id]] = node.weight; + sumNodeWeights += node.weight; + } + + normalize(nodeTeleportWeights, sumNodeWeights); + } else { + // Teleport to links + + // Teleport proportionally to out-degree, or in-degree if recorded teleportation. + for (const auto& link : flowLinks) { + auto toNode = config.recordedTeleportation ? link.target : link.source; + nodeTeleportWeights[toNode] += link.flow / sumLinkWeight; + } + } + + // Normalize link weights with respect to its source nodes total out-link weight; + for (auto& link : flowLinks) { + if (sumLinkOutWeight[link.source] > 0) { + link.flow /= sumLinkOutWeight[link.source]; + } + } + + std::vector nodeFlowTmp(numNodes, 0.0); + double danglingRank; + + // Calculate PageRank + const auto iteration = [&](const auto iter, const double alpha, const double beta) { + danglingRank = std::accumulate(cbegin(nodeFlow), cbegin(nodeFlow) + nonDanglingStartIndex, 0.0); + + // Flow from teleportation + const auto teleportationFlow = alpha + beta * danglingRank; + for (unsigned int i = 0; i < numNodes; ++i) { + nodeFlowTmp[i] = teleportationFlow * nodeTeleportWeights[i]; + } + + // Flow from links + for (const auto& link : flowLinks) { + nodeFlowTmp[link.target] += beta * link.flow * nodeFlow[link.source]; + } + + // Update node flow from the power iteration above and check if converged + double nodeFlowDiff = -1.0; // Start with -1.0 so we don't have to subtract it later + double error = 0.0; + for (unsigned int i = 0; i < numNodes; ++i) { + nodeFlowDiff += nodeFlowTmp[i]; + error += std::abs(nodeFlowTmp[i] - nodeFlow[i]); + } + + nodeFlow = nodeFlowTmp; + + // Normalize if needed + if (std::abs(nodeFlowDiff) > 1.0e-10) { + Log() << "(Normalizing ranks after " << iter << " power iterations with error " << nodeFlowDiff << ") "; + normalize(nodeFlow, nodeFlowDiff + 1.0); + } + + return error; + }; + + const auto result = powerIterate(config.teleportationProbability, iteration); + + double sumNodeRank = 1.0; + double beta = result.beta; + + if (!config.recordedTeleportation) { + // Take one last power iteration excluding the teleportation + // and normalize node flow + sumNodeRank = 1.0 - danglingRank; + nodeFlow.assign(numNodes, 0.0); + + for (const auto& link : flowLinks) { + nodeFlow[link.target] += link.flow * nodeFlowTmp[link.source] / sumNodeRank; + } + + beta = 1.0; + } + + // Update the links with their global flow from the PageRank values. + // Note: beta is set to 1 if unrecorded teleportation + for (auto& link : flowLinks) { + link.flow *= beta * nodeFlowTmp[link.source] / sumNodeRank; + } +} + +void FlowCalculator::calcDirectedRegularizedFlow(const StateNetwork& network, const Config& config) noexcept +{ + Log() << "\n -> Using recorded teleportation to nodes according to a fully connected Bayesian prior. " << std::flush; + + // Calculate node weights w_i = s_i/k_i, where s_i is the node strength (weighted degree) and k_i the (unweighted) degree + unsigned int N = network.numNodes(); + + std::vector k_out(N, 0); + std::vector k_in(N, 0); + std::vector s_out(N, 0); + std::vector s_in(N, 0); + double sum_s = sumWeightedDegree; + unsigned int sum_k = network.sumDegree(); + double average_weight = sum_s / sum_k; + + for (auto& link : flowLinks) { + k_out[link.source] += 1; + s_out[link.source] += link.flow; + k_in[link.target] += 1; + s_in[link.target] += link.flow; + } + + double min_u_out = std::numeric_limits::max(); + double min_u_in = std::numeric_limits::max(); + for (unsigned int i = 0; i < N; ++i) { + if (k_out[i] > 0) { + min_u_out = std::min(min_u_out, s_out[i] / k_out[i]); + } + if (k_in[i] > 0) { + min_u_in = std::min(min_u_in, s_in[i] / k_in[i]); + } + } + + auto u_out = [s_out, k_out, min_u_out](auto i) { return k_out[i] == 0 ? min_u_out : s_out[i] / k_out[i]; }; + auto u_in = [s_in, k_in, min_u_in](auto i) { return k_in[i] == 0 ? min_u_in : s_in[i] / k_in[i]; }; + + unsigned int numNodesAsTeleportationTargets = config.noSelfLinks ? N - 1 : N; + double lambda = config.regularizationStrength * std::log(N) / numNodesAsTeleportationTargets; + double u_t = average_weight; + + double sum_u_in = 0.0; + for (unsigned int i = 0; i < N; ++i) { + sum_u_in += u_in(i); + } + + for (unsigned int i = 0; i < N; ++i) { + nodeTeleportWeights[i] = u_in(i) / sum_u_in; + } + + std::function t_out_withoutSelfLinks = [lambda, u_t, u_out, u_in, sum_u_in](unsigned int i) { return lambda / u_t * u_out(i) * (sum_u_in - u_in(i)); }; + std::function t_out_withSelfLinks = [lambda, u_t, u_out, sum_u_in](unsigned int i) { return lambda / u_t * u_out(i) * sum_u_in; }; + auto t_out = config.noSelfLinks ? t_out_withoutSelfLinks : t_out_withSelfLinks; + + std::vector alpha(N, 0); + for (unsigned int i = 0; i < N; ++i) { + auto t_i = t_out(i); + alpha[i] = t_i / (s_out[i] + t_i); // = 1 for dangling nodes + if (config.noSelfLinks) { + // Inflate to adjust for no self-teleportation + // TODO: Check possible side-effects + alpha[i] /= 1 - nodeTeleportWeights[i]; + } + } + + // Normalize link weights with respect to its source nodes total out-link weight; + for (auto& link : flowLinks) { + if (sumLinkOutWeight[link.source] > 0) { + link.flow /= sumLinkOutWeight[link.source]; + } + } + + std::vector nodeFlowTmp(numNodes, 0.0); + + // Calculate PageRank + const auto iteration = [&](const auto iter) { + double teleTmp = 0.0; + for (unsigned int i = 0; i < N; ++i) { + teleTmp += alpha[i] * nodeFlow[i]; + } + + for (unsigned int i = 0; i < N; ++i) { + nodeFlowTmp[i] = nodeTeleportWeights[i] * (config.noSelfLinks ? (teleTmp - alpha[i] * nodeFlow[i]) : teleTmp); + } + + // Flow from links + for (const auto& link : flowLinks) { + double beta = 1 - alpha[link.source] * (config.noSelfLinks ? 1 - nodeTeleportWeights[link.source] : 1); + nodeFlowTmp[link.target] += beta * link.flow * nodeFlow[link.source]; + } + + // Update node flow from the power iteration above and check if converged + double nodeFlowDiff = -1.0; // Start with -1.0 so we don't have to subtract it later + double error = 0.0; + for (unsigned int i = 0; i < numNodes; ++i) { + nodeFlowDiff += nodeFlowTmp[i]; + error += std::abs(nodeFlowTmp[i] - nodeFlow[i]); + } + + nodeFlow = nodeFlowTmp; + + // Normalize if needed + if (std::abs(nodeFlowDiff) > 1.0e-10) { + Log() << "(Normalizing ranks after " << iter << " power iterations with error " << nodeFlowDiff << ") "; + normalize(nodeFlow, nodeFlowDiff + 1.0); + } + + return error; + }; + + unsigned int iterations = 0; + double err = 0.0; + + do { + double oldErr = err; + err = iteration(iterations); + + // Perturb the system if equilibrium + if (std::abs(err - oldErr) < 1e-15) { + } + + ++iterations; + } while (iterations < 200 && (err > 1.0e-15 || iterations < 50)); + + Log() << "\n -> PageRank calculation done in " << iterations << " iterations.\n"; + + double sumNodeRank = 1.0; + for (auto& link : flowLinks) { + double beta = 1 - alpha[link.source] * (config.noSelfLinks ? 1 - nodeTeleportWeights[link.source] : 1); + link.flow *= beta * nodeFlow[link.source] / sumNodeRank; + } + + nodeTeleportFlow.assign(numNodes, 0.0); + for (unsigned int i = 0; i < N; ++i) { + nodeTeleportFlow[i] = nodeFlow[i] * alpha[i]; + } +} + +void FlowCalculator::calcUndirectedRegularizedFlow(const StateNetwork& network, const Config& config) noexcept +{ + Log() << "\n -> Using recorded teleportation to nodes according to a fully connected Bayesian prior. " << std::flush; + + // Calculate node weights w_i = s_i/k_i, where s_i is the node strength (weighted degree) and k_i the (unweighted) degree + unsigned int N = network.numNodes(); + std::vector k(N, 0); + std::vector s(N, 0); + double sum_s = sumWeightedDegree; + unsigned int sum_k = network.sumDegree(); + double average_weight = sum_s / sum_k; + + for (auto& link : flowLinks) { + k[link.source] += 1; + s[link.source] += link.flow; + if (link.source != link.target) { + k[link.target] += 1; + s[link.target] += link.flow; + } + } + + double min_u = std::numeric_limits::max(); + for (unsigned int i = 0; i < N; ++i) { + if (k[i] > 0) { + min_u = std::min(min_u, s[i] / k[i]); + } + } + + auto u = [s, k, min_u](auto i) { return k[i] == 0 ? min_u : s[i] / k[i]; }; + + unsigned int numNodesAsTeleportationTargets = config.noSelfLinks ? N - 1 : N; + double lambda = config.regularizationStrength * std::log(N) / numNodesAsTeleportationTargets; + double u_t = average_weight; + + double sum_u = 0.0; + for (unsigned int i = 0; i < N; ++i) { + sum_u += u(i); + } + + // nodeTeleportWeights is the fraction of teleportation flow landing on each node. This is proportional to u_in + for (unsigned int i = 0; i < N; ++i) { + nodeTeleportWeights[i] = u(i) / sum_u; + } + + std::function t_withoutSelfLinks = [lambda, u_t, u, sum_u](unsigned int i) { return lambda / u_t * u(i) * (sum_u - u(i)); }; + std::function t_withSelfLinks = [lambda, u_t, u, sum_u](unsigned int i) { return lambda / u_t * u(i) * sum_u; }; + auto t = config.noSelfLinks ? t_withoutSelfLinks : t_withSelfLinks; + + std::vector alpha(N, 0); + double sum_t = 0.0; + for (unsigned int i = 0; i < N; ++i) { + auto t_i = t(i); + alpha[i] = t_i / (s[i] + t_i); + if (config.noSelfLinks) { + // Inflate to adjust for no self-teleportation + // TODO: No later side effects of cheating here? Need to normalize targets instead? + alpha[i] /= 1 - nodeTeleportWeights[i]; + } + sum_t += t_i; + } + + for (auto& link : flowLinks) { + if (sumLinkOutWeight[link.source] > 0) { + link.flow /= sumLinkOutWeight[link.source]; + } + } + + for (unsigned int i = 0; i < N; ++i) { + nodeFlow[i] = (s[i] + t(i)) / (sum_s + sum_t); + } + + nodeTeleportFlow.assign(numNodes, 0.0); + for (unsigned int i = 0; i < N; ++i) { + nodeTeleportFlow[i] = nodeFlow[i] * alpha[i]; + } + + for (auto& link : flowLinks) { + // TODO: Side effect from inflating alpha, need real alpha here. + double beta = 1 - alpha[link.source] * (config.noSelfLinks ? 1 - nodeTeleportWeights[link.source] : 1); + link.flow *= beta * nodeFlow[link.source] * 2; + } +} + +void FlowCalculator::calcDirectedBipartiteFlow(const StateNetwork& network, const Config& config) noexcept +{ + Log() << "\n -> Using bipartite " << (config.recordedTeleportation ? "recorded" : "unrecorded") << " teleportation to " << (config.teleportToNodes ? "nodes" : "links") << ". " << std::flush; + + const auto bipartiteStartId = network.bipartiteStartId(); + + if (config.teleportToNodes) { + for (const auto& nodeIt : network.nodes()) { + auto& node = nodeIt.second; + if (node.id < bipartiteStartId) { + nodeTeleportWeights[nodeIndexMap[node.id]] = node.weight; + } + } + } else { + // Teleport proportionally to out-degree, or in-degree if recorded teleportation. + // Two-step degree: sum of products between incoming and outgoing links from bipartite nodes + + if (config.recordedTeleportation) { + for (auto link = begin(flowLinks) + bipartiteLinkStartIndex; link != end(flowLinks); ++link) { + // target is an ordinary node + nodeTeleportWeights[link->target] += link->flow; + } + } else { + // Unrecorded teleportation + + for (auto link = begin(flowLinks); link != begin(flowLinks) + bipartiteLinkStartIndex; ++link) { + // source is an ordinary node + nodeTeleportWeights[link->source] += link->flow; + } + } + } + + normalize(nodeTeleportWeights); + + nodeFlow = nodeTeleportWeights; + + // Normalize link weights with respect to its source nodes total out-link weight; + for (auto& link : flowLinks) { + if (sumLinkOutWeight[link.source] > 0) { + link.flow /= sumLinkOutWeight[link.source]; + } + } + + std::vector danglingIndices; + for (size_t i = 0; i < numNodes; ++i) { + if (nodeOutDegree[i] == 0) { + danglingIndices.push_back(i); + } + } + + std::vector nodeFlowTmp(numNodes, 0.0); + double danglingRank; + + // Calculate two-step PageRank + const auto iteration = [&](const auto iter, const double alpha, const double beta) { + danglingRank = 0.0; + for (const auto& i : danglingIndices) { + danglingRank += nodeFlow[i]; + } + + // Flow from teleportation + const auto teleportationFlow = alpha + beta * danglingRank; + for (unsigned int i = 0; i < bipartiteStartIndex; ++i) { + nodeFlowTmp[i] = teleportationFlow * nodeTeleportWeights[i]; + } + + for (unsigned int i = bipartiteStartIndex; i < numNodes; ++i) { + nodeFlowTmp[i] = 0.0; + } + + // Flow from links + // First step + for (auto link = begin(flowLinks); link != begin(flowLinks) + bipartiteLinkStartIndex; ++link) { + nodeFlow[link->target] += beta * link->flow * nodeFlow[link->source]; + } + + // Second step back to primary nodes + for (auto link = begin(flowLinks) + bipartiteLinkStartIndex; link != end(flowLinks); ++link) { + nodeFlowTmp[link->target] += link->flow * nodeFlow[link->source]; + } + + // Update node flow from the power iteration above and check if converged + double nodeFlowDiff = -1.0; + double error = 0.0; + for (unsigned int i = 0; i < bipartiteStartIndex; ++i) { + nodeFlowDiff += nodeFlowTmp[i]; + error += std::abs(nodeFlowTmp[i] - nodeFlow[i]); + } + + nodeFlow = nodeFlowTmp; + + // Normalize if needed + if (std::abs(nodeFlowDiff) > 1.0e-10) { + Log() << "(Normalizing ranks after " << iter << " power iterations with error " << nodeFlowDiff << ") "; + normalize(nodeFlow, nodeFlowDiff + 1.0); + } + + return error; + }; + + const auto result = powerIterate(config.teleportationProbability, iteration); + + double sumNodeRank = 1.0; + double beta = result.beta; + + if (!config.recordedTeleportation) { + // Take one last power iteration excluding the teleportation (and normalize node flow to sum 1.0) + sumNodeRank = 1.0 - danglingRank; + nodeFlow.assign(numNodes, 0.0); + + for (auto link = begin(flowLinks); link != begin(flowLinks) + bipartiteLinkStartIndex; ++link) { + nodeFlowTmp[link->target] += link->flow * nodeFlowTmp[link->source]; + } + // Second step back to primary nodes + for (auto link = begin(flowLinks) + bipartiteLinkStartIndex; link != end(flowLinks); ++link) { + nodeFlow[link->target] += link->flow * nodeFlowTmp[link->source]; + } + + beta = 1.0; + } + + // Update the links with their global flow from the PageRank values. + // Note: beta is set to 1 if unrecorded teleportation + for (auto& link : flowLinks) { + link.flow *= beta * nodeFlowTmp[link.source] / sumNodeRank; + } +} + +void FlowCalculator::finalize(StateNetwork& network, const Config& config, bool normalizeNodeFlow) noexcept +{ + unsigned int N = network.numNodes(); + // TODO: Skip bipartite flow adjustment for directed / rawdir / .. ? + if (network.isBipartite()) { + Log() << "\n -> Using bipartite links."; + + if (!config.skipAdjustBipartiteFlow && !config.bipartiteTeleportation) { + // Only links between ordinary nodes and feature nodes in bipartite network + // Don't code feature nodes -> distribute all flow from those to ordinary nodes + for (auto& link : flowLinks) { + auto sourceIsFeature = link.source >= bipartiteStartIndex; + + if (sourceIsFeature) { + nodeFlow[link.target] += link.flow; + nodeFlow[link.source] = 0.0; // Doesn't matter if done multiple times on each node. + } else { + nodeFlow[link.source] += link.flow; + nodeFlow[link.target] = 0.0; // Doesn't matter if done multiple times on each node. + } + // TODO: Should flow double before moving to nodes, does it cancel out in normalization? + + // Markov time 2 on the full network will correspond to markov time 1 between the real nodes. + link.flow *= 2; + } + // TODO: Should flow double before moving to nodes, does it cancel out in normalization? + + normalizeNodeFlow = true; + + } else if (config.bipartiteTeleportation) { + for (auto& link : flowLinks) { + // Markov time 2 on the full network will correspond to markov time 1 between the real nodes. + link.flow *= 2; + } + } + } + + if (config.useNodeWeightsAsFlow) { + Log() << "\n -> Using node weights as flow."; + + for (auto& nodeIt : network.nodes()) { + auto& node = nodeIt.second; + nodeFlow[nodeIndexMap[node.id]] = node.weight; + } + + normalizeNodeFlow = true; + } + + if (normalizeNodeFlow) { + normalize(nodeFlow); + } + + // Write back flow to network + double sumNodeFlow = 0.0; + double sumLinkFlow = 0.0; + unsigned int linkIndex = 0; + auto featureLinkIndex = bipartiteLinkStartIndex; + + for (auto& node : network.m_nodeLinkMap) { + for (auto& link : node.second) { + auto& linkData = link.second; + if (network.isBipartite() && node.first.id >= network.bipartiteStartId()) { + linkData.flow = flowLinks[featureLinkIndex++].flow; + } else { + linkData.flow = flowLinks[linkIndex++].flow; + } + sumLinkFlow += linkData.flow; + } + } + + for (auto& nodeIt : network.m_nodes) { + auto& node = nodeIt.second; + const auto nodeIndex = nodeIndexMap[node.id]; + node.flow = nodeFlow[nodeIndex]; + node.weight = nodeTeleportWeights[nodeIndex]; + node.teleFlow = !nodeTeleportFlow.empty() ? nodeTeleportFlow[nodeIndex] : nodeFlow[nodeIndex] * (nodeOutDegree[nodeIndex] == 0 ? 1 : config.teleportationProbability); + node.enterFlow = node.flow; + node.exitFlow = node.flow; + + if (!config.noSelfLinks) { + // Remove self-teleportation flow + node.enterFlow -= node.teleFlow * node.weight; + node.exitFlow -= node.teleFlow * node.weight; + + // Remove self-link flow + unsigned int norm = config.isUndirectedFlow() ? 2 : 1; + auto& outLinks = network.m_nodeLinkMap[node.id]; + for (auto& link : outLinks) { + auto& linkData = link.second; + if (node.id == link.first.id) { + node.enterFlow -= linkData.flow / norm; + node.exitFlow -= linkData.flow / norm; + break; + } + } + } + + sumNodeFlow += node.flow; + } + + // Enter/exit flow + if (!config.isUndirectedClustering() && !config.regularized) { + enterFlow.assign(N, 0); + exitFlow.assign(N, 0); + double alpha = config.teleportationProbability; + double sumDanglingFlow = 0.0; + for (unsigned int i = 0; i < N; ++i) { + if (nodeOutDegree[i] == 0) { + sumDanglingFlow += nodeFlow[i]; + } + } + for (auto& nodeIt : network.m_nodes) { + auto& node = nodeIt.second; + const auto sourceIndex = nodeIndexMap[node.id]; + auto& outLinks = network.m_nodeLinkMap[node.id]; + double danglingFlow = outLinks.empty() ? node.flow : 0.0; + if (config.recordedTeleportation) { + // Don't let self-teleportation add to the enter/exit flow (i.e. multiply with (1.0 - node.data.teleportWeight)) + exitFlow[sourceIndex] += alpha * node.flow * (1.0 - node.weight); + enterFlow[sourceIndex] += (alpha * (1.0 - node.flow) + (1 - alpha) * (sumDanglingFlow - danglingFlow)) * node.weight; + } + for (auto& link : outLinks) { + auto& linkData = link.second; + const auto targetIndex = nodeIndexMap[link.first.id]; + exitFlow[sourceIndex] += linkData.flow; + enterFlow[targetIndex] += linkData.flow; + } + } + for (auto& nodeIt : network.m_nodes) { + auto& node = nodeIt.second; + const auto nodeIndex = nodeIndexMap[node.id]; + node.enterFlow = enterFlow[nodeIndex]; + node.exitFlow = exitFlow[nodeIndex]; + } + } + + Log() << "\n => Sum node flow: " << sumNodeFlow << ", sum link flow: " << sumLinkFlow << "\n"; +} + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/FlowCalculator.h b/src/vendor/cigraph/vendor/infomap/src/utils/FlowCalculator.h new file mode 100644 index 00000000000..88294b37c4b --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/FlowCalculator.h @@ -0,0 +1,75 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef FLOW_CALCULATOR_H_ +#define FLOW_CALCULATOR_H_ + +#include +#include + +namespace infomap { + +struct Config; +class StateNetwork; + +namespace detail { + struct FlowLink { + unsigned int source; + unsigned int target; + double flow; + }; +} // namespace detail + +/** + * Calculate flow on network based on different flow models + */ +class FlowCalculator { +public: + FlowCalculator(StateNetwork&, const Config&); + +private: + void calcUndirectedFlow() noexcept; + void calcDirectedFlow(const StateNetwork&, const Config&) noexcept; + void calcUndirectedRegularizedFlow(const StateNetwork&, const Config&) noexcept; + void calcDirectedRegularizedFlow(const StateNetwork&, const Config&) noexcept; + void calcDirectedBipartiteFlow(const StateNetwork&, const Config&) noexcept; + void calcDirdirFlow(const Config&) noexcept; + void calcRawdirFlow() noexcept; + void usePrecomputedFlow(const StateNetwork&, const Config&); + + void finalize(StateNetwork&, const Config&, bool) noexcept; + + unsigned int numNodes; + unsigned int nonDanglingStartIndex = 0; + unsigned int bipartiteStartIndex = 0; + unsigned int bipartiteLinkStartIndex = 0; + + double sumLinkWeight = 0; + double sumWeightedDegree = 0; + + std::map nodeIndexMap; + std::vector nodeFlow; + std::vector nodeTeleportWeights; + std::vector nodeTeleportFlow; + std::vector enterFlow; + std::vector exitFlow; + std::vector sumLinkOutWeight; + std::vector nodeOutDegree; + using FlowLink = detail::FlowLink; + std::vector flowLinks; +}; + +inline void calculateFlow(StateNetwork& network, const Config& config) +{ + FlowCalculator(network, config); +} + +} // namespace infomap + +#endif // FLOW_CALCULATOR_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/Log.cpp b/src/vendor/cigraph/vendor/infomap/src/utils/Log.cpp new file mode 100644 index 00000000000..f16f2b0843b --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/Log.cpp @@ -0,0 +1,17 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#include "Log.h" + +namespace infomap { + +unsigned int Log::s_verboseLevel = 0; +bool Log::s_silent = false; + +} // namespace infomap diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/Log.h b/src/vendor/cigraph/vendor/infomap/src/utils/Log.h new file mode 100644 index 00000000000..412dcd516e1 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/Log.h @@ -0,0 +1,110 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef LOG_H_ +#define LOG_H_ + +#include +#include +#include +#include + +namespace infomap { + +struct hideIf; + +class Log { + using ostreamFuncPtr = std::add_pointer_t; + +public: + /** + * Log when level is below or equal Log::verboseLevel() + * and maxLevel is above or equal Log::verboseLevel() + */ + explicit Log(unsigned int level = 0, unsigned int maxLevel = std::numeric_limits::max()) + : m_level(level), m_maxLevel(maxLevel), m_visible(isVisible(m_level, m_maxLevel)) { } + + bool isVisible() const { return isVisible(m_level, m_maxLevel); } + + void hide(bool value) { m_visible = !value && isVisible(); } + + Log& operator<<(const hideIf&) { return *this; } + + template + Log& operator<<(const T& data) + { +#if 0 + if (m_visible) + m_ostream << data; +#endif + return *this; + } + + Log& operator<<(ostreamFuncPtr f) + { +#if 0 + if (m_visible) + m_ostream << f; +#endif + return *this; + } + + static void init(unsigned int verboseLevel, bool silent, unsigned int numberPrecision) + { + setVerboseLevel(verboseLevel); + setSilent(silent); + Log() << std::setprecision(static_cast(numberPrecision)); + } + + static bool isVisible(unsigned int level, unsigned int maxLevel) + { + return !s_silent && s_verboseLevel >= level && s_verboseLevel <= maxLevel; + } + + static void setVerboseLevel(unsigned int level) { s_verboseLevel = level; } + + static void setSilent(bool silent) { s_silent = silent; } + + static bool isSilent() { return s_silent; } + + /* precision() is patched in igraph to avoid references to std::cout */ + static std::streamsize precision() { return 6; } + + static std::streamsize precision(std::streamsize) + { + return precision(); + } + +private: + unsigned int m_level; + unsigned int m_maxLevel; + bool m_visible; +#if 0 + std::ostream& m_ostream = std::cout; +#endif + + static unsigned int s_verboseLevel; + static bool s_silent; +}; + +struct hideIf { + explicit hideIf(bool value) : hide(value) { } + + friend Log& operator<<(Log& out, const hideIf& manip) + { + out.hide(manip.hide); + return out; + } + + bool hide; +}; + +} // namespace infomap + +#endif // LOG_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/MetaCollection.h b/src/vendor/cigraph/vendor/infomap/src/utils/MetaCollection.h new file mode 100644 index 00000000000..67a60d3befe --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/MetaCollection.h @@ -0,0 +1,153 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef META_COLLECTION_H_ +#define META_COLLECTION_H_ + +#include "infomath.h" +#include +#include + +namespace infomap { + +struct FlowCount { + FlowCount() = default; + + explicit FlowCount(double flow) + : flow(flow), count(1) { } + + FlowCount& operator+=(const FlowCount& o) + { + flow += o.flow; + count += o.count; + return *this; + } + + FlowCount& operator+=(double f) + { + flow += f; + ++count; + return *this; + } + + FlowCount& operator-=(const FlowCount& o) + { + flow -= o.flow; + count -= o.count; + return *this; + } + + FlowCount& operator-=(double f) + { + flow -= f; + --count; + return *this; + } + + friend std::ostream& operator<<(std::ostream& out, const FlowCount& o) + { + return out << o.flow << "/" << o.count; + } + + void reset() + { + flow = 0.0; + count = 0; + } + + bool empty() const { return count == 0; } + double flow = 0.0; + unsigned int count = 0; +}; + +using MetaToFlowCount = std::map; // metaId -> (flow,count) + +class MetaCollection { +protected: + FlowCount m_total; + MetaToFlowCount m_metaToFlowCount; + +public: + unsigned int size() const { return m_metaToFlowCount.size(); } + + bool empty() const { return m_metaToFlowCount.empty(); } + + MetaToFlowCount::iterator begin() { return m_metaToFlowCount.begin(); } + MetaToFlowCount::iterator end() { return m_metaToFlowCount.end(); } + MetaToFlowCount::const_iterator begin() const { return m_metaToFlowCount.begin(); } + MetaToFlowCount::const_iterator end() const { return m_metaToFlowCount.end(); } + + void add(unsigned int meta, double flow = 1.0) + { + m_total += flow; + m_metaToFlowCount[meta] += flow; + } + + void add(unsigned int meta, const FlowCount& flow) + { + m_total += flow; + m_metaToFlowCount[meta] += flow; + } + + void add(const MetaCollection& other) + { + for (auto& it : other) { + auto metaId = it.first; + auto& flowCount = it.second; + add(metaId, flowCount); + } + } + + void remove(unsigned int meta, const FlowCount& flow) + { + m_total -= flow; + auto& metaFlowCount = m_metaToFlowCount[meta]; + metaFlowCount -= flow; + if (metaFlowCount.empty()) + m_metaToFlowCount.erase(meta); + } + + void remove(const MetaCollection& other) + { + for (auto& it : other) { + auto metaId = it.first; + auto& flowCount = it.second; + remove(metaId, flowCount); + } + } + + double calculateEntropy() + { + double metaCodelength = 0.0; + for (auto& it : m_metaToFlowCount) { + metaCodelength -= infomath::plogp(it.second.flow / m_total.flow); + } + return m_total.flow * metaCodelength; + } + + void clear() + { + m_total.reset(); + m_metaToFlowCount.clear(); + } + + friend std::ostream& operator<<(std::ostream& out, const MetaCollection& m) + { + out << "<( " << m.m_total << ": "; + for (auto& it : m.m_metaToFlowCount) { + out << "(" << it.first << "," << it.second << ") "; + } + out << ")>"; + return out; + } +}; + +} // namespace infomap + +#endif // META_COLLECTION_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/Random.h b/src/vendor/cigraph/vendor/infomap/src/utils/Random.h new file mode 100644 index 00000000000..6a50069a444 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/Random.h @@ -0,0 +1,45 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef RANDOM_H_ +#define RANDOM_H_ + +#include + +#include +#include + +namespace infomap { + +class Random { + igraph_rng_t* m_randGen; + +public: + Random() : m_randGen(igraph_rng_default()) { } + + unsigned int randInt(unsigned int min, unsigned int max) + { + return igraph_rng_get_integer(m_randGen, min, max); + } + + /** + * Get a random permutation of indices of the size of the input vector + */ + void getRandomizedIndexVector(std::vector& randomOrder) + { + unsigned int size = randomOrder.size(); + for (unsigned int i = 0; i < size; ++i) + randomOrder[i] = i; + for (unsigned int i = 0; i < size; ++i) + std::swap(randomOrder[i], randomOrder[i + randInt(0, size - i - 1)]); + } +}; +} // namespace infomap + +#endif // RANDOM_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/Stopwatch.h b/src/vendor/cigraph/vendor/infomap/src/utils/Stopwatch.h new file mode 100644 index 00000000000..9ee4210e953 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/Stopwatch.h @@ -0,0 +1,103 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef STOPWATCH_H_ +#define STOPWATCH_H_ + +#include +#include +#include +#include + +namespace infomap { + +class Stopwatch { +public: + using Clock = std::chrono::high_resolution_clock; + using TimeType = std::chrono::time_point; + + explicit Stopwatch(bool startImmediately) + : m_start(now()), m_stop(now()), m_running(false) + { + if (startImmediately) { + start(); + } + } + + void start() + { + m_start = Clock::now(); + m_running = true; + } + + void reset() + { + if (m_running) + m_start = Clock::now(); + } + + void stop() + { + if (m_running) { + m_stop = Clock::now(); + m_running = false; + } + } + + TimeType getCurrentTimePoint() const + { + return m_running ? Clock::now() : m_stop; + } + + double getElapsedTimeInSec() const + { + std::chrono::duration diff = getCurrentTimePoint() - m_start; + return diff.count(); + } + + double getElapsedTimeInMilliSec() const + { + std::chrono::duration diff = getCurrentTimePoint() - m_start; + return diff.count(); + } + + static TimeType now() + { + return Clock::now(); + } + + friend std::ostream& operator<<(std::ostream& out, const Stopwatch& stopwatch) + { + auto temp = static_cast(std::floor(stopwatch.getElapsedTimeInMilliSec())); + if (temp > 60'000) { + if (temp > 3600'000) { + if (temp > 86'400'000) { + out << temp / 86'400'000 << "d "; + temp %= 86'400'000; + } + out << temp / 3600'000 << "h "; + temp %= 3600'000; + } + out << temp / 60'000 << "m "; + temp %= 60'000; + out << temp * 1.0 / 1000 << "s"; + } else { + out << stopwatch.getElapsedTimeInSec() << "s"; + } + return out; + } + +private: + TimeType m_start, m_stop; + bool m_running; +}; + +} // namespace infomap + +#endif // STOPWATCH_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/VectorMap.h b/src/vendor/cigraph/vendor/infomap/src/utils/VectorMap.h new file mode 100644 index 00000000000..63994bc92ac --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/VectorMap.h @@ -0,0 +1,82 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef VECTOR_MAP_H_ +#define VECTOR_MAP_H_ + +#include +#include +#include + +namespace infomap { + +template +class VectorMap { +public: + VectorMap(unsigned int capacity = 0) + : m_capacity(capacity), + m_values(capacity), + m_redirect(capacity, 0), + m_maxOffset(std::numeric_limits::max() - 1 - capacity) { } + + void startRound() + { + if (m_size > 0) { + m_offset += m_capacity; + m_size = 0; + } + if (m_offset > m_maxOffset) { + m_redirect.assign(m_capacity, 0); + m_offset = 1; + } + } + + void add(unsigned int index, T value) + { + if (isSet(index)) { + m_values[m_redirect[index] - m_offset] += value; + } else { + m_redirect[index] = m_offset + m_size; + m_values[m_size] = value; + ++m_size; + } + } + + bool isSet(unsigned int index) + { + return m_redirect[index] >= m_offset; + } + + unsigned int size() + { + return m_size; + } + + T& operator[](unsigned int index) + { + return m_values[m_redirect[index] - m_offset]; + } + + std::vector& values() + { + return m_values; + } + +private: + unsigned int m_capacity = 0; + std::vector m_values; + std::vector m_redirect; + unsigned int m_maxOffset = std::numeric_limits::max() - 1; + unsigned int m_offset = 1; + unsigned int m_size = 0; +}; + +} // namespace infomap + +#endif // VECTOR_MAP_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/convert.h b/src/vendor/cigraph/vendor/infomap/src/utils/convert.h new file mode 100644 index 00000000000..f8e5077a268 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/convert.h @@ -0,0 +1,216 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef CONVERT_H_ +#define CONVERT_H_ + +#include +#include +#include +#include +#include // std::locale, std::tolower +#include +#include + +namespace infomap { + +template +struct TypeInfo { + static bool isNumeric() { return false; } +}; +template <> +struct TypeInfo { + static bool isNumeric() { return false; } +}; +template <> +struct TypeInfo { + static bool isNumeric() { return true; } +}; +template <> +struct TypeInfo { + static bool isNumeric() { return true; } +}; +template <> +struct TypeInfo { + static bool isNumeric() { return true; } +}; + +namespace io { + + inline std::string tolower(std::string str) + { + std::locale loc; + for (char& c : str) + c = std::tolower(c, loc); + return str; + } + + template + inline std::string stringify(T& x) + { + std::ostringstream o; + if (!(o << x)) + throw std::runtime_error((o << "stringify(" << x << ")", o.str())); + return o.str(); + } + + template <> + inline std::string stringify(bool& x) + { + return x ? "true" : "false"; + } + + template + inline std::string stringify(const Container& cont, const std::string& delimiter) + { + std::ostringstream o; + if (cont.empty()) + return ""; + unsigned int maxIndex = cont.size() - 1; + for (unsigned int i = 0; i < maxIndex; ++i) { + if (!(o << cont[i])) + throw std::runtime_error((o << "stringify(container[" << i << "])", o.str())); + o << delimiter; + } + if (!(o << cont[maxIndex])) + throw std::runtime_error((o << "stringify(container[" << maxIndex << "])", o.str())); + return o.str(); + } + + struct InsensitiveCompare { + bool operator()(const std::string& a, const std::string& b) const + { + auto lhs = a.begin(); + auto rhs = b.begin(); + + std::locale loc; + for (; lhs != a.end() && rhs != b.end(); ++lhs, ++rhs) { + auto lhs_val = std::tolower(*lhs, loc); + auto rhs_val = std::tolower(*rhs, loc); + + if (lhs_val != rhs_val) + return lhs_val < rhs_val; + } + + return (rhs != b.end()); + } + }; + + inline std::vector& split(const std::string& s, char delim, std::vector& items) + { + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + if (item.length() > 0) { + items.push_back(item); + } + } + return items; + } + + inline std::vector split(const std::string& s, char delim) + { + std::vector items; + split(s, delim, items); + return items; + } + + class Str { + public: + Str() = default; + template + Str& operator<<(const T& t) + { + m_oss << stringify(t); + return *this; + } + Str& operator<<(std::ostream& (*f)(std::ostream&)) + { + m_oss << f; + return *this; + } + operator std::string() const + { + return m_oss.str(); + } + + private: + std::ostringstream m_oss; + }; + + template + inline bool stringToValue(std::string const& str, T& value) + { + std::istringstream istream(str); + return !!(istream >> value); + } + + template <> + inline bool stringToValue(std::string const& str, unsigned int& value) + { + std::istringstream istream(str); + int target = 0; + istream >> target; + if (target < 0) return false; + value = target; + return true; + } + + template <> + inline bool stringToValue(std::string const& str, unsigned long& value) + { + std::istringstream istream(str); + int target = 0; + istream >> target; + if (target < 0) return false; + value = target; + return true; + } + + inline std::string firstWord(const std::string& line) + { + std::istringstream ss; + std::string buf; + ss.str(line); + ss >> buf; + return buf; + } + + template + inline std::string padValue(T value, const std::string::size_type size, bool rightAligned = true, const char paddingChar = ' ') + { + std::string valStr = stringify(value); + if (size == valStr.size()) + return valStr; + if (size < valStr.size()) + return valStr.substr(0, size); + + if (!rightAligned) + return valStr.append(size - valStr.size(), paddingChar); + + return std::string(size - valStr.size(), paddingChar).append(valStr); + } + + inline std::string toPrecision(double value, unsigned int precision = 10, bool fixed = false) + { + std::ostringstream o; + if (fixed) + o << std::fixed << std::setprecision(static_cast(precision)); + else + o << std::setprecision(static_cast(precision)); + if (!(o << value)) + throw std::runtime_error((o << "stringify(" << value << ")", o.str())); + return o.str(); + } + +} // namespace io + +} // namespace infomap + +#endif // CONVERT_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/utils/infomath.h b/src/vendor/cigraph/vendor/infomap/src/utils/infomath.h new file mode 100644 index 00000000000..7c09add1385 --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/utils/infomath.h @@ -0,0 +1,57 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef INFOMATH_H_ +#define INFOMATH_H_ + +#include +#include + +namespace infomap { +namespace infomath { + + using std::log2; + + inline double plogp(double p) + { + return p > 0.0 ? p * log2(p) : 0.0; + } + + inline double isEqual(double a, double b, double tol = 1e-8) + { + return std::abs(a - b) <= tol; + } + + /** + * Tsallis entropy S_q of a uniform probability distribution of length n + */ + inline double tsallisEntropyUniform(double n, double q = 1) + { + if (isEqual(q, 1)) { + return std::log2(n); + } + return 1 / (q - 1) * (1 - pow(n, (1 - q))) / std::log(2); + } + + /** + * Interpolate from linear (q = 0) to log (q = 1) + * linlog(k, 0) = k + * linlog(k, 1) = log2(k) + */ + inline double linlog(double k, double q = 1) + { + double baseCorrection = q <= 1 ? (1 - q) * std::log(2) + q : 1; + double offsetCorrection = q <= 1 ? 1 - q : 0; + return tsallisEntropyUniform(k, q) * baseCorrection + offsetCorrection; + } + +} // namespace infomath +} // namespace infomap + +#endif // INFOMATH_H_ diff --git a/src/vendor/cigraph/vendor/infomap/src/version.h b/src/vendor/cigraph/vendor/infomap/src/version.h new file mode 100644 index 00000000000..0671d20162b --- /dev/null +++ b/src/vendor/cigraph/vendor/infomap/src/version.h @@ -0,0 +1,19 @@ +/******************************************************************************* + Infomap software package for multi-level network clustering + Copyright (c) 2013, 2014 Daniel Edler, Anton Holmgren, Martin Rosvall + + This file is part of the Infomap software package. + See file LICENSE_GPLv3.txt for full license details. + For more information, see + ******************************************************************************/ + +#ifndef VERSION_H_ +#define VERSION_H_ + +namespace infomap { + +const char* const INFOMAP_VERSION = "2.8.0"; + +} + +#endif // VERSION_H_ diff --git a/src/vendor/cigraph/vendor/lapack/fortran_intrinsics.c b/src/vendor/cigraph/vendor/lapack/fortran_intrinsics.c index e6bb599afc8..e0b126f0a61 100644 --- a/src/vendor/cigraph/vendor/lapack/fortran_intrinsics.c +++ b/src/vendor/cigraph/vendor/lapack/fortran_intrinsics.c @@ -1,6 +1,5 @@ -/* -*- mode: C -*- */ /* - IGraph library. + igraph library. Copyright (C) 2011-12 Gabor Csardi 334 Harvard street, Cambridge MA, 02139 USA diff --git a/src/vendor/cigraph/vendor/mini-gmp/mini-gmp.c b/src/vendor/cigraph/vendor/mini-gmp/mini-gmp.c index df99e070ba8..4540fd93c03 100644 --- a/src/vendor/cigraph/vendor/mini-gmp/mini-gmp.c +++ b/src/vendor/cigraph/vendor/mini-gmp/mini-gmp.c @@ -2710,6 +2710,66 @@ mpn_gcd_11 (mp_limb_t u, mp_limb_t v) return u << shift; } +mp_size_t +mpn_gcd (mp_ptr rp, mp_ptr up, mp_size_t un, mp_ptr vp, mp_size_t vn) +{ + assert (un >= vn); + assert (vn > 0); + assert (!GMP_MPN_OVERLAP_P (up, un, vp, vn)); + assert (vp[vn-1] > 0); + assert ((up[0] | vp[0]) & 1); + + if (un > vn) + mpn_div_qr (NULL, up, un, vp, vn); + + un = mpn_normalized_size (up, vn); + if (un == 0) + { + mpn_copyi (rp, vp, vn); + return vn; + } + + if (!(vp[0] & 1)) + MPN_PTR_SWAP (up, un, vp, vn); + + while (un > 1 || vn > 1) + { + int shift; + assert (vp[0] & 1); + + while (up[0] == 0) + { + up++; + un--; + } + gmp_ctz (shift, up[0]); + if (shift > 0) + { + gmp_assert_nocarry (mpn_rshift(up, up, un, shift)); + un -= (up[un-1] == 0); + } + + if (un < vn) + MPN_PTR_SWAP (up, un, vp, vn); + else if (un == vn) + { + int c = mpn_cmp (up, vp, un); + if (c == 0) + { + mpn_copyi (rp, up, un); + return un; + } + else if (c < 0) + MP_PTR_SWAP (up, vp); + } + + gmp_assert_nocarry (mpn_sub (up, up, un, vp, vn)); + un = mpn_normalized_size (up, un); + } + rp[0] = mpn_gcd_11 (up[0], vp[0]); + return 1; +} + unsigned long mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v) { @@ -2769,42 +2829,11 @@ mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v) if (tu->_mp_size < tv->_mp_size) mpz_swap (tu, tv); - mpz_tdiv_r (tu, tu, tv); - if (tu->_mp_size == 0) - { - mpz_swap (g, tv); - } - else - for (;;) - { - int c; - - mpz_make_odd (tu); - c = mpz_cmp (tu, tv); - if (c == 0) - { - mpz_swap (g, tu); - break; - } - if (c < 0) - mpz_swap (tu, tv); + tu->_mp_size = mpn_gcd (tu->_mp_d, tu->_mp_d, tu->_mp_size, tv->_mp_d, tv->_mp_size); + mpz_mul_2exp (g, tu, gz); - if (tv->_mp_size == 1) - { - mp_limb_t *gp; - - mpz_tdiv_r (tu, tu, tv); - gp = MPZ_REALLOC (g, 1); /* gp = mpz_limbs_modify (g, 1); */ - *gp = mpn_gcd_11 (tu->_mp_d[0], tv->_mp_d[0]); - - g->_mp_size = *gp != 0; /* mpz_limbs_finish (g, 1); */ - break; - } - mpz_sub (tu, tu, tv); - } mpz_clear (tu); mpz_clear (tv); - mpz_mul_2exp (g, g, gz); } void @@ -2813,6 +2842,7 @@ mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v) mpz_t tu, tv, s0, s1, t0, t1; mp_bitcnt_t uz, vz, gz; mp_bitcnt_t power; + int cmp; if (u->_mp_size == 0) { @@ -2964,12 +2994,21 @@ mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v) mpz_tdiv_q_2exp (t0, t0, 1); } - /* Arrange so that |s| < |u| / 2g */ + /* Choose small cofactors (they should generally satify + + |s| < |u| / 2g and |t| < |v| / 2g, + + with some documented exceptions). Always choose the smallest s, + if there are two choices for s with same absolute value, choose + the one with smallest corresponding t (this asymmetric condition + is needed to prefer s = 0, |t| = 1 when g = |a| = |b|). */ mpz_add (s1, s0, s1); - if (mpz_cmpabs (s0, s1) > 0) + mpz_sub (t1, t0, t1); + cmp = mpz_cmpabs (s0, s1); + if (cmp > 0 || (cmp == 0 && mpz_cmpabs (t0, t1) > 0)) { mpz_swap (s0, s1); - mpz_sub (t0, t0, t1); + mpz_swap (t0, t1); } if (u->_mp_size < 0) mpz_neg (s0, s0); @@ -4480,6 +4519,11 @@ mpz_import (mpz_t r, size_t count, int order, size_t size, int endian, assert (order == 1 || order == -1); assert (endian >= -1 && endian <= 1); + if (count == 0) + { + r->_mp_size = 0; + return; + } if (endian == 0) endian = gmp_detect_endian (); diff --git a/src/vendor/cigraph/vendor/mini-gmp/mini-gmp.h b/src/vendor/cigraph/vendor/mini-gmp/mini-gmp.h index 59c24cf5111..f28cb360ce1 100644 --- a/src/vendor/cigraph/vendor/mini-gmp/mini-gmp.h +++ b/src/vendor/cigraph/vendor/mini-gmp/mini-gmp.h @@ -105,6 +105,7 @@ void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t); void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t); int mpn_perfect_square_p (mp_srcptr, mp_size_t); mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t); +mp_size_t mpn_gcd (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t); mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int); mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int); diff --git a/src/vendor/cigraph/vendor/nanoflann/nanoflann.hpp b/src/vendor/cigraph/vendor/nanoflann/nanoflann.hpp new file mode 100644 index 00000000000..43fbded03f3 --- /dev/null +++ b/src/vendor/cigraph/vendor/nanoflann/nanoflann.hpp @@ -0,0 +1,2740 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * Copyright 2011-2025 Jose Luis Blanco (joseluisblancoc@gmail.com). + * All rights reserved. + * + * THE BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + +/** \mainpage nanoflann C++ API documentation + * nanoflann is a C++ header-only library for building KD-Trees, mostly + * optimized for 2D or 3D point clouds. + * + * nanoflann does not require compiling or installing, just an + * #include in your code. + * + * See: + * - [Online README](https://github.com/jlblancoc/nanoflann) + * - [C++ API documentation](https://jlblancoc.github.io/nanoflann/) + */ + +#pragma once + +#include +#include +#include +#include +#include // for abs() +#include +#include // for abs() +#include // std::reference_wrapper +#include +#include +#include // std::numeric_limits +#include +#include +#include +#include + +/** Library version: 0xMmP (M=Major,m=minor,P=patch) */ +#define NANOFLANN_VERSION 0x171 + +// Avoid conflicting declaration of min/max macros in Windows headers +#if !defined(NOMINMAX) && \ + (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64)) +#define NOMINMAX +#ifdef max +#undef max +#undef min +#endif +#endif +// Avoid conflicts with X11 headers +#ifdef None +#undef None +#endif + +namespace nanoflann +{ +/** @addtogroup nanoflann_grp nanoflann C++ library for KD-trees + * @{ */ + +/** the PI constant (required to avoid MSVC missing symbols) */ +template +T pi_const() +{ + return static_cast(3.14159265358979323846); +} + +/** + * Traits if object is resizable and assignable (typically has a resize | assign + * method) + */ +template +struct has_resize : std::false_type +{ +}; + +template +struct has_resize().resize(1), 0)> + : std::true_type +{ +}; + +template +struct has_assign : std::false_type +{ +}; + +template +struct has_assign().assign(1, 0), 0)> + : std::true_type +{ +}; + +/** + * Free function to resize a resizable object + */ +template +inline typename std::enable_if::value, void>::type resize( + Container& c, const size_t nElements) +{ + c.resize(nElements); +} + +/** + * Free function that has no effects on non resizable containers (e.g. + * std::array) It raises an exception if the expected size does not match + */ +template +inline typename std::enable_if::value, void>::type + resize(Container& c, const size_t nElements) +{ + if (nElements != c.size()) + throw std::logic_error("Try to change the size of a std::array."); +} + +/** + * Free function to assign to a container + */ +template +inline typename std::enable_if::value, void>::type assign( + Container& c, const size_t nElements, const T& value) +{ + c.assign(nElements, value); +} + +/** + * Free function to assign to a std::array + */ +template +inline typename std::enable_if::value, void>::type + assign(Container& c, const size_t nElements, const T& value) +{ + for (size_t i = 0; i < nElements; i++) c[i] = value; +} + +/** operator "<" for std::sort() */ +struct IndexDist_Sorter +{ + /** PairType will be typically: ResultItem */ + template + bool operator()(const PairType& p1, const PairType& p2) const + { + return p1.second < p2.second; + } +}; + +/** + * Each result element in RadiusResultSet. Note that distances and indices + * are named `first` and `second` to keep backward-compatibility with the + * `std::pair<>` type used in the past. In contrast, this structure is ensured + * to be `std::is_standard_layout` so it can be used in wrappers to other + * languages. + * See: https://github.com/jlblancoc/nanoflann/issues/166 + */ +template +struct ResultItem +{ + ResultItem() = default; + ResultItem(const IndexType index, const DistanceType distance) + : first(index), second(distance) + { + } + + IndexType first; //!< Index of the sample in the dataset + DistanceType second; //!< Distance from sample to query point +}; + +/** @addtogroup result_sets_grp Result set classes + * @{ */ + +/** Result set for KNN searches (N-closest neighbors) */ +template < + typename _DistanceType, typename _IndexType = size_t, + typename _CountType = size_t> +class KNNResultSet +{ + public: + using DistanceType = _DistanceType; + using IndexType = _IndexType; + using CountType = _CountType; + + private: + IndexType* indices; + DistanceType* dists; + CountType capacity; + CountType count; + + public: + explicit KNNResultSet(CountType capacity_) + : indices(nullptr), dists(nullptr), capacity(capacity_), count(0) + { + } + + void init(IndexType* indices_, DistanceType* dists_) + { + indices = indices_; + dists = dists_; + count = 0; + } + + CountType size() const { return count; } + bool empty() const { return count == 0; } + bool full() const { return count == capacity; } + + /** + * Called during search to add an element matching the criteria. + * @return true if the search should be continued, false if the results are + * sufficient + */ + bool addPoint(DistanceType dist, IndexType index) + { + CountType i; + for (i = count; i > 0; --i) + { + /** If defined and two points have the same distance, the one with + * the lowest-index will be returned first. */ +#ifdef NANOFLANN_FIRST_MATCH + if ((dists[i - 1] > dist) || + ((dist == dists[i - 1]) && (indices[i - 1] > index))) + { +#else + if (dists[i - 1] > dist) + { +#endif + if (i < capacity) + { + dists[i] = dists[i - 1]; + indices[i] = indices[i - 1]; + } + } + else + break; + } + if (i < capacity) + { + dists[i] = dist; + indices[i] = index; + } + if (count < capacity) count++; + + // tell caller that the search shall continue + return true; + } + + //! Returns the worst distance among found solutions if the search result is + //! full, or the maximum possible distance, if not full yet. + DistanceType worstDist() const + { + return (count < capacity || !count) + ? std::numeric_limits::max() + : dists[count - 1]; + } + + void sort() + { + // already sorted + } +}; + +/** Result set for RKNN searches (N-closest neighbors with a maximum radius) */ +template < + typename _DistanceType, typename _IndexType = size_t, + typename _CountType = size_t> +class RKNNResultSet +{ + public: + using DistanceType = _DistanceType; + using IndexType = _IndexType; + using CountType = _CountType; + + private: + IndexType* indices; + DistanceType* dists; + CountType capacity; + CountType count; + DistanceType maximumSearchDistanceSquared; + + public: + explicit RKNNResultSet( + CountType capacity_, DistanceType maximumSearchDistanceSquared_) + : indices(nullptr), + dists(nullptr), + capacity(capacity_), + count(0), + maximumSearchDistanceSquared(maximumSearchDistanceSquared_) + { + } + + void init(IndexType* indices_, DistanceType* dists_) + { + indices = indices_; + dists = dists_; + count = 0; + if (capacity) dists[capacity - 1] = maximumSearchDistanceSquared; + } + + CountType size() const { return count; } + bool empty() const { return count == 0; } + bool full() const { return count == capacity; } + + /** + * Called during search to add an element matching the criteria. + * @return true if the search should be continued, false if the results are + * sufficient + */ + bool addPoint(DistanceType dist, IndexType index) + { + CountType i; + for (i = count; i > 0; --i) + { + /** If defined and two points have the same distance, the one with + * the lowest-index will be returned first. */ +#ifdef NANOFLANN_FIRST_MATCH + if ((dists[i - 1] > dist) || + ((dist == dists[i - 1]) && (indices[i - 1] > index))) + { +#else + if (dists[i - 1] > dist) + { +#endif + if (i < capacity) + { + dists[i] = dists[i - 1]; + indices[i] = indices[i - 1]; + } + } + else + break; + } + if (i < capacity) + { + dists[i] = dist; + indices[i] = index; + } + if (count < capacity) count++; + + // tell caller that the search shall continue + return true; + } + + //! Returns the worst distance among found solutions if the search result is + //! full, or the maximum possible distance, if not full yet. + DistanceType worstDist() const + { + return (count < capacity || !count) ? maximumSearchDistanceSquared + : dists[count - 1]; + } + + void sort() + { + // already sorted + } +}; + +/** + * A result-set class used when performing a radius based search. + */ +template +class RadiusResultSet +{ + public: + using DistanceType = _DistanceType; + using IndexType = _IndexType; + + public: + const DistanceType radius; + + std::vector>& m_indices_dists; + + explicit RadiusResultSet( + DistanceType radius_, + std::vector>& indices_dists) + : radius(radius_), m_indices_dists(indices_dists) + { + init(); + } + + void init() { clear(); } + void clear() { m_indices_dists.clear(); } + + size_t size() const { return m_indices_dists.size(); } + size_t empty() const { return m_indices_dists.empty(); } + + bool full() const { return true; } + + /** + * Called during search to add an element matching the criteria. + * @return true if the search should be continued, false if the results are + * sufficient + */ + bool addPoint(DistanceType dist, IndexType index) + { + if (dist < radius) m_indices_dists.emplace_back(index, dist); + return true; + } + + DistanceType worstDist() const { return radius; } + + /** + * Find the worst result (farthest neighbor) without copying or sorting + * Pre-conditions: size() > 0 + */ + ResultItem worst_item() const + { + if (m_indices_dists.empty()) + throw std::runtime_error( + "Cannot invoke RadiusResultSet::worst_item() on " + "an empty list of results."); + auto it = std::max_element( + m_indices_dists.begin(), m_indices_dists.end(), IndexDist_Sorter()); + return *it; + } + + void sort() + { + std::sort( + m_indices_dists.begin(), m_indices_dists.end(), IndexDist_Sorter()); + } +}; + +/** @} */ + +/** @addtogroup loadsave_grp Load/save auxiliary functions + * @{ */ +template +void save_value(std::ostream& stream, const T& value) +{ + stream.write(reinterpret_cast(&value), sizeof(T)); +} + +template +void save_value(std::ostream& stream, const std::vector& value) +{ + size_t size = value.size(); + stream.write(reinterpret_cast(&size), sizeof(size_t)); + stream.write(reinterpret_cast(value.data()), sizeof(T) * size); +} + +template +void load_value(std::istream& stream, T& value) +{ + stream.read(reinterpret_cast(&value), sizeof(T)); +} + +template +void load_value(std::istream& stream, std::vector& value) +{ + size_t size; + stream.read(reinterpret_cast(&size), sizeof(size_t)); + value.resize(size); + stream.read(reinterpret_cast(value.data()), sizeof(T) * size); +} +/** @} */ + +/** @addtogroup metric_grp Metric (distance) classes + * @{ */ + +struct Metric +{ +}; + +/** Manhattan distance functor (generic version, optimized for + * high-dimensionality data sets). Corresponding distance traits: + * nanoflann::metric_L1 + * + * \tparam T Type of the elements (e.g. double, float, uint8_t) + * \tparam DataSource Source of the data, i.e. where the vectors are stored + * \tparam _DistanceType Type of distance variables (must be signed) + * \tparam IndexType Type of the arguments with which the data can be + * accessed (e.g. float, double, int64_t, T*) + */ +template < + class T, class DataSource, typename _DistanceType = T, + typename IndexType = size_t> +struct L1_Adaptor +{ + using ElementType = T; + using DistanceType = _DistanceType; + + const DataSource& data_source; + + L1_Adaptor(const DataSource& _data_source) : data_source(_data_source) {} + + DistanceType evalMetric( + const T* a, const IndexType b_idx, size_t size, + DistanceType worst_dist = -1) const + { + DistanceType result = DistanceType(); + const T* last = a + size; + const T* lastgroup = last - 3; + size_t d = 0; + + /* Process 4 items with each loop for efficiency. */ + while (a < lastgroup) + { + const DistanceType diff0 = + std::abs(a[0] - data_source.kdtree_get_pt(b_idx, d++)); + const DistanceType diff1 = + std::abs(a[1] - data_source.kdtree_get_pt(b_idx, d++)); + const DistanceType diff2 = + std::abs(a[2] - data_source.kdtree_get_pt(b_idx, d++)); + const DistanceType diff3 = + std::abs(a[3] - data_source.kdtree_get_pt(b_idx, d++)); + result += diff0 + diff1 + diff2 + diff3; + a += 4; + if ((worst_dist > 0) && (result > worst_dist)) { return result; } + } + /* Process last 0-3 components. Not needed for standard vector lengths. + */ + while (a < last) + { + result += std::abs(*a++ - data_source.kdtree_get_pt(b_idx, d++)); + } + return result; + } + + template + DistanceType accum_dist(const U a, const V b, const size_t) const + { + return std::abs(a - b); + } +}; + +/** **Squared** Euclidean distance functor (generic version, optimized for + * high-dimensionality data sets). Corresponding distance traits: + * nanoflann::metric_L2 + * + * \tparam T Type of the elements (e.g. double, float, uint8_t) + * \tparam DataSource Source of the data, i.e. where the vectors are stored + * \tparam _DistanceType Type of distance variables (must be signed) + * \tparam IndexType Type of the arguments with which the data can be + * accessed (e.g. float, double, int64_t, T*) + */ +template < + class T, class DataSource, typename _DistanceType = T, + typename IndexType = size_t> +struct L2_Adaptor +{ + using ElementType = T; + using DistanceType = _DistanceType; + + const DataSource& data_source; + + L2_Adaptor(const DataSource& _data_source) : data_source(_data_source) {} + + DistanceType evalMetric( + const T* a, const IndexType b_idx, size_t size, + DistanceType worst_dist = -1) const + { + DistanceType result = DistanceType(); + const T* last = a + size; + const T* lastgroup = last - 3; + size_t d = 0; + + /* Process 4 items with each loop for efficiency. */ + while (a < lastgroup) + { + const DistanceType diff0 = + a[0] - data_source.kdtree_get_pt(b_idx, d++); + const DistanceType diff1 = + a[1] - data_source.kdtree_get_pt(b_idx, d++); + const DistanceType diff2 = + a[2] - data_source.kdtree_get_pt(b_idx, d++); + const DistanceType diff3 = + a[3] - data_source.kdtree_get_pt(b_idx, d++); + result += + diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3; + a += 4; + if ((worst_dist > 0) && (result > worst_dist)) { return result; } + } + /* Process last 0-3 components. Not needed for standard vector lengths. + */ + while (a < last) + { + const DistanceType diff0 = + *a++ - data_source.kdtree_get_pt(b_idx, d++); + result += diff0 * diff0; + } + return result; + } + + template + DistanceType accum_dist(const U a, const V b, const size_t) const + { + return (a - b) * (a - b); + } +}; + +/** **Squared** Euclidean (L2) distance functor (suitable for low-dimensionality + * datasets, like 2D or 3D point clouds) Corresponding distance traits: + * nanoflann::metric_L2_Simple + * + * \tparam T Type of the elements (e.g. double, float, uint8_t) + * \tparam DataSource Source of the data, i.e. where the vectors are stored + * \tparam _DistanceType Type of distance variables (must be signed) + * \tparam IndexType Type of the arguments with which the data can be + * accessed (e.g. float, double, int64_t, T*) + */ +template < + class T, class DataSource, typename _DistanceType = T, + typename IndexType = size_t> +struct L2_Simple_Adaptor +{ + using ElementType = T; + using DistanceType = _DistanceType; + + const DataSource& data_source; + + L2_Simple_Adaptor(const DataSource& _data_source) + : data_source(_data_source) + { + } + + DistanceType evalMetric( + const T* a, const IndexType b_idx, size_t size) const + { + DistanceType result = DistanceType(); + for (size_t i = 0; i < size; ++i) + { + const DistanceType diff = + a[i] - data_source.kdtree_get_pt(b_idx, i); + result += diff * diff; + } + return result; + } + + template + DistanceType accum_dist(const U a, const V b, const size_t) const + { + return (a - b) * (a - b); + } +}; + +/** SO2 distance functor + * Corresponding distance traits: nanoflann::metric_SO2 + * + * \tparam T Type of the elements (e.g. double, float, uint8_t) + * \tparam DataSource Source of the data, i.e. where the vectors are stored + * \tparam _DistanceType Type of distance variables (must be signed) (e.g. + * float, double) orientation is constrained to be in [-pi, pi] + * \tparam IndexType Type of the arguments with which the data can be + * accessed (e.g. float, double, int64_t, T*) + */ +template < + class T, class DataSource, typename _DistanceType = T, + typename IndexType = size_t> +struct SO2_Adaptor +{ + using ElementType = T; + using DistanceType = _DistanceType; + + const DataSource& data_source; + + SO2_Adaptor(const DataSource& _data_source) : data_source(_data_source) {} + + DistanceType evalMetric( + const T* a, const IndexType b_idx, size_t size) const + { + return accum_dist( + a[size - 1], data_source.kdtree_get_pt(b_idx, size - 1), size - 1); + } + + /** Note: this assumes that input angles are already in the range [-pi,pi] + */ + template + DistanceType accum_dist(const U a, const V b, const size_t) const + { + DistanceType result = DistanceType(); + DistanceType PI = pi_const(); + result = b - a; + if (result > PI) + result -= 2 * PI; + else if (result < -PI) + result += 2 * PI; + return result; + } +}; + +/** SO3 distance functor (Uses L2_Simple) + * Corresponding distance traits: nanoflann::metric_SO3 + * + * \tparam T Type of the elements (e.g. double, float, uint8_t) + * \tparam DataSource Source of the data, i.e. where the vectors are stored + * \tparam _DistanceType Type of distance variables (must be signed) (e.g. + * float, double) + * \tparam IndexType Type of the arguments with which the data can be + * accessed (e.g. float, double, int64_t, T*) + */ +template < + class T, class DataSource, typename _DistanceType = T, + typename IndexType = size_t> +struct SO3_Adaptor +{ + using ElementType = T; + using DistanceType = _DistanceType; + + L2_Simple_Adaptor + distance_L2_Simple; + + SO3_Adaptor(const DataSource& _data_source) + : distance_L2_Simple(_data_source) + { + } + + DistanceType evalMetric( + const T* a, const IndexType b_idx, size_t size) const + { + return distance_L2_Simple.evalMetric(a, b_idx, size); + } + + template + DistanceType accum_dist(const U a, const V b, const size_t idx) const + { + return distance_L2_Simple.accum_dist(a, b, idx); + } +}; + +/** Metaprogramming helper traits class for the L1 (Manhattan) metric */ +struct metric_L1 : public Metric +{ + template + struct traits + { + using distance_t = L1_Adaptor; + }; +}; +/** Metaprogramming helper traits class for the L2 (Euclidean) **squared** + * distance metric */ +struct metric_L2 : public Metric +{ + template + struct traits + { + using distance_t = L2_Adaptor; + }; +}; +/** Metaprogramming helper traits class for the L2_simple (Euclidean) + * **squared** distance metric */ +struct metric_L2_Simple : public Metric +{ + template + struct traits + { + using distance_t = L2_Simple_Adaptor; + }; +}; +/** Metaprogramming helper traits class for the SO3_InnerProdQuat metric */ +struct metric_SO2 : public Metric +{ + template + struct traits + { + using distance_t = SO2_Adaptor; + }; +}; +/** Metaprogramming helper traits class for the SO3_InnerProdQuat metric */ +struct metric_SO3 : public Metric +{ + template + struct traits + { + using distance_t = SO3_Adaptor; + }; +}; + +/** @} */ + +/** @addtogroup param_grp Parameter structs + * @{ */ + +enum class KDTreeSingleIndexAdaptorFlags +{ + None = 0, + SkipInitialBuildIndex = 1 +}; + +inline std::underlying_type::type operator&( + KDTreeSingleIndexAdaptorFlags lhs, KDTreeSingleIndexAdaptorFlags rhs) +{ + using underlying = + typename std::underlying_type::type; + return static_cast(lhs) & static_cast(rhs); +} + +/** Parameters (see README.md) */ +struct KDTreeSingleIndexAdaptorParams +{ + KDTreeSingleIndexAdaptorParams( + size_t _leaf_max_size = 10, + KDTreeSingleIndexAdaptorFlags _flags = + KDTreeSingleIndexAdaptorFlags::None, + unsigned int _n_thread_build = 1) + : leaf_max_size(_leaf_max_size), + flags(_flags), + n_thread_build(_n_thread_build) + { + } + + size_t leaf_max_size; + KDTreeSingleIndexAdaptorFlags flags; + unsigned int n_thread_build; +}; + +/** Search options for KDTreeSingleIndexAdaptor::findNeighbors() */ +struct SearchParameters +{ + SearchParameters(float eps_ = 0, bool sorted_ = true) + : eps(eps_), sorted(sorted_) + { + } + + float eps; //!< search for eps-approximate neighbours (default: 0) + bool sorted; //!< only for radius search, require neighbours sorted by + //!< distance (default: true) +}; +/** @} */ + +/** @addtogroup memalloc_grp Memory allocation + * @{ */ + +/** + * Pooled storage allocator + * + * The following routines allow for the efficient allocation of storage in + * small chunks from a specified pool. Rather than allowing each structure + * to be freed individually, an entire pool of storage is freed at once. + * This method has two advantages over just using malloc() and free(). First, + * it is far more efficient for allocating small objects, as there is + * no overhead for remembering all the information needed to free each + * object or consolidating fragmented memory. Second, the decision about + * how long to keep an object is made at the time of allocation, and there + * is no need to track down all the objects to free them. + * + */ +class PooledAllocator +{ + static constexpr size_t WORDSIZE = 16; // WORDSIZE must >= 8 + static constexpr size_t BLOCKSIZE = 8192; + + /* We maintain memory alignment to word boundaries by requiring that all + allocations be in multiples of the machine wordsize. */ + /* Size of machine word in bytes. Must be power of 2. */ + /* Minimum number of bytes requested at a time from the system. Must be + * multiple of WORDSIZE. */ + + using Size = size_t; + + Size remaining_ = 0; //!< Number of bytes left in current block of storage + void* base_ = nullptr; //!< Pointer to base of current block of storage + void* loc_ = nullptr; //!< Current location in block to next allocate + + void internal_init() + { + remaining_ = 0; + base_ = nullptr; + usedMemory = 0; + wastedMemory = 0; + } + + public: + Size usedMemory = 0; + Size wastedMemory = 0; + + /** + Default constructor. Initializes a new pool. + */ + PooledAllocator() { internal_init(); } + + /** + * Destructor. Frees all the memory allocated in this pool. + */ + ~PooledAllocator() { free_all(); } + + /** Frees all allocated memory chunks */ + void free_all() + { + while (base_ != nullptr) + { + // Get pointer to prev block + void* prev = *(static_cast(base_)); + ::free(base_); + base_ = prev; + } + internal_init(); + } + + /** + * Returns a pointer to a piece of new memory of the given size in bytes + * allocated from the pool. + */ + void* malloc(const size_t req_size) + { + /* Round size up to a multiple of wordsize. The following expression + only works for WORDSIZE that is a power of 2, by masking last bits + of incremented size to zero. + */ + const Size size = (req_size + (WORDSIZE - 1)) & ~(WORDSIZE - 1); + + /* Check whether a new block must be allocated. Note that the first + word of a block is reserved for a pointer to the previous block. + */ + if (size > remaining_) + { + wastedMemory += remaining_; + + /* Allocate new storage. */ + const Size blocksize = + size > BLOCKSIZE ? size + WORDSIZE : BLOCKSIZE + WORDSIZE; + + // use the standard C malloc to allocate memory + void* m = ::malloc(blocksize); + if (!m) + { + throw std::bad_alloc(); + } + + /* Fill first word of new block with pointer to previous block. */ + static_cast(m)[0] = base_; + base_ = m; + + remaining_ = blocksize - WORDSIZE; + loc_ = static_cast(m) + WORDSIZE; + } + void* rloc = loc_; + loc_ = static_cast(loc_) + size; + remaining_ -= size; + + usedMemory += size; + + return rloc; + } + + /** + * Allocates (using this pool) a generic type T. + * + * Params: + * count = number of instances to allocate. + * Returns: pointer (of type T*) to memory buffer + */ + template + T* allocate(const size_t count = 1) + { + T* mem = static_cast(this->malloc(sizeof(T) * count)); + return mem; + } +}; +/** @} */ + +/** @addtogroup nanoflann_metaprog_grp Auxiliary metaprogramming stuff + * @{ */ + +/** Used to declare fixed-size arrays when DIM>0, dynamically-allocated vectors + * when DIM=-1. Fixed size version for a generic DIM: + */ +template +struct array_or_vector +{ + using type = std::array; +}; +/** Dynamic size version */ +template +struct array_or_vector<-1, T> +{ + using type = std::vector; +}; + +/** @} */ + +/** kd-tree base-class + * + * Contains the member functions common to the classes KDTreeSingleIndexAdaptor + * and KDTreeSingleIndexDynamicAdaptor_. + * + * \tparam Derived The name of the class which inherits this class. + * \tparam DatasetAdaptor The user-provided adaptor, which must be ensured to + * have a lifetime equal or longer than the instance of this class. + * \tparam Distance The distance metric to use, these are all classes derived + * from nanoflann::Metric + * \tparam DIM Dimensionality of data points (e.g. 3 for 3D points) + * \tparam IndexType Type of the arguments with which the data can be + * accessed (e.g. float, double, int64_t, T*) + */ +template < + class Derived, typename Distance, class DatasetAdaptor, int32_t DIM = -1, + typename index_t = uint32_t> +class KDTreeBaseClass +{ + public: + /** Frees the previously-built index. Automatically called within + * buildIndex(). */ + void freeIndex(Derived& obj) + { + obj.pool_.free_all(); + obj.root_node_ = nullptr; + obj.size_at_index_build_ = 0; + } + + using ElementType = typename Distance::ElementType; + using DistanceType = typename Distance::DistanceType; + using IndexType = index_t; + + /** + * Array of indices to vectors in the dataset_. + */ + std::vector vAcc_; + + using Offset = typename decltype(vAcc_)::size_type; + using Size = typename decltype(vAcc_)::size_type; + using Dimension = int32_t; + + /*--------------------------- + * Internal Data Structures + * --------------------------*/ + struct Node + { + /** Union used because a node can be either a LEAF node or a non-leaf + * node, so both data fields are never used simultaneously */ + union + { + struct leaf + { + Offset left, right; //!< Indices of points in leaf node + } lr; + struct nonleaf + { + Dimension divfeat; //!< Dimension used for subdivision. + /// The values used for subdivision. + DistanceType divlow, divhigh; + } sub; + } node_type; + + /** Child nodes (both=nullptr mean its a leaf node) */ + Node *child1 = nullptr, *child2 = nullptr; + }; + + using NodePtr = Node*; + using NodeConstPtr = const Node*; + + struct Interval + { + ElementType low, high; + }; + + NodePtr root_node_ = nullptr; + + Size leaf_max_size_ = 0; + + /// Number of thread for concurrent tree build + Size n_thread_build_ = 1; + /// Number of current points in the dataset + Size size_ = 0; + /// Number of points in the dataset when the index was built + Size size_at_index_build_ = 0; + Dimension dim_ = 0; //!< Dimensionality of each data point + + /** Define "BoundingBox" as a fixed-size or variable-size container + * depending on "DIM" */ + using BoundingBox = typename array_or_vector::type; + + /** Define "distance_vector_t" as a fixed-size or variable-size container + * depending on "DIM" */ + using distance_vector_t = typename array_or_vector::type; + + /** The KD-tree used to find neighbours */ + BoundingBox root_bbox_; + + /** + * Pooled memory allocator. + * + * Using a pooled memory allocator is more efficient + * than allocating memory directly when there is a large + * number small of memory allocations. + */ + PooledAllocator pool_; + + /** Returns number of points in dataset */ + Size size(const Derived& obj) const { return obj.size_; } + + /** Returns the length of each point in the dataset */ + Size veclen(const Derived& obj) const { return DIM > 0 ? DIM : obj.dim; } + + /// Helper accessor to the dataset points: + ElementType dataset_get( + const Derived& obj, IndexType element, Dimension component) const + { + return obj.dataset_.kdtree_get_pt(element, component); + } + + /** + * Computes the index memory usage + * Returns: memory used by the index + */ + Size usedMemory(const Derived& obj) const + { + return obj.pool_.usedMemory + obj.pool_.wastedMemory + + obj.dataset_.kdtree_get_point_count() * + sizeof(IndexType); // pool memory and vind array memory + } + + /** + * Compute the minimum and maximum element values in the specified dimension + */ + void computeMinMax( + const Derived& obj, Offset ind, Size count, Dimension element, + ElementType& min_elem, ElementType& max_elem) const + { + min_elem = dataset_get(obj, vAcc_[ind], element); + max_elem = min_elem; + for (Offset i = 1; i < count; ++i) + { + ElementType val = dataset_get(obj, vAcc_[ind + i], element); + if (val < min_elem) min_elem = val; + if (val > max_elem) max_elem = val; + } + } + + /** + * Create a tree node that subdivides the list of vecs from vind[first] + * to vind[last]. The routine is called recursively on each sublist. + * + * @param left index of the first vector + * @param right index of the last vector + * @param bbox bounding box used as input for splitting and output for parent node + */ + NodePtr divideTree( + Derived& obj, const Offset left, const Offset right, BoundingBox& bbox) + { + assert(left < obj.dataset_.kdtree_get_point_count()); + + NodePtr node = obj.pool_.template allocate(); // allocate memory + const auto dims = (DIM > 0 ? DIM : obj.dim_); + + /* If too few exemplars remain, then make this a leaf node. */ + if ((right - left) <= static_cast(obj.leaf_max_size_)) + { + node->child1 = node->child2 = nullptr; /* Mark as leaf node. */ + node->node_type.lr.left = left; + node->node_type.lr.right = right; + + // compute bounding-box of leaf points + for (Dimension i = 0; i < dims; ++i) + { + bbox[i].low = dataset_get(obj, obj.vAcc_[left], i); + bbox[i].high = dataset_get(obj, obj.vAcc_[left], i); + } + for (Offset k = left + 1; k < right; ++k) + { + for (Dimension i = 0; i < dims; ++i) + { + const auto val = dataset_get(obj, obj.vAcc_[k], i); + if (bbox[i].low > val) bbox[i].low = val; + if (bbox[i].high < val) bbox[i].high = val; + } + } + } + else + { + /* Determine the index, dimension and value for split plane */ + Offset idx; + Dimension cutfeat; + DistanceType cutval; + middleSplit_(obj, left, right - left, idx, cutfeat, cutval, bbox); + + node->node_type.sub.divfeat = cutfeat; + + /* Recurse on left */ + BoundingBox left_bbox(bbox); + left_bbox[cutfeat].high = cutval; + node->child1 = this->divideTree(obj, left, left + idx, left_bbox); + + /* Recurse on right */ + BoundingBox right_bbox(bbox); + right_bbox[cutfeat].low = cutval; + node->child2 = this->divideTree(obj, left + idx, right, right_bbox); + + node->node_type.sub.divlow = left_bbox[cutfeat].high; + node->node_type.sub.divhigh = right_bbox[cutfeat].low; + + for (Dimension i = 0; i < dims; ++i) + { + bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low); + bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high); + } + } + + return node; + } + + /** + * Create a tree node that subdivides the list of vecs from vind[first] to + * vind[last] concurrently. The routine is called recursively on each + * sublist. + * + * @param left index of the first vector + * @param right index of the last vector + * @param bbox bounding box used as input for splitting and output for parent node + * @param thread_count count of std::async threads + * @param mutex mutex for mempool allocation + */ + NodePtr divideTreeConcurrent( + Derived& obj, const Offset left, const Offset right, BoundingBox& bbox, + std::atomic& thread_count, std::mutex& mutex) + { + std::unique_lock lock(mutex); + NodePtr node = obj.pool_.template allocate(); // allocate memory + lock.unlock(); + + const auto dims = (DIM > 0 ? DIM : obj.dim_); + + /* If too few exemplars remain, then make this a leaf node. */ + if ((right - left) <= static_cast(obj.leaf_max_size_)) + { + node->child1 = node->child2 = nullptr; /* Mark as leaf node. */ + node->node_type.lr.left = left; + node->node_type.lr.right = right; + + // compute bounding-box of leaf points + for (Dimension i = 0; i < dims; ++i) + { + bbox[i].low = dataset_get(obj, obj.vAcc_[left], i); + bbox[i].high = dataset_get(obj, obj.vAcc_[left], i); + } + for (Offset k = left + 1; k < right; ++k) + { + for (Dimension i = 0; i < dims; ++i) + { + const auto val = dataset_get(obj, obj.vAcc_[k], i); + if (bbox[i].low > val) bbox[i].low = val; + if (bbox[i].high < val) bbox[i].high = val; + } + } + } + else + { + /* Determine the index, dimension and value for split plane */ + Offset idx; + Dimension cutfeat; + DistanceType cutval; + middleSplit_(obj, left, right - left, idx, cutfeat, cutval, bbox); + + node->node_type.sub.divfeat = cutfeat; + + std::future right_future; + + /* Recurse on right concurrently, if possible */ + + BoundingBox right_bbox(bbox); + right_bbox[cutfeat].low = cutval; + if (++thread_count < n_thread_build_) + { + /* Concurrent thread for right recursion */ + + right_future = std::async( + std::launch::async, &KDTreeBaseClass::divideTreeConcurrent, + this, std::ref(obj), left + idx, right, + std::ref(right_bbox), std::ref(thread_count), + std::ref(mutex)); + } + else { --thread_count; } + + /* Recurse on left in this thread */ + + BoundingBox left_bbox(bbox); + left_bbox[cutfeat].high = cutval; + node->child1 = this->divideTreeConcurrent( + obj, left, left + idx, left_bbox, thread_count, mutex); + + if (right_future.valid()) + { + /* Block and wait for concurrent right from above */ + + node->child2 = right_future.get(); + --thread_count; + } + else + { + /* Otherwise, recurse on right in this thread */ + + node->child2 = this->divideTreeConcurrent( + obj, left + idx, right, right_bbox, thread_count, mutex); + } + + node->node_type.sub.divlow = left_bbox[cutfeat].high; + node->node_type.sub.divhigh = right_bbox[cutfeat].low; + + for (Dimension i = 0; i < dims; ++i) + { + bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low); + bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high); + } + } + + return node; + } + + void middleSplit_( + const Derived& obj, const Offset ind, const Size count, Offset& index, + Dimension& cutfeat, DistanceType& cutval, const BoundingBox& bbox) + { + const auto dims = (DIM > 0 ? DIM : obj.dim_); + const auto EPS = static_cast(0.00001); + ElementType max_span = bbox[0].high - bbox[0].low; + for (Dimension i = 1; i < dims; ++i) + { + ElementType span = bbox[i].high - bbox[i].low; + if (span > max_span) { max_span = span; } + } + ElementType max_spread = -1; + cutfeat = 0; + ElementType min_elem = 0, max_elem = 0; + for (Dimension i = 0; i < dims; ++i) + { + ElementType span = bbox[i].high - bbox[i].low; + if (span >= (1 - EPS) * max_span) + { + ElementType min_elem_, max_elem_; + computeMinMax(obj, ind, count, i, min_elem_, max_elem_); + ElementType spread = max_elem_ - min_elem_; + if (spread > max_spread) + { + cutfeat = i; + max_spread = spread; + min_elem = min_elem_; + max_elem = max_elem_; + } + } + } + // split in the middle + DistanceType split_val = (bbox[cutfeat].low + bbox[cutfeat].high) / 2; + + if (split_val < min_elem) + cutval = min_elem; + else if (split_val > max_elem) + cutval = max_elem; + else + cutval = split_val; + + Offset lim1, lim2; + planeSplit(obj, ind, count, cutfeat, cutval, lim1, lim2); + + if (lim1 > count / 2) + index = lim1; + else if (lim2 < count / 2) + index = lim2; + else + index = count / 2; + } + + /** + * Subdivide the list of points by a plane perpendicular on the axis + * corresponding to the 'cutfeat' dimension at 'cutval' position. + * + * On return: + * dataset[ind[0..lim1-1]][cutfeat] < cutval + * dataset[ind[lim1..lim2-1]][cutfeat] == cutval + * dataset[ind[lim2..count]][cutfeat] > cutval + */ + void planeSplit( + const Derived& obj, const Offset ind, const Size count, + const Dimension cutfeat, const DistanceType& cutval, Offset& lim1, + Offset& lim2) + { + /* First pass. + * Determine lim1 with all values less than cutval to the left. + */ + Offset left = 0; + Offset right = count - 1; + for (;;) + { + while (left <= right && + dataset_get(obj, vAcc_[ind + left], cutfeat) < cutval) + ++left; + while (right && left <= right && + dataset_get(obj, vAcc_[ind + right], cutfeat) >= cutval) + --right; + if (left > right || !right) + break; // "!right" was added to support unsigned Index types + std::swap(vAcc_[ind + left], vAcc_[ind + right]); + ++left; + --right; + } + /* Second pass + * Determine lim2 with all values greater than cutval to the right + * The middle is used for balancing the tree + */ + lim1 = left; + right = count - 1; + for (;;) + { + while (left <= right && + dataset_get(obj, vAcc_[ind + left], cutfeat) <= cutval) + ++left; + while (right && left <= right && + dataset_get(obj, vAcc_[ind + right], cutfeat) > cutval) + --right; + if (left > right || !right) + break; // "!right" was added to support unsigned Index types + std::swap(vAcc_[ind + left], vAcc_[ind + right]); + ++left; + --right; + } + lim2 = left; + } + + DistanceType computeInitialDistances( + const Derived& obj, const ElementType* vec, + distance_vector_t& dists) const + { + assert(vec); + DistanceType dist = DistanceType(); + + for (Dimension i = 0; i < (DIM > 0 ? DIM : obj.dim_); ++i) + { + if (vec[i] < obj.root_bbox_[i].low) + { + dists[i] = + obj.distance_.accum_dist(vec[i], obj.root_bbox_[i].low, i); + dist += dists[i]; + } + if (vec[i] > obj.root_bbox_[i].high) + { + dists[i] = + obj.distance_.accum_dist(vec[i], obj.root_bbox_[i].high, i); + dist += dists[i]; + } + } + return dist; + } + + static void save_tree( + const Derived& obj, std::ostream& stream, const NodeConstPtr tree) + { + save_value(stream, *tree); + if (tree->child1 != nullptr) { save_tree(obj, stream, tree->child1); } + if (tree->child2 != nullptr) { save_tree(obj, stream, tree->child2); } + } + + static void load_tree(Derived& obj, std::istream& stream, NodePtr& tree) + { + tree = obj.pool_.template allocate(); + load_value(stream, *tree); + if (tree->child1 != nullptr) { load_tree(obj, stream, tree->child1); } + if (tree->child2 != nullptr) { load_tree(obj, stream, tree->child2); } + } + + /** Stores the index in a binary file. + * IMPORTANT NOTE: The set of data points is NOT stored in the file, so + * when loading the index object it must be constructed associated to the + * same source of data points used while building it. See the example: + * examples/saveload_example.cpp \sa loadIndex */ + void saveIndex(const Derived& obj, std::ostream& stream) const + { + save_value(stream, obj.size_); + save_value(stream, obj.dim_); + save_value(stream, obj.root_bbox_); + save_value(stream, obj.leaf_max_size_); + save_value(stream, obj.vAcc_); + if (obj.root_node_) save_tree(obj, stream, obj.root_node_); + } + + /** Loads a previous index from a binary file. + * IMPORTANT NOTE: The set of data points is NOT stored in the file, so + * the index object must be constructed associated to the same source of + * data points used while building the index. See the example: + * examples/saveload_example.cpp \sa loadIndex */ + void loadIndex(Derived& obj, std::istream& stream) + { + load_value(stream, obj.size_); + load_value(stream, obj.dim_); + load_value(stream, obj.root_bbox_); + load_value(stream, obj.leaf_max_size_); + load_value(stream, obj.vAcc_); + load_tree(obj, stream, obj.root_node_); + } +}; + +/** @addtogroup kdtrees_grp KD-tree classes and adaptors + * @{ */ + +/** kd-tree static index + * + * Contains the k-d trees and other information for indexing a set of points + * for nearest-neighbor matching. + * + * The class "DatasetAdaptor" must provide the following interface (can be + * non-virtual, inlined methods): + * + * \code + * // Must return the number of data poins + * size_t kdtree_get_point_count() const { ... } + * + * + * // Must return the dim'th component of the idx'th point in the class: + * T kdtree_get_pt(const size_t idx, const size_t dim) const { ... } + * + * // Optional bounding-box computation: return false to default to a standard + * bbox computation loop. + * // Return true if the BBOX was already computed by the class and returned + * in "bb" so it can be avoided to redo it again. + * // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 + * for point clouds) template bool kdtree_get_bbox(BBOX &bb) const + * { + * bb[0].low = ...; bb[0].high = ...; // 0th dimension limits + * bb[1].low = ...; bb[1].high = ...; // 1st dimension limits + * ... + * return true; + * } + * + * \endcode + * + * \tparam DatasetAdaptor The user-provided adaptor, which must be ensured to + * have a lifetime equal or longer than the instance of this class. + * \tparam Distance The distance metric to use: nanoflann::metric_L1, + * nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. \tparam DIM + * Dimensionality of data points (e.g. 3 for 3D points) \tparam IndexType Will + * be typically size_t or int + */ +template < + typename Distance, class DatasetAdaptor, int32_t DIM = -1, + typename index_t = uint32_t> +class KDTreeSingleIndexAdaptor + : public KDTreeBaseClass< + KDTreeSingleIndexAdaptor, + Distance, DatasetAdaptor, DIM, index_t> +{ + public: + /** Deleted copy constructor*/ + explicit KDTreeSingleIndexAdaptor( + const KDTreeSingleIndexAdaptor< + Distance, DatasetAdaptor, DIM, index_t>&) = delete; + + /** The data source used by this index */ + const DatasetAdaptor& dataset_; + + const KDTreeSingleIndexAdaptorParams indexParams; + + Distance distance_; + + using Base = typename nanoflann::KDTreeBaseClass< + nanoflann::KDTreeSingleIndexAdaptor< + Distance, DatasetAdaptor, DIM, index_t>, + Distance, DatasetAdaptor, DIM, index_t>; + + using Offset = typename Base::Offset; + using Size = typename Base::Size; + using Dimension = typename Base::Dimension; + + using ElementType = typename Base::ElementType; + using DistanceType = typename Base::DistanceType; + using IndexType = typename Base::IndexType; + + using Node = typename Base::Node; + using NodePtr = Node*; + + using Interval = typename Base::Interval; + + /** Define "BoundingBox" as a fixed-size or variable-size container + * depending on "DIM" */ + using BoundingBox = typename Base::BoundingBox; + + /** Define "distance_vector_t" as a fixed-size or variable-size container + * depending on "DIM" */ + using distance_vector_t = typename Base::distance_vector_t; + + /** + * KDTree constructor + * + * Refer to docs in README.md or online in + * https://github.com/jlblancoc/nanoflann + * + * The KD-Tree point dimension (the length of each point in the datase, e.g. + * 3 for 3D points) is determined by means of: + * - The \a DIM template parameter if >0 (highest priority) + * - Otherwise, the \a dimensionality parameter of this constructor. + * + * @param inputData Dataset with the input features. Its lifetime must be + * equal or longer than that of the instance of this class. + * @param params Basically, the maximum leaf node size + * + * Note that there is a variable number of optional additional parameters + * which will be forwarded to the metric class constructor. Refer to example + * `examples/pointcloud_custom_metric.cpp` for a use case. + * + */ + template + explicit KDTreeSingleIndexAdaptor( + const Dimension dimensionality, const DatasetAdaptor& inputData, + const KDTreeSingleIndexAdaptorParams& params, Args&&... args) + : dataset_(inputData), + indexParams(params), + distance_(inputData, std::forward(args)...) + { + init(dimensionality, params); + } + + explicit KDTreeSingleIndexAdaptor( + const Dimension dimensionality, const DatasetAdaptor& inputData, + const KDTreeSingleIndexAdaptorParams& params = {}) + : dataset_(inputData), indexParams(params), distance_(inputData) + { + init(dimensionality, params); + } + + private: + void init( + const Dimension dimensionality, + const KDTreeSingleIndexAdaptorParams& params) + { + Base::size_ = dataset_.kdtree_get_point_count(); + Base::size_at_index_build_ = Base::size_; + Base::dim_ = dimensionality; + if (DIM > 0) Base::dim_ = DIM; + Base::leaf_max_size_ = params.leaf_max_size; + if (params.n_thread_build > 0) + { + Base::n_thread_build_ = params.n_thread_build; + } + else + { + Base::n_thread_build_ = + std::max(std::thread::hardware_concurrency(), 1u); + } + + if (!(params.flags & + KDTreeSingleIndexAdaptorFlags::SkipInitialBuildIndex)) + { + // Build KD-tree: + buildIndex(); + } + } + + public: + /** + * Builds the index + */ + void buildIndex() + { + Base::size_ = dataset_.kdtree_get_point_count(); + Base::size_at_index_build_ = Base::size_; + init_vind(); + this->freeIndex(*this); + Base::size_at_index_build_ = Base::size_; + if (Base::size_ == 0) return; + computeBoundingBox(Base::root_bbox_); + // construct the tree + if (Base::n_thread_build_ == 1) + { + Base::root_node_ = + this->divideTree(*this, 0, Base::size_, Base::root_bbox_); + } + else + { +#ifndef NANOFLANN_NO_THREADS + std::atomic thread_count(0u); + std::mutex mutex; + Base::root_node_ = this->divideTreeConcurrent( + *this, 0, Base::size_, Base::root_bbox_, thread_count, mutex); +#else /* NANOFLANN_NO_THREADS */ + throw std::runtime_error("Multithreading is disabled"); +#endif /* NANOFLANN_NO_THREADS */ + } + } + + /** \name Query methods + * @{ */ + + /** + * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored + * inside the result object. + * + * Params: + * result = the result object in which the indices of the + * nearest-neighbors are stored vec = the vector for which to search the + * nearest neighbors + * + * \tparam RESULTSET Should be any ResultSet + * \return True if the requested neighbors could be found. + * \sa knnSearch, radiusSearch + * + * \note If L2 norms are used, all returned distances are actually squared + * distances. + */ + template + bool findNeighbors( + RESULTSET& result, const ElementType* vec, + const SearchParameters& searchParams = {}) const + { + assert(vec); + if (this->size(*this) == 0) return false; + if (!Base::root_node_) + throw std::runtime_error( + "[nanoflann] findNeighbors() called before building the " + "index."); + float epsError = 1 + searchParams.eps; + + // fixed or variable-sized container (depending on DIM) + distance_vector_t dists; + // Fill it with zeros. + auto zero = static_cast(0); + assign(dists, (DIM > 0 ? DIM : Base::dim_), zero); + DistanceType dist = this->computeInitialDistances(*this, vec, dists); + searchLevel(result, vec, Base::root_node_, dist, dists, epsError); + + if (searchParams.sorted) result.sort(); + + return result.full(); + } + + /** + * Find the "num_closest" nearest neighbors to the \a query_point[0:dim-1]. + * Their indices and distances are stored in the provided pointers to + * array/vector. + * + * \sa radiusSearch, findNeighbors + * \return Number `N` of valid points in the result set. + * + * \note If L2 norms are used, all returned distances are actually squared + * distances. + * + * \note Only the first `N` entries in `out_indices` and `out_distances` + * will be valid. Return is less than `num_closest` only if the + * number of elements in the tree is less than `num_closest`. + */ + Size knnSearch( + const ElementType* query_point, const Size num_closest, + IndexType* out_indices, DistanceType* out_distances) const + { + nanoflann::KNNResultSet resultSet(num_closest); + resultSet.init(out_indices, out_distances); + findNeighbors(resultSet, query_point); + return resultSet.size(); + } + + /** + * Find all the neighbors to \a query_point[0:dim-1] within a maximum + * radius. The output is given as a vector of pairs, of which the first + * element is a point index and the second the corresponding distance. + * Previous contents of \a IndicesDists are cleared. + * + * If searchParams.sorted==true, the output list is sorted by ascending + * distances. + * + * For a better performance, it is advisable to do a .reserve() on the + * vector if you have any wild guess about the number of expected matches. + * + * \sa knnSearch, findNeighbors, radiusSearchCustomCallback + * \return The number of points within the given radius (i.e. indices.size() + * or dists.size() ) + * + * \note If L2 norms are used, search radius and all returned distances + * are actually squared distances. + */ + Size radiusSearch( + const ElementType* query_point, const DistanceType& radius, + std::vector>& IndicesDists, + const SearchParameters& searchParams = {}) const + { + RadiusResultSet resultSet( + radius, IndicesDists); + const Size nFound = + radiusSearchCustomCallback(query_point, resultSet, searchParams); + return nFound; + } + + /** + * Just like radiusSearch() but with a custom callback class for each point + * found in the radius of the query. See the source of RadiusResultSet<> as + * a start point for your own classes. \sa radiusSearch + */ + template + Size radiusSearchCustomCallback( + const ElementType* query_point, SEARCH_CALLBACK& resultSet, + const SearchParameters& searchParams = {}) const + { + findNeighbors(resultSet, query_point, searchParams); + return resultSet.size(); + } + + /** + * Find the first N neighbors to \a query_point[0:dim-1] within a maximum + * radius. The output is given as a vector of pairs, of which the first + * element is a point index and the second the corresponding distance. + * Previous contents of \a IndicesDists are cleared. + * + * \sa radiusSearch, findNeighbors + * \return Number `N` of valid points in the result set. + * + * \note If L2 norms are used, all returned distances are actually squared + * distances. + * + * \note Only the first `N` entries in `out_indices` and `out_distances` + * will be valid. Return is less than `num_closest` only if the + * number of elements in the tree is less than `num_closest`. + */ + Size rknnSearch( + const ElementType* query_point, const Size num_closest, + IndexType* out_indices, DistanceType* out_distances, + const DistanceType& radius) const + { + nanoflann::RKNNResultSet resultSet( + num_closest, radius); + resultSet.init(out_indices, out_distances); + findNeighbors(resultSet, query_point); + return resultSet.size(); + } + + /** @} */ + + public: + /** Make sure the auxiliary list \a vind has the same size than the current + * dataset, and re-generate if size has changed. */ + void init_vind() + { + // Create a permutable array of indices to the input vectors. + Base::size_ = dataset_.kdtree_get_point_count(); + if (Base::vAcc_.size() != Base::size_) Base::vAcc_.resize(Base::size_); + for (IndexType i = 0; i < static_cast(Base::size_); i++) + Base::vAcc_[i] = i; + } + + void computeBoundingBox(BoundingBox& bbox) + { + const auto dims = (DIM > 0 ? DIM : Base::dim_); + resize(bbox, dims); + if (dataset_.kdtree_get_bbox(bbox)) + { + // Done! It was implemented in derived class + } + else + { + const Size N = dataset_.kdtree_get_point_count(); + if (!N) + throw std::runtime_error( + "[nanoflann] computeBoundingBox() called but " + "no data points found."); + for (Dimension i = 0; i < dims; ++i) + { + bbox[i].low = bbox[i].high = + this->dataset_get(*this, Base::vAcc_[0], i); + } + for (Offset k = 1; k < N; ++k) + { + for (Dimension i = 0; i < dims; ++i) + { + const auto val = + this->dataset_get(*this, Base::vAcc_[k], i); + if (val < bbox[i].low) bbox[i].low = val; + if (val > bbox[i].high) bbox[i].high = val; + } + } + } + } + + /** + * Performs an exact search in the tree starting from a node. + * \tparam RESULTSET Should be any ResultSet + * \return true if the search should be continued, false if the results are + * sufficient + */ + template + bool searchLevel( + RESULTSET& result_set, const ElementType* vec, const NodePtr node, + DistanceType mindist, distance_vector_t& dists, + const float epsError) const + { + /* If this is a leaf node, then do check and return. */ + if ((node->child1 == nullptr) && (node->child2 == nullptr)) + { + DistanceType worst_dist = result_set.worstDist(); + for (Offset i = node->node_type.lr.left; + i < node->node_type.lr.right; ++i) + { + const IndexType accessor = Base::vAcc_[i]; // reorder... : i; + DistanceType dist = distance_.evalMetric( + vec, accessor, (DIM > 0 ? DIM : Base::dim_)); + if (dist < worst_dist) + { + if (!result_set.addPoint(dist, Base::vAcc_[i])) + { + // the resultset doesn't want to receive any more + // points, we're done searching! + return false; + } + } + } + return true; + } + + /* Which child branch should be taken first? */ + Dimension idx = node->node_type.sub.divfeat; + ElementType val = vec[idx]; + DistanceType diff1 = val - node->node_type.sub.divlow; + DistanceType diff2 = val - node->node_type.sub.divhigh; + + NodePtr bestChild; + NodePtr otherChild; + DistanceType cut_dist; + if ((diff1 + diff2) < 0) + { + bestChild = node->child1; + otherChild = node->child2; + cut_dist = + distance_.accum_dist(val, node->node_type.sub.divhigh, idx); + } + else + { + bestChild = node->child2; + otherChild = node->child1; + cut_dist = + distance_.accum_dist(val, node->node_type.sub.divlow, idx); + } + + /* Call recursively to search next level down. */ + if (!searchLevel(result_set, vec, bestChild, mindist, dists, epsError)) + { + // the resultset doesn't want to receive any more points, we're done + // searching! + return false; + } + + DistanceType dst = dists[idx]; + mindist = mindist + cut_dist - dst; + dists[idx] = cut_dist; + if (mindist * epsError <= result_set.worstDist()) + { + if (!searchLevel( + result_set, vec, otherChild, mindist, dists, epsError)) + { + // the resultset doesn't want to receive any more points, we're + // done searching! + return false; + } + } + dists[idx] = dst; + return true; + } + + public: + /** Stores the index in a binary file. + * IMPORTANT NOTE: The set of data points is NOT stored in the file, so + * when loading the index object it must be constructed associated to the + * same source of data points used while building it. See the example: + * examples/saveload_example.cpp \sa loadIndex */ + void saveIndex(std::ostream& stream) const + { + Base::saveIndex(*this, stream); + } + + /** Loads a previous index from a binary file. + * IMPORTANT NOTE: The set of data points is NOT stored in the file, so + * the index object must be constructed associated to the same source of + * data points used while building the index. See the example: + * examples/saveload_example.cpp \sa loadIndex */ + void loadIndex(std::istream& stream) { Base::loadIndex(*this, stream); } + +}; // class KDTree + +/** kd-tree dynamic index + * + * Contains the k-d trees and other information for indexing a set of points + * for nearest-neighbor matching. + * + * The class "DatasetAdaptor" must provide the following interface (can be + * non-virtual, inlined methods): + * + * \code + * // Must return the number of data poins + * size_t kdtree_get_point_count() const { ... } + * + * // Must return the dim'th component of the idx'th point in the class: + * T kdtree_get_pt(const size_t idx, const size_t dim) const { ... } + * + * // Optional bounding-box computation: return false to default to a standard + * bbox computation loop. + * // Return true if the BBOX was already computed by the class and returned + * in "bb" so it can be avoided to redo it again. + * // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 + * for point clouds) template bool kdtree_get_bbox(BBOX &bb) const + * { + * bb[0].low = ...; bb[0].high = ...; // 0th dimension limits + * bb[1].low = ...; bb[1].high = ...; // 1st dimension limits + * ... + * return true; + * } + * + * \endcode + * + * \tparam DatasetAdaptor The user-provided adaptor (see comments above). + * \tparam Distance The distance metric to use: nanoflann::metric_L1, + * nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. + * \tparam DIM Dimensionality of data points (e.g. 3 for 3D points) + * \tparam IndexType Type of the arguments with which the data can be + * accessed (e.g. float, double, int64_t, T*) + */ +template < + typename Distance, class DatasetAdaptor, int32_t DIM = -1, + typename IndexType = uint32_t> +class KDTreeSingleIndexDynamicAdaptor_ + : public KDTreeBaseClass< + KDTreeSingleIndexDynamicAdaptor_< + Distance, DatasetAdaptor, DIM, IndexType>, + Distance, DatasetAdaptor, DIM, IndexType> +{ + public: + /** + * The dataset used by this index + */ + const DatasetAdaptor& dataset_; //!< The source of our data + + KDTreeSingleIndexAdaptorParams index_params_; + + std::vector& treeIndex_; + + Distance distance_; + + using Base = typename nanoflann::KDTreeBaseClass< + nanoflann::KDTreeSingleIndexDynamicAdaptor_< + Distance, DatasetAdaptor, DIM, IndexType>, + Distance, DatasetAdaptor, DIM, IndexType>; + + using ElementType = typename Base::ElementType; + using DistanceType = typename Base::DistanceType; + + using Offset = typename Base::Offset; + using Size = typename Base::Size; + using Dimension = typename Base::Dimension; + + using Node = typename Base::Node; + using NodePtr = Node*; + + using Interval = typename Base::Interval; + /** Define "BoundingBox" as a fixed-size or variable-size container + * depending on "DIM" */ + using BoundingBox = typename Base::BoundingBox; + + /** Define "distance_vector_t" as a fixed-size or variable-size container + * depending on "DIM" */ + using distance_vector_t = typename Base::distance_vector_t; + + /** + * KDTree constructor + * + * Refer to docs in README.md or online in + * https://github.com/jlblancoc/nanoflann + * + * The KD-Tree point dimension (the length of each point in the datase, e.g. + * 3 for 3D points) is determined by means of: + * - The \a DIM template parameter if >0 (highest priority) + * - Otherwise, the \a dimensionality parameter of this constructor. + * + * @param inputData Dataset with the input features. Its lifetime must be + * equal or longer than that of the instance of this class. + * @param params Basically, the maximum leaf node size + */ + KDTreeSingleIndexDynamicAdaptor_( + const Dimension dimensionality, const DatasetAdaptor& inputData, + std::vector& treeIndex, + const KDTreeSingleIndexAdaptorParams& params = + KDTreeSingleIndexAdaptorParams()) + : dataset_(inputData), + index_params_(params), + treeIndex_(treeIndex), + distance_(inputData) + { + Base::size_ = 0; + Base::size_at_index_build_ = 0; + for (auto& v : Base::root_bbox_) v = {}; + Base::dim_ = dimensionality; + if (DIM > 0) Base::dim_ = DIM; + Base::leaf_max_size_ = params.leaf_max_size; + if (params.n_thread_build > 0) + { + Base::n_thread_build_ = params.n_thread_build; + } + else + { + Base::n_thread_build_ = + std::max(std::thread::hardware_concurrency(), 1u); + } + } + + /** Explicitly default the copy constructor */ + KDTreeSingleIndexDynamicAdaptor_( + const KDTreeSingleIndexDynamicAdaptor_& rhs) = default; + + /** Assignment operator definiton */ + KDTreeSingleIndexDynamicAdaptor_ operator=( + const KDTreeSingleIndexDynamicAdaptor_& rhs) + { + KDTreeSingleIndexDynamicAdaptor_ tmp(rhs); + std::swap(Base::vAcc_, tmp.Base::vAcc_); + std::swap(Base::leaf_max_size_, tmp.Base::leaf_max_size_); + std::swap(index_params_, tmp.index_params_); + std::swap(treeIndex_, tmp.treeIndex_); + std::swap(Base::size_, tmp.Base::size_); + std::swap(Base::size_at_index_build_, tmp.Base::size_at_index_build_); + std::swap(Base::root_node_, tmp.Base::root_node_); + std::swap(Base::root_bbox_, tmp.Base::root_bbox_); + std::swap(Base::pool_, tmp.Base::pool_); + return *this; + } + + /** + * Builds the index + */ + void buildIndex() + { + Base::size_ = Base::vAcc_.size(); + this->freeIndex(*this); + Base::size_at_index_build_ = Base::size_; + if (Base::size_ == 0) return; + computeBoundingBox(Base::root_bbox_); + // construct the tree + if (Base::n_thread_build_ == 1) + { + Base::root_node_ = + this->divideTree(*this, 0, Base::size_, Base::root_bbox_); + } + else + { +#ifndef NANOFLANN_NO_THREADS + std::atomic thread_count(0u); + std::mutex mutex; + Base::root_node_ = this->divideTreeConcurrent( + *this, 0, Base::size_, Base::root_bbox_, thread_count, mutex); +#else /* NANOFLANN_NO_THREADS */ + throw std::runtime_error("Multithreading is disabled"); +#endif /* NANOFLANN_NO_THREADS */ + } + } + + /** \name Query methods + * @{ */ + + /** + * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored + * inside the result object. + * This is the core search function, all others are wrappers around this + * one. + * + * \param result The result object in which the indices of the + * nearest-neighbors are stored. + * \param vec The vector of the query point for which to search the + * nearest neighbors. + * \param searchParams Optional parameters for the search. + * + * \tparam RESULTSET Should be any ResultSet + * \return True if the requested neighbors could be found. + * + * \sa knnSearch(), radiusSearch(), radiusSearchCustomCallback() + * + * \note If L2 norms are used, all returned distances are actually squared + * distances. + */ + template + bool findNeighbors( + RESULTSET& result, const ElementType* vec, + const SearchParameters& searchParams = {}) const + { + assert(vec); + if (this->size(*this) == 0) return false; + if (!Base::root_node_) return false; + float epsError = 1 + searchParams.eps; + + // fixed or variable-sized container (depending on DIM) + distance_vector_t dists; + // Fill it with zeros. + assign( + dists, (DIM > 0 ? DIM : Base::dim_), + static_cast(0)); + DistanceType dist = this->computeInitialDistances(*this, vec, dists); + searchLevel(result, vec, Base::root_node_, dist, dists, epsError); + return result.full(); + } + + /** + * Find the "num_closest" nearest neighbors to the \a query_point[0:dim-1]. + * Their indices are stored inside the result object. \sa radiusSearch, + * findNeighbors + * \return Number `N` of valid points in + * the result set. + * + * \note If L2 norms are used, all returned distances are actually squared + * distances. + * + * \note Only the first `N` entries in `out_indices` and `out_distances` + * will be valid. Return may be less than `num_closest` only if the + * number of elements in the tree is less than `num_closest`. + */ + Size knnSearch( + const ElementType* query_point, const Size num_closest, + IndexType* out_indices, DistanceType* out_distances, + const SearchParameters& searchParams = {}) const + { + nanoflann::KNNResultSet resultSet(num_closest); + resultSet.init(out_indices, out_distances); + findNeighbors(resultSet, query_point, searchParams); + return resultSet.size(); + } + + /** + * Find all the neighbors to \a query_point[0:dim-1] within a maximum + * radius. The output is given as a vector of pairs, of which the first + * element is a point index and the second the corresponding distance. + * Previous contents of \a IndicesDists are cleared. + * + * If searchParams.sorted==true, the output list is sorted by ascending + * distances. + * + * For a better performance, it is advisable to do a .reserve() on the + * vector if you have any wild guess about the number of expected matches. + * + * \sa knnSearch, findNeighbors, radiusSearchCustomCallback + * \return The number of points within the given radius (i.e. indices.size() + * or dists.size() ) + * + * \note If L2 norms are used, search radius and all returned distances + * are actually squared distances. + */ + Size radiusSearch( + const ElementType* query_point, const DistanceType& radius, + std::vector>& IndicesDists, + const SearchParameters& searchParams = {}) const + { + RadiusResultSet resultSet( + radius, IndicesDists); + const size_t nFound = + radiusSearchCustomCallback(query_point, resultSet, searchParams); + return nFound; + } + + /** + * Just like radiusSearch() but with a custom callback class for each point + * found in the radius of the query. See the source of RadiusResultSet<> as + * a start point for your own classes. \sa radiusSearch + */ + template + Size radiusSearchCustomCallback( + const ElementType* query_point, SEARCH_CALLBACK& resultSet, + const SearchParameters& searchParams = {}) const + { + findNeighbors(resultSet, query_point, searchParams); + return resultSet.size(); + } + + /** @} */ + + public: + void computeBoundingBox(BoundingBox& bbox) + { + const auto dims = (DIM > 0 ? DIM : Base::dim_); + resize(bbox, dims); + + if (dataset_.kdtree_get_bbox(bbox)) + { + // Done! It was implemented in derived class + } + else + { + const Size N = Base::size_; + if (!N) + throw std::runtime_error( + "[nanoflann] computeBoundingBox() called but " + "no data points found."); + for (Dimension i = 0; i < dims; ++i) + { + bbox[i].low = bbox[i].high = + this->dataset_get(*this, Base::vAcc_[0], i); + } + for (Offset k = 1; k < N; ++k) + { + for (Dimension i = 0; i < dims; ++i) + { + const auto val = + this->dataset_get(*this, Base::vAcc_[k], i); + if (val < bbox[i].low) bbox[i].low = val; + if (val > bbox[i].high) bbox[i].high = val; + } + } + } + } + + /** + * Performs an exact search in the tree starting from a node. + * \tparam RESULTSET Should be any ResultSet + */ + template + void searchLevel( + RESULTSET& result_set, const ElementType* vec, const NodePtr node, + DistanceType mindist, distance_vector_t& dists, + const float epsError) const + { + /* If this is a leaf node, then do check and return. */ + if ((node->child1 == nullptr) && (node->child2 == nullptr)) + { + DistanceType worst_dist = result_set.worstDist(); + for (Offset i = node->node_type.lr.left; + i < node->node_type.lr.right; ++i) + { + const IndexType index = Base::vAcc_[i]; // reorder... : i; + if (treeIndex_[index] == -1) continue; + DistanceType dist = distance_.evalMetric( + vec, index, (DIM > 0 ? DIM : Base::dim_)); + if (dist < worst_dist) + { + if (!result_set.addPoint( + static_cast(dist), + static_cast( + Base::vAcc_[i]))) + { + // the resultset doesn't want to receive any more + // points, we're done searching! + return; // false; + } + } + } + return; + } + + /* Which child branch should be taken first? */ + Dimension idx = node->node_type.sub.divfeat; + ElementType val = vec[idx]; + DistanceType diff1 = val - node->node_type.sub.divlow; + DistanceType diff2 = val - node->node_type.sub.divhigh; + + NodePtr bestChild; + NodePtr otherChild; + DistanceType cut_dist; + if ((diff1 + diff2) < 0) + { + bestChild = node->child1; + otherChild = node->child2; + cut_dist = + distance_.accum_dist(val, node->node_type.sub.divhigh, idx); + } + else + { + bestChild = node->child2; + otherChild = node->child1; + cut_dist = + distance_.accum_dist(val, node->node_type.sub.divlow, idx); + } + + /* Call recursively to search next level down. */ + searchLevel(result_set, vec, bestChild, mindist, dists, epsError); + + DistanceType dst = dists[idx]; + mindist = mindist + cut_dist - dst; + dists[idx] = cut_dist; + if (mindist * epsError <= result_set.worstDist()) + { + searchLevel(result_set, vec, otherChild, mindist, dists, epsError); + } + dists[idx] = dst; + } + + public: + /** Stores the index in a binary file. + * IMPORTANT NOTE: The set of data points is NOT stored in the file, so + * when loading the index object it must be constructed associated to the + * same source of data points used while building it. See the example: + * examples/saveload_example.cpp \sa loadIndex */ + void saveIndex(std::ostream& stream) { saveIndex(*this, stream); } + + /** Loads a previous index from a binary file. + * IMPORTANT NOTE: The set of data points is NOT stored in the file, so + * the index object must be constructed associated to the same source of + * data points used while building the index. See the example: + * examples/saveload_example.cpp \sa loadIndex */ + void loadIndex(std::istream& stream) { loadIndex(*this, stream); } +}; + +/** kd-tree dynaimic index + * + * class to create multiple static index and merge their results to behave as + * single dynamic index as proposed in Logarithmic Approach. + * + * Example of usage: + * examples/dynamic_pointcloud_example.cpp + * + * \tparam DatasetAdaptor The user-provided adaptor (see comments above). + * \tparam Distance The distance metric to use: nanoflann::metric_L1, + * nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. \tparam DIM + * Dimensionality of data points (e.g. 3 for 3D points) \tparam IndexType + * Will be typically size_t or int + */ +template < + typename Distance, class DatasetAdaptor, int32_t DIM = -1, + typename IndexType = uint32_t> +class KDTreeSingleIndexDynamicAdaptor +{ + public: + using ElementType = typename Distance::ElementType; + using DistanceType = typename Distance::DistanceType; + + using Offset = typename KDTreeSingleIndexDynamicAdaptor_< + Distance, DatasetAdaptor, DIM>::Offset; + using Size = typename KDTreeSingleIndexDynamicAdaptor_< + Distance, DatasetAdaptor, DIM>::Size; + using Dimension = typename KDTreeSingleIndexDynamicAdaptor_< + Distance, DatasetAdaptor, DIM>::Dimension; + + protected: + Size leaf_max_size_; + Size treeCount_; + Size pointCount_; + + /** + * The dataset used by this index + */ + const DatasetAdaptor& dataset_; //!< The source of our data + + /** treeIndex[idx] is the index of tree in which point at idx is stored. + * treeIndex[idx]=-1 means that point has been removed. */ + std::vector treeIndex_; + std::unordered_set removedPoints_; + + KDTreeSingleIndexAdaptorParams index_params_; + + Dimension dim_; //!< Dimensionality of each data point + + using index_container_t = KDTreeSingleIndexDynamicAdaptor_< + Distance, DatasetAdaptor, DIM, IndexType>; + std::vector index_; + + public: + /** Get a const ref to the internal list of indices; the number of indices + * is adapted dynamically as the dataset grows in size. */ + const std::vector& getAllIndices() const + { + return index_; + } + + private: + /** finds position of least significant unset bit */ + int First0Bit(IndexType num) + { + int pos = 0; + while (num & 1) + { + num = num >> 1; + pos++; + } + return pos; + } + + /** Creates multiple empty trees to handle dynamic support */ + void init() + { + using my_kd_tree_t = KDTreeSingleIndexDynamicAdaptor_< + Distance, DatasetAdaptor, DIM, IndexType>; + std::vector index( + treeCount_, + my_kd_tree_t(dim_ /*dim*/, dataset_, treeIndex_, index_params_)); + index_ = index; + } + + public: + Distance distance_; + + /** + * KDTree constructor + * + * Refer to docs in README.md or online in + * https://github.com/jlblancoc/nanoflann + * + * The KD-Tree point dimension (the length of each point in the datase, e.g. + * 3 for 3D points) is determined by means of: + * - The \a DIM template parameter if >0 (highest priority) + * - Otherwise, the \a dimensionality parameter of this constructor. + * + * @param inputData Dataset with the input features. Its lifetime must be + * equal or longer than that of the instance of this class. + * @param params Basically, the maximum leaf node size + */ + explicit KDTreeSingleIndexDynamicAdaptor( + const int dimensionality, const DatasetAdaptor& inputData, + const KDTreeSingleIndexAdaptorParams& params = + KDTreeSingleIndexAdaptorParams(), + const size_t maximumPointCount = 1000000000U) + : dataset_(inputData), index_params_(params), distance_(inputData) + { + treeCount_ = static_cast(std::log2(maximumPointCount)) + 1; + pointCount_ = 0U; + dim_ = dimensionality; + treeIndex_.clear(); + if (DIM > 0) dim_ = DIM; + leaf_max_size_ = params.leaf_max_size; + init(); + const size_t num_initial_points = dataset_.kdtree_get_point_count(); + if (num_initial_points > 0) { addPoints(0, num_initial_points - 1); } + } + + /** Deleted copy constructor*/ + explicit KDTreeSingleIndexDynamicAdaptor( + const KDTreeSingleIndexDynamicAdaptor< + Distance, DatasetAdaptor, DIM, IndexType>&) = delete; + + /** Add points to the set, Inserts all points from [start, end] */ + void addPoints(IndexType start, IndexType end) + { + const Size count = end - start + 1; + int maxIndex = 0; + treeIndex_.resize(treeIndex_.size() + count); + for (IndexType idx = start; idx <= end; idx++) + { + const int pos = First0Bit(pointCount_); + maxIndex = std::max(pos, maxIndex); + treeIndex_[pointCount_] = pos; + + const auto it = removedPoints_.find(idx); + if (it != removedPoints_.end()) + { + removedPoints_.erase(it); + treeIndex_[idx] = pos; + } + + for (int i = 0; i < pos; i++) + { + for (int j = 0; j < static_cast(index_[i].vAcc_.size()); + j++) + { + index_[pos].vAcc_.push_back(index_[i].vAcc_[j]); + if (treeIndex_[index_[i].vAcc_[j]] != -1) + treeIndex_[index_[i].vAcc_[j]] = pos; + } + index_[i].vAcc_.clear(); + } + index_[pos].vAcc_.push_back(idx); + pointCount_++; + } + + for (int i = 0; i <= maxIndex; ++i) + { + index_[i].freeIndex(index_[i]); + if (!index_[i].vAcc_.empty()) index_[i].buildIndex(); + } + } + + /** Remove a point from the set (Lazy Deletion) */ + void removePoint(size_t idx) + { + if (idx >= pointCount_) return; + removedPoints_.insert(idx); + treeIndex_[idx] = -1; + } + + /** + * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored + * inside the result object. + * + * Params: + * result = the result object in which the indices of the + * nearest-neighbors are stored vec = the vector for which to search the + * nearest neighbors + * + * \tparam RESULTSET Should be any ResultSet + * \return True if the requested neighbors could be found. + * \sa knnSearch, radiusSearch + * + * \note If L2 norms are used, all returned distances are actually squared + * distances. + */ + template + bool findNeighbors( + RESULTSET& result, const ElementType* vec, + const SearchParameters& searchParams = {}) const + { + for (size_t i = 0; i < treeCount_; i++) + { + index_[i].findNeighbors(result, &vec[0], searchParams); + } + return result.full(); + } +}; + +/** An L2-metric KD-tree adaptor for working with data directly stored in an + * Eigen Matrix, without duplicating the data storage. You can select whether a + * row or column in the matrix represents a point in the state space. + * + * Example of usage: + * \code + * Eigen::Matrix mat; + * + * // Fill out "mat"... + * using my_kd_tree_t = nanoflann::KDTreeEigenMatrixAdaptor< + * Eigen::Matrix>; + * + * const int max_leaf = 10; + * my_kd_tree_t mat_index(mat, max_leaf); + * mat_index.index->... + * \endcode + * + * \tparam DIM If set to >0, it specifies a compile-time fixed dimensionality + * for the points in the data set, allowing more compiler optimizations. + * \tparam Distance The distance metric to use: nanoflann::metric_L1, + * nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. + * \tparam row_major If set to true the rows of the matrix are used as the + * points, if set to false the columns of the matrix are used as the + * points. + */ +template < + class MatrixType, int32_t DIM = -1, class Distance = nanoflann::metric_L2, + bool row_major = true> +struct KDTreeEigenMatrixAdaptor +{ + using self_t = + KDTreeEigenMatrixAdaptor; + using num_t = typename MatrixType::Scalar; + using IndexType = typename MatrixType::Index; + using metric_t = typename Distance::template traits< + num_t, self_t, IndexType>::distance_t; + + using index_t = KDTreeSingleIndexAdaptor< + metric_t, self_t, + row_major ? MatrixType::ColsAtCompileTime + : MatrixType::RowsAtCompileTime, + IndexType>; + + index_t* index_; //! The kd-tree index for the user to call its methods as + //! usual with any other FLANN index. + + using Offset = typename index_t::Offset; + using Size = typename index_t::Size; + using Dimension = typename index_t::Dimension; + + /// Constructor: takes a const ref to the matrix object with the data points + explicit KDTreeEigenMatrixAdaptor( + const Dimension dimensionality, + const std::reference_wrapper& mat, + const int leaf_max_size = 10, const unsigned int n_thread_build = 1) + : m_data_matrix(mat) + { + const auto dims = row_major ? mat.get().cols() : mat.get().rows(); + if (static_cast(dims) != dimensionality) + throw std::runtime_error( + "Error: 'dimensionality' must match column count in data " + "matrix"); + if (DIM > 0 && static_cast(dims) != DIM) + throw std::runtime_error( + "Data set dimensionality does not match the 'DIM' template " + "argument"); + index_ = new index_t( + dims, *this /* adaptor */, + nanoflann::KDTreeSingleIndexAdaptorParams( + leaf_max_size, nanoflann::KDTreeSingleIndexAdaptorFlags::None, + n_thread_build)); + } + + public: + /** Deleted copy constructor */ + KDTreeEigenMatrixAdaptor(const self_t&) = delete; + + ~KDTreeEigenMatrixAdaptor() { delete index_; } + + const std::reference_wrapper m_data_matrix; + + /** Query for the \a num_closest closest points to a given point (entered as + * query_point[0:dim-1]). Note that this is a short-cut method for + * index->findNeighbors(). The user can also call index->... methods as + * desired. + * + * \note If L2 norms are used, all returned distances are actually squared + * distances. + */ + void query( + const num_t* query_point, const Size num_closest, + IndexType* out_indices, num_t* out_distances) const + { + nanoflann::KNNResultSet resultSet(num_closest); + resultSet.init(out_indices, out_distances); + index_->findNeighbors(resultSet, query_point); + } + + /** @name Interface expected by KDTreeSingleIndexAdaptor + * @{ */ + + const self_t& derived() const { return *this; } + self_t& derived() { return *this; } + + // Must return the number of data points + Size kdtree_get_point_count() const + { + if (row_major) + return m_data_matrix.get().rows(); + else + return m_data_matrix.get().cols(); + } + + // Returns the dim'th component of the idx'th point in the class: + num_t kdtree_get_pt(const IndexType idx, size_t dim) const + { + if (row_major) + return m_data_matrix.get().coeff(idx, IndexType(dim)); + else + return m_data_matrix.get().coeff(IndexType(dim), idx); + } + + // Optional bounding-box computation: return false to default to a standard + // bbox computation loop. + // Return true if the BBOX was already computed by the class and returned + // in "bb" so it can be avoided to redo it again. Look at bb.size() to + // find out the expected dimensionality (e.g. 2 or 3 for point clouds) + template + bool kdtree_get_bbox(BBOX& /*bb*/) const + { + return false; + } + + /** @} */ + +}; // end of KDTreeEigenMatrixAdaptor +/** @} */ + +/** @} */ // end of grouping +} // namespace nanoflann diff --git a/src/vendor/cigraph/vendor/plfit/gss.h b/src/vendor/cigraph/vendor/plfit/gss.h index 45276fda075..afb6aefa459 100644 --- a/src/vendor/cigraph/vendor/plfit/gss.h +++ b/src/vendor/cigraph/vendor/plfit/gss.h @@ -22,7 +22,7 @@ #include "plfit_decls.h" -__BEGIN_DECLS +PLFIT_BEGIN_C_DECLS /** * Enum specifying what the search should do when the function is not U-shaped. @@ -133,6 +133,6 @@ unsigned short int gss_get_warning_flag(void); */ void gss_parameter_init(gss_parameter_t *param); -__END_DECLS +PLFIT_END_C_DECLS #endif /* __GSS_H__ */ diff --git a/src/vendor/cigraph/vendor/plfit/hzeta.h b/src/vendor/cigraph/vendor/plfit/hzeta.h index 39a7e01a7cc..598f12d5866 100644 --- a/src/vendor/cigraph/vendor/plfit/hzeta.h +++ b/src/vendor/cigraph/vendor/plfit/hzeta.h @@ -34,7 +34,7 @@ #include "plfit_decls.h" -__BEGIN_DECLS +PLFIT_BEGIN_C_DECLS /* Hurwitz Zeta Function @@ -83,6 +83,6 @@ double hsl_sf_lnhzeta_deriv(const double s, const double q); double hsl_sf_lnhzeta_deriv_tuple(const double s, const double q, double * deriv0, double * deriv1); -__END_DECLS +PLFIT_END_C_DECLS #endif // __HZETA_H__ diff --git a/src/vendor/cigraph/vendor/plfit/kolmogorov.h b/src/vendor/cigraph/vendor/plfit/kolmogorov.h index 9615bcb74be..b635baa0db6 100644 --- a/src/vendor/cigraph/vendor/plfit/kolmogorov.h +++ b/src/vendor/cigraph/vendor/plfit/kolmogorov.h @@ -23,12 +23,12 @@ #include #include "plfit_decls.h" -__BEGIN_DECLS +PLFIT_BEGIN_C_DECLS double plfit_kolmogorov(double z); double plfit_ks_test_one_sample_p(double d, size_t n); double plfit_ks_test_two_sample_p(double d, size_t n1, size_t n2); -__END_DECLS +PLFIT_END_C_DECLS #endif diff --git a/src/vendor/cigraph/vendor/plfit/lbfgs.h b/src/vendor/cigraph/vendor/plfit/lbfgs.h index 8390ec3c79d..73d99e445a9 100644 --- a/src/vendor/cigraph/vendor/plfit/lbfgs.h +++ b/src/vendor/cigraph/vendor/plfit/lbfgs.h @@ -31,7 +31,7 @@ #include "plfit_decls.h" -__BEGIN_DECLS +PLFIT_BEGIN_C_DECLS /* * The default precision of floating point values is 64bit (double). @@ -59,7 +59,7 @@ typedef double lbfgsfloatval_t; #endif -/** +/** * \addtogroup liblbfgs_api libLBFGS API * @{ * @@ -68,7 +68,7 @@ typedef double lbfgsfloatval_t; /** * Return values of lbfgs(). - * + * * Roughly speaking, a negative value indicates an error. */ enum { @@ -365,7 +365,7 @@ typedef struct { * function and its gradients when needed. A client program must implement * this function to evaluate the values of the objective function and its * gradients, given current values of variables. - * + * * @param instance The user data sent for lbfgs() function by the client. * @param x The current values of variables. * @param g The gradient vector. The callback function must compute @@ -502,14 +502,14 @@ void lbfgs_parameter_init(lbfgs_parameter_t *param); * when libLBFGS is built with SSE/SSE2 optimization routines. A user does * not have to use this function for libLBFGS built without SSE/SSE2 * optimization. - * + * * @param n The number of variables. */ lbfgsfloatval_t* lbfgs_malloc(int n); /** * Free an array of variables. - * + * * @param x The array of variables allocated by ::lbfgs_malloc * function. */ @@ -524,7 +524,7 @@ const char* lbfgs_strerror(int err); /** @} */ -__END_DECLS +PLFIT_END_C_DECLS diff --git a/src/vendor/cigraph/vendor/plfit/plfit.c b/src/vendor/cigraph/vendor/plfit/plfit.c index bfc8eeb5ba7..26525da03ce 100644 --- a/src/vendor/cigraph/vendor/plfit/plfit.c +++ b/src/vendor/cigraph/vendor/plfit/plfit.c @@ -1,4 +1,3 @@ -/* vim:set ts=4 sw=4 sts=4 et: */ /* plfit.c * * Copyright (C) 2010-2011 Tamas Nepusz diff --git a/src/vendor/cigraph/vendor/plfit/plfit.h b/src/vendor/cigraph/vendor/plfit/plfit.h index a312790f221..54d57a19c2d 100644 --- a/src/vendor/cigraph/vendor/plfit/plfit.h +++ b/src/vendor/cigraph/vendor/plfit/plfit.h @@ -1,4 +1,3 @@ -/* vim:set ts=4 sw=4 sts=4 et: */ /* plfit.h * * Copyright (C) 2010-2011 Tamas Nepusz @@ -28,7 +27,7 @@ #include "plfit_sampling.h" #include "plfit_version.h" -__BEGIN_DECLS +PLFIT_BEGIN_C_DECLS typedef unsigned short int plfit_bool_t; @@ -128,6 +127,6 @@ PLFIT_EXPORT int plfit_calculate_p_value_discrete(const double* xs, size_t n, PLFIT_EXPORT int plfit_moments(const double* data, size_t n, double* mean, double* variance, double* skewness, double* kurtosis); -__END_DECLS +PLFIT_END_C_DECLS #endif /* PLFIT_H */ diff --git a/src/vendor/cigraph/vendor/plfit/plfit_decls.h b/src/vendor/cigraph/vendor/plfit/plfit_decls.h index ee45c3bed3e..de57912386b 100644 --- a/src/vendor/cigraph/vendor/plfit/plfit_decls.h +++ b/src/vendor/cigraph/vendor/plfit/plfit_decls.h @@ -20,14 +20,14 @@ #ifndef PLFIT_DECLS_H #define PLFIT_DECLS_H -#undef __BEGIN_DECLS -#undef __END_DECLS +#undef PLFIT_BEGIN_C_DECLS +#undef PLFIT_END_C_DECLS #ifdef __cplusplus - #define __BEGIN_DECLS extern "C" { - #define __END_DECLS } + #define PLFIT_BEGIN_C_DECLS extern "C" { + #define PLFIT_END_C_DECLS } #else - #define __BEGIN_DECLS /* empty */ - #define __END_DECLS /* empty */ + #define PLFIT_BEGIN_C_DECLS /* empty */ + #define PLFIT_END_C_DECLS /* empty */ #endif #define PLFIT_EXPORT /* empty */ diff --git a/src/vendor/cigraph/vendor/plfit/plfit_error.h b/src/vendor/cigraph/vendor/plfit/plfit_error.h index c6c5dff3251..b94519ee3d3 100644 --- a/src/vendor/cigraph/vendor/plfit/plfit_error.h +++ b/src/vendor/cigraph/vendor/plfit/plfit_error.h @@ -22,7 +22,7 @@ #include "plfit_decls.h" -__BEGIN_DECLS +PLFIT_BEGIN_C_DECLS enum { PLFIT_SUCCESS = 0, @@ -67,6 +67,6 @@ PLFIT_EXPORT plfit_error_handler_t* plfit_set_error_handler(plfit_error_handler_ PLFIT_EXPORT void plfit_error(const char *reason, const char *file, int line, int plfit_errno); PLFIT_EXPORT const char* plfit_strerror(const int plfit_errno); -__END_DECLS +PLFIT_END_C_DECLS #endif /* PLFIT_ERROR_H */ diff --git a/src/vendor/cigraph/vendor/plfit/plfit_mt.h b/src/vendor/cigraph/vendor/plfit/plfit_mt.h index 99c5f96b1fd..6905095d1a9 100644 --- a/src/vendor/cigraph/vendor/plfit/plfit_mt.h +++ b/src/vendor/cigraph/vendor/plfit/plfit_mt.h @@ -17,7 +17,7 @@ #include #include "plfit_decls.h" -__BEGIN_DECLS +PLFIT_BEGIN_C_DECLS #define PLFIT_MT_LEN 624 @@ -82,6 +82,6 @@ PLFIT_EXPORT uint32_t plfit_mt_random(plfit_mt_rng_t* rng); */ PLFIT_EXPORT double plfit_mt_uniform_01(plfit_mt_rng_t* rng); -__END_DECLS +PLFIT_END_C_DECLS #endif /* PLFIT_MT_H */ diff --git a/src/vendor/cigraph/vendor/plfit/plfit_sampling.h b/src/vendor/cigraph/vendor/plfit/plfit_sampling.h index ed89c2cd05e..edde225132b 100644 --- a/src/vendor/cigraph/vendor/plfit/plfit_sampling.h +++ b/src/vendor/cigraph/vendor/plfit/plfit_sampling.h @@ -24,7 +24,7 @@ #include "plfit_decls.h" #include "plfit_mt.h" -__BEGIN_DECLS +PLFIT_BEGIN_C_DECLS /** * Draws a sample from a binomial distribution with the given count and @@ -163,6 +163,6 @@ PLFIT_EXPORT void plfit_walker_alias_sampler_destroy(plfit_walker_alias_sampler_ PLFIT_EXPORT int plfit_walker_alias_sampler_sample(const plfit_walker_alias_sampler_t* sampler, long int* xs, size_t n, plfit_mt_rng_t* rng); -__END_DECLS +PLFIT_END_C_DECLS #endif /* PLFIT_SAMPLING_H */ diff --git a/src/vendor/cigraph/vendor/qhull/CHANGES.md b/src/vendor/cigraph/vendor/qhull/CHANGES.md new file mode 100644 index 00000000000..917243989d0 --- /dev/null +++ b/src/vendor/cigraph/vendor/qhull/CHANGES.md @@ -0,0 +1,12 @@ +Modifying from https://github.com/qhull/qhull on commit d1c2fc0caa5f644f3a0f220290d4a868c68ed4f6 + +Changed `userprintf_r.c` to not print when passed a null pointer as file handle. + +Changed `usermem_r.c` to not reference `exit()`. Even though this `exit()` is never called, it is necessary to keep igraph free of any references to it to satisfy CRAN requirements and comply with Debian guidelines. + +Changed the following settings in `user_r.h`: + + - `#define qh_KEEPstatistics 0`, do not incude statistics gathering code + - `#define qh_NOtrace`, do not include tracing code + +Patched with https://github.com/qhull/qhull/pull/165. diff --git a/src/vendor/cigraph/vendor/qhull/CMakeLists.txt b/src/vendor/cigraph/vendor/qhull/CMakeLists.txt new file mode 100644 index 00000000000..2e7cf5eb718 --- /dev/null +++ b/src/vendor/cigraph/vendor/qhull/CMakeLists.txt @@ -0,0 +1,48 @@ +# Declare the files needed to compile our vendored plfit copy +add_library( + qhull_vendored + OBJECT + EXCLUDE_FROM_ALL + libqhull_r/accessors_r.c + libqhull_r/geom_r.c + libqhull_r/geom2_r.c + libqhull_r/global_r.c + libqhull_r/io_r.c + libqhull_r/libqhull_r.c + libqhull_r/mem_r.c + libqhull_r/merge_r.c + libqhull_r/poly_r.c + libqhull_r/poly2_r.c + libqhull_r/qset_r.c + libqhull_r/random_r.c + libqhull_r/rboxlib_r.c + libqhull_r/stat_r.c + libqhull_r/user_r.c + libqhull_r/usermem_r.c + libqhull_r/userprintf_r.c + libqhull_r/userprintf_rbox_r.c +) + +target_include_directories( + qhull_vendored + PRIVATE + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_BINARY_DIR}/include + #PUBLIC + #${CMAKE_CURRENT_SOURCE_DIR} +) + +if (BUILD_SHARED_LIBS) + set_property(TARGET qhull_vendored PROPERTY POSITION_INDEPENDENT_CODE ON) +endif() + +# Since these are included as object files, they should call the +# function as is (without visibility specification) +target_compile_definitions(qhull_vendored PRIVATE IGRAPH_STATIC) + +use_all_warnings(qhull_vendored) + +target_compile_options( + qhull_vendored PRIVATE + $<$:-Wno-unused-variable> +) \ No newline at end of file diff --git a/src/vendor/cigraph/vendor/qhull/COPYING.txt b/src/vendor/cigraph/vendor/qhull/COPYING.txt new file mode 100644 index 00000000000..122a00a4fa9 --- /dev/null +++ b/src/vendor/cigraph/vendor/qhull/COPYING.txt @@ -0,0 +1,39 @@ + Qhull, Copyright (c) 1993-2020 + + C.B. Barber + Arlington, MA + + and + + The National Science and Technology Research Center for + Computation and Visualization of Geometric Structures + (The Geometry Center) + University of Minnesota + + email: qhull@qhull.org + +This software includes Qhull from C.B. Barber and The Geometry Center. +Files derived from Qhull 1.0 are copyrighted by the Geometry Center. The +remaining files are copyrighted by C.B. Barber. Qhull is free software +and may be obtained via http from www.qhull.org. It may be freely copied, +modified, and redistributed under the following conditions: + +1. All copyright notices must remain intact in all files. + +2. A copy of this text file must be distributed along with any copies + of Qhull that you redistribute; this includes copies that you have + modified, or copies of programs or other software products that + include Qhull. + +3. If you modify Qhull, you must include a notice giving the + name of the person performing the modification, the date of + modification, and the reason for such modification. + +4. When distributing modified versions of Qhull, or other software + products that include Qhull, you must provide notice that the original + source code may be obtained as noted above. + +5. There is no warranty or other guarantee of fitness for Qhull, it is + provided solely "as is". Bug reports or fixes may be sent to + qhull_bug@qhull.org; the authors may or may not act on them as + they desire. diff --git a/src/vendor/cigraph/vendor/qhull/README.txt b/src/vendor/cigraph/vendor/qhull/README.txt new file mode 100644 index 00000000000..baf1b80aa90 --- /dev/null +++ b/src/vendor/cigraph/vendor/qhull/README.txt @@ -0,0 +1,720 @@ +Name + + qhull, rbox 2020.2 2020/08/31 (8.0.2) + +Convex hull, Delaunay triangulation, Voronoi diagrams, Halfspace intersection + + Documentation: + html/index.htm + + + Available from: + + + (git@github.com:qhull/qhull.git) + + News and a paper: + + + + Version 1 (simplicial only): + + +Purpose + + Qhull is a general dimension convex hull program that reads a set + of points from stdin, and outputs the smallest convex set that contains + the points to stdout. It also generates Delaunay triangulations, Voronoi + diagrams, furthest-site Voronoi diagrams, and halfspace intersections + about a point. + + Rbox is a useful tool in generating input for Qhull; it generates + hypercubes, diamonds, cones, circles, simplices, spirals, + lattices, and random points. + + Qhull produces graphical output for Geomview. This helps with + understanding the output. + +Environment requirements + + Qhull and rbox should run on all 32-bit and 64-bit computers. Use + an ANSI C or C++ compiler to compile the program. The software is + self-contained. It comes with examples and test scripts. + + Qhull's C++ interface uses the STL. The C++ test program uses QTestLib + from the Qt Framework. + + Qhull is copyrighted software. Please read COPYING.txt and REGISTER.txt + before using or distributing Qhull. + +To cite Qhull, please use + + Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull + algorithm for convex hulls," ACM Trans. on Mathematical Software, + 22(4):469-483, Dec 1996, http://www.qhull.org. + +To modify Qhull, particularly the C++ interface + + Qhull is on GitHub + (http://github.com/qhull/qhull/wiki, git@github.com:qhull/qhull.git) + + For internal documentation, see html/qh-code.htm + +To install Qhull + + Qhull is precompiled for Windows 32-bit, otherwise it needs compilation. + + Qhull includes Makefiles for gcc and other targets, CMakeLists.txt for CMake, + .sln/.vcproj/.vcxproj files for Microsoft Visual Studio, and .pro files + for Qt Creator. It compiles under Windows with mingw. + () + + Install and build instructions follow. + + See the end of this document for a list of distributed files. + +------------------ +Index + +Installing Qhull on Windows 10, 8, 7 (32- or 64-bit), Windows XP, and Windows NT +Installing Qhull on Unix with gcc +Installing Qhull with CMake 2.6 or later +Installing Qhull with Qt +Working with Qhull's C++ interface +Calling Qhull from C programs +Compiling Qhull with Microsoft Visual C++ +Compiling Qhull with Qt Creator +Compiling Qhull with mingw/gcc on Windows +Compiling Qhull with cygwin on Windows +Compiling from Makfile without gcc +Compiling on other machines and compilers +Distributed files +Authors + +------------------ +Installing Qhull on Windows 10, 8, 7 (32- or 64-bit), Windows XP, and Windows NT + + The zip file contains rbox.exe, qhull.exe, qconvex.exe, qdelaunay.exe, + qhalf.exe, qvoronoi.exe, testqset.exe, user_eg*.exe, documentation files, + and source files. Qhull.exe and user-eg3.exe are compiled with the reentrant + library while the other executables use the non-reentrant library. + + To install Qhull: + - Unzip the files into a directory (e.g., named 'qhull') + - Click on QHULL-GO or open a command window into Qhull's bin directory. + - Test with 'rbox D4 | qhull' + + To uninstall Qhull + - Delete the qhull directory + + To learn about Qhull: + - Execute 'qconvex' for a synopsis and examples. + Or 'qconvex --help' or 'qconvex -?' + - Execute 'rbox 10 | qconvex' to compute the convex hull of 10 random points. + - Execute 'rbox 10 | qconvex i TO file' to write results to 'file'. + - Browse the documentation: qhull\html\index.htm + - If an error occurs, Windows sends the error to stdout instead of stderr. + Use 'TO xxx' to send normal output to xxx + + To improve the command window + - Double-click the window bar to increase the size of the window + - Right-click the window bar + - Select Properties + - Check QuickEdit Mode + Select text with right-click or Enter + Paste text with right-click + - Change Font to Lucinda Console + - Change Layout to Screen Buffer Height 999, Window Size Height 55 + - Change Colors to Screen Background White, Screen Text Black + - Click OK + - Select 'Modify shortcut that started this window', then OK + + If you regularly use qhull on a Windows host, install a bash shell such as + https://gitforwindows.org/ # based on MSYS2 + https://github.com/git-for-windows/git/wiki + http://www.msys2.org/ + https://github.com/msys2/msys2/wiki + [mar'19] Git for Windows v2.21 requires 'qhull --help' + Install in C:\Git\... # Not 'Program Files\...' otherwise './configure && make' fails + www.cygwin.com + www.mingw.org/wiki/msys # for Windows XP + Road Bash (www.qhull.org/bash) # based on MSYS + +------------------ +Installing Qhull on Unix with gcc + + To build Qhull, static libraries, shared library, and C++ interface + - Download and extract Qhull (either GitHub, .tgz file, or .zip file) + - make + - export LD_LIBRARY_PATH=$PWD/lib:$LD_LIBRARY_PATH + - make test + + 'make install' installs Qhull at '/usr/local/'. It installs pkg-config files + at '/usr/local/lib/pkgconfig'. Change the install directory with DESTDIR and PREFIX. + + To build 32-bit Qhull on a 64-bit host (uses 33% less memory in 4-d) + - make new M32=-m32 + + To build 32-bit Qhull without -fpic (may be faster, but shared library may fail) + - make new M32=-m32 FPIC= + + The Makefiles may be edited for other compilers. + If 'testqset' exits with an error, qhull is broken + + A simple Makefile for Qhull is in src/libqhull and src/libqhull_r. + To build the Qhull executables and libqhullstatic + - Extract Qhull from qhull...tgz or qhull...zip + - cd src/libqhull_r # cd src/libqhull + - make + + +------------------ +Installing Qhull with CMake 2.6 or later + + See CMakeLists.txt for examples and further build instructions + + To build Qhull, static libraries, shared library, and C++ interface + - Download and extract Qhull (either GitHub, .tgz file, or .zip file) + - cd build + - cmake --help # List build generators + - cmake -G "" .. # e.g., for MINGW-w64 -- cmake -G "MSYS Makefiles" .. + - cmake .. + - make + - ctest + - make install # If MSYS or UNIX, default CMAKE_INSTALL_PREFIX is '/usr/local' + # otherwise if WINDOWS, installs to ../bin, ../include, and ../lib + - make uninstall # Delete the files in install_manifest.txt + + The ".." is important. It refers to the parent directory (i.e., qhull/) + + CMake installs lib/pkgconfig/qhull*.pc for use with pkg-config + + If CMAKE_INSTALL_PREFIX is C:/Program Files/qhull, you may need to give 'Users' "full control" + to qhull's sub-directories: bin, doc, include, lib, and man (folder > Properties > Security > Edit > Users). + + On Windows, CMake's 64-bit generators have a "Win64" tag. Qhull's data structures + are substantial larger as 64-bit code than as 32-bit code. This may slow down Qhull. + + If cmake fails with "No CMAKE_C_COMPILER could be found" + - cmake was not able to find the build environment specified by -G "..." + + If cmake's gcc smoketest fails after a Windows update + - Reinstall MINGW-w64 and delete build/CMakeCache.txt. A Windows update can break gcc process creation for cc1. + +------------------ +Installing Qhull with Qt + + To build Qhull, including its C++ test program (qhulltest) + - Download and extract Qhull (either GitHub, .tgz file, or .zip file) + - Load src/qhull-all.pro into QtCreator + - Configure the project to use a Shadow build at the same level as 'src', 'bin', and 'lib' + If, instead, the shadow build is a subdirectory of 'build', Qt Creator will install Qhull in 'build/bin' and 'build/lib' + - Build + + - Build qhulltest with a C++11 or later compiler + - qhulltest depends on shared libraries QtCore.a and QtTest.a. They may need to be copied + into the bin directory. On Windows, copy Qt5Core.dll and Qt5Test.dll, e.g., /qt/5.11.2/msvc2017_64/bin + - If qhulltest fails with exit status 127 and no error message, + check for missing Q5Core.dll and Qt5Test.dll + +------------------ +Working with Qhull's C++ interface + + See html/qh-code.htm#cpp for calling Qhull from C++ programs + + Class and method documentation is limited + + See html/qh-code.htm#reentrant for converting from Qhull-2012 + + Examples of using the C++ interface + user_eg3_r.cpp + qhulltest/*_test.cpp + + Qhull's C++ interface is likely to change. Stay current with GitHub. + + To clone Qhull's next branch from http://github.com/qhull/qhull/wiki + git init + git clone git@github.com:qhull/qhull.git + cd qhull + git checkout next + ... + git pull origin next + + Compile qhullcpp and libqhullstatic_r with the same compiler. Both libraries + use the C routines setjmp() and longjmp() for error handling. They must + be compiled with the same compiler. + + Qhull provides pkg-config support with build/qhull.pc.in and lib/pkgconfig/qhull*.pc + With back-ticks, you can compile your C++ program with the Qhull libraries: + g++ `pkg-config --cflags --libs qhullcpp qhullstatic_r` -o my_app my_app.cpp + or + g++ `pkg-config --cflags --libs qhullcpp qhull_r` -o my_app my_app.cpp + + qhullcpp must be linked before qhull_r, otherwise the linker reports + an error -- "QhullUser ... multiple definition of `qh_fprintf'" + +------------------ +Calling Qhull from C programs + + See html/qh-code.htm#library for calling Qhull from C programs + + Qhull provides pkg-config support with build/qhull.pc.in and lib/pkgconfig/qhull*.pc + With back-ticks, you can compile your C program with the Qhull library + gcc `pkg-config --cflags --libs qhull_r` -o my_app my_app.c + + See html/qh-code.htm#reentrant for converting from Qhull-2012 + + Warning: You will need to understand Qhull's data structures and read the + code. Most users will find it easier to call Qhull as an external command. + + The reentrant 'C' code (src/libqhull_r), passes a pointer to qhT + to most Qhull routines. This allows multiple instances of Qhull to run + at the same time. It simplifies the C++ interface. + + The non-reentrant 'C' code (src/libqhull) looks unusual. It refers to + Qhull's global data structure, qhT, through a 'qh' macro (e.g., 'qh ferr'). + This allows the same code to use static memory or heap memory. + If qh_QHpointer is defined, qh_qh is a pointer to an allocated qhT; + otherwise qh_qh is a global static data structure of type qhT. + +------------------ +Compiling Qhull with Microsoft Visual C++ + + To compile 32-bit Qhull with Microsoft Visual C++ 2010 and later + - Download and extract Qhull (either GitHub, .tgz file, or .zip file) + - Load solution build/qhull-32.sln + - Right-click 'Retarget solution' from toolset v110 to your Platform Toolset + File > Save All + - Build target 'Win32' + - Project qhulltest requires Qt for DevStudio (http://www.qt.io) + Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/5.2.0/5.2.0/msvc2012) + If QTDIR is incorrect, precompile will fail with 'Can not locate the file specified' + - Copy Qt shared libraries, QtCore.dll and QtTest.dll, into the bin directory + + To compile 64-bit Qhull with Microsoft Visual C++ 2010 and later + - 64-bit Qhull has larger data structures due to 64-bit pointers. This may slow down Qhull. + - Download and extract Qhull (either GitHub, .tgz file, or .zip file) + - Load solution build/qhull-64.sln + - Right-click 'Retarget solution' from toolset v110 to your Platform Toolset + File > Save All + - Build target 'x64' + - If build as 32-bit fails, use solution build/qhull-32.sln + - Project qhulltest requires Qt for DevStudio (http://www.qt.io) + Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/5.2.0/5.2.0/msvc2012_64) + If QTDIR is incorrect, precompile will fail with 'Can not locate the file specified' + + If error -- MSB8020: The build tools for Visual Studio 2012 (Platform Toolset = 'v110') cannot be found. + - 'Project > Retarget solution' for both qhull-32.sln and qhull-64.sln + - 'File > Open' your preferred solution (qhull-32.sln or qhull-64.sln) + - 'Save All' both projects + - DevStudio may need a restart + + To compile Qhull with Microsoft Visual C++ 2005 (vcproj files) + - Download and extract Qhull (either GitHub, .tgz file, or .zip file) + - Load solution build/qhull.sln + - Build target 'win32' (not 'x64') + - Project qhulltest requires Qt for DevStudio (http://www.qt.io) + Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/4.7.4) + If QTDIR is incorrect, precompile will fail with 'Can not locate the file specified' + +------------------ +Compiling Qhull with Qt Creator + + Qt (http://www.qt.io) is a C++ framework for Windows, Linux, and Macintosh + + Qhull uses QTestLib to test qhull's C++ interface (see src/qhulltest/) + + To compile Qhull with Qt Creator + - Download and extract Qhull (either GitHub, .tgz file, or .zip file) + - Download the Qt SDK + - Start Qt Creator + - Load src/qhull-all.pro + - Configure the project to use a Shadow build at the same level as 'src', 'bin', and 'lib' + If, instead, the shadow build is a subdirectory of 'build', Qt Creator will install Qhull in 'build/bin' and 'build/lib' + - Build + + - Build qhulltest with a C++11 or later compiler + - qhulltest depends on shared libraries QtCore.a and QtTest.a. They may need to be copied + into the bin directory. On Windows, copy Qt5Core.dll and Qt5Test.dll, e.g., /qt/5.11.2/msvc2017_64/bin + - If qhulltest fails with exit status 127 and no error message, + check for missing Q5Core.dll and Qt5Test.dll + +------------------ +Compiling Qhull with mingw/gcc on Windows + + To compile Qhull with MINGW + - Download and extract Qhull (either GitHub, .tgz file, or .zip file) + - Install GitForWindows (https://gitforwindows.org/) + or MSYS2 (http://www.msys2.org/) + Install in C:\Git\... # Not 'Program Files\...' otherwise './configure && make' will not work + - Install MINGW-w64 with gcc (https://mingw-w64.org/) + 1) Goto sourceforge -- https://sourceforge.net/projects/mingw-w64/files/ + 2) in folder -- mingw-w64 + 3) download installer -- MinGW-W64-install.exe + Run the installer + 1) Select i686/posix/dwarf + 2) Install in 'C:\mingw-w64' # Not 'Program Files\...' + Rename /c/mingw-w64/mingw32/bin/mingw32-make.exe to make.exe + Add the 'C:\mingw-w64\mingw32\bin' directory to your $PATH environment variable + Execute 'which make' to check that 'make' is mingw-w64's make + - Compile Qhull from the home directory + make help + make + + Notes + - Mingw is included with Qt SDK in qt/Tools/mingw53_32 + - If you use Windows XP + Install Road Bash (http://www.qhull.org/bash) or MSYS (http://www.mingw.org/wiki/msys) + Install MINGW (http://mingw.org/) + +------------------ +Compiling Qhull with cygwin on Windows + + To compile Qhull with cygwin + - Download and extract Qhull (either GitHub, .tgz file, or .zip file) + - Install cygwin (http://www.cygwin.com) + - Include packages for gcc, make, ar, and ln + - make + +------------------ +Compiling from Makfile without gcc + + The file, qhull-src.tgz, contains documentation and source files for + qhull and rbox. + + To unpack the tgz file + - tar zxf qhull-src.tgz + - cd qhull + - Use qhull/Makefile + Simpler Makefiles are qhull/src/libqhull/Makefile and qhull/src/libqhull_r/Makefile + + Compiling qhull and rbox with Makefile + - in Makefile, check the CC, CCOPTS1, PRINTMAN, and PRINTC defines + - the defaults are gcc and enscript + - CCOPTS1 should include the ANSI flag. It defines __STDC__ + - in user.h, check the definitions of qh_SECticks and qh_CPUclock. + - use '#define qh_CLOCKtype 2' for timing runs longer than 1 hour + - type: make + - this builds: qhull qconvex qdelaunay qhalf qvoronoi rbox libqhull.a libqhull_r.a + - type: make doc + - this prints the man page + - See also qhull/html/index.htm + - if your compiler reports many errors, it is probably not a ANSI C compiler + - you will need to set the -ansi switch or find another compiler + - if your compiler warns about missing prototypes for fprintf() etc. + - this is ok, your compiler should have these in stdio.h + - if your compiler warns about missing prototypes for memset() etc. + - include memory.h in qhull_a.h + - if your compiler reports "global.c: storage size of 'qh_qh' isn't known" + - delete the initializer "={0}" in global.c, stat.c and mem.c + - if your compiler warns about "stat.c: improper initializer" + - this is ok, the initializer is not used + - if you have trouble building libqhull.a with 'ar' + - try 'make -f Makefile.txt qhullx' + - if the code compiles, the qhull test case will automatically execute + - if an error occurs, there's an incompatibility between machines + - If you can, try a different compiler + - You can turn off the Qhull memory manager with qh_NOmem in mem.h + - You can turn off compiler optimization (-O2 in Makefile) + - If you find the source of the problem, please let us know + - to install the programs and their man pages: + - define MANDIR and BINDIR + - type 'make install' + + - if you have Geomview (www.geomview.org) + - try 'rbox 100 | qconvex G >a' and load 'a' into Geomview + - run 'q_eg' for Geomview examples of Qhull output (see qh-eg.htm) + +------------------ +Compiling on other machines and compilers + + Qhull may compile with Borland C++ 5.0 bcc32. A Makefile is included. + Execute 'cd src/libqhull; make -f Mborland'. If you use the Borland IDE, set + the ANSI option in Options:Project:Compiler:Source:Language-compliance. + + Qhull may compile with Borland C++ 4.02 for Win32 and DOS Power Pack. + Use 'cd src/libqhull; make -f Mborland -D_DPMI'. Qhull 1.0 compiles with + Borland C++ 4.02. For rbox 1.0, use "bcc32 -WX -w- -O2-e -erbox -lc rbox.c". + Use the same options for Qhull 1.0. [D. Zwick] + + If you have troubles with the memory manager, you can turn it off by + defining qh_NOmem in mem.h. + +------------------ +Distributed files + + README.txt // Instructions for installing Qhull + REGISTER.txt // Qhull registration + COPYING.txt // Copyright notice + QHULL-GO.lnk // Windows icon for eg/qhull-go.bat + Announce.txt // Announcement + CMakeLists.txt // CMake build file (2.6 or later) + File_id.diz // Package descriptor + index.htm // Home page + Makefile // Makefile for gcc and other compilers + qhull*.md5sum // md5sum for all files + + bin/* // Qhull executables and dll (.zip only) + build/CMakeModules/CheckLFS.cmake // enables Large File Support in CMake + build/config.cmake.in // extract target variables + build/qhull.pc.in // pkg-config template for creating lib/pkgconfig/qhull*.pc + build/qhull-32.sln // 32-bit DevStudio solution and project files (2010 and later) + build/*-32.vcxproj + build/qhull-64.sln // 64-bit DevStudio solution and project files (2010 and later) + build/*-64.vcxproj + build/qhull.sln // DevStudio solution and project files (2005 and 2009) + build/*.vcproj + build/qhulltest/ // DevStudio project files for qhulltest (C++ and Qt) + build/README-build.txt // Contents of build/ + eg/* // Test scripts and geomview files from q_eg + html/index.htm // Manual + html/qh-faq.htm // Frequently asked questions + html/qh-get.htm // Download page + html/qhull-cpp.xml // C++ style notes as a Road FAQ (www.qhull.org/road) + src/Changes.txt // Change history for Qhull and rbox + src/qhull-all.pro // Qt project + +eg/ + q_benchmark // shell script for precision and performance benchmark + q_benchmark-ok.txt // reviewed output from q_benchmark + q_eg // shell script for Geomview examples (eg.01.cube) + q_egtest // shell script for Geomview test examples + q_test // shell script to test qhull + q_test.bat // Windows batch test for QHULL-GO.bat + // cd bin; ..\eg\q_test.bat >q_test.x 2>&1 + q_test-ok.txt // reviewed output from q_test + qhulltest-ok.txt // reviewed output from qhulltest (Qt only) + make-qhull_qh.sh // shell script to create non-reentrant qhull_qh from reentrant Qhull + make-vcproj.sh // shell script to create vcproj and vcxprog files + qhull-zip.sh // shell script to create distribution files + qtest.sh // shell script for testing and logging qhull + +rbox consists of (bin, html): + rbox.exe // Win32 executable (.zip only) + rbox.htm // html manual + rbox.man // Unix man page + rbox.txt + +qhull consists of (bin, html): + qconvex.exe // Win32 executables and dlls (.zip download only) + qhull.exe // Built with the reentrant library (about 2% slower) + qdelaunay.exe + qhalf.exe + qvoronoi.exe + qhull_r.dll + qhull-go.bat // command window + qconvex.htm // html manual + qdelaun.htm + qdelau_f.htm + qhalf.htm + qvoronoi.htm + qvoron_f.htm + qh-eg.htm + qh-code.htm + qh-impre.htm + index.htm + qh-opt*.htm + qh-quick.htm + qh--*.gif // images for manual + normal_voronoi_knauss_oesterle.jpg + qh_findbestfacet-drielsma.pdf + qhull.man // Unix man page + qhull.txt + +bin/ + msvcr80.dll // Visual C++ redistributable file (.zip download only) + +src/ + qhull/unix.c // Qhull and rbox applications using non-reentrant libqhullstatic.a + rbox/rbox.c + qconvex/qconvex.c + qhalf/qhalf.c + qdelaunay/qdelaunay.c + qvoronoi/qvoronoi.c + + qhull/unix_r.c // Qhull and rbox applications using reentrant libqhullstatic_r.a + rbox/rbox_r.c + qconvex/qconvex_r.c // Qhull applications built with reentrant libqhull_r/Makefile + qhalf/qhalf_r.c + qdelaunay/qdelaun_r.c + qvoronoi/qvoronoi_r.c + + user_eg/user_eg_r.c // example of using qhull_r.dll from a user program + user_eg2/user_eg2_r.c // example of using libqhullstatic_r.a from a user program + user_eg3/user_eg3_r.cpp // example of Qhull's C++ interface libqhullcpp with libqhullstatic_r.a + qhulltest/qhulltest.cpp // Test of Qhull's C++ interface using Qt's QTestLib + qhull-*.pri // Include files for Qt projects + testqset_r/testqset_r.c // Test of reentrant qset_r.c and mem_r.c + testqset/testqset.c // Test of non-rentrant qset.c and mem.c + +src/libqhull + libqhull.pro // Qt project for non-rentrant, shared library (qhull.dll) + index.htm // design documentation for libqhull + qh-*.htm + qhull-exports.def // Export Definition files for Visual C++ + qhull-nomerge-exports.def + qhull_p-exports.def + qhull_p-nomerge-exports.def + Makefile // Simple gcc Makefile for qhull and libqhullstatic.a + Mborland // Makefile for Borland C++ 5.0 + + libqhull.h // header file for qhull + user.h // header file of user definable constants + libqhull.c // Quickhull algorithm with partitioning + user.c // user re-definable functions + usermem.c + userprintf.c + userprintf_rbox.c + + qhull_a.h // include files for libqhull/*.c + geom.c // geometric routines + geom2.c + geom.h + global.c // global variables + io.c // input-output routines + io.h + mem.c // memory routines, this is stand-alone code + mem.h + merge.c // merging of non-convex facets + merge.h + poly.c // polyhedron routines + poly2.c + poly.h + qset.c // set routines, this only depends on mem.c + qset.h + random.c // utilities w/ Park & Miller's random number generator + random.h + rboxlib.c // point set generator for rbox + stat.c // statistics + stat.h + +src/libqhull_r + libqhull_r.pro // Qt project for rentrant, shared library (qhull_r.dll) + index.htm // design documentation for libqhull_r + qh-*_r.htm + qhull_r-exports.def // Export Definition files for Visual C++ + qhull_r-nomerge-exports.def + Makefile // Simple gcc Makefile for qhull and libqhullstatic.a + + libqhull_r.h // header file for qhull + user_r.h // header file of user definable constants + libqhull_r.c // Quickhull algorithm wi_r.hpartitioning + user_r.c // user re-definable functions + usermem.c + userprintf.c + userprintf_rbox.c + qhull_ra.h // include files for libqhull/*_r.c + geom_r.c // geometric routines + geom2.c + geom_r.h + global_r.c // global variables + io_r.c // input-output routines + io_r.h + mem_r.c // memory routines, this is stand-alone code + mem.h + merge_r.c // merging of non-convex facets + merge.h + poly_r.c // polyhedron routines + poly2.c + poly_r.h + qset_r.c // set routines, this only depends on mem_r.c + qset.h + random_r.c // utilities w/ Park & Miller's random number generator + random.h + rboxlib_r.c // point set generator for rbox + stat_r.c // statistics + stat.h + +src/libqhullcpp/ + libqhullcpp.pro // Qt project for renentrant, static C++ library + Qhull.cpp // Calls libqhull_r.c from C++ + Qhull.h + qt-qhull.cpp // Supporting methods for Qt + + Coordinates.cpp // input classes + Coordinates.h + + PointCoordinates.cpp + PointCoordinates.h + RboxPoints.cpp // call rboxlib.c from C++ + RboxPoints.h + + QhullFacet.cpp // data structure classes + QhullFacet.h + QhullHyperplane.cpp + QhullHyperplane.h + QhullPoint.cpp + QhullPoint.h + QhullQh.cpp + QhullRidge.cpp + QhullRidge.h + QhullVertex.cpp + QhullVertex.h + + QhullFacetList.cpp // collection classes + QhullFacetList.h + QhullFacetSet.cpp + QhullFacetSet.h + QhullIterator.h + QhullLinkedList.h + QhullPoints.cpp + QhullPoints.h + QhullPointSet.cpp + QhullPointSet.h + QhullSet.cpp + QhullSet.h + QhullSets.h + QhullVertexSet.cpp + QhullVertexSet.h + + functionObjects.h // supporting classes + QhullError.cpp + QhullError.h + QhullQh.cpp + QhullQh.h + QhullStat.cpp + QhullStat.h + QhullUser.cpp + QhullUser.h + RoadError.cpp // Supporting base classes + RoadError.h + RoadLogEvent.cpp + RoadLogEvent.h + usermem_r-cpp.cpp // Optional override for qh_exit() to throw an error + +src/libqhullstatic/ + libqhullstatic.pro // Qt project for non-reentrant, static library + +src/libqhullstatic_r/ + libqhullstatic_r.pro // Qt project for reentrant, static library + +src/qhulltest/ + qhulltest.pro // Qt project for test of C++ interface + Coordinates_test.cpp // Test of each class + PointCoordinates_test.cpp + Qhull_test.cpp + QhullFacet_test.cpp + QhullFacetList_test.cpp + QhullFacetSet_test.cpp + QhullHyperplane_test.cpp + QhullLinkedList_test.cpp + QhullPoint_test.cpp + QhullPoints_test.cpp + QhullPointSet_test.cpp + QhullRidge_test.cpp + QhullSet_test.cpp + QhullVertex_test.cpp + QhullVertexSet_test.cpp + RboxPoints_test.cpp + RoadTest.cpp // Run multiple test files with QTestLib + RoadTest.h + +------------------ +Authors + + C. Bradford Barber Hannu Huhdanpaa (Version 1.0) + bradb@shore.net hannu@qhull.org + + Qhull 1.0 and 2.0 were developed under NSF grants NSF/DMS-8920161 + and NSF-CCR-91-15793 750-7504 at the Geometry Center and Harvard + University. If you find Qhull useful, please let us know. diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/accessors_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/accessors_r.c new file mode 100644 index 00000000000..5052e0890c3 --- /dev/null +++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/accessors_r.c @@ -0,0 +1,69 @@ +#include +#include "libqhull_r.h" + +qhT *qh_alloc_qh(FILE *errfile) { + qhT *qh = (qhT*) qh_malloc(sizeof(qhT)); + QHULL_LIB_CHECK + if (qh) qh_zero(qh, errfile); + return qh; +} + +/* Free the qhT pointer. + + Note: qh_freeqhull and qh_memfreeshort should be called before calling qh_free_qh. */ +void qh_free_qh(qhT *qh) { + qh_free(qh); +} + +#define GETTER(TYPE, FIELD) TYPE qh_get_##FIELD(const qhT *qh) { return qh->FIELD; } +#define SETTER(TYPE, FIELD) void qh_set_##FIELD(qhT *qh, TYPE _val_) { qh->FIELD = _val_; } + +/* required to emulate the various FOR* macros */ +GETTER(facetT*, facet_list) +GETTER(pointT*, first_point) +GETTER(int, hull_dim) +GETTER(int, num_facets) +GETTER(int, num_points) +GETTER(int, num_vertices) +GETTER(vertexT*, vertex_list) + +/* suggested by @blegat based on Qhull.jl wrappers */ +GETTER(realT, totarea) +GETTER(realT, totvol) +GETTER(boolT, hasAreaVolume) +SETTER(boolT, hasAreaVolume) +GETTER(boolT, hasTriangulation) +SETTER(boolT, hasTriangulation) + +/* suggested by @JuhaHeiskala based on his DirectQHull.jl wrapper */ +GETTER(int, num_good) +GETTER(setT*, del_vertices) +GETTER(int, input_dim) + +/* other accessors, mimicking those provided by the scipy API: */ +GETTER(boolT, DELAUNAY) +GETTER(boolT, SCALElast) +GETTER(boolT, KEEPcoplanar) +GETTER(boolT, MERGEexact) +GETTER(boolT, NOerrexit) +GETTER(boolT, PROJECTdelaunay) +GETTER(boolT, ATinfinity) +GETTER(boolT, UPPERdelaunay) +GETTER(int, normal_size) +GETTER(int, num_visible) +GETTER(int, center_size) +GETTER(const char *, qhull_command) +GETTER(facetT*, facet_tail) +GETTER(vertexT*, vertex_tail) +GETTER(unsigned int, facet_id) +GETTER(unsigned int, visit_id) +GETTER(unsigned int, vertex_visit) +GETTER(pointT*, input_points) +GETTER(coordT*, feasible_point) +GETTER(realT, last_low) +GETTER(realT, last_high) +GETTER(realT, last_newhigh) +GETTER(realT, max_outside) +GETTER(realT, MINoutside) +GETTER(realT, DISTround) +GETTER(setT*, other_points) diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/geom2_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/geom2_r.c new file mode 100644 index 00000000000..7d171e4bd60 --- /dev/null +++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/geom2_r.c @@ -0,0 +1,2302 @@ +/*
  ---------------------------------
+
+
+   geom2_r.c
+   infrequently used geometric routines of qhull
+
+   see qh-geom_r.htm and geom_r.h
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/geom2_r.c#18 $$Change: 3396 $
+   $DateTime: 2023/01/02 16:59:48 $$Author: bbarber $
+
+   frequently used code goes into geom_r.c
+*/
+
+#include "qhull_ra.h"
+
+/*================== functions in alphabetic order ============*/
+
+/*---------------------------------
+
+  qh_copypoints(qh, points, numpoints, dimension )
+    return qh_malloc'd copy of points
+
+  notes:
+    qh_free the returned points to avoid a memory leak
+*/
+coordT *qh_copypoints(qhT *qh, coordT *points, int numpoints, int dimension)
+{
+  int size;
+  coordT *newpoints;
+
+  size= numpoints * dimension * (int)sizeof(coordT);
+  if (!(newpoints= (coordT *)qh_malloc((size_t)size))) {
+    qh_fprintf(qh, qh->ferr, 6004, "qhull error: insufficient memory to copy %d points\n",
+        numpoints);
+    qh_errexit(qh, qh_ERRmem, NULL, NULL);
+  }
+  memcpy((char *)newpoints, (char *)points, (size_t)size); /* newpoints!=0 by QH6004 */
+  return newpoints;
+} /* copypoints */
+
+/*---------------------------------
+
+  qh_crossproduct( dim, vecA, vecB, vecC )
+    crossproduct of 2 dim vectors
+    C= A x B
+
+  notes:
+    from Glasner, Graphics Gems I, p. 639
+    only defined for dim==3
+*/
+void qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]){
+
+  if (dim == 3) {
+    vecC[0]=   det2_(vecA[1], vecA[2],
+                     vecB[1], vecB[2]);
+    vecC[1]= - det2_(vecA[0], vecA[2],
+                     vecB[0], vecB[2]);
+    vecC[2]=   det2_(vecA[0], vecA[1],
+                     vecB[0], vecB[1]);
+  }
+} /* vcross */
+
+/*---------------------------------
+
+  qh_determinant(qh, rows, dim, nearzero )
+    compute signed determinant of a square matrix
+    uses qh.NEARzero to test for degenerate matrices
+
+  returns:
+    determinant
+    overwrites rows and the matrix
+    if dim == 2 or 3
+      nearzero iff determinant < qh->NEARzero[dim-1]
+      (!quite correct, not critical)
+    if dim >= 4
+      nearzero iff diagonal[k] < qh->NEARzero[k]
+*/
+realT qh_determinant(qhT *qh, realT **rows, int dim, boolT *nearzero) {
+  realT det=0;
+  int i;
+  boolT sign= False;
+
+  *nearzero= False;
+  if (dim < 2) {
+    qh_fprintf(qh, qh->ferr, 6005, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }else if (dim == 2) {
+    det= det2_(rows[0][0], rows[0][1],
+                 rows[1][0], rows[1][1]);
+    if (fabs_(det) < 10*qh->NEARzero[1])  /* QH11031 FIX: not really correct, what should this be? */
+      *nearzero= True;
+  }else if (dim == 3) {
+    det= det3_(rows[0][0], rows[0][1], rows[0][2],
+                 rows[1][0], rows[1][1], rows[1][2],
+                 rows[2][0], rows[2][1], rows[2][2]);
+    if (fabs_(det) < 10*qh->NEARzero[2])  /* QH11031 FIX: what should this be?  det 5.5e-12 was flat for qh_maxsimplex of qdelaunay 0,0 27,27 -36,36 -9,63 */
+      *nearzero= True;
+  }else {
+    qh_gausselim(qh, rows, dim, dim, &sign, nearzero);  /* if nearzero, diagonal still ok */
+    det= 1.0;
+    for (i=dim; i--; )
+      det *= (rows[i])[i];
+    if (sign)
+      det= -det;
+  }
+  return det;
+} /* determinant */
+
+/*---------------------------------
+
+  qh_detjoggle(qh, points, numpoints, dimension )
+    determine default max joggle for point array
+      as qh_distround * qh_JOGGLEdefault
+
+  returns:
+    initial value for JOGGLEmax from points and REALepsilon
+
+  notes:
+    computes DISTround since qh_maxmin not called yet
+    if qh->SCALElast, last dimension will be scaled later to MAXwidth
+
+    loop duplicated from qh_maxmin
+*/
+realT qh_detjoggle(qhT *qh, pointT *points, int numpoints, int dimension) {
+  realT abscoord, distround, joggle, maxcoord, mincoord;
+  pointT *point, *pointtemp;
+  realT maxabs= -REALmax;
+  realT sumabs= 0;
+  realT maxwidth= 0;
+  int k;
+
+  if (qh->SETroundoff)
+    distround= qh->DISTround; /* 'En' */
+  else{
+    for (k=0; k < dimension; k++) {
+      if (qh->SCALElast && k == dimension-1)
+        abscoord= maxwidth;
+      else if (qh->DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */
+        abscoord= 2 * maxabs * maxabs;  /* may be low by qh->hull_dim/2 */
+      else {
+        maxcoord= -REALmax;
+        mincoord= REALmax;
+        FORALLpoint_(qh, points, numpoints) {
+          maximize_(maxcoord, point[k]);
+          minimize_(mincoord, point[k]);
+        }
+        maximize_(maxwidth, maxcoord-mincoord);
+        abscoord= fmax_(maxcoord, -mincoord);
+      }
+      sumabs += abscoord;
+      maximize_(maxabs, abscoord);
+    } /* for k */
+    distround= qh_distround(qh, qh->hull_dim, maxabs, sumabs);
+  }
+  joggle= distround * qh_JOGGLEdefault;
+  maximize_(joggle, REALepsilon * qh_JOGGLEdefault);
+  trace2((qh, qh->ferr, 2001, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));
+  return joggle;
+} /* detjoggle */
+
+/*---------------------------------
+
+  qh_detmaxoutside(qh);
+    determine qh.MAXoutside target for qh_RATIO... tests of distance
+    updates option '_max-outside'
+
+  notes:
+    called from qh_addpoint and qh_detroundoff
+    accounts for qh.ONEmerge, qh.DISTround, qh.MINoutside ('Wn'), qh.max_outside
+    see qh_maxout for qh.max_outside with qh.DISTround
+*/
+
+void qh_detmaxoutside(qhT *qh) {
+  realT maxoutside;
+
+  maxoutside= fmax_(qh->max_outside, qh->ONEmerge + qh->DISTround);
+  maximize_(maxoutside, qh->MINoutside);
+  qh->MAXoutside= maxoutside;
+  trace3((qh, qh->ferr, 3056, "qh_detmaxoutside: MAXoutside %2.2g from qh.max_outside %2.2g, ONEmerge %2.2g, MINoutside %2.2g, DISTround %2.2g\n",
+      qh->MAXoutside, qh->max_outside, qh->ONEmerge, qh->MINoutside, qh->DISTround));
+} /* detmaxoutside */
+
+/*---------------------------------
+
+  qh_detroundoff(qh)
+    determine maximum roundoff errors from
+      REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord,
+      qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1
+
+    accounts for qh.SETroundoff, qh.RANDOMdist, qh->MERGEexact
+      qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum,
+      qh.postmerge_centrum, qh.MINoutside,
+      qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar
+
+  returns:
+    sets qh.DISTround, etc. (see below)
+    appends precision constants to qh.qhull_options
+
+  see:
+    qh_maxmin() for qh.NEARzero
+
+  design:
+    determine qh.DISTround for distance computations
+    determine minimum denominators for qh_divzero
+    determine qh.ANGLEround for angle computations
+    adjust qh.premerge_cos,... for roundoff error
+    determine qh.ONEmerge for maximum error due to a single merge
+    determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible,
+      qh.MINoutside, qh.WIDEfacet
+    initialize qh.max_vertex and qh.minvertex
+*/
+void qh_detroundoff(qhT *qh) {
+
+  qh_option(qh, "_max-width", NULL, &qh->MAXwidth);
+  if (!qh->SETroundoff) {
+    qh->DISTround= qh_distround(qh, qh->hull_dim, qh->MAXabs_coord, qh->MAXsumcoord);
+    qh_option(qh, "Error-roundoff", NULL, &qh->DISTround);
+  }
+  qh->MINdenom= qh->MINdenom_1 * qh->MAXabs_coord;
+  qh->MINdenom_1_2= sqrt(qh->MINdenom_1 * qh->hull_dim) ;  /* if will be normalized */
+  qh->MINdenom_2= qh->MINdenom_1_2 * qh->MAXabs_coord;
+                                              /* for inner product */
+  qh->ANGLEround= 1.01 * qh->hull_dim * REALepsilon;
+  if (qh->RANDOMdist) {
+    qh->ANGLEround += qh->RANDOMfactor;
+    trace4((qh, qh->ferr, 4096, "qh_detroundoff: increase qh.ANGLEround by option 'R%2.2g'\n", qh->RANDOMfactor));
+  }
+  if (qh->premerge_cos < REALmax/2) {
+    qh->premerge_cos -= qh->ANGLEround;
+    if (qh->RANDOMdist)
+      qh_option(qh, "Angle-premerge-with-random", NULL, &qh->premerge_cos);
+  }
+  if (qh->postmerge_cos < REALmax/2) {
+    qh->postmerge_cos -= qh->ANGLEround;
+    if (qh->RANDOMdist)
+      qh_option(qh, "Angle-postmerge-with-random", NULL, &qh->postmerge_cos);
+  }
+  qh->premerge_centrum += 2 * qh->DISTround;    /*2 for centrum and distplane()*/
+  qh->postmerge_centrum += 2 * qh->DISTround;
+  if (qh->RANDOMdist && (qh->MERGEexact || qh->PREmerge))
+    qh_option(qh, "Centrum-premerge-with-random", NULL, &qh->premerge_centrum);
+  if (qh->RANDOMdist && qh->POSTmerge)
+    qh_option(qh, "Centrum-postmerge-with-random", NULL, &qh->postmerge_centrum);
+  { /* compute ONEmerge, max vertex offset for merging simplicial facets */
+    realT maxangle= 1.0, maxrho;
+
+    minimize_(maxangle, qh->premerge_cos);
+    minimize_(maxangle, qh->postmerge_cos);
+    /* max diameter * sin theta + DISTround for vertex to its hyperplane */
+    qh->ONEmerge= sqrt((realT)qh->hull_dim) * qh->MAXwidth *
+      sqrt(1.0 - maxangle * maxangle) + qh->DISTround;
+    maxrho= qh->hull_dim * qh->premerge_centrum + qh->DISTround;
+    maximize_(qh->ONEmerge, maxrho);
+    maxrho= qh->hull_dim * qh->postmerge_centrum + qh->DISTround;
+    maximize_(qh->ONEmerge, maxrho);
+    if (qh->MERGING)
+      qh_option(qh, "_one-merge", NULL, &qh->ONEmerge);
+  }
+  qh->NEARinside= qh->ONEmerge * qh_RATIOnearinside; /* only used if qh->KEEPnearinside */
+  if (qh->JOGGLEmax < REALmax/2 && (qh->KEEPcoplanar || qh->KEEPinside)) {
+    realT maxdist;             /* adjust qh.NEARinside for joggle */
+    qh->KEEPnearinside= True;
+    maxdist= sqrt((realT)qh->hull_dim) * qh->JOGGLEmax + qh->DISTround;
+    maxdist= 2*maxdist;        /* vertex and coplanar point can joggle in opposite directions */
+    maximize_(qh->NEARinside, maxdist);  /* must agree with qh_nearcoplanar() */
+  }
+  if (qh->KEEPnearinside)
+    qh_option(qh, "_near-inside", NULL, &qh->NEARinside);
+  if (qh->JOGGLEmax < qh->DISTround) {
+    qh_fprintf(qh, qh->ferr, 6006, "qhull option error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n",
+         qh->JOGGLEmax, qh->DISTround);
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  if (qh->MINvisible > REALmax/2) {
+    if (!qh->MERGING)
+      qh->MINvisible= qh->DISTround;
+    else if (qh->hull_dim <= 3)
+      qh->MINvisible= qh->premerge_centrum;
+    else
+      qh->MINvisible= qh_COPLANARratio * qh->premerge_centrum;
+    if (qh->APPROXhull && qh->MINvisible > qh->MINoutside)
+      qh->MINvisible= qh->MINoutside;
+    qh_option(qh, "Visible-distance", NULL, &qh->MINvisible);
+  }
+  if (qh->MAXcoplanar > REALmax/2) {
+    qh->MAXcoplanar= qh->MINvisible;
+    qh_option(qh, "U-max-coplanar", NULL, &qh->MAXcoplanar);
+  }
+  if (!qh->APPROXhull) {             /* user may specify qh->MINoutside */
+    qh->MINoutside= 2 * qh->MINvisible;
+    if (qh->premerge_cos < REALmax/2)
+      maximize_(qh->MINoutside, (1- qh->premerge_cos) * qh->MAXabs_coord);
+    qh_option(qh, "Width-outside", NULL, &qh->MINoutside);
+  }
+  qh->WIDEfacet= qh->MINoutside;
+  maximize_(qh->WIDEfacet, qh_WIDEcoplanar * qh->MAXcoplanar);
+  maximize_(qh->WIDEfacet, qh_WIDEcoplanar * qh->MINvisible);
+  qh_option(qh, "_wide-facet", NULL, &qh->WIDEfacet);
+  if (qh->MINvisible > qh->MINoutside + 3 * REALepsilon
+  && !qh->BESToutside && !qh->FORCEoutput)
+    qh_fprintf(qh, qh->ferr, 7001, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g.  Flipped facets are likely.\n",
+             qh->MINvisible, qh->MINoutside);
+  qh->max_vertex= qh->DISTround;
+  qh->min_vertex= -qh->DISTround;
+  /* numeric constants reported in printsummary */
+  qh_detmaxoutside(qh);
+} /* detroundoff */
+
+/*---------------------------------
+
+  qh_detsimplex(qh, apex, points, dim, nearzero )
+    compute determinant of a simplex with point apex and base points
+
+  returns:
+     signed determinant and nearzero from qh_determinant
+
+  notes:
+     called by qh_maxsimplex and qh_initialvertices
+     uses qh.gm_matrix/qh.gm_row (assumes they're big enough)
+
+  design:
+    construct qm_matrix by subtracting apex from points
+    compute determinate
+*/
+realT qh_detsimplex(qhT *qh, pointT *apex, setT *points, int dim, boolT *nearzero) {
+  pointT *coorda, *coordp, *gmcoord, *point, **pointp;
+  coordT **rows;
+  int k,  i=0;
+  realT det;
+
+  zinc_(Zdetsimplex);
+  gmcoord= qh->gm_matrix;
+  rows= qh->gm_row;
+  FOREACHpoint_(points) {
+    if (i == dim)
+      break;
+    rows[i++]= gmcoord;
+    coordp= point;
+    coorda= apex;
+    for (k=dim; k--; )
+      *(gmcoord++)= *coordp++ - *coorda++;
+  }
+  if (i < dim) {
+    qh_fprintf(qh, qh->ferr, 6007, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n",
+               i, dim);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  det= qh_determinant(qh, rows, dim, nearzero);
+  trace2((qh, qh->ferr, 2002, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",
+          det, qh_pointid(qh, apex), dim, *nearzero));
+  return det;
+} /* detsimplex */
+
+/*---------------------------------
+
+  qh_distnorm( dim, point, normal, offset )
+    return distance from point to hyperplane at normal/offset
+
+  returns:
+    dist
+
+  notes:
+    dist > 0 if point is outside of hyperplane
+
+  see:
+    qh_distplane in geom_r.c
+*/
+realT qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp) {
+  coordT *normalp= normal, *coordp= point;
+  realT dist;
+  int k;
+
+  dist= *offsetp;
+  for (k=dim; k--; )
+    dist += *(coordp++) * *(normalp++);
+  return dist;
+} /* distnorm */
+
+/*---------------------------------
+
+  qh_distround(qh, dimension, maxabs, maxsumabs )
+    compute maximum round-off error for a distance computation
+      to a normalized hyperplane
+    maxabs is the maximum absolute value of a coordinate
+    maxsumabs is the maximum possible sum of absolute coordinate values
+    if qh.RANDOMdist ('Qr'), adjusts qh_distround
+
+  returns:
+    max dist round for qh.REALepsilon and qh.RANDOMdist
+
+  notes:
+    calculate roundoff error according to Golub & van Loan, 1983, Lemma 3.2-1, "Rounding Errors"
+    use sqrt(dim) since one vector is normalized
+      or use maxsumabs since one vector is < 1
+*/
+realT qh_distround(qhT *qh, int dimension, realT maxabs, realT maxsumabs) {
+  realT maxdistsum, maxround, delta;
+
+  maxdistsum= sqrt((realT)dimension) * maxabs;
+  minimize_( maxdistsum, maxsumabs);
+  maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);
+              /* adds maxabs for offset */
+  if (qh->RANDOMdist) {
+    delta= qh->RANDOMfactor * maxabs;
+    maxround += delta;
+    trace4((qh, qh->ferr, 4092, "qh_distround: increase roundoff by random delta %2.2g for option 'R%2.2g'\n", delta, qh->RANDOMfactor));
+  }
+  trace4((qh, qh->ferr, 4008, "qh_distround: %2.2g, maxabs %2.2g, maxsumabs %2.2g, maxdistsum %2.2g\n",
+            maxround, maxabs, maxsumabs, maxdistsum));
+  return maxround;
+} /* distround */
+
+/*---------------------------------
+
+  qh_divzero( numer, denom, mindenom1, zerodiv )
+    divide by a number that's nearly zero
+    mindenom1= minimum denominator for dividing into 1.0
+
+  returns:
+    quotient
+    sets zerodiv and returns 0.0 if it would overflow
+
+  design:
+    if numer is nearly zero and abs(numer) < abs(denom)
+      return numer/denom
+    else if numer is nearly zero
+      return 0 and zerodiv
+    else if denom/numer non-zero
+      return numer/denom
+    else
+      return 0 and zerodiv
+*/
+realT qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv) {
+  realT temp, numerx, denomx;
+
+
+  if (numer < mindenom1 && numer > -mindenom1) {
+    numerx= fabs_(numer);
+    denomx= fabs_(denom);
+    if (numerx < denomx) {
+      *zerodiv= False;
+      return numer/denom;
+    }else {
+      *zerodiv= True;
+      return 0.0;
+    }
+  }
+  temp= denom/numer;
+  if (temp > mindenom1 || temp < -mindenom1) {
+    *zerodiv= False;
+    return numer/denom;
+  }else {
+    *zerodiv= True;
+    return 0.0;
+  }
+} /* divzero */
+
+
+/*---------------------------------
+
+  qh_facetarea(qh, facet )
+    return area for a facet
+
+  notes:
+    if non-simplicial,
+      uses centrum to triangulate facet and sums the projected areas.
+    if (qh->DELAUNAY),
+      computes projected area instead for last coordinate
+    assumes facet->normal exists
+    projecting tricoplanar facets to the hyperplane does not appear to make a difference
+
+  design:
+    if simplicial
+      compute area
+    else
+      for each ridge
+        compute area from centrum to ridge
+    negate area if upper Delaunay facet
+*/
+realT qh_facetarea(qhT *qh, facetT *facet) {
+  vertexT *apex;
+  pointT *centrum;
+  realT area= 0.0;
+  ridgeT *ridge, **ridgep;
+
+  if (facet->simplicial) {
+    apex= SETfirstt_(facet->vertices, vertexT);
+    area= qh_facetarea_simplex(qh, qh->hull_dim, apex->point, facet->vertices,
+                    apex, facet->toporient, facet->normal, &facet->offset);
+  }else {
+    if (qh->CENTERtype == qh_AScentrum)
+      centrum= facet->center;
+    else
+      centrum= qh_getcentrum(qh, facet);
+    FOREACHridge_(facet->ridges)
+      area += qh_facetarea_simplex(qh, qh->hull_dim, centrum, ridge->vertices,
+                 NULL, (boolT)(ridge->top == facet),  facet->normal, &facet->offset);
+    if (qh->CENTERtype != qh_AScentrum)
+      qh_memfree(qh, centrum, qh->normal_size);
+  }
+  if (facet->upperdelaunay && qh->DELAUNAY)
+    area= -area;  /* the normal should be [0,...,1] */
+  trace4((qh, qh->ferr, 4009, "qh_facetarea: f%d area %2.2g\n", facet->id, area));
+  return area;
+} /* facetarea */
+
+/*---------------------------------
+
+  qh_facetarea_simplex(qh, dim, apex, vertices, notvertex, toporient, normal, offset )
+    return area for a simplex defined by
+      an apex, a base of vertices, an orientation, and a unit normal
+    if simplicial or tricoplanar facet,
+      notvertex is defined and it is skipped in vertices
+
+  returns:
+    computes area of simplex projected to plane [normal,offset]
+    returns 0 if vertex too far below plane (qh->WIDEfacet)
+      vertex can't be apex of tricoplanar facet
+
+  notes:
+    if (qh->DELAUNAY),
+      computes projected area instead for last coordinate
+    uses qh->gm_matrix/gm_row and qh->hull_dim
+    helper function for qh_facetarea
+
+  design:
+    if Notvertex
+      translate simplex to apex
+    else
+      project simplex to normal/offset
+      translate simplex to apex
+    if Delaunay
+      set last row/column to 0 with -1 on diagonal
+    else
+      set last row to Normal
+    compute determinate
+    scale and flip sign for area
+*/
+realT qh_facetarea_simplex(qhT *qh, int dim, coordT *apex, setT *vertices,
+        vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset) {
+  pointT *coorda, *coordp, *gmcoord;
+  coordT **rows, *normalp;
+  int k,  i=0;
+  realT area, dist;
+  vertexT *vertex, **vertexp;
+  boolT nearzero;
+
+  gmcoord= qh->gm_matrix;
+  rows= qh->gm_row;
+  FOREACHvertex_(vertices) {
+    if (vertex == notvertex)
+      continue;
+    rows[i++]= gmcoord;
+    coorda= apex;
+    coordp= vertex->point;
+    normalp= normal;
+    if (notvertex) {
+      for (k=dim; k--; )
+        *(gmcoord++)= *coordp++ - *coorda++;
+    }else {
+      dist= *offset;
+      for (k=dim; k--; )
+        dist += *coordp++ * *normalp++;
+      if (dist < -qh->WIDEfacet) {
+        zinc_(Znoarea);
+        return 0.0;
+      }
+      coordp= vertex->point;
+      normalp= normal;
+      for (k=dim; k--; )
+        *(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;
+    }
+  }
+  if (i != dim-1) {
+    qh_fprintf(qh, qh->ferr, 6008, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n",
+               i, dim);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  rows[i]= gmcoord;
+  if (qh->DELAUNAY) {
+    for (i=0; i < dim-1; i++)
+      rows[i][dim-1]= 0.0;
+    for (k=dim; k--; )
+      *(gmcoord++)= 0.0;
+    rows[dim-1][dim-1]= -1.0;
+  }else {
+    normalp= normal;
+    for (k=dim; k--; )
+      *(gmcoord++)= *normalp++;
+  }
+  zinc_(Zdetfacetarea);
+  area= qh_determinant(qh, rows, dim, &nearzero);
+  if (toporient)
+    area= -area;
+  area *= qh->AREAfactor;
+  trace4((qh, qh->ferr, 4010, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n",
+          area, qh_pointid(qh, apex), toporient, nearzero));
+  return area;
+} /* facetarea_simplex */
+
+/*---------------------------------
+
+  qh_facetcenter(qh, vertices )
+    return Voronoi center (Voronoi vertex) for a facet's vertices
+
+  returns:
+    return temporary point equal to the center
+
+  see:
+    qh_voronoi_center()
+*/
+pointT *qh_facetcenter(qhT *qh, setT *vertices) {
+  setT *points= qh_settemp(qh, qh_setsize(qh, vertices));
+  vertexT *vertex, **vertexp;
+  pointT *center;
+
+  FOREACHvertex_(vertices)
+    qh_setappend(qh, &points, vertex->point);
+  center= qh_voronoi_center(qh, qh->hull_dim-1, points);
+  qh_settempfree(qh, &points);
+  return center;
+} /* facetcenter */
+
+/*---------------------------------
+
+  qh_findgooddist(qh, point, facetA, dist, facetlist )
+    find best good facet visible for point from facetA
+    assumes facetA is visible from point
+
+  returns:
+    best facet, i.e., good facet that is furthest from point
+      distance to best facet
+      NULL if none
+
+    moves good, visible facets (and some other visible facets)
+      to end of qh->facet_list
+
+  notes:
+    uses qh->visit_id
+
+  design:
+    initialize bestfacet if facetA is good
+    move facetA to end of facetlist
+    for each facet on facetlist
+      for each unvisited neighbor of facet
+        move visible neighbors to end of facetlist
+        update best good neighbor
+        if no good neighbors, update best facet
+*/
+facetT *qh_findgooddist(qhT *qh, pointT *point, facetT *facetA, realT *distp,
+               facetT **facetlist) {
+  realT bestdist= -REALmax, dist;
+  facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;
+  boolT goodseen= False;
+
+  if (facetA->good) {
+    zzinc_(Zcheckpart);  /* calls from check_bestdist occur after print stats */
+    qh_distplane(qh, point, facetA, &bestdist);
+    bestfacet= facetA;
+    goodseen= True;
+  }
+  qh_removefacet(qh, facetA);
+  qh_appendfacet(qh, facetA);
+  *facetlist= facetA;
+  facetA->visitid= ++qh->visit_id;
+  FORALLfacet_(*facetlist) {
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid == qh->visit_id)
+        continue;
+      neighbor->visitid= qh->visit_id;
+      if (goodseen && !neighbor->good)
+        continue;
+      zzinc_(Zcheckpart);
+      qh_distplane(qh, point, neighbor, &dist);
+      if (dist > 0) {
+        qh_removefacet(qh, neighbor);
+        qh_appendfacet(qh, neighbor);
+        if (neighbor->good) {
+          goodseen= True;
+          if (dist > bestdist) {
+            bestdist= dist;
+            bestfacet= neighbor;
+          }
+        }
+      }
+    }
+  }
+  if (bestfacet) {
+    *distp= bestdist;
+    trace2((qh, qh->ferr, 2003, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",
+      qh_pointid(qh, point), bestdist, bestfacet->id));
+    return bestfacet;
+  }
+  trace4((qh, qh->ferr, 4011, "qh_findgooddist: no good facet for p%d above f%d\n",
+      qh_pointid(qh, point), facetA->id));
+  return NULL;
+}  /* findgooddist */
+
+/*---------------------------------
+
+  qh_furthestnewvertex(qh, unvisited, facet, &maxdist )
+    return furthest unvisited, new vertex to a facet
+
+  return:
+    NULL if no vertex is above facet
+    maxdist to facet
+    updates v.visitid
+
+  notes:
+    Ignores vertices in facetB
+    Does not change qh.vertex_visit.  Use in conjunction with qh_furthestvertex
+*/
+vertexT *qh_furthestnewvertex(qhT *qh, unsigned int unvisited, facetT *facet, realT *maxdistp /* qh.newvertex_list */) {
+  vertexT *maxvertex= NULL, *vertex;
+  coordT dist, maxdist= 0.0;
+
+  FORALLvertex_(qh->newvertex_list) {
+    if (vertex->newfacet && vertex->visitid <= unvisited) {
+      vertex->visitid= qh->vertex_visit;
+      qh_distplane(qh, vertex->point, facet, &dist);
+      if (dist > maxdist) {
+        maxdist= dist;
+        maxvertex= vertex;
+      }
+    }
+  }
+  trace4((qh, qh->ferr, 4085, "qh_furthestnewvertex: v%d dist %2.2g is furthest new vertex for f%d\n",
+    getid_(maxvertex), maxdist, facet->id));
+  *maxdistp= maxdist;
+  return maxvertex;
+} /* furthestnewvertex */
+
+/*---------------------------------
+
+  qh_furthestvertex(qh, facetA, facetB, &maxdist, &mindist )
+    return furthest vertex in facetA from facetB, or NULL if none
+
+  return:
+    maxdist and mindist to facetB or 0.0 if none
+    updates qh.vertex_visit
+
+  notes:
+    Ignores vertices in facetB
+*/
+vertexT *qh_furthestvertex(qhT *qh, facetT *facetA, facetT *facetB, realT *maxdistp, realT *mindistp) {
+  vertexT *maxvertex= NULL, *vertex, **vertexp;
+  coordT dist, maxdist= -REALmax, mindist= REALmax;
+
+  qh->vertex_visit++;
+  FOREACHvertex_(facetB->vertices)
+    vertex->visitid= qh->vertex_visit;
+  FOREACHvertex_(facetA->vertices) {
+    if (vertex->visitid != qh->vertex_visit) {
+      vertex->visitid= qh->vertex_visit;
+      zzinc_(Zvertextests);
+      qh_distplane(qh, vertex->point, facetB, &dist);
+      if (!maxvertex) {
+        maxdist= dist;
+        mindist= dist;
+        maxvertex= vertex;
+      }else if (dist > maxdist) {
+        maxdist= dist;
+        maxvertex= vertex;
+      }else if (dist < mindist)
+        mindist= dist;
+    }
+  }
+  if (!maxvertex) {
+    trace3((qh, qh->ferr, 3067, "qh_furthestvertex: all vertices of f%d are in f%d.  Returning 0.0 for max and mindist\n",
+      facetA->id, facetB->id));
+    maxdist= mindist= 0.0;
+  }else {
+    trace4((qh, qh->ferr, 4084, "qh_furthestvertex: v%d dist %2.2g is furthest (mindist %2.2g) of f%d above f%d\n",
+      maxvertex->id, maxdist, mindist, facetA->id, facetB->id));
+  }
+  *maxdistp= maxdist;
+  *mindistp= mindist;
+  return maxvertex;
+} /* furthestvertex */
+
+/*---------------------------------
+
+  qh_getarea(qh, facetlist )
+    set area of all facets in facetlist
+    collect statistics
+    nop if hasAreaVolume
+
+  returns:
+    sets qh->totarea/totvol to total area and volume of convex hull
+    for Delaunay triangulation, computes projected area of the lower or upper hull
+      ignores upper hull if qh->ATinfinity
+
+  notes:
+    could compute outer volume by expanding facet area by rays from interior
+    the following attempt at perpendicular projection underestimated badly:
+      qh.totoutvol += (-dist + facet->maxoutside + qh->DISTround)
+                            * area/ qh->hull_dim;
+  design:
+    for each facet on facetlist
+      compute facet->area
+      update qh.totarea and qh.totvol
+*/
+void qh_getarea(qhT *qh, facetT *facetlist) {
+  realT area;
+  realT dist;
+  facetT *facet;
+
+  if (qh->hasAreaVolume)
+    return;
+  if (qh->REPORTfreq)
+    qh_fprintf(qh, qh->ferr, 8020, "computing area of each facet and volume of the convex hull\n");
+  else
+    trace1((qh, qh->ferr, 1001, "qh_getarea: computing area for each facet and its volume to qh.interior_point (dist*area/dim)\n"));
+  qh->totarea= qh->totvol= 0.0;
+  FORALLfacet_(facetlist) {
+    if (!facet->normal)
+      continue;
+    if (facet->upperdelaunay && qh->ATinfinity)
+      continue;
+    if (!facet->isarea) {
+      facet->f.area= qh_facetarea(qh, facet);
+      facet->isarea= True;
+    }
+    area= facet->f.area;
+    if (qh->DELAUNAY) {
+      if (facet->upperdelaunay == qh->UPPERdelaunay)
+        qh->totarea += area;
+    }else {
+      qh->totarea += area;
+      qh_distplane(qh, qh->interior_point, facet, &dist);
+      qh->totvol += -dist * area/ qh->hull_dim;
+    }
+    if (qh->PRINTstatistics) {
+      wadd_(Wareatot, area);
+      wmax_(Wareamax, area);
+      wmin_(Wareamin, area);
+    }
+  }
+  qh->hasAreaVolume= True;
+} /* getarea */
+
+/*---------------------------------
+
+  qh_gram_schmidt(qh, dim, row )
+    implements Gram-Schmidt orthogonalization by rows
+
+  returns:
+    false if zero norm
+    overwrites rows[dim][dim]
+
+  notes:
+    see Golub & van Loan, 1983, Algorithm 6.2-2, "Modified Gram-Schmidt"
+    overflow due to small divisors not handled
+
+  design:
+    for each row
+      compute norm for row
+      if non-zero, normalize row
+      for each remaining rowA
+        compute inner product of row and rowA
+        reduce rowA by row * inner product
+*/
+boolT qh_gram_schmidt(qhT *qh, int dim, realT **row) {
+  realT *rowi, *rowj, norm;
+  int i, j, k;
+
+  for (i=0; i < dim; i++) {
+    rowi= row[i];
+    for (norm=0.0, k=dim; k--; rowi++)
+      norm += *rowi * *rowi;
+    norm= sqrt(norm);
+    wmin_(Wmindenom, norm);
+    if (norm == 0.0)  /* either 0 or overflow due to sqrt */
+      return False;
+    for (k=dim; k--; )
+      *(--rowi) /= norm;
+    for (j=i+1; j < dim; j++) {
+      rowj= row[j];
+      for (norm=0.0, k=dim; k--; )
+        norm += *rowi++ * *rowj++;
+      for (k=dim; k--; )
+        *(--rowj) -= *(--rowi) * norm;
+    }
+  }
+  return True;
+} /* gram_schmidt */
+
+
+/*---------------------------------
+
+  qh_inthresholds(qh, normal, angle )
+    return True if normal within qh.lower_/upper_threshold
+
+  returns:
+    estimate of angle by summing of threshold diffs
+      angle may be NULL
+      smaller "angle" is better
+
+  notes:
+    invalid if qh.SPLITthresholds
+
+  see:
+    qh.lower_threshold in qh_initbuild()
+    qh_initthresholds()
+
+  design:
+    for each dimension
+      test threshold
+*/
+boolT qh_inthresholds(qhT *qh, coordT *normal, realT *angle) {
+  boolT within= True;
+  int k;
+  realT threshold;
+
+  if (angle)
+    *angle= 0.0;
+  for (k=0; k < qh->hull_dim; k++) {
+    threshold= qh->lower_threshold[k];
+    if (threshold > -REALmax/2) {
+      if (normal[k] < threshold)
+        within= False;
+      if (angle) {
+        threshold -= normal[k];
+        *angle += fabs_(threshold);
+      }
+    }
+    if (qh->upper_threshold[k] < REALmax/2) {
+      threshold= qh->upper_threshold[k];
+      if (normal[k] > threshold)
+        within= False;
+      if (angle) {
+        threshold -= normal[k];
+        *angle += fabs_(threshold);
+      }
+    }
+  }
+  return within;
+} /* inthresholds */
+
+
+/*---------------------------------
+
+  qh_joggleinput(qh)
+    randomly joggle input to Qhull by qh.JOGGLEmax
+    initial input is qh.first_point/qh.num_points of qh.hull_dim
+      repeated calls use qh.input_points/qh.num_points
+
+  returns:
+    joggles points at qh.first_point/qh.num_points
+    copies data to qh.input_points/qh.input_malloc if first time
+    determines qh.JOGGLEmax if it was zero
+    if qh.DELAUNAY
+      computes the Delaunay projection of the joggled points
+
+  notes:
+    if qh.DELAUNAY, unnecessarily joggles the last coordinate
+    the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease
+
+  design:
+    if qh.DELAUNAY
+      set qh.SCALElast for reduced precision errors
+    if first call
+      initialize qh.input_points to the original input points
+      if qh.JOGGLEmax == 0
+        determine default qh.JOGGLEmax
+    else
+      increase qh.JOGGLEmax according to qh.build_cnt
+    joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]
+    if qh.DELAUNAY
+      sets the Delaunay projection
+*/
+void qh_joggleinput(qhT *qh) {
+  int i, seed, size;
+  coordT *coordp, *inputp;
+  realT randr, randa, randb;
+
+  if (!qh->input_points) { /* first call */
+    qh->input_points= qh->first_point;
+    qh->input_malloc= qh->POINTSmalloc;
+    size= qh->num_points * qh->hull_dim * (int)sizeof(coordT);
+    if (!(qh->first_point= (coordT *)qh_malloc((size_t)size))) {
+      qh_fprintf(qh, qh->ferr, 6009, "qhull error: insufficient memory to joggle %d points\n",
+          qh->num_points);
+      qh_errexit(qh, qh_ERRmem, NULL, NULL);
+    }
+    qh->POINTSmalloc= True;
+    if (qh->JOGGLEmax == 0.0) {
+      qh->JOGGLEmax= qh_detjoggle(qh, qh->input_points, qh->num_points, qh->hull_dim);
+      qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);
+    }
+  }else {                 /* repeated call */
+    if (!qh->RERUN && qh->build_cnt > qh_JOGGLEretry) {
+      if (((qh->build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {
+        realT maxjoggle= qh->MAXwidth * qh_JOGGLEmaxincrease;
+        if (qh->JOGGLEmax < maxjoggle) {
+          qh->JOGGLEmax *= qh_JOGGLEincrease;
+          minimize_(qh->JOGGLEmax, maxjoggle);
+        }
+      }
+    }
+    qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);
+  }
+  if (qh->build_cnt > 1 && qh->JOGGLEmax > fmax_(qh->MAXwidth/4, 0.1)) {
+      qh_fprintf(qh, qh->ferr, 6010, "qhull input error (qh_joggleinput): the current joggle for 'QJn', %.2g, is too large for the width\nof the input.  If possible, recompile Qhull with higher-precision reals.\n",
+                qh->JOGGLEmax);
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  /* for some reason, using qh->ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */
+  seed= qh_RANDOMint;
+  qh_option(qh, "_joggle-seed", &seed, NULL);
+  trace0((qh, qh->ferr, 6, "qh_joggleinput: joggle input by %4.4g with seed %d\n",
+    qh->JOGGLEmax, seed));
+  inputp= qh->input_points;
+  coordp= qh->first_point;
+  randa= 2.0 * qh->JOGGLEmax/qh_RANDOMmax;
+  randb= -qh->JOGGLEmax;
+  size= qh->num_points * qh->hull_dim;
+  for (i=size; i--; ) {
+    randr= qh_RANDOMint;
+    *(coordp++)= *(inputp++) + (randr * randa + randb);
+  }
+  if (qh->DELAUNAY) {
+    qh->last_low= qh->last_high= qh->last_newhigh= REALmax;
+    qh_setdelaunay(qh, qh->hull_dim, qh->num_points, qh->first_point);
+  }
+} /* joggleinput */
+
+/*---------------------------------
+
+  qh_maxabsval( normal, dim )
+    return pointer to maximum absolute value of a dim vector
+    returns NULL if dim=0
+*/
+realT *qh_maxabsval(realT *normal, int dim) {
+  realT maxval= -REALmax;
+  realT *maxp= NULL, *colp, absval;
+  int k;
+
+  for (k=dim, colp= normal; k--; colp++) {
+    absval= fabs_(*colp);
+    if (absval > maxval) {
+      maxval= absval;
+      maxp= colp;
+    }
+  }
+  return maxp;
+} /* maxabsval */
+
+
+/*---------------------------------
+
+  qh_maxmin(qh, points, numpoints, dimension )
+    return max/min points for each dimension
+    determine max and min coordinates
+
+  returns:
+    returns a temporary set of max and min points
+      may include duplicate points. Does not include qh.GOODpoint
+    sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth
+         qh.MAXlastcoord, qh.MINlastcoord
+    initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok
+
+  notes:
+    loop duplicated in qh_detjoggle()
+
+  design:
+    initialize global precision variables
+    checks definition of REAL...
+    for each dimension
+      for each point
+        collect maximum and minimum point
+      collect maximum of maximums and minimum of minimums
+      determine qh.NEARzero for Gaussian Elimination
+*/
+setT *qh_maxmin(qhT *qh, pointT *points, int numpoints, int dimension) {
+  int k;
+  realT maxcoord, temp;
+  pointT *minimum, *maximum, *point, *pointtemp;
+  setT *set;
+
+  qh->max_outside= 0.0;
+  qh->MAXabs_coord= 0.0;
+  qh->MAXwidth= -REALmax;
+  qh->MAXsumcoord= 0.0;
+  qh->min_vertex= 0.0;
+  qh->WAScoplanar= False;
+  if (qh->ZEROcentrum)
+    qh->ZEROall_ok= True;
+  if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax
+  && REALmax > 0.0 && -REALmax < 0.0)
+    ; /* all ok */
+  else {
+    qh_fprintf(qh, qh->ferr, 6011, "qhull error: one or more floating point constants in user_r.h are inconsistent. REALmin %g, -REALmax %g, 0.0, REALepsilon %g, REALmax %g\n",
+          REALmin, -REALmax, REALepsilon, REALmax);
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  set= qh_settemp(qh, 2*dimension);
+  trace1((qh, qh->ferr, 8082, "qh_maxmin: dim             min             max           width    nearzero  min-point  max-point\n"));
+  for (k=0; k < dimension; k++) {
+    if (points == qh->GOODpointp)
+      minimum= maximum= points + dimension;
+    else
+      minimum= maximum= points;
+    FORALLpoint_(qh, points, numpoints) {
+      if (point == qh->GOODpointp)
+        continue;
+      if (maximum[k] < point[k])
+        maximum= point;
+      else if (minimum[k] > point[k])
+        minimum= point;
+    }
+    if (k == dimension-1) {
+      qh->MINlastcoord= minimum[k];
+      qh->MAXlastcoord= maximum[k];
+    }
+    if (qh->SCALElast && k == dimension-1)
+      maxcoord= qh->MAXabs_coord;
+    else {
+      maxcoord= fmax_(maximum[k], -minimum[k]);
+      if (qh->GOODpointp) {
+        temp= fmax_(qh->GOODpointp[k], -qh->GOODpointp[k]);
+        maximize_(maxcoord, temp);
+      }
+      temp= maximum[k] - minimum[k];
+      maximize_(qh->MAXwidth, temp);
+    }
+    maximize_(qh->MAXabs_coord, maxcoord);
+    qh->MAXsumcoord += maxcoord;
+    qh_setappend(qh, &set, minimum);
+    qh_setappend(qh, &set, maximum);
+    /* calculation of qh NEARzero is based on Golub & van Loan, 1983,
+       Eq. 4.4-13 for "Gaussian elimination with complete pivoting".
+       Golub & van Loan say that n^3 can be ignored and 10 be used in
+       place of rho */
+    qh->NEARzero[k]= 80 * qh->MAXsumcoord * REALepsilon;
+    trace1((qh, qh->ferr, 8106, "           %3d % 14.8e % 14.8e % 14.8e  %4.4e  p%-9d p%-d\n",
+            k, minimum[k], maximum[k], maximum[k]-minimum[k], qh->NEARzero[k], qh_pointid(qh, minimum), qh_pointid(qh, maximum)));
+    if (qh->SCALElast && k == dimension-1)
+      trace1((qh, qh->ferr, 8107, "           last coordinate scaled to (%4.4g, %4.4g), width %4.4e for option 'Qbb'\n",
+            qh->MAXabs_coord - qh->MAXwidth, qh->MAXabs_coord, qh->MAXwidth));
+  }
+  if (qh->IStracing >= 1)
+    qh_printpoints(qh, qh->ferr, "qh_maxmin: found the max and min points (by dim):", set);
+  return(set);
+} /* maxmin */
+
+/*---------------------------------
+
+  qh_maxouter(qh)
+    return maximum distance from facet to outer plane
+    normally this is qh.max_outside+qh.DISTround
+    does not include qh.JOGGLEmax
+
+  see:
+    qh_outerinner()
+
+  notes:
+    need to add another qh.DISTround if testing actual point with computation
+    see qh_detmaxoutside for a qh_RATIO... target
+
+  for joggle:
+    qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)
+    need to use Wnewvertexmax since could have a coplanar point for a high
+      facet that is replaced by a low facet
+    need to add qh.JOGGLEmax if testing input points
+*/
+realT qh_maxouter(qhT *qh) {
+  realT dist;
+
+  dist= fmax_(qh->max_outside, qh->DISTround);
+  dist += qh->DISTround;
+  trace4((qh, qh->ferr, 4012, "qh_maxouter: max distance from facet to outer plane is %4.4g, qh.max_outside is %4.4g\n", dist, qh->max_outside));
+  return dist;
+} /* maxouter */
+
+/*---------------------------------
+
+  qh_maxsimplex(qh, dim, maxpoints, points, numpoints, simplex )
+    determines maximum simplex for a set of points
+    maxpoints is the subset of points with a min or max coordinate
+    may start with points already in simplex
+    skips qh.GOODpointp (assumes that it isn't in maxpoints)
+
+  returns:
+    simplex with dim+1 points
+
+  notes:
+    called by qh_initialvertices, qh_detvnorm, and qh_voronoi_center
+    requires qh.MAXwidth to estimate determinate for each vertex
+    assumes at least needed points in points
+    maximizes determinate for x,y,z,w, etc.
+    uses maxpoints as long as determinate is clearly non-zero
+
+  design:
+    initialize simplex with at least two points
+      (find points with max or min x coordinate)
+    create a simplex of dim+1 vertices as follows
+      add point from maxpoints that maximizes the determinate of the point and the simplex vertices  
+      if last point and maxdet/prevdet < qh_RATIOmaxsimplex (3.0e-2)
+        flag maybe_falsenarrow
+      if no maxpoint or maxnearzero or maybe_falsenarrow
+        search all points for maximum determinate
+        early exit if maybe_falsenarrow and !maxnearzero and maxdet > prevdet
+*/
+void qh_maxsimplex(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {
+  pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;
+  boolT nearzero, maxnearzero= False, maybe_falsenarrow;
+  int i, sizinit;
+  realT maxdet= -1.0, prevdet= -1.0, det, mincoord= REALmax, maxcoord= -REALmax, mindet, ratio, targetdet;
+
+  if (qh->MAXwidth <= 0.0) {
+    qh_fprintf(qh, qh->ferr, 6421, "qhull internal error (qh_maxsimplex): qh.MAXwidth required for qh_maxsimplex.  Used to estimate determinate\n");
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  sizinit= qh_setsize(qh, *simplex);
+  if (sizinit >= 2) {
+    maxdet= pow(qh->MAXwidth, sizinit - 1);
+  }else {
+    if (qh_setsize(qh, maxpoints) >= 2) {
+      FOREACHpoint_(maxpoints) {
+        if (maxcoord < point[0]) {
+          maxcoord= point[0];
+          maxx= point;
+        }
+        if (mincoord > point[0]) {
+          mincoord= point[0];
+          minx= point;
+        }
+      }
+    }else {
+      FORALLpoint_(qh, points, numpoints) {
+        if (point == qh->GOODpointp)
+          continue;
+        if (maxcoord < point[0]) {
+          maxcoord= point[0];
+          maxx= point;
+        }
+        if (mincoord > point[0]) {
+          mincoord= point[0];
+          minx= point;
+        }
+      }
+    }
+    maxdet= maxcoord - mincoord;
+    qh_setunique(qh, simplex, minx);
+    if (qh_setsize(qh, *simplex) < 2)
+      qh_setunique(qh, simplex, maxx);
+    sizinit= qh_setsize(qh, *simplex);
+    if (sizinit < 2) {
+      qh_joggle_restart(qh, "input has same x coordinate");
+      if (zzval_(Zsetplane) > qh->hull_dim+1) {
+        qh_fprintf(qh, qh->ferr, 6012, "qhull precision error (qh_maxsimplex for voronoi_center): %d points with the same x coordinate %4.4g\n",
+                 qh_setsize(qh, maxpoints)+numpoints, mincoord);
+        qh_errexit(qh, qh_ERRprec, NULL, NULL);
+      }else {
+        qh_fprintf(qh, qh->ferr, 6013, "qhull input error: input is less than %d-dimensional since all points have the same x coordinate %4.4g\n",
+                 qh->hull_dim, mincoord);
+        qh_errexit(qh, qh_ERRinput, NULL, NULL);
+      }
+    }
+  }
+  for (i=sizinit; i < dim+1; i++) {
+    prevdet= maxdet;
+    maxpoint= NULL;
+    maxdet= -1.0;
+    FOREACHpoint_(maxpoints) {
+      if (!qh_setin(*simplex, point) && point != maxpoint) {
+        det= qh_detsimplex(qh, point, *simplex, i, &nearzero); /* retests maxpoints if duplicate or multiple iterations */
+        if ((det= fabs_(det)) > maxdet) {
+          maxdet= det;
+          maxpoint= point;
+          maxnearzero= nearzero;
+        }
+      }
+    }
+    maybe_falsenarrow= False;
+    ratio= 1.0;
+    targetdet= prevdet * qh->MAXwidth;
+    mindet= 10 * qh_RATIOmaxsimplex * targetdet;
+    if (maxdet > 0.0) {
+      ratio= maxdet / targetdet;
+      if (ratio < qh_RATIOmaxsimplex)
+        maybe_falsenarrow= True;
+    }
+    if (!maxpoint || maxnearzero || maybe_falsenarrow) {
+      zinc_(Zsearchpoints);
+      if (!maxpoint) {
+        trace0((qh, qh->ferr, 7, "qh_maxsimplex: searching all points for %d-th initial vertex, better than mindet %4.4g, targetdet %4.4g\n",
+                i+1, mindet, targetdet));
+      }else if (qh->ALLpoints) {
+        trace0((qh, qh->ferr, 30, "qh_maxsimplex: searching all points ('Qs') for %d-th initial vertex, better than p%d det %4.4g, targetdet %4.4g, ratio %4.4g\n",
+                i+1, qh_pointid(qh, maxpoint), maxdet, targetdet, ratio));
+      }else if (maybe_falsenarrow) {
+        trace0((qh, qh->ferr, 17, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %4.4g and mindet %4.4g, ratio %4.4g\n",
+                i+1, qh_pointid(qh, maxpoint), maxdet, mindet, ratio));
+      }else {
+        trace0((qh, qh->ferr, 8, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g and mindet %4.4g, targetdet %4.4g\n",
+                i+1, qh_pointid(qh, maxpoint), maxdet, mindet, targetdet));
+      }
+      FORALLpoint_(qh, points, numpoints) {
+        if (point == qh->GOODpointp)
+          continue;
+        if (!qh_setin(maxpoints, point) && !qh_setin(*simplex, point)) {
+          det= qh_detsimplex(qh, point, *simplex, i, &nearzero);
+          if ((det= fabs_(det)) > maxdet) {
+            maxdet= det;
+            maxpoint= point;
+            maxnearzero= nearzero;
+            if (!maxnearzero && !qh->ALLpoints && maxdet > mindet)
+              break;
+          }
+        }
+      }
+    } /* !maxpoint */
+    if (!maxpoint) {
+      qh_fprintf(qh, qh->ferr, 6014, "qhull internal error (qh_maxsimplex): not enough points available\n");
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }
+    qh_setappend(qh, simplex, maxpoint);
+    trace1((qh, qh->ferr, 1002, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%4.4g, targetdet=%4.4g, mindet=%4.4g\n",
+            qh_pointid(qh, maxpoint), i+1, maxdet, prevdet * qh->MAXwidth, mindet));
+  } /* i */
+} /* maxsimplex */
+
+/*---------------------------------
+
+  qh_minabsval( normal, dim )
+    return minimum absolute value of a dim vector
+*/
+realT qh_minabsval(realT *normal, int dim) {
+  realT minval= 0;
+  realT maxval= 0;
+  realT *colp;
+  int k;
+
+  for (k=dim, colp=normal; k--; colp++) {
+    maximize_(maxval, *colp);
+    minimize_(minval, *colp);
+  }
+  return fmax_(maxval, -minval);
+} /* minabsval */
+
+
+/*---------------------------------
+
+  qh_mindif(qh, vecA, vecB, dim )
+    return index of min abs. difference of two vectors
+*/
+int qh_mindiff(realT *vecA, realT *vecB, int dim) {
+  realT mindiff= REALmax, diff;
+  realT *vecAp= vecA, *vecBp= vecB;
+  int k, mink= 0;
+
+  for (k=0; k < dim; k++) {
+    diff= *vecAp++ - *vecBp++;
+    diff= fabs_(diff);
+    if (diff < mindiff) {
+      mindiff= diff;
+      mink= k;
+    }
+  }
+  return mink;
+} /* mindiff */
+
+
+
+/*---------------------------------
+
+  qh_orientoutside(qh, facet  )
+    make facet outside oriented via qh.interior_point
+
+  returns:
+    True if facet reversed orientation.
+*/
+boolT qh_orientoutside(qhT *qh, facetT *facet) {
+  int k;
+  realT dist;
+
+  qh_distplane(qh, qh->interior_point, facet, &dist);
+  if (dist > 0) {
+    for (k=qh->hull_dim; k--; )
+      facet->normal[k]= -facet->normal[k];
+    facet->offset= -facet->offset;
+    return True;
+  }
+  return False;
+} /* orientoutside */
+
+/*---------------------------------
+
+  qh_outerinner(qh, facet, outerplane, innerplane  )
+    if facet and qh.maxoutdone (i.e., qh_check_maxout)
+      returns outer and inner plane for facet
+    else
+      returns maximum outer and inner plane
+    accounts for qh.JOGGLEmax
+
+  see:
+    qh_maxouter(qh), qh_check_bestdist(), qh_check_points()
+
+  notes:
+    outerplaner or innerplane may be NULL
+    facet is const
+    Does not error (QhullFacet)
+
+    includes qh.DISTround for actual points
+    adds another qh.DISTround if testing with floating point arithmetic
+*/
+void qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane) {
+  realT dist, mindist;
+  vertexT *vertex, **vertexp;
+
+  if (outerplane) {
+    if (!qh_MAXoutside || !facet || !qh->maxoutdone) {
+      *outerplane= qh_maxouter(qh);       /* includes qh.DISTround */
+    }else { /* qh_MAXoutside ... */
+#if qh_MAXoutside
+      *outerplane= facet->maxoutside + qh->DISTround;
+#endif
+
+    }
+    if (qh->JOGGLEmax < REALmax/2)
+      *outerplane += qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
+  }
+  if (innerplane) {
+    if (facet) {
+      mindist= REALmax;
+      FOREACHvertex_(facet->vertices) {
+        zinc_(Zdistio);
+        qh_distplane(qh, vertex->point, facet, &dist);
+        minimize_(mindist, dist);
+      }
+      *innerplane= mindist - qh->DISTround;
+    }else
+      *innerplane= qh->min_vertex - qh->DISTround;
+    if (qh->JOGGLEmax < REALmax/2)
+      *innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
+  }
+} /* outerinner */
+
+/*---------------------------------
+
+  qh_pointdist( point1, point2, dim )
+    return distance between two points
+
+  notes:
+    returns distance squared if 'dim' is negative
+*/
+coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {
+  coordT dist, diff;
+  int k;
+
+  dist= 0.0;
+  for (k= (dim > 0 ? dim : -dim); k--; ) {
+    diff= *point1++ - *point2++;
+    dist += diff * diff;
+  }
+  if (dim > 0)
+    return(sqrt(dist));
+  return dist;
+} /* pointdist */
+
+
+/*---------------------------------
+
+  qh_printmatrix(qh, fp, string, rows, numrow, numcol )
+    print matrix to fp given by row vectors
+    print string as header
+    qh may be NULL if fp is defined
+
+  notes:
+    print a vector by qh_printmatrix(qh, fp, "", &vect, 1, len)
+*/
+void qh_printmatrix(qhT *qh, FILE *fp, const char *string, realT **rows, int numrow, int numcol) {
+  realT *rowp;
+  realT r; /*bug fix*/
+  int i,k;
+
+  qh_fprintf(qh, fp, 9001, "%s\n", string);
+  for (i=0; i < numrow; i++) {
+    rowp= rows[i];
+    for (k=0; k < numcol; k++) {
+      r= *rowp++;
+      qh_fprintf(qh, fp, 9002, "%6.3g ", r);
+    }
+    qh_fprintf(qh, fp, 9003, "\n");
+  }
+} /* printmatrix */
+
+
+/*---------------------------------
+
+  qh_printpoints(qh, fp, string, points )
+    print pointids to fp for a set of points
+    if string, prints string and 'p' point ids
+*/
+void qh_printpoints(qhT *qh, FILE *fp, const char *string, setT *points) {
+  pointT *point, **pointp;
+
+  if (string) {
+    qh_fprintf(qh, fp, 9004, "%s", string);
+    FOREACHpoint_(points)
+      qh_fprintf(qh, fp, 9005, " p%d", qh_pointid(qh, point));
+    qh_fprintf(qh, fp, 9006, "\n");
+  }else {
+    FOREACHpoint_(points)
+      qh_fprintf(qh, fp, 9007, " %d", qh_pointid(qh, point));
+    qh_fprintf(qh, fp, 9008, "\n");
+  }
+} /* printpoints */
+
+
+/*---------------------------------
+
+  qh_projectinput(qh)
+    project input points using qh.lower_bound/upper_bound and qh->DELAUNAY
+    if qh.lower_bound[k]=qh.upper_bound[k]= 0,
+      removes dimension k
+    if halfspace intersection
+      removes dimension k from qh.feasible_point
+    input points in qh->first_point, num_points, input_dim
+
+  returns:
+    new point array in qh->first_point of qh->hull_dim coordinates
+    sets qh->POINTSmalloc
+    if qh->DELAUNAY
+      projects points to paraboloid
+      lowbound/highbound is also projected
+    if qh->ATinfinity
+      adds point "at-infinity"
+    if qh->POINTSmalloc
+      frees old point array
+
+  notes:
+    checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY
+
+
+  design:
+    sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)
+    determines newdim and newnum for qh->hull_dim and qh->num_points
+    projects points to newpoints
+    projects qh.lower_bound to itself
+    projects qh.upper_bound to itself
+    if qh->DELAUNAY
+      if qh->ATINFINITY
+        projects points to paraboloid
+        computes "infinity" point as vertex average and 10% above all points
+      else
+        uses qh_setdelaunay to project points to paraboloid
+*/
+void qh_projectinput(qhT *qh) {
+  int k,i;
+  int newdim= qh->input_dim, newnum= qh->num_points;
+  signed char *project;
+  int projectsize= (qh->input_dim + 1) * (int)sizeof(*project);
+  pointT *newpoints, *coord, *infinity;
+  realT paraboloid, maxboloid= 0;
+
+  project= (signed char *)qh_memalloc(qh, projectsize);
+  memset((char *)project, 0, (size_t)projectsize);
+  for (k=0; k < qh->input_dim; k++) {   /* skip Delaunay bound */
+    if (qh->lower_bound[k] == 0.0 && qh->upper_bound[k] == 0.0) {
+      project[k]= -1;
+      newdim--;
+    }
+  }
+  if (qh->DELAUNAY) {
+    project[k]= 1;
+    newdim++;
+    if (qh->ATinfinity)
+      newnum++;
+  }
+  if (newdim != qh->hull_dim) {
+    qh_memfree(qh, project, projectsize);
+    qh_fprintf(qh, qh->ferr, 6015, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh->hull_dim);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  if (!(newpoints= qh->temp_malloc= (coordT *)qh_malloc((size_t)(newnum * newdim) * sizeof(coordT)))) {
+    qh_memfree(qh, project, projectsize);
+    qh_fprintf(qh, qh->ferr, 6016, "qhull error: insufficient memory to project %d points\n",
+           qh->num_points);
+    qh_errexit(qh, qh_ERRmem, NULL, NULL);
+  }
+  /* qh_projectpoints throws error if mismatched dimensions */
+  qh_projectpoints(qh, project, qh->input_dim+1, qh->first_point,
+                    qh->num_points, qh->input_dim, newpoints, newdim);
+  trace1((qh, qh->ferr, 1003, "qh_projectinput: updating lower and upper_bound\n"));
+  qh_projectpoints(qh, project, qh->input_dim+1, qh->lower_bound,
+                    1, qh->input_dim+1, qh->lower_bound, newdim+1);
+  qh_projectpoints(qh, project, qh->input_dim+1, qh->upper_bound,
+                    1, qh->input_dim+1, qh->upper_bound, newdim+1);
+  if (qh->HALFspace) {
+    if (!qh->feasible_point) {
+      qh_memfree(qh, project, projectsize);
+      qh_fprintf(qh, qh->ferr, 6017, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }
+    qh_projectpoints(qh, project, qh->input_dim, qh->feasible_point,
+                      1, qh->input_dim, qh->feasible_point, newdim);
+  }
+  qh_memfree(qh, project, projectsize);
+  if (qh->POINTSmalloc)
+    qh_free(qh->first_point);
+  qh->first_point= newpoints;
+  qh->POINTSmalloc= True;
+  qh->temp_malloc= NULL;
+  if (qh->DELAUNAY && qh->ATinfinity) {
+    coord= qh->first_point;
+    infinity= qh->first_point + qh->hull_dim * qh->num_points;
+    for (k=qh->hull_dim-1; k--; )
+      infinity[k]= 0.0;
+    for (i=qh->num_points; i--; ) {
+      paraboloid= 0.0;
+      for (k=0; k < qh->hull_dim-1; k++) {
+        paraboloid += *coord * *coord;
+        infinity[k] += *coord;
+        coord++;
+      }
+      *(coord++)= paraboloid;
+      maximize_(maxboloid, paraboloid);
+    }
+    /* coord == infinity */
+    for (k=qh->hull_dim-1; k--; )
+      *(coord++) /= qh->num_points;
+    *(coord++)= maxboloid * 1.1;
+    qh->num_points++;
+    trace0((qh, qh->ferr, 9, "qh_projectinput: projected points to paraboloid for Delaunay\n"));
+  }else if (qh->DELAUNAY)  /* !qh->ATinfinity */
+    qh_setdelaunay(qh, qh->hull_dim, qh->num_points, qh->first_point);
+} /* projectinput */
+
+
+/*---------------------------------
+
+  qh_projectpoints(qh, project, n, points, numpoints, dim, newpoints, newdim )
+    project points/numpoints/dim to newpoints/newdim
+    if project[k] == -1
+      delete dimension k
+    if project[k] == 1
+      add dimension k by duplicating previous column
+    n is size of project
+
+  notes:
+    newpoints may be points if only adding dimension at end
+
+  design:
+    check that 'project' and 'newdim' agree
+    for each dimension
+      if project == -1
+        skip dimension
+      else
+        determine start of column in newpoints
+        determine start of column in points
+          if project == +1, duplicate previous column
+        copy dimension (column) from points to newpoints
+*/
+void qh_projectpoints(qhT *qh, signed char *project, int n, realT *points,
+        int numpoints, int dim, realT *newpoints, int newdim) {
+  int testdim= dim, oldk=0, newk=0, i,j=0,k;
+  realT *newp, *oldp;
+
+  for (k=0; k < n; k++)
+    testdim += project[k];
+  if (testdim != newdim) {
+    qh_fprintf(qh, qh->ferr, 6018, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",
+      newdim, testdim);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  for (j=0; j= dim)
+          continue;
+        oldp= points+oldk;
+      }else
+        oldp= points+oldk++;
+      for (i=numpoints; i--; ) {
+        *newp= *oldp;
+        newp += newdim;
+        oldp += dim;
+      }
+    }
+    if (oldk >= dim)
+      break;
+  }
+  trace1((qh, qh->ferr, 1004, "qh_projectpoints: projected %d points from dim %d to dim %d\n",
+    numpoints, dim, newdim));
+} /* projectpoints */
+
+
+/*---------------------------------
+
+  qh_rotateinput(qh, rows )
+    rotate input using row matrix
+    input points given by qh->first_point, num_points, hull_dim
+    assumes rows[dim] is a scratch buffer
+    if qh->POINTSmalloc, overwrites input points, else mallocs a new array
+
+  returns:
+    rotated input
+    sets qh->POINTSmalloc
+
+  design:
+    see qh_rotatepoints
+*/
+void qh_rotateinput(qhT *qh, realT **rows) {
+
+  if (!qh->POINTSmalloc) {
+    qh->first_point= qh_copypoints(qh, qh->first_point, qh->num_points, qh->hull_dim);
+    qh->POINTSmalloc= True;
+  }
+  qh_rotatepoints(qh, qh->first_point, qh->num_points, qh->hull_dim, rows);
+}  /* rotateinput */
+
+/*---------------------------------
+
+  qh_rotatepoints(qh, points, numpoints, dim, row )
+    rotate numpoints points by a d-dim row matrix
+    assumes rows[dim] is a scratch buffer
+
+  returns:
+    rotated points in place
+
+  design:
+    for each point
+      for each coordinate
+        use row[dim] to compute partial inner product
+      for each coordinate
+        rotate by partial inner product
+*/
+void qh_rotatepoints(qhT *qh, realT *points, int numpoints, int dim, realT **row) {
+  realT *point, *rowi, *coord= NULL, sum, *newval;
+  int i,j,k;
+
+  if (qh->IStracing >= 1)
+    qh_printmatrix(qh, qh->ferr, "qh_rotatepoints: rotate points by", row, dim, dim);
+  for (point=points, j=numpoints; j--; point += dim) {
+    newval= row[dim];
+    for (i=0; i < dim; i++) {
+      rowi= row[i];
+      coord= point;
+      for (sum=0.0, k=dim; k--; )
+        sum += *rowi++ * *coord++;
+      *(newval++)= sum;
+    }
+    for (k=dim; k--; )
+      *(--coord)= *(--newval);
+  }
+} /* rotatepoints */
+
+
+/*---------------------------------
+
+  qh_scaleinput(qh)
+    scale input points using qh->low_bound/high_bound
+    input points given by qh->first_point, num_points, hull_dim
+    if qh->POINTSmalloc, overwrites input points, else mallocs a new array
+
+  returns:
+    scales coordinates of points to low_bound[k], high_bound[k]
+    sets qh->POINTSmalloc
+
+  design:
+    see qh_scalepoints
+*/
+void qh_scaleinput(qhT *qh) {
+
+  if (!qh->POINTSmalloc) {
+    qh->first_point= qh_copypoints(qh, qh->first_point, qh->num_points, qh->hull_dim);
+    qh->POINTSmalloc= True;
+  }
+  qh_scalepoints(qh, qh->first_point, qh->num_points, qh->hull_dim,
+       qh->lower_bound, qh->upper_bound);
+}  /* scaleinput */
+
+/*---------------------------------
+
+  qh_scalelast(qh, points, numpoints, dim, low, high, newhigh )
+    scale last coordinate to [0.0, newhigh], for Delaunay triangulation
+    input points given by points, numpoints, dim
+
+  returns:
+    changes scale of last coordinate from [low, high] to [0.0, newhigh]
+    overwrites last coordinate of each point
+    saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()
+
+  notes:
+    to reduce precision issues, qh_scalelast makes the last coordinate similar to other coordinates
+      the last coordinate for Delaunay triangulation is the sum of squares of input coordinates
+      note that the range [0.0, newwidth] is wrong for narrow distributions with large positive coordinates (e.g., [995933.64, 995963.48])
+
+    when called by qh_setdelaunay, low/high may not match the data passed to qh_setdelaunay
+
+  design:
+    compute scale and shift factors
+    apply to last coordinate of each point
+*/
+void qh_scalelast(qhT *qh, coordT *points, int numpoints, int dim, coordT low,
+                   coordT high, coordT newhigh) {
+  realT scale, shift;
+  coordT *coord, newlow;
+  int i;
+  boolT nearzero= False;
+
+  newlow= 0.0;
+  trace4((qh, qh->ferr, 4013, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [%2.2g, %2.2g]\n",
+    low, high, newlow, newhigh));
+  qh->last_low= low;
+  qh->last_high= high;
+  qh->last_newhigh= newhigh;
+  scale= qh_divzero(newhigh - newlow, high - low,
+                  qh->MINdenom_1, &nearzero);
+  if (nearzero) {
+    if (qh->DELAUNAY)
+      qh_fprintf(qh, qh->ferr, 6019, "qhull input error (qh_scalelast): can not scale last coordinate to [%4.4g, %4.4g].  Input is cocircular or cospherical.   Use option 'Qz' to add a point at infinity.\n",
+             newlow, newhigh);
+    else
+      qh_fprintf(qh, qh->ferr, 6020, "qhull input error (qh_scalelast): can not scale last coordinate to [%4.4g, %4.4g].  New bounds are too wide for compared to existing bounds [%4.4g, %4.4g] (width %4.4g)\n",
+             newlow, newhigh, low, high, high-low);
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  shift= newlow - low * scale;
+  coord= points + dim - 1;
+  for (i=numpoints; i--; coord += dim)
+    *coord= *coord * scale + shift;
+} /* scalelast */
+
+/*---------------------------------
+
+  qh_scalepoints(qh, points, numpoints, dim, newlows, newhighs )
+    scale points to new lowbound and highbound
+    retains old bound when newlow= -REALmax or newhigh= +REALmax
+
+  returns:
+    scaled points
+    overwrites old points
+
+  design:
+    for each coordinate
+      compute current low and high bound
+      compute scale and shift factors
+      scale all points
+      enforce new low and high bound for all points
+*/
+void qh_scalepoints(qhT *qh, pointT *points, int numpoints, int dim,
+        realT *newlows, realT *newhighs) {
+  int i,k;
+  realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;
+  boolT nearzero= False;
+
+  for (k=0; k < dim; k++) {
+    newhigh= newhighs[k];
+    newlow= newlows[k];
+    if (newhigh > REALmax/2 && newlow < -REALmax/2)
+      continue;
+    low= REALmax;
+    high= -REALmax;
+    for (i=numpoints, coord=points+k; i--; coord += dim) {
+      minimize_(low, *coord);
+      maximize_(high, *coord);
+    }
+    if (newhigh > REALmax/2)
+      newhigh= high;
+    if (newlow < -REALmax/2)
+      newlow= low;
+    if (qh->DELAUNAY && k == dim-1 && newhigh < newlow) {
+      qh_fprintf(qh, qh->ferr, 6021, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",
+               k, k, newhigh, newlow);
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    scale= qh_divzero(newhigh - newlow, high - low,
+                  qh->MINdenom_1, &nearzero);
+    if (nearzero) {
+      qh_fprintf(qh, qh->ferr, 6022, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n",
+              k, newlow, newhigh, low, high);
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    shift= (newlow * high - low * newhigh)/(high-low);
+    coord= points+k;
+    for (i=numpoints; i--; coord += dim)
+      *coord= *coord * scale + shift;
+    coord= points+k;
+    if (newlow < newhigh) {
+      mincoord= newlow;
+      maxcoord= newhigh;
+    }else {
+      mincoord= newhigh;
+      maxcoord= newlow;
+    }
+    for (i=numpoints; i--; coord += dim) {
+      minimize_(*coord, maxcoord);  /* because of roundoff error */
+      maximize_(*coord, mincoord);
+    }
+    trace0((qh, qh->ferr, 10, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n",
+      k, low, high, newlow, newhigh, numpoints, scale, shift));
+  }
+} /* scalepoints */
+
+
+/*---------------------------------
+
+  qh_setdelaunay(qh, dim, count, points )
+    project count points to dim-d paraboloid for Delaunay triangulation
+
+    dim is one more than the dimension of the input set
+    assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)
+
+    points is a dim*count realT array.  The first dim-1 coordinates
+    are the coordinates of the first input point.  array[dim] is
+    the first coordinate of the second input point.  array[2*dim] is
+    the first coordinate of the third input point.
+
+    if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)
+      calls qh_scalelast to scale the last coordinate the same as the other points
+
+  returns:
+    for each point
+      sets point[dim-1] to sum of squares of coordinates
+    scale points to 'Qbb' if needed
+
+  notes:
+    to project one point, use
+      qh_setdelaunay(qh, qh->hull_dim, 1, point)
+
+    Do not use options 'Qbk', 'QBk', or 'QbB' since they scale
+    the coordinates after the original projection.
+
+*/
+void qh_setdelaunay(qhT *qh, int dim, int count, pointT *points) {
+  int i, k;
+  coordT *coordp, coord;
+  realT paraboloid;
+
+  trace0((qh, qh->ferr, 11, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));
+  coordp= points;
+  for (i=0; i < count; i++) {
+    coord= *coordp++;
+    paraboloid= coord*coord;
+    for (k=dim-2; k--; ) {
+      coord= *coordp++;
+      paraboloid += coord*coord;
+    }
+    *coordp++= paraboloid;
+  }
+  if (qh->last_low < REALmax/2)
+    qh_scalelast(qh, points, count, dim, qh->last_low, qh->last_high, qh->last_newhigh);
+} /* setdelaunay */
+
+
+/*---------------------------------
+
+  qh_sethalfspace(qh, dim, coords, nextp, normal, offset, feasible )
+    set point to dual of halfspace relative to feasible point
+    halfspace is normal coefficients and offset.
+
+  returns:
+    false and prints error if feasible point is outside of hull
+    overwrites coordinates for point at dim coords
+    nextp= next point (coords)
+    does not call qh_errexit
+
+  design:
+    compute distance from feasible point to halfspace
+    divide each normal coefficient by -dist
+*/
+boolT qh_sethalfspace(qhT *qh, int dim, coordT *coords, coordT **nextp,
+         coordT *normal, coordT *offset, coordT *feasible) {
+  coordT *normp= normal, *feasiblep= feasible, *coordp= coords;
+  realT dist;
+  realT r; /*bug fix*/
+  int k;
+  boolT zerodiv;
+
+  dist= *offset;
+  for (k=dim; k--; )
+    dist += *(normp++) * *(feasiblep++);
+  if (dist > 0)
+    goto LABELerroroutside;
+  normp= normal;
+  if (dist < -qh->MINdenom) {
+    for (k=dim; k--; )
+      *(coordp++)= *(normp++) / -dist;
+  }else {
+    for (k=dim; k--; ) {
+      *(coordp++)= qh_divzero(*(normp++), -dist, qh->MINdenom_1, &zerodiv);
+      if (zerodiv)
+        goto LABELerroroutside;
+    }
+  }
+  *nextp= coordp;
+#ifndef qh_NOtrace
+  if (qh->IStracing >= 4) {
+    qh_fprintf(qh, qh->ferr, 8021, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);
+    for (k=dim, coordp=coords; k--; ) {
+      r= *coordp++;
+      qh_fprintf(qh, qh->ferr, 8022, " %6.2g", r);
+    }
+    qh_fprintf(qh, qh->ferr, 8023, "\n");
+  }
+#endif
+  return True;
+LABELerroroutside:
+  feasiblep= feasible;
+  normp= normal;
+  qh_fprintf(qh, qh->ferr, 6023, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");
+  for (k=dim; k--; )
+    qh_fprintf(qh, qh->ferr, 8024, qh_REAL_1, r=*(feasiblep++));
+  qh_fprintf(qh, qh->ferr, 8025, "\n     halfspace: ");
+  for (k=dim; k--; )
+    qh_fprintf(qh, qh->ferr, 8026, qh_REAL_1, r=*(normp++));
+  qh_fprintf(qh, qh->ferr, 8027, "\n     at offset: ");
+  qh_fprintf(qh, qh->ferr, 8028, qh_REAL_1, *offset);
+  qh_fprintf(qh, qh->ferr, 8029, " and distance: ");
+  qh_fprintf(qh, qh->ferr, 8030, qh_REAL_1, dist);
+  qh_fprintf(qh, qh->ferr, 8031, "\n");
+  return False;
+} /* sethalfspace */
+
+/*---------------------------------
+
+  qh_sethalfspace_all(qh, dim, count, halfspaces, feasible )
+    generate dual for halfspace intersection with feasible point
+    array of count halfspaces
+      each halfspace is normal coefficients followed by offset
+      the origin is inside the halfspace if the offset is negative
+    feasible is a point inside all halfspaces (http://www.qhull.org/html/qhalf.htm#notes)
+
+  returns:
+    malloc'd array of count X dim-1 points
+
+  notes:
+    call before qh_init_B or qh_initqhull_globals
+    free memory when done
+    unused/untested code: please email bradb@shore.net if this works ok for you
+    if using option 'Fp', qh.feasible_point must be set (e.g., to 'feasible')
+    qh->feasible_point is a malloc'd array that is freed by qh_freebuffers.
+
+  design:
+    see qh_sethalfspace
+*/
+coordT *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible) {
+  int i, newdim;
+  pointT *newpoints;
+  coordT *coordp, *normalp, *offsetp;
+
+  trace0((qh, qh->ferr, 12, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));
+  newdim= dim - 1;
+  if (!(newpoints= (coordT *)qh_malloc((size_t)(count * newdim) * sizeof(coordT)))){
+    qh_fprintf(qh, qh->ferr, 6024, "qhull error: insufficient memory to compute dual of %d halfspaces\n",
+          count);
+    qh_errexit(qh, qh_ERRmem, NULL, NULL);
+  }
+  coordp= newpoints;
+  normalp= halfspaces;
+  for (i=0; i < count; i++) {
+    offsetp= normalp + newdim;
+    if (!qh_sethalfspace(qh, newdim, coordp, &coordp, normalp, offsetp, feasible)) {
+      qh_free(newpoints);  /* feasible is not inside halfspace as reported by qh_sethalfspace */
+      qh_fprintf(qh, qh->ferr, 8032, "The halfspace was at index %d\n", i);
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    normalp= offsetp + 1;
+  }
+  return newpoints;
+} /* sethalfspace_all */
+
+
+/*---------------------------------
+
+  qh_sharpnewfacets(qh)
+
+  returns:
+    true if could be an acute angle (facets in different quadrants)
+
+  notes:
+    for qh_findbest
+
+  design:
+    for all facets on qh.newfacet_list
+      if two facets are in different quadrants
+        set issharp
+*/
+boolT qh_sharpnewfacets(qhT *qh) {
+  facetT *facet;
+  boolT issharp= False;
+  int *quadrant, k;
+
+  quadrant= (int *)qh_memalloc(qh, qh->hull_dim * (int)sizeof(int));
+  FORALLfacet_(qh->newfacet_list) {
+    if (facet == qh->newfacet_list) {
+      for (k=qh->hull_dim; k--; )
+        quadrant[ k]= (facet->normal[ k] > 0);
+    }else {
+      for (k=qh->hull_dim; k--; ) {
+        if (quadrant[ k] != (facet->normal[ k] > 0)) {
+          issharp= True;
+          break;
+        }
+      }
+    }
+    if (issharp)
+      break;
+  }
+  qh_memfree(qh, quadrant, qh->hull_dim * (int)sizeof(int));
+  trace3((qh, qh->ferr, 3001, "qh_sharpnewfacets: %d\n", issharp));
+  return issharp;
+} /* sharpnewfacets */
+
+/*---------------------------------
+
+  qh_vertex_bestdist(qh, vertices )
+  qh_vertex_bestdist2(qh, vertices, vertexp, vertexp2 )
+    return nearest distance between vertices
+    optionally returns vertex and vertex2
+
+  notes:
+    called by qh_partitioncoplanar, qh_mergefacet, qh_check_maxout, qh_checkpoint
+*/
+coordT qh_vertex_bestdist(qhT *qh, setT *vertices) {
+  vertexT *vertex, *vertex2;
+
+  return qh_vertex_bestdist2(qh, vertices, &vertex, &vertex2);
+} /* vertex_bestdist */
+
+coordT qh_vertex_bestdist2(qhT *qh, setT *vertices, vertexT **vertexp/*= NULL*/, vertexT **vertexp2/*= NULL*/) {
+  vertexT *vertex, *vertexA, *bestvertex= NULL, *bestvertex2= NULL;
+  coordT dist, bestdist= REALmax;
+  int k, vertex_i, vertex_n;
+
+  FOREACHvertex_i_(qh, vertices) {
+    for (k= vertex_i+1; k < vertex_n; k++) {
+      vertexA= SETelemt_(vertices, k, vertexT);
+      dist= qh_pointdist(vertex->point, vertexA->point, -qh->hull_dim);
+      if (dist < bestdist) {
+        bestdist= dist;
+        bestvertex= vertex;
+        bestvertex2= vertexA;
+      }
+    }
+  }
+  *vertexp= bestvertex;
+  *vertexp2= bestvertex2;
+  return sqrt(bestdist);
+} /* vertex_bestdist */
+
+/*---------------------------------
+
+  qh_voronoi_center(qh, dim, points )
+    return Voronoi center for a set of points
+    dim is the original dimension of the points
+    gh.gm_matrix/qh.gm_row are scratch buffers
+
+  returns:
+    center as a temporary point (qh_memalloc)
+    if non-simplicial,
+      returns center for max simplex of points
+
+  notes:
+    only called by qh_facetcenter
+    from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65
+
+  design:
+    if non-simplicial
+      determine max simplex for points
+    translate point0 of simplex to origin
+    compute sum of squares of diagonal
+    compute determinate
+    compute Voronoi center (see Bowyer & Woodwark)
+*/
+pointT *qh_voronoi_center(qhT *qh, int dim, setT *points) {
+  pointT *point, **pointp, *point0;
+  pointT *center= (pointT *)qh_memalloc(qh, qh->center_size);
+  setT *simplex;
+  int i, j, k, size= qh_setsize(qh, points);
+  coordT *gmcoord;
+  realT *diffp, sum2, *sum2row, *sum2p, det, factor;
+  boolT nearzero, infinite;
+
+  if (size == dim+1)
+    simplex= points;
+  else if (size < dim+1) {
+    qh_memfree(qh, center, qh->center_size);
+    qh_fprintf(qh, qh->ferr, 6025, "qhull internal error (qh_voronoi_center):  need at least %d points to construct a Voronoi center\n",
+             dim+1);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    simplex= points;  /* never executed -- avoids warning */
+  }else {
+    simplex= qh_settemp(qh, dim+1);
+    qh_maxsimplex(qh, dim, points, NULL, 0, &simplex);
+  }
+  point0= SETfirstt_(simplex, pointT);
+  gmcoord= qh->gm_matrix;
+  for (k=0; k < dim; k++) {
+    qh->gm_row[k]= gmcoord;
+    FOREACHpoint_(simplex) {
+      if (point != point0)
+        *(gmcoord++)= point[k] - point0[k];
+    }
+  }
+  sum2row= gmcoord;
+  for (i=0; i < dim; i++) {
+    sum2= 0.0;
+    for (k=0; k < dim; k++) {
+      diffp= qh->gm_row[k] + i;
+      sum2 += *diffp * *diffp;
+    }
+    *(gmcoord++)= sum2;
+  }
+  det= qh_determinant(qh, qh->gm_row, dim, &nearzero);
+  factor= qh_divzero(0.5, det, qh->MINdenom, &infinite);
+  if (infinite) {
+    for (k=dim; k--; )
+      center[k]= qh_INFINITE;
+    if (qh->IStracing)
+      qh_printpoints(qh, qh->ferr, "qh_voronoi_center: at infinity for ", simplex);
+  }else {
+    for (i=0; i < dim; i++) {
+      gmcoord= qh->gm_matrix;
+      sum2p= sum2row;
+      for (k=0; k < dim; k++) {
+        qh->gm_row[k]= gmcoord;
+        if (k == i) {
+          for (j=dim; j--; )
+            *(gmcoord++)= *sum2p++;
+        }else {
+          FOREACHpoint_(simplex) {
+            if (point != point0)
+              *(gmcoord++)= point[k] - point0[k];
+          }
+        }
+      }
+      center[i]= qh_determinant(qh, qh->gm_row, dim, &nearzero)*factor + point0[i];
+    }
+#ifndef qh_NOtrace
+    if (qh->IStracing >= 3) {
+      qh_fprintf(qh, qh->ferr, 3061, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
+      qh_printmatrix(qh, qh->ferr, "center:", ¢er, 1, dim);
+      if (qh->IStracing >= 5) {
+        qh_printpoints(qh, qh->ferr, "points", simplex);
+        FOREACHpoint_(simplex)
+          qh_fprintf(qh, qh->ferr, 8034, "p%d dist %.2g, ", qh_pointid(qh, point),
+                   qh_pointdist(point, center, dim));
+        qh_fprintf(qh, qh->ferr, 8035, "\n");
+      }
+    }
+#endif
+  }
+  if (simplex != points)
+    qh_settempfree(qh, &simplex);
+  return center;
+} /* voronoi_center */
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/geom_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/geom_r.c
new file mode 100644
index 00000000000..22faead499f
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/geom_r.c
@@ -0,0 +1,1284 @@
+/*
  ---------------------------------
+
+   geom_r.c
+   geometric routines of qhull
+
+   see qh-geom_r.htm and geom_r.h
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/geom_r.c#5 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+
+   infrequent code goes into geom2_r.c
+*/
+
+#include "qhull_ra.h"
+
+/*---------------------------------
+
+  qh_distplane(qh, point, facet, dist )
+    return distance from point to facet
+
+  returns:
+    dist
+    if qh.RANDOMdist, joggles result
+
+  notes:
+    dist > 0 if point is above facet (i.e., outside)
+    does not error (for qh_sortfacets, qh_outerinner)
+    for nearly coplanar points, the returned values may be duplicates
+      for example pairs of nearly incident points, rbox 175 C1,2e-13 t1538759579 | qhull d T4
+      622 qh_distplane: e-014  # count of two or more duplicate values for unique calls
+      258 qh_distplane: e-015
+      38 qh_distplane: e-016
+      40 qh_distplane: e-017
+      6 qh_distplane: e-018
+      5 qh_distplane: -e-018
+      33 qh_distplane: -e-017
+         3153 qh_distplane: -2.775557561562891e-017  # duplicated value for 3153 unique calls
+      42 qh_distplane: -e-016
+      307 qh_distplane: -e-015
+      1271 qh_distplane: -e-014
+      13 qh_distplane: -e-013
+
+  see:
+    qh_distnorm in geom2_r.c
+    qh_distplane [geom_r.c], QhullFacet::distance, and QhullHyperplane::distance are copies
+*/
+void qh_distplane(qhT *qh, pointT *point, facetT *facet, realT *dist) {
+  coordT *normal= facet->normal, *coordp, randr;
+  int k;
+
+  switch (qh->hull_dim){
+  case 2:
+    *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];
+    break;
+  case 3:
+    *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
+    break;
+  case 4:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
+    break;
+  case 5:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
+    break;
+  case 6:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
+    break;
+  case 7:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
+    break;
+  case 8:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
+    break;
+  default:
+    *dist= facet->offset;
+    coordp= point;
+    for (k=qh->hull_dim; k--; )
+      *dist += *coordp++ * *normal++;
+    break;
+  }
+  zzinc_(Zdistplane);
+  if (!qh->RANDOMdist && qh->IStracing < 4)
+    return;
+  if (qh->RANDOMdist) {
+    randr= qh_RANDOMint;
+    *dist += (2.0 * randr / qh_RANDOMmax - 1.0) *
+      qh->RANDOMfactor * qh->MAXabs_coord;
+  }
+#ifndef qh_NOtrace
+  if (qh->IStracing >= 4) {
+    qh_fprintf(qh, qh->ferr, 8001, "qh_distplane: ");
+    qh_fprintf(qh, qh->ferr, 8002, qh_REAL_1, *dist);
+    qh_fprintf(qh, qh->ferr, 8003, "from p%d to f%d\n", qh_pointid(qh, point), facet->id);
+  }
+#endif
+  return;
+} /* distplane */
+
+
+/*---------------------------------
+
+  qh_findbest(qh, point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart )
+    find facet that is furthest below a point
+    for upperDelaunay facets
+      returns facet only if !qh_NOupper and clearly above
+
+  input:
+    starts search at 'startfacet' (can not be flipped)
+    if !bestoutside(qh_ALL), stops at qh.MINoutside
+
+  returns:
+    best facet (reports error if NULL)
+    early out if isoutside defined and bestdist > qh.MINoutside
+    dist is distance to facet
+    isoutside is true if point is outside of facet
+    numpart counts the number of distance tests
+
+  see also:
+    qh_findbestnew()
+
+  notes:
+    If merging (testhorizon), searches horizon facets of coplanar best facets because
+    after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d
+      avoid calls to distplane, function calls, and real number operations.
+    caller traces result
+    Optimized for outside points.   Tried recording a search set for qh_findhorizon.
+    Made code more complicated.
+
+  when called by qh_partitionvisible():
+    indicated by qh_ISnewfacets
+    qh.newfacet_list is list of simplicial, new facets
+    qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew)
+    qh.bestfacet_notsharp set if qh_sharpnewfacets returns False
+
+  when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(),
+                 qh_check_bestdist(), qh_addpoint()
+    indicated by !qh_ISnewfacets
+    returns best facet in neighborhood of given facet
+      this is best facet overall if dist >= -qh.MAXcoplanar
+        or hull has at least a "spherical" curvature
+
+  design:
+    initialize and test for early exit
+    repeat while there are better facets
+      for each neighbor of facet
+        exit if outside facet found
+        test for better facet
+    if point is inside and partitioning
+      test for new facets with a "sharp" intersection
+      if so, future calls go to qh_findbestnew()
+    test horizon facets
+*/
+facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,
+                     boolT bestoutside, boolT isnewfacets, boolT noupper,
+                     realT *dist, boolT *isoutside, int *numpart) {
+  realT bestdist= -REALmax/2 /* avoid underflow */;
+  facetT *facet, *neighbor, **neighborp;
+  facetT *bestfacet= NULL, *lastfacet= NULL;
+  int oldtrace= qh->IStracing;
+  unsigned int visitid= ++qh->visit_id;
+  int numpartnew=0;
+  boolT testhorizon= True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
+
+  zinc_(Zfindbest);
+#ifndef qh_NOtrace
+  if (qh->IStracing >= 4 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {
+    if (qh->TRACElevel > qh->IStracing)
+      qh->IStracing= qh->TRACElevel;
+    qh_fprintf(qh, qh->ferr, 8004, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g,",
+             qh_pointid(qh, point), startfacet->id, isnewfacets, bestoutside, qh->MINoutside);
+    qh_fprintf(qh, qh->ferr, 8005, " testhorizon? %d, noupper? %d,", testhorizon, noupper);
+    qh_fprintf(qh, qh->ferr, 8006, " Last qh_addpoint p%d,", qh->furthest_id);
+    qh_fprintf(qh, qh->ferr, 8007, " Last merge #%d, max_outside %2.2g\n", zzval_(Ztotmerge), qh->max_outside);
+  }
+#endif
+  if (isoutside)
+    *isoutside= True;
+  if (!startfacet->flipped) {  /* test startfacet before testing its neighbors */
+    *numpart= 1;
+    qh_distplane(qh, point, startfacet, dist);  /* this code is duplicated below */
+    if (!bestoutside && *dist >= qh->MINoutside
+    && (!startfacet->upperdelaunay || !noupper)) {
+      bestfacet= startfacet;
+      goto LABELreturn_best;
+    }
+    bestdist= *dist;
+    if (!startfacet->upperdelaunay) {
+      bestfacet= startfacet;
+    }
+  }else
+    *numpart= 0;
+  startfacet->visitid= visitid;
+  facet= startfacet;
+  while (facet) {
+    trace4((qh, qh->ferr, 4001, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n",
+                facet->id, bestdist, getid_(bestfacet)));
+    lastfacet= facet;
+    FOREACHneighbor_(facet) {
+      if (!neighbor->newfacet && isnewfacets)
+        continue;
+      if (neighbor->visitid == visitid)
+        continue;
+      neighbor->visitid= visitid;
+      if (!neighbor->flipped) {  /* code duplicated above */
+        (*numpart)++;
+        qh_distplane(qh, point, neighbor, dist);
+        if (*dist > bestdist) {
+          if (!bestoutside && *dist >= qh->MINoutside
+          && (!neighbor->upperdelaunay || !noupper)) {
+            bestfacet= neighbor;
+            goto LABELreturn_best;
+          }
+          if (!neighbor->upperdelaunay) {
+            bestfacet= neighbor;
+            bestdist= *dist;
+            break; /* switch to neighbor */
+          }else if (!bestfacet) {
+            bestdist= *dist;
+            break; /* switch to neighbor */
+          }
+        } /* end of *dist>bestdist */
+      } /* end of !flipped */
+    } /* end of FOREACHneighbor */
+    facet= neighbor;  /* non-NULL only if *dist>bestdist */
+  } /* end of while facet (directed search) */
+  if (isnewfacets) {
+    if (!bestfacet) { /* startfacet is upperdelaunay (or flipped) w/o !flipped newfacet neighbors */
+      bestdist= -REALmax/2;
+      bestfacet= qh_findbestnew(qh, point, qh->newfacet_list, &bestdist, bestoutside, isoutside, &numpartnew);
+      testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
+    }else if (!qh->findbest_notsharp && bestdist < -qh->DISTround) {
+      if (qh_sharpnewfacets(qh)) {
+        /* seldom used, qh_findbestnew will retest all facets */
+        zinc_(Zfindnewsharp);
+        bestfacet= qh_findbestnew(qh, point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew);
+        testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
+        qh->findbestnew= True;
+      }else
+        qh->findbest_notsharp= True;
+    }
+  }
+  if (!bestfacet)
+    bestfacet= qh_findbestlower(qh, lastfacet, point, &bestdist, numpart); /* lastfacet is non-NULL because startfacet is non-NULL */
+  if (testhorizon) /* qh_findbestnew not called */
+    bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew);
+  *dist= bestdist;
+  if (isoutside && bestdist < qh->MINoutside)
+    *isoutside= False;
+LABELreturn_best:
+  zadd_(Zfindbesttot, *numpart);
+  zmax_(Zfindbestmax, *numpart);
+  (*numpart) += numpartnew;
+  qh->IStracing= oldtrace;
+  return bestfacet;
+}  /* findbest */
+
+
+/*---------------------------------
+
+  qh_findbesthorizon(qh, qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart )
+    search coplanar and better horizon facets from startfacet/bestdist
+    ischeckmax turns off statistics and minsearch update
+    all arguments must be initialized, including *bestdist and *numpart
+    qh.coplanarfacetset used to maintain current search set, reset whenever best facet is substantially better
+  returns(ischeckmax):
+    best facet
+    updates f.maxoutside for neighbors of searched facets (if qh_MAXoutside)
+  returns(!ischeckmax):
+    best facet that is not upperdelaunay or newfacet (qh.first_newfacet)
+    allows upperdelaunay that is clearly outside
+  returns:
+    bestdist is distance to bestfacet
+    numpart -- updates number of distance tests
+
+  notes:
+    called by qh_findbest if point is not outside a facet (directed search)
+    called by qh_findbestnew if point is not outside a new facet
+    called by qh_check_maxout for each point in hull
+    called by qh_check_bestdist for each point in hull (rarely used)
+
+    no early out -- use qh_findbest() or qh_findbestnew()
+    Searches coplanar or better horizon facets
+
+  when called by qh_check_maxout() (qh_IScheckmax)
+    startfacet must be closest to the point
+      Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum
+      even though other facets are below the point.
+    updates facet->maxoutside for good, visited facets
+    may return NULL
+
+    searchdist is qh.max_outside + 2 * DISTround
+      + max( MINvisible('Vn'), MAXcoplanar('Un'));
+    This setting is a guess.  It must be at least max_outside + 2*DISTround
+    because a facet may have a geometric neighbor across a vertex
+
+  design:
+    for each horizon facet of coplanar best facets
+      continue if clearly inside
+      unless upperdelaunay or clearly outside
+         update best facet
+*/
+facetT *qh_findbesthorizon(qhT *qh, boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) {
+  facetT *bestfacet= startfacet;
+  realT dist;
+  facetT *neighbor, **neighborp, *facet;
+  facetT *nextfacet= NULL; /* optimize last facet of coplanarfacetset */
+  int numpartinit= *numpart, coplanarfacetset_size, numcoplanar= 0, numfacet= 0;
+  unsigned int visitid= ++qh->visit_id;
+  boolT newbest= False; /* for tracing */
+  realT minsearch, searchdist;  /* skip facets that are too far from point */
+  boolT is_5x_minsearch;
+
+  if (!ischeckmax) {
+    zinc_(Zfindhorizon);
+  }else {
+#if qh_MAXoutside
+    if ((!qh->ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside)
+      startfacet->maxoutside= *bestdist;
+#endif
+  }
+  searchdist= qh_SEARCHdist; /* an expression, a multiple of qh.max_outside and precision constants */
+  minsearch= *bestdist - searchdist;
+  if (ischeckmax) {
+    /* Always check coplanar facets.  Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */
+    minimize_(minsearch, -searchdist);
+  }
+  coplanarfacetset_size= 0;
+  startfacet->visitid= visitid;
+  facet= startfacet;
+  while (True) {
+    numfacet++;
+    is_5x_minsearch= (ischeckmax && facet->nummerge > 10 && qh_setsize(qh, facet->neighbors) > 100);  /* QH11033 FIX: qh_findbesthorizon: many tests for facets with many merges and neighbors.  Can hide coplanar facets, e.g., 'rbox 1000 s Z1 G1e-13' with 4400+ neighbors */
+    trace4((qh, qh->ferr, 4002, "qh_findbesthorizon: test neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g is_5x? %d searchdist %2.2g\n",
+                facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper,
+                minsearch, is_5x_minsearch, searchdist));
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid == visitid)
+        continue;
+      neighbor->visitid= visitid;
+      if (!neighbor->flipped) {  /* neighbors of flipped facets always searched via nextfacet */
+        qh_distplane(qh, point, neighbor, &dist); /* duplicate qh_distpane for new facets, they may be coplanar */
+        (*numpart)++;
+        if (dist > *bestdist) {
+          if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh->MINoutside)) {
+            if (!ischeckmax) {
+              minsearch= dist - searchdist;
+              if (dist > *bestdist + searchdist) {
+                zinc_(Zfindjump);  /* everything in qh.coplanarfacetset at least searchdist below */
+                coplanarfacetset_size= 0;
+              }
+            }
+            bestfacet= neighbor;
+            *bestdist= dist;
+            newbest= True;
+          }
+        }else if (is_5x_minsearch) {
+          if (dist < 5 * minsearch)
+            continue; /* skip this neighbor, do not set nextfacet.  dist is negative */
+        }else if (dist < minsearch)
+          continue;  /* skip this neighbor, do not set nextfacet.  If ischeckmax, dist can't be positive */
+#if qh_MAXoutside
+        if (ischeckmax && dist > neighbor->maxoutside)
+          neighbor->maxoutside= dist;
+#endif
+      } /* end of !flipped, need to search neighbor */
+      if (nextfacet) {
+        numcoplanar++;
+        if (!coplanarfacetset_size++) {
+          SETfirst_(qh->coplanarfacetset)= nextfacet;
+          SETtruncate_(qh->coplanarfacetset, 1);
+        }else
+          qh_setappend(qh, &qh->coplanarfacetset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv
+                                                 and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv  */
+      }
+      nextfacet= neighbor;
+    } /* end of EACHneighbor */
+    facet= nextfacet;
+    if (facet)
+      nextfacet= NULL;
+    else if (!coplanarfacetset_size)
+      break;
+    else if (!--coplanarfacetset_size) {
+      facet= SETfirstt_(qh->coplanarfacetset, facetT);
+      SETtruncate_(qh->coplanarfacetset, 0);
+    }else
+      facet= (facetT *)qh_setdellast(qh->coplanarfacetset);
+  } /* while True, i.e., "for each facet in qh.coplanarfacetset" */
+  if (!ischeckmax) {
+    zadd_(Zfindhorizontot, *numpart - numpartinit);
+    zmax_(Zfindhorizonmax, *numpart - numpartinit);
+    if (newbest)
+      zinc_(Znewbesthorizon);
+  }
+  trace4((qh, qh->ferr, 4003, "qh_findbesthorizon: p%d, newbest? %d, bestfacet f%d, bestdist %2.2g, numfacet %d, coplanarfacets %d, numdist %d\n",
+    qh_pointid(qh, point), newbest, getid_(bestfacet), *bestdist, numfacet, numcoplanar, *numpart - numpartinit));
+  return bestfacet;
+}  /* findbesthorizon */
+
+/*---------------------------------
+
+  qh_findbestnew(qh, point, startfacet, dist, isoutside, numpart )
+    find best newfacet for point
+    searches all of qh.newfacet_list starting at startfacet
+    searches horizon facets of coplanar best newfacets
+    searches all facets if startfacet == qh.facet_list
+  returns:
+    best new or horizon facet that is not upperdelaunay
+    early out if isoutside and not 'Qf'
+    dist is distance to facet
+    isoutside is true if point is outside of facet
+    numpart is number of distance tests
+
+  notes:
+    Always used for merged new facets (see qh_USEfindbestnew)
+    Avoids upperdelaunay facet unless (isoutside and outside)
+
+    Uses qh.visit_id, qh.coplanarfacetset.
+    If share visit_id with qh_findbest, coplanarfacetset is incorrect.
+
+    If merging (testhorizon), searches horizon facets of coplanar best facets because
+    a point maybe coplanar to the bestfacet, below its horizon facet,
+    and above a horizon facet of a coplanar newfacet.  For example,
+      rbox 1000 s Z1 G1e-13 | qhull
+      rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc
+
+    qh_findbestnew() used if
+       qh_sharpnewfacets -- newfacets contains a sharp angle
+       if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew)
+
+  see also:
+    qh_partitionall() and qh_findbest()
+
+  design:
+    for each new facet starting from startfacet
+      test distance from point to facet
+      return facet if clearly outside
+      unless upperdelaunay and a lowerdelaunay exists
+         update best facet
+    test horizon facets
+*/
+facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet,
+           realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) {
+  realT bestdist= -REALmax/2;
+  facetT *bestfacet= NULL, *facet;
+  int oldtrace= qh->IStracing, i;
+  unsigned int visitid= ++qh->visit_id;
+  realT distoutside= 0.0;
+  boolT isdistoutside; /* True if distoutside is defined */
+  boolT testhorizon= True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
+
+  if (!startfacet || !startfacet->next) {
+    if (qh->MERGING) {
+      qh_fprintf(qh, qh->ferr, 6001, "qhull topology error (qh_findbestnew): merging has formed and deleted a cone of new facets.  Can not continue.\n");
+      qh_errexit(qh, qh_ERRtopology, NULL, NULL);
+    }else {
+      qh_fprintf(qh, qh->ferr, 6002, "qhull internal error (qh_findbestnew): no new facets for point p%d\n",
+              qh->furthest_id);
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }
+  }
+  zinc_(Zfindnew);
+  if (qh->BESToutside || bestoutside)
+    isdistoutside= False;
+  else {
+    isdistoutside= True;
+    distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user_r.h */
+  }
+  if (isoutside)
+    *isoutside= True;
+  *numpart= 0;
+#ifndef qh_NOtrace
+  if (qh->IStracing >= 4 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {
+    if (qh->TRACElevel > qh->IStracing)
+      qh->IStracing= qh->TRACElevel;
+    qh_fprintf(qh, qh->ferr, 8008, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g,",
+             qh_pointid(qh, point), startfacet->id, isdistoutside, distoutside);
+    qh_fprintf(qh, qh->ferr, 8009, " Last qh_addpoint p%d, qh.visit_id %d, vertex_visit %d,",  qh->furthest_id, visitid, qh->vertex_visit);
+    qh_fprintf(qh, qh->ferr, 8010, " Last merge #%d\n", zzval_(Ztotmerge));
+  }
+#endif
+  /* visit all new facets starting with startfacet, maybe qh->facet_list */
+  for (i=0, facet=startfacet; i < 2; i++, facet= qh->newfacet_list) {
+    FORALLfacet_(facet) {
+      if (facet == startfacet && i)
+        break;
+      facet->visitid= visitid;
+      if (!facet->flipped) {
+        qh_distplane(qh, point, facet, dist);
+        (*numpart)++;
+        if (*dist > bestdist) {
+          if (!facet->upperdelaunay || *dist >= qh->MINoutside) {
+            bestfacet= facet;
+            if (isdistoutside && *dist >= distoutside)
+              goto LABELreturn_bestnew;
+            bestdist= *dist;
+          }
+        }
+      } /* end of !flipped */
+    } /* FORALLfacet from startfacet or qh->newfacet_list */
+  }
+  if (testhorizon || !bestfacet) /* testhorizon is always True.  Keep the same code as qh_findbest */
+    bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet ? bestfacet : startfacet,
+                                        !qh_NOupper, &bestdist, numpart);
+  *dist= bestdist;
+  if (isoutside && *dist < qh->MINoutside)
+    *isoutside= False;
+LABELreturn_bestnew:
+  zadd_(Zfindnewtot, *numpart);
+  zmax_(Zfindnewmax, *numpart);
+  trace4((qh, qh->ferr, 4004, "qh_findbestnew: bestfacet f%d bestdist %2.2g for p%d f%d bestoutside? %d \n",
+    getid_(bestfacet), *dist, qh_pointid(qh, point), startfacet->id, bestoutside));
+  qh->IStracing= oldtrace;
+  return bestfacet;
+}  /* findbestnew */
+
+/* ============ hyperplane functions -- keep code together [?] ============ */
+
+/*---------------------------------
+
+  qh_backnormal(qh, rows, numrow, numcol, sign, normal, nearzero )
+    given an upper-triangular rows array and a sign,
+    solve for normal equation x using back substitution over rows U
+
+  returns:
+     normal= x
+
+     if will not be able to divzero() when normalized(qh.MINdenom_2 and qh.MINdenom_1_2),
+       if fails on last row
+         this means that the hyperplane intersects [0,..,1]
+         sets last coordinate of normal to sign
+       otherwise
+         sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0]
+         sets nearzero
+
+  notes:
+     assumes numrow == numcol-1
+
+     see Golub & van Loan, 1983, Eq. 4.4-9 for "Gaussian elimination with complete pivoting"
+
+     solves Ux=b where Ax=b and PA=LU
+     b= [0,...,0,sign or 0]  (sign is either -1 or +1)
+     last row of A= [0,...,0,1]
+
+     1) Ly=Pb == y=b since P only permutes the 0's of   b
+
+  design:
+    for each row from end
+      perform back substitution
+      if near zero
+        use qh_divzero for division
+        if zero divide and not last row
+          set tail of normal to 0
+*/
+void qh_backnormal(qhT *qh, realT **rows, int numrow, int numcol, boolT sign,
+        coordT *normal, boolT *nearzero) {
+  int i, j;
+  coordT *normalp, *normal_tail, *ai, *ak;
+  realT diagonal;
+  boolT waszero;
+  int zerocol= -1;
+
+  normalp= normal + numcol - 1;
+  *normalp--= (sign ? -1.0 : 1.0);
+  for (i=numrow; i--; ) {
+    *normalp= 0.0;
+    ai= rows[i] + i + 1;
+    ak= normalp+1;
+    for (j=i+1; j < numcol; j++)
+      *normalp -= *ai++ * *ak++;
+    diagonal= (rows[i])[i];
+    if (fabs_(diagonal) > qh->MINdenom_2)
+      *(normalp--) /= diagonal;
+    else {
+      waszero= False;
+      *normalp= qh_divzero(*normalp, diagonal, qh->MINdenom_1_2, &waszero);
+      if (waszero) {
+        zerocol= i;
+        *(normalp--)= (sign ? -1.0 : 1.0);
+        for (normal_tail= normalp+2; normal_tail < normal + numcol; normal_tail++)
+          *normal_tail= 0.0;
+      }else
+        normalp--;
+    }
+  }
+  if (zerocol != -1) {
+    *nearzero= True;
+    trace4((qh, qh->ferr, 4005, "qh_backnormal: zero diagonal at column %d.\n", i));
+    zzinc_(Zback0);
+    qh_joggle_restart(qh, "zero diagonal on back substitution");
+  }
+} /* backnormal */
+
+/*---------------------------------
+
+  qh_gausselim(qh, rows, numrow, numcol, sign )
+    Gaussian elimination with partial pivoting
+
+  returns:
+    rows is upper triangular (includes row exchanges)
+    flips sign for each row exchange
+    sets nearzero if pivot[k] < qh.NEARzero[k], else clears it
+
+  notes:
+    if nearzero, the determinant's sign may be incorrect.
+    assumes numrow <= numcol
+
+  design:
+    for each row
+      determine pivot and exchange rows if necessary
+      test for near zero
+      perform gaussian elimination step
+*/
+void qh_gausselim(qhT *qh, realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {
+  realT *ai, *ak, *rowp, *pivotrow;
+  realT n, pivot, pivot_abs= 0.0, temp;
+  int i, j, k, pivoti, flip=0;
+
+  *nearzero= False;
+  for (k=0; k < numrow; k++) {
+    pivot_abs= fabs_((rows[k])[k]);
+    pivoti= k;
+    for (i=k+1; i < numrow; i++) {
+      if ((temp= fabs_((rows[i])[k])) > pivot_abs) {
+        pivot_abs= temp;
+        pivoti= i;
+      }
+    }
+    if (pivoti != k) {
+      rowp= rows[pivoti];
+      rows[pivoti]= rows[k];
+      rows[k]= rowp;
+      *sign ^= 1;
+      flip ^= 1;
+    }
+    if (pivot_abs <= qh->NEARzero[k]) {
+      *nearzero= True;
+      if (pivot_abs == 0.0) {   /* remainder of column == 0 */
+#ifndef qh_NOtrace
+        if (qh->IStracing >= 4) {
+          qh_fprintf(qh, qh->ferr, 8011, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh->DISTround);
+          qh_printmatrix(qh, qh->ferr, "Matrix:", rows, numrow, numcol);
+        }
+#endif
+        zzinc_(Zgauss0);
+        qh_joggle_restart(qh, "zero pivot for Gaussian elimination");
+        goto LABELnextcol;
+      }
+    }
+    pivotrow= rows[k] + k;
+    pivot= *pivotrow++;  /* signed value of pivot, and remainder of row */
+    for (i=k+1; i < numrow; i++) {
+      ai= rows[i] + k;
+      ak= pivotrow;
+      n= (*ai++)/pivot;   /* divzero() not needed since |pivot| >= |*ai| */
+      for (j= numcol - (k+1); j--; )
+        *ai++ -= n * *ak++;
+    }
+  LABELnextcol:
+    ;
+  }
+  wmin_(Wmindenom, pivot_abs);  /* last pivot element */
+  if (qh->IStracing >= 5)
+    qh_printmatrix(qh, qh->ferr, "qh_gausselem: result", rows, numrow, numcol);
+} /* gausselim */
+
+
+/*---------------------------------
+
+  qh_getangle(qh, vect1, vect2 )
+    returns the dot product of two vectors
+    if qh.RANDOMdist, joggles result
+
+  notes:
+    the angle may be > 1.0 or < -1.0 because of roundoff errors
+
+*/
+realT qh_getangle(qhT *qh, pointT *vect1, pointT *vect2) {
+  realT angle= 0, randr;
+  int k;
+
+  for (k=qh->hull_dim; k--; )
+    angle += *vect1++ * *vect2++;
+  if (qh->RANDOMdist) {
+    randr= qh_RANDOMint;
+    angle += (2.0 * randr / qh_RANDOMmax - 1.0) *
+      qh->RANDOMfactor;
+  }
+  trace4((qh, qh->ferr, 4006, "qh_getangle: %4.4g\n", angle));
+  return(angle);
+} /* getangle */
+
+
+/*---------------------------------
+
+  qh_getcenter(qh, vertices )
+    returns arithmetic center of a set of vertices as a new point
+
+  notes:
+    allocates point array for center
+*/
+pointT *qh_getcenter(qhT *qh, setT *vertices) {
+  int k;
+  pointT *center, *coord;
+  vertexT *vertex, **vertexp;
+  int count= qh_setsize(qh, vertices);
+
+  if (count < 2) {
+    qh_fprintf(qh, qh->ferr, 6003, "qhull internal error (qh_getcenter): not defined for %d points\n", count);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  center= (pointT *)qh_memalloc(qh, qh->normal_size);
+  for (k=0; k < qh->hull_dim; k++) {
+    coord= center+k;
+    *coord= 0.0;
+    FOREACHvertex_(vertices)
+      *coord += vertex->point[k];
+    *coord /= count;  /* count>=2 by QH6003 */
+  }
+  return(center);
+} /* getcenter */
+
+
+/*---------------------------------
+
+  qh_getcentrum(qh, facet )
+    returns the centrum for a facet as a new point
+
+  notes:
+    allocates the centrum
+*/
+pointT *qh_getcentrum(qhT *qh, facetT *facet) {
+  realT dist;
+  pointT *centrum, *point;
+
+  point= qh_getcenter(qh, facet->vertices);
+  zzinc_(Zcentrumtests);
+  qh_distplane(qh, point, facet, &dist);
+  centrum= qh_projectpoint(qh, point, facet, dist);
+  qh_memfree(qh, point, qh->normal_size);
+  trace4((qh, qh->ferr, 4007, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",
+          facet->id, qh_setsize(qh, facet->vertices), dist));
+  return centrum;
+} /* getcentrum */
+
+
+/*---------------------------------
+
+  qh_getdistance(qh, facet, neighbor, mindist, maxdist )
+    returns the min and max distance to neighbor of non-neighbor vertices in facet
+
+  returns:
+    the max absolute value
+
+  design:
+    for each vertex of facet that is not in neighbor
+      test the distance from vertex to neighbor
+*/
+coordT qh_getdistance(qhT *qh, facetT *facet, facetT *neighbor, coordT *mindist, coordT *maxdist) {
+  vertexT *vertex, **vertexp;
+  coordT dist, maxd, mind;
+
+  FOREACHvertex_(facet->vertices)
+    vertex->seen= False;
+  FOREACHvertex_(neighbor->vertices)
+    vertex->seen= True;
+  mind= 0.0;
+  maxd= 0.0;
+  FOREACHvertex_(facet->vertices) {
+    if (!vertex->seen) {
+      zzinc_(Zbestdist);
+      qh_distplane(qh, vertex->point, neighbor, &dist);
+      if (dist < mind)
+        mind= dist;
+      else if (dist > maxd)
+        maxd= dist;
+    }
+  }
+  *mindist= mind;
+  *maxdist= maxd;
+  mind= -mind;
+  if (maxd > mind)
+    return maxd;
+  else
+    return mind;
+} /* getdistance */
+
+
+/*---------------------------------
+
+  qh_normalize(qh, normal, dim, toporient )
+    normalize a vector and report if too small
+    does not use min norm
+
+  see:
+    qh_normalize2
+*/
+void qh_normalize(qhT *qh, coordT *normal, int dim, boolT toporient) {
+  qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
+} /* normalize */
+
+/*---------------------------------
+
+  qh_normalize2(qh, normal, dim, toporient, minnorm, ismin )
+    normalize a vector and report if too small
+    qh.MINdenom/MINdenom1 are the upper limits for divide overflow
+
+  returns:
+    normalized vector
+    flips sign if !toporient
+    if minnorm non-NULL,
+      sets ismin if normal < minnorm
+
+  notes:
+    if zero norm
+       sets all elements to sqrt(1.0/dim)
+    if divide by zero (divzero())
+       sets largest element to   +/-1
+       bumps Znearlysingular
+
+  design:
+    computes norm
+    test for minnorm
+    if not near zero
+      normalizes normal
+    else if zero norm
+      sets normal to standard value
+    else
+      uses qh_divzero to normalize
+      if nearzero
+        sets norm to direction of maximum value
+*/
+void qh_normalize2(qhT *qh, coordT *normal, int dim, boolT toporient,
+            realT *minnorm, boolT *ismin) {
+  int k;
+  realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;
+  boolT zerodiv;
+
+  norm1= normal+1;
+  norm2= normal+2;
+  norm3= normal+3;
+  if (dim == 2)
+    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));
+  else if (dim == 3)
+    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));
+  else if (dim == 4) {
+    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
+               + (*norm3)*(*norm3));
+  }else if (dim > 4) {
+    norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
+               + (*norm3)*(*norm3);
+    for (k=dim-4, colp=normal+4; k--; colp++)
+      norm += (*colp) * (*colp);
+    norm= sqrt(norm);
+  }
+  if (minnorm) {
+    if (norm < *minnorm)
+      *ismin= True;
+    else
+      *ismin= False;
+  }
+  wmin_(Wmindenom, norm);
+  if (norm > qh->MINdenom) {
+    if (!toporient)
+      norm= -norm;
+    *normal /= norm;
+    *norm1 /= norm;
+    if (dim == 2)
+      ; /* all done */
+    else if (dim == 3)
+      *norm2 /= norm;
+    else if (dim == 4) {
+      *norm2 /= norm;
+      *norm3 /= norm;
+    }else if (dim >4) {
+      *norm2 /= norm;
+      *norm3 /= norm;
+      for (k=dim-4, colp=normal+4; k--; )
+        *colp++ /= norm;
+    }
+  }else if (norm == 0.0) {
+    temp= sqrt(1.0/dim);
+    for (k=dim, colp=normal; k--; )
+      *colp++= temp;
+  }else {
+    if (!toporient)
+      norm= -norm;
+    for (k=dim, colp=normal; k--; colp++) { /* k used below */
+      temp= qh_divzero(*colp, norm, qh->MINdenom_1, &zerodiv);
+      if (!zerodiv)
+        *colp= temp;
+      else {
+        maxp= qh_maxabsval(normal, dim);
+        temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0);
+        for (k=dim, colp=normal; k--; colp++)
+          *colp= 0.0;
+        *maxp= temp;
+        zzinc_(Znearlysingular);
+        /* qh_joggle_restart ignored for Znearlysingular, normal part of qh_sethyperplane_gauss */
+        trace0((qh, qh->ferr, 1, "qh_normalize: norm=%2.2g too small during p%d\n",
+               norm, qh->furthest_id));
+        return;
+      }
+    }
+  }
+} /* normalize */
+
+
+/*---------------------------------
+
+  qh_projectpoint(qh, point, facet, dist )
+    project point onto a facet by dist
+
+  returns:
+    returns a new point
+
+  notes:
+    if dist= distplane(point,facet)
+      this projects point to hyperplane
+    assumes qh_memfree_() is valid for normal_size
+*/
+pointT *qh_projectpoint(qhT *qh, pointT *point, facetT *facet, realT dist) {
+  pointT *newpoint, *np, *normal;
+  int normsize= qh->normal_size;
+  int k;
+  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
+
+  qh_memalloc_(qh, normsize, freelistp, newpoint, pointT);
+  np= newpoint;
+  normal= facet->normal;
+  for (k=qh->hull_dim; k--; )
+    *(np++)= *point++ - dist * *normal++;
+  return(newpoint);
+} /* projectpoint */
+
+
+/*---------------------------------
+
+  qh_setfacetplane(qh, facet )
+    sets the hyperplane for a facet
+    if qh.RANDOMdist, joggles hyperplane
+
+  notes:
+    uses global buffers qh.gm_matrix and qh.gm_row
+    overwrites facet->normal if already defined
+    updates Wnewvertex if PRINTstatistics
+    sets facet->upperdelaunay if upper envelope of Delaunay triangulation
+
+  design:
+    copy vertex coordinates to qh.gm_matrix/gm_row
+    compute determinate
+    if nearzero
+      recompute determinate with gaussian elimination
+      if nearzero
+        force outside orientation by testing interior point
+*/
+void qh_setfacetplane(qhT *qh, facetT *facet) {
+  pointT *point;
+  vertexT *vertex, **vertexp;
+  int normsize= qh->normal_size;
+  int k,i, oldtrace= 0;
+  realT dist;
+  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
+  coordT *coord, *gmcoord;
+  pointT *point0= SETfirstt_(facet->vertices, vertexT)->point;
+  boolT nearzero= False;
+
+  zzinc_(Zsetplane);
+  if (!facet->normal)
+    qh_memalloc_(qh, normsize, freelistp, facet->normal, coordT);
+#ifndef qh_NOtrace
+  if (facet == qh->tracefacet) {
+    oldtrace= qh->IStracing;
+    qh->IStracing= 5;
+    qh_fprintf(qh, qh->ferr, 8012, "qh_setfacetplane: facet f%d created.\n", facet->id);
+    qh_fprintf(qh, qh->ferr, 8013, "  Last point added to hull was p%d.", qh->furthest_id);
+    if (zzval_(Ztotmerge))
+      qh_fprintf(qh, qh->ferr, 8014, "  Last merge was #%d.", zzval_(Ztotmerge));
+    qh_fprintf(qh, qh->ferr, 8015, "\n\nCurrent summary is:\n");
+      qh_printsummary(qh, qh->ferr);
+  }
+#endif
+  if (qh->hull_dim <= 4) {
+    i= 0;
+    if (qh->RANDOMdist) {
+      gmcoord= qh->gm_matrix;
+      FOREACHvertex_(facet->vertices) {
+        qh->gm_row[i++]= gmcoord;
+        coord= vertex->point;
+        for (k=qh->hull_dim; k--; )
+          *(gmcoord++)= *coord++ * qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);
+      }
+    }else {
+      FOREACHvertex_(facet->vertices)
+       qh->gm_row[i++]= vertex->point;
+    }
+    qh_sethyperplane_det(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,
+                facet->normal, &facet->offset, &nearzero);
+  }
+  if (qh->hull_dim > 4 || nearzero) {
+    i= 0;
+    gmcoord= qh->gm_matrix;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->point != point0) {
+        qh->gm_row[i++]= gmcoord;
+        coord= vertex->point;
+        point= point0;
+        for (k=qh->hull_dim; k--; )
+          *(gmcoord++)= *coord++ - *point++;
+      }
+    }
+    qh->gm_row[i]= gmcoord;  /* for areasimplex */
+    if (qh->RANDOMdist) {
+      gmcoord= qh->gm_matrix;
+      for (i=qh->hull_dim-1; i--; ) {
+        for (k=qh->hull_dim; k--; )
+          *(gmcoord++) *= qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);
+      }
+    }
+    qh_sethyperplane_gauss(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,
+                facet->normal, &facet->offset, &nearzero);
+    if (nearzero) {
+      if (qh_orientoutside(qh, facet)) {
+        trace0((qh, qh->ferr, 2, "qh_setfacetplane: flipped orientation due to nearzero gauss and interior_point test.  During p%d\n", qh->furthest_id));
+      /* this is part of using Gaussian Elimination.  For example in 5-d
+           1 1 1 1 0
+           1 1 1 1 1
+           0 0 0 1 0
+           0 1 0 0 0
+           1 0 0 0 0
+           norm= 0.38 0.38 -0.76 0.38 0
+         has a determinate of 1, but g.e. after subtracting pt. 0 has
+         0's in the diagonal, even with full pivoting.  It does work
+         if you subtract pt. 4 instead. */
+      }
+    }
+  }
+  facet->upperdelaunay= False;
+  if (qh->DELAUNAY) {
+    if (qh->UPPERdelaunay) {     /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */
+      if (facet->normal[qh->hull_dim -1] >= qh->ANGLEround * qh_ZEROdelaunay)
+        facet->upperdelaunay= True;
+    }else {
+      if (facet->normal[qh->hull_dim -1] > -qh->ANGLEround * qh_ZEROdelaunay)
+        facet->upperdelaunay= True;
+    }
+  }
+  if (qh->PRINTstatistics || qh->IStracing || qh->TRACElevel || qh->JOGGLEmax < REALmax) {
+    qh->old_randomdist= qh->RANDOMdist;
+    qh->RANDOMdist= False;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->point != point0) {
+        boolT istrace= False;
+        zinc_(Zdiststat);
+        qh_distplane(qh, vertex->point, facet, &dist);
+        dist= fabs_(dist);
+        zinc_(Znewvertex);
+        wadd_(Wnewvertex, dist);
+        if (dist > wwval_(Wnewvertexmax)) {
+          wwval_(Wnewvertexmax)= dist;
+          if (dist > qh->max_outside) {
+            qh->max_outside= dist;  /* used by qh_maxouter(qh) */
+            if (dist > qh->TRACEdist)
+              istrace= True;
+          }
+        }else if (-dist > qh->TRACEdist)
+          istrace= True;
+        if (istrace) {
+          qh_fprintf(qh, qh->ferr, 3060, "qh_setfacetplane: ====== vertex p%d(v%d) increases max_outside to %2.2g for new facet f%d last p%d\n",
+                qh_pointid(qh, vertex->point), vertex->id, dist, facet->id, qh->furthest_id);
+          qh_errprint(qh, "DISTANT", facet, NULL, NULL, NULL);
+        }
+      }
+    }
+    qh->RANDOMdist= qh->old_randomdist;
+  }
+#ifndef qh_NOtrace
+  if (qh->IStracing >= 4) {
+    qh_fprintf(qh, qh->ferr, 8017, "qh_setfacetplane: f%d offset %2.2g normal: ",
+             facet->id, facet->offset);
+    for (k=0; k < qh->hull_dim; k++)
+      qh_fprintf(qh, qh->ferr, 8018, "%2.2g ", facet->normal[k]);
+    qh_fprintf(qh, qh->ferr, 8019, "\n");
+  }
+#endif
+  qh_checkflipped(qh, facet, NULL, qh_ALL);
+  if (facet == qh->tracefacet) {
+    qh->IStracing= oldtrace;
+    qh_printfacet(qh, qh->ferr, facet);
+  }
+} /* setfacetplane */
+
+
+/*---------------------------------
+
+  qh_sethyperplane_det(qh, dim, rows, point0, toporient, normal, offset, nearzero )
+    given dim X dim array indexed by rows[], one row per point,
+        toporient(flips all signs),
+        and point0 (any row)
+    set normalized hyperplane equation from oriented simplex
+
+  returns:
+    normal (normalized)
+    offset (places point0 on the hyperplane)
+    sets nearzero if hyperplane not through points
+
+  notes:
+    only defined for dim == 2..4
+    rows[] is not modified
+    solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane
+    see Bower & Woodworth, A programmer's geometry, Butterworths 1983.
+
+  derivation of 3-d minnorm
+    Goal: all vertices V_i within qh.one_merge of hyperplane
+    Plan: exactly translate the facet so that V_0 is the origin
+          exactly rotate the facet so that V_1 is on the x-axis and y_2=0.
+          exactly rotate the effective perturbation to only effect n_0
+             this introduces a factor of sqrt(3)
+    n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm
+    Let M_d be the max coordinate difference
+    Let M_a be the greater of M_d and the max abs. coordinate
+    Let u be machine roundoff and distround be max error for distance computation
+    The max error for n_0 is sqrt(3) u M_a M_d / norm.  n_1 is approx. 1 and n_2 is approx. 0
+    The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm.  Offset=0 at origin
+    Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge
+    Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d
+
+  derivation of 4-d minnorm
+    same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0
+     [if two vertices fixed on x-axis, can rotate the other two in yzw.]
+    n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3
+     [all other terms contain at least two factors nearly zero.]
+    The max error for n_0 is sqrt(4) u M_a M_d M_d / norm
+    Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge
+    Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d
+*/
+void qh_sethyperplane_det(qhT *qh, int dim, coordT **rows, coordT *point0,
+          boolT toporient, coordT *normal, realT *offset, boolT *nearzero) {
+  realT maxround, dist;
+  int i;
+  pointT *point;
+
+
+  if (dim == 2) {
+    normal[0]= dY(1,0);
+    normal[1]= dX(0,1);
+    qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
+    *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);
+    *nearzero= False;  /* since nearzero norm => incident points */
+  }else if (dim == 3) {
+    normal[0]= det2_(dY(2,0), dZ(2,0),
+                     dY(1,0), dZ(1,0));
+    normal[1]= det2_(dX(1,0), dZ(1,0),
+                     dX(2,0), dZ(2,0));
+    normal[2]= det2_(dX(2,0), dY(2,0),
+                     dX(1,0), dY(1,0));
+    qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
+    *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
+               + point0[2]*normal[2]);
+    maxround= qh->DISTround;
+    for (i=dim; i--; ) {
+      point= rows[i];
+      if (point != point0) {
+        dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
+               + point[2]*normal[2]);
+        if (dist > maxround || dist < -maxround) {
+          *nearzero= True;
+          break;
+        }
+      }
+    }
+  }else if (dim == 4) {
+    normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),
+                        dY(1,0), dZ(1,0), dW(1,0),
+                        dY(3,0), dZ(3,0), dW(3,0));
+    normal[1]=   det3_(dX(2,0), dZ(2,0), dW(2,0),
+                        dX(1,0), dZ(1,0), dW(1,0),
+                        dX(3,0), dZ(3,0), dW(3,0));
+    normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),
+                        dX(1,0), dY(1,0), dW(1,0),
+                        dX(3,0), dY(3,0), dW(3,0));
+    normal[3]=   det3_(dX(2,0), dY(2,0), dZ(2,0),
+                        dX(1,0), dY(1,0), dZ(1,0),
+                        dX(3,0), dY(3,0), dZ(3,0));
+    qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
+    *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
+               + point0[2]*normal[2] + point0[3]*normal[3]);
+    maxround= qh->DISTround;
+    for (i=dim; i--; ) {
+      point= rows[i];
+      if (point != point0) {
+        dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
+               + point[2]*normal[2] + point[3]*normal[3]);
+        if (dist > maxround || dist < -maxround) {
+          *nearzero= True;
+          break;
+        }
+      }
+    }
+  }
+  if (*nearzero) {
+    zzinc_(Zminnorm);
+    /* qh_joggle_restart not needed, will call qh_sethyperplane_gauss instead */
+    trace0((qh, qh->ferr, 3, "qh_sethyperplane_det: degenerate norm during p%d, use qh_sethyperplane_gauss instead.\n", qh->furthest_id));
+  }
+} /* sethyperplane_det */
+
+
+/*---------------------------------
+
+  qh_sethyperplane_gauss(qh, dim, rows, point0, toporient, normal, offset, nearzero )
+    given(dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)
+    set normalized hyperplane equation from oriented simplex
+
+  returns:
+    normal (normalized)
+    offset (places point0 on the hyperplane)
+
+  notes:
+    if nearzero
+      orientation may be incorrect because of incorrect sign flips in gausselim
+    solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1]
+        or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0]
+    i.e., N is normal to the hyperplane, and the unnormalized
+        distance to [0 .. 1] is either 1 or   0
+
+  design:
+    perform gaussian elimination
+    flip sign for negative values
+    perform back substitution
+    normalize result
+    compute offset
+*/
+void qh_sethyperplane_gauss(qhT *qh, int dim, coordT **rows, pointT *point0,
+                boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {
+  coordT *pointcoord, *normalcoef;
+  int k;
+  boolT sign= toporient, nearzero2= False;
+
+  qh_gausselim(qh, rows, dim-1, dim, &sign, nearzero);
+  for (k=dim-1; k--; ) {
+    if ((rows[k])[k] < 0)
+      sign ^= 1;
+  }
+  if (*nearzero) {
+    zzinc_(Znearlysingular);
+    /* qh_joggle_restart ignored for Znearlysingular, normal part of qh_sethyperplane_gauss */
+    trace0((qh, qh->ferr, 4, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh->furthest_id));
+    qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);
+  }else {
+    qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);
+    if (nearzero2) {
+      zzinc_(Znearlysingular);
+      trace0((qh, qh->ferr, 5, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh->furthest_id));
+    }
+  }
+  if (nearzero2)
+    *nearzero= True;
+  qh_normalize2(qh, normal, dim, True, NULL, NULL);
+  pointcoord= point0;
+  normalcoef= normal;
+  *offset= -(*pointcoord++ * *normalcoef++);
+  for (k=dim-1; k--; )
+    *offset -= *pointcoord++ * *normalcoef++;
+} /* sethyperplane_gauss */
+
+
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/geom_r.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/geom_r.h
new file mode 100644
index 00000000000..f3f8ee81400
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/geom_r.h
@@ -0,0 +1,189 @@
+/*
  ---------------------------------
+
+  geom_r.h
+    header file for geometric routines
+
+   see qh-geom_r.htm and geom_r.c
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/geom_r.h#2 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+*/
+
+#ifndef qhDEFgeom
+#define qhDEFgeom 1
+
+#include "libqhull_r.h"
+
+/* ============ -macros- ======================== */
+
+/*----------------------------------
+
+  fabs_(a)
+    returns the absolute value of a
+*/
+#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))
+
+/*----------------------------------
+
+  fmax_(a,b)
+    returns the maximum value of a and b
+*/
+#define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )
+
+/*----------------------------------
+
+  fmin_(a,b)
+    returns the minimum value of a and b
+*/
+#define fmin_( a,b )  ( ( a ) > ( b ) ? ( b ) : ( a ) )
+
+/*----------------------------------
+
+  maximize_(maxval, val)
+    set maxval to val if val is greater than maxval
+*/
+#define maximize_( maxval, val ) { if (( maxval ) < ( val )) ( maxval )= ( val ); }
+
+/*----------------------------------
+
+  minimize_(minval, val)
+    set minval to val if val is less than minval
+*/
+#define minimize_( minval, val ) { if (( minval ) > ( val )) ( minval )= ( val ); }
+
+/*----------------------------------
+
+  det2_(a1, a2,
+        b1, b2)
+
+    compute a 2-d determinate
+*/
+#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))
+
+/*----------------------------------
+
+  det3_(a1, a2, a3,
+       b1, b2, b3,
+       c1, c2, c3)
+
+    compute a 3-d determinate
+*/
+#define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \
+                - ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) )
+
+/*----------------------------------
+
+  dX( p1, p2 )
+  dY( p1, p2 )
+  dZ( p1, p2 )
+
+    given two indices into rows[],
+
+    compute the difference between X, Y, or Z coordinates
+*/
+#define dX( p1,p2 )  ( *( rows[p1] ) - *( rows[p2] ))
+#define dY( p1,p2 )  ( *( rows[p1]+1 ) - *( rows[p2]+1 ))
+#define dZ( p1,p2 )  ( *( rows[p1]+2 ) - *( rows[p2]+2 ))
+#define dW( p1,p2 )  ( *( rows[p1]+3 ) - *( rows[p2]+3 ))
+
+/*============= prototypes in alphabetical order, infrequent at end ======= */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void    qh_backnormal(qhT *qh, realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero);
+void    qh_distplane(qhT *qh, pointT *point, facetT *facet, realT *dist);
+facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,
+                     boolT bestoutside, boolT isnewfacets, boolT noupper,
+                     realT *dist, boolT *isoutside, int *numpart);
+facetT *qh_findbesthorizon(qhT *qh, boolT ischeckmax, pointT *point,
+                     facetT *startfacet, boolT noupper, realT *bestdist, int *numpart);
+facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet, realT *dist,
+                     boolT bestoutside, boolT *isoutside, int *numpart);
+void    qh_gausselim(qhT *qh, realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero);
+realT   qh_getangle(qhT *qh, pointT *vect1, pointT *vect2);
+pointT *qh_getcenter(qhT *qh, setT *vertices);
+pointT *qh_getcentrum(qhT *qh, facetT *facet);
+coordT  qh_getdistance(qhT *qh, facetT *facet, facetT *neighbor, coordT *mindist, coordT *maxdist);
+void    qh_normalize(qhT *qh, coordT *normal, int dim, boolT toporient);
+void    qh_normalize2(qhT *qh, coordT *normal, int dim, boolT toporient,
+            realT *minnorm, boolT *ismin);
+pointT *qh_projectpoint(qhT *qh, pointT *point, facetT *facet, realT dist);
+
+void    qh_setfacetplane(qhT *qh, facetT *newfacets);
+void    qh_sethyperplane_det(qhT *qh, int dim, coordT **rows, coordT *point0,
+              boolT toporient, coordT *normal, realT *offset, boolT *nearzero);
+void    qh_sethyperplane_gauss(qhT *qh, int dim, coordT **rows, pointT *point0,
+             boolT toporient, coordT *normal, coordT *offset, boolT *nearzero);
+boolT   qh_sharpnewfacets(qhT *qh);
+
+/*========= infrequently used code in geom2_r.c =============*/
+
+coordT *qh_copypoints(qhT *qh, coordT *points, int numpoints, int dimension);
+void    qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]);
+realT   qh_determinant(qhT *qh, realT **rows, int dim, boolT *nearzero);
+realT   qh_detjoggle(qhT *qh, pointT *points, int numpoints, int dimension);
+void    qh_detmaxoutside(qhT *qh);
+void    qh_detroundoff(qhT *qh);
+realT   qh_detsimplex(qhT *qh, pointT *apex, setT *points, int dim, boolT *nearzero);
+realT   qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp);
+realT   qh_distround(qhT *qh, int dimension, realT maxabs, realT maxsumabs);
+realT   qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv);
+realT   qh_facetarea(qhT *qh, facetT *facet);
+realT   qh_facetarea_simplex(qhT *qh, int dim, coordT *apex, setT *vertices,
+          vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset);
+pointT *qh_facetcenter(qhT *qh, setT *vertices);
+facetT *qh_findgooddist(qhT *qh, pointT *point, facetT *facetA, realT *distp, facetT **facetlist);
+vertexT *qh_furthestnewvertex(qhT *qh, unsigned int unvisited, facetT *facet, realT *maxdistp /* qh.newvertex_list */);
+vertexT *qh_furthestvertex(qhT *qh, facetT *facetA, facetT *facetB, realT *maxdistp, realT *mindistp);
+void    qh_getarea(qhT *qh, facetT *facetlist);
+boolT   qh_gram_schmidt(qhT *qh, int dim, realT **rows);
+boolT   qh_inthresholds(qhT *qh, coordT *normal, realT *angle);
+void    qh_joggleinput(qhT *qh);
+realT  *qh_maxabsval(realT *normal, int dim);
+setT   *qh_maxmin(qhT *qh, pointT *points, int numpoints, int dimension);
+realT   qh_maxouter(qhT *qh);
+void    qh_maxsimplex(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex);
+realT   qh_minabsval(realT *normal, int dim);
+int     qh_mindiff(realT *vecA, realT *vecB, int dim);
+boolT   qh_orientoutside(qhT *qh, facetT *facet);
+void    qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane);
+coordT  qh_pointdist(pointT *point1, pointT *point2, int dim);
+void    qh_printmatrix(qhT *qh, FILE *fp, const char *string, realT **rows, int numrow, int numcol);
+void    qh_printpoints(qhT *qh, FILE *fp, const char *string, setT *points);
+void    qh_projectinput(qhT *qh);
+void    qh_projectpoints(qhT *qh, signed char *project, int n, realT *points,
+             int numpoints, int dim, realT *newpoints, int newdim);
+void    qh_rotateinput(qhT *qh, realT **rows);
+void    qh_rotatepoints(qhT *qh, realT *points, int numpoints, int dim, realT **rows);
+void    qh_scaleinput(qhT *qh);
+void    qh_scalelast(qhT *qh, coordT *points, int numpoints, int dim, coordT low,
+                   coordT high, coordT newhigh);
+void    qh_scalepoints(qhT *qh, pointT *points, int numpoints, int dim,
+                realT *newlows, realT *newhighs);
+boolT   qh_sethalfspace(qhT *qh, int dim, coordT *coords, coordT **nextp,
+              coordT *normal, coordT *offset, coordT *feasible);
+coordT *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible);
+coordT  qh_vertex_bestdist(qhT *qh, setT *vertices);
+coordT  qh_vertex_bestdist2(qhT *qh, setT *vertices, vertexT **vertexp, vertexT **vertexp2);
+pointT *qh_voronoi_center(qhT *qh, int dim, setT *points);
+
+#ifdef __cplusplus
+} /* extern "C"*/
+#endif
+
+#endif /* qhDEFgeom */
+
+
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/global_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/global_r.c
new file mode 100644
index 00000000000..d8f0f0b0165
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/global_r.c
@@ -0,0 +1,2268 @@
+
+/*
  ---------------------------------
+
+   global_r.c
+   initializes all the globals of the qhull application
+
+   see README
+
+   see libqhull_r.h for qh.globals and function prototypes
+
+   see qhull_ra.h for internal functions
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/global_r.c#21 $$Change: 3664 $
+   $DateTime: 2024/07/22 23:55:01 $$Author: bbarber $
+ */
+
+#include "qhull_ra.h"
+
+/*========= qh->definition -- globals defined in libqhull_r.h =======================*/
+
+/*----------------------------------
+
+  qh_version
+    version string by year and date
+    qh_version2 for Unix users and -V
+
+    the revision increases on code changes only
+
+  notes:
+    change date:    Changes.txt, Announce.txt, index.htm, README.txt,
+                    qhull-news.html, Eudora signatures, CMakeLists.txt
+    change version: README.txt, qh-get.htm, File_id.diz, Makefile.txt, CMakeLists.txt
+    check that CMakeLists.txt @version is the same as qh_version2
+    change year:    Copying.txt
+    check download size
+    recompile user_eg_r.c, rbox_r.c, libqhull_r.c, qconvex_r.c, qdelaun_r.c qvoronoi_r.c, qhalf_r.c, testqset_r.c
+*/
+
+const char qh_version[]= "2020.2.r 2023/01/02";
+const char qh_version2[]= "qhull_r 8.1-alpha3 (2020.2.r 2023/01/02)";
+
+/*---------------------------------
+
+  qh_appendprint(qh, printFormat )
+    append printFormat to qh.PRINTout unless already defined
+*/
+void qh_appendprint(qhT *qh, qh_PRINT format) {
+  int i;
+
+  for (i=0; i < qh_PRINTEND; i++) {
+    if (qh->PRINTout[i] == format && format != qh_PRINTqhull)
+      break;
+    if (!qh->PRINTout[i]) {
+      qh->PRINTout[i]= format;
+      break;
+    }
+  }
+} /* appendprint */
+
+/*---------------------------------
+
+  qh_checkflags(qh, commandStr, hiddenFlags )
+    errors if commandStr contains hiddenFlags
+    hiddenFlags starts and ends with a space and is space delimited (checked)
+
+  notes:
+    ignores first word (e.g., "qconvex i")
+    use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
+
+  see:
+    qh_initflags() initializes Qhull according to commandStr
+*/
+void qh_checkflags(qhT *qh, char *command, char *hiddenflags) {
+  char *s= command, *t, *chkerr; /* qh_skipfilename is non-const */
+  char key, opt, prevopt;
+  char chkkey[]=  "   ";    /* check one character options ('s') */
+  char chkopt[]=  "    ";   /* check two character options ('Ta') */
+  char chkopt2[]= "     ";  /* check three character options ('Q12') */
+  boolT waserr= False;
+
+  if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {
+    qh_fprintf(qh, qh->ferr, 6026, "qhull internal error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"\n", hiddenflags);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  if (strpbrk(hiddenflags, ",\n\r\t")) {
+    qh_fprintf(qh, qh->ferr, 6027, "qhull internal error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"\n", hiddenflags);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  while (*s && !isspace(*s))  /* skip program name */
+    s++;
+  while (*s) {
+    while (*s && isspace(*s))
+      s++;
+    if (*s == '-')
+      s++;
+    if (!*s)
+      break;
+    key= *s++;
+    chkerr= NULL;
+    if (key == 'T' && (*s == 'I' || *s == 'O')) {  /* TI or TO 'file name' */
+      s= qh_skipfilename(qh, ++s);
+      continue;
+    }
+    chkkey[1]= key;
+    if (strstr(hiddenflags, chkkey)) {
+      chkerr= chkkey;
+    }else if (isupper(key)) {
+      opt= ' ';
+      prevopt= ' ';
+      chkopt[1]= key;
+      chkopt2[1]= key;
+      while (!chkerr && *s && !isspace(*s)) {
+        opt= *s++;
+        if (isalpha(opt)) {
+          chkopt[2]= opt;
+          if (strstr(hiddenflags, chkopt))
+            chkerr= chkopt;
+          if (prevopt != ' ') {
+            chkopt2[2]= prevopt;
+            chkopt2[3]= opt;
+            if (strstr(hiddenflags, chkopt2))
+              chkerr= chkopt2;
+          }
+        }else if (key == 'Q' && isdigit(opt) && prevopt != 'b'
+              && (prevopt == ' ' || islower(prevopt))) {
+            if (isdigit(*s)) {  /* Q12 */
+              chkopt2[2]= opt;
+              chkopt2[3]= *s++;
+              if (strstr(hiddenflags, chkopt2))
+                chkerr= chkopt2;
+            }else {
+              chkopt[2]= opt;
+              if (strstr(hiddenflags, chkopt))
+                chkerr= chkopt;
+            }
+        }else {
+          qh_strtod(s-1, &t);
+          if (s < t)
+            s= t;
+        }
+        prevopt= opt;
+      }
+    }
+    if (chkerr) {
+      *chkerr= '\'';
+      chkerr[strlen(chkerr)-1]=  '\'';
+      qh_fprintf(qh, qh->ferr, 6029, "qhull option error: option %s is not used with this program.\n             It may be used with qhull.\n", chkerr);
+      waserr= True;
+    }
+  }
+  if (waserr)
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+} /* checkflags */
+
+/*---------------------------------
+
+  qh_clear_outputflags(qh)
+    Clear output flags for QhullPoints
+*/
+void qh_clear_outputflags(qhT *qh) {
+  int i,k;
+
+  qh->ANNOTATEoutput= False;
+  qh->DOintersections= False;
+  qh->DROPdim= -1;
+  qh->FORCEoutput= False;
+  qh->GETarea= False;
+  qh->GOODpoint= 0;
+  qh->GOODpointp= NULL;
+  qh->GOODthreshold= False;
+  qh->GOODvertex= 0;
+  qh->GOODvertexp= NULL;
+  qh->IStracing= 0;
+  qh->KEEParea= False;
+  qh->KEEPmerge= False;
+  qh->KEEPminArea= REALmax;
+  qh->PRINTcentrums= False;
+  qh->PRINTcoplanar= False;
+  qh->PRINTdots= False;
+  qh->PRINTgood= False;
+  qh->PRINTinner= False;
+  qh->PRINTneighbors= False;
+  qh->PRINTnoplanes= False;
+  qh->PRINToptions1st= False;
+  qh->PRINTouter= False;
+  qh->PRINTprecision= True;
+  qh->PRINTridges= False;
+  qh->PRINTspheres= False;
+  qh->PRINTstatistics= False;
+  qh->PRINTsummary= False;
+  qh->PRINTtransparent= False;
+  qh->SPLITthresholds= False;
+  qh->TRACElevel= 0;
+  qh->TRInormals= False;
+  qh->USEstdout= False;
+  qh->VERIFYoutput= False;
+  for (k=qh->input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */
+    qh->lower_threshold[k]= -REALmax;
+    qh->upper_threshold[k]= REALmax;
+    qh->lower_bound[k]= -REALmax;
+    qh->upper_bound[k]= REALmax;
+  }
+
+  for (i=0; i < qh_PRINTEND; i++) {
+    qh->PRINTout[i]= qh_PRINTnone;
+  }
+
+  if (!qh->qhull_commandsiz2)
+      qh->qhull_commandsiz2= (int)strlen(qh->qhull_command); /* WARN64 */
+  else {
+      qh->qhull_command[qh->qhull_commandsiz2]= '\0';
+  }
+  if (!qh->qhull_optionsiz2)
+    qh->qhull_optionsiz2= (int)strlen(qh->qhull_options);  /* WARN64 */
+  else {
+    qh->qhull_options[qh->qhull_optionsiz2]= '\0';
+    qh->qhull_optionlen= qh_OPTIONline;  /* start a new line */
+  }
+} /* clear_outputflags */
+
+/*---------------------------------
+
+  qh_clock()
+    return user CPU time in 100ths (qh_SECtick)
+    only defined for qh_CLOCKtype == 2
+
+  notes:
+    use first value to determine time 0
+    from Stevens '92 8.15
+*/
+unsigned long qh_clock(qhT *qh) {
+
+#if (qh_CLOCKtype == 2)
+  struct tms time;
+  static long clktck;  /* initialized first call and never updated */
+  double ratio, cpu;
+  unsigned long ticks;
+
+  if (!clktck) {
+    if ((clktck= sysconf(_SC_CLK_TCK)) < 0) {
+      qh_fprintf(qh, qh->ferr, 6030, "qhull internal error (qh_clock): sysconf() failed.  Use qh_CLOCKtype 1 in user_r.h\n");
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }
+  }
+  if (times(&time) == -1) {
+    qh_fprintf(qh, qh->ferr, 6031, "qhull internal error (qh_clock): times() failed.  Use qh_CLOCKtype 1 in user_r.h\n");
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  ratio= qh_SECticks / (double)clktck;
+  ticks= time.tms_utime * ratio;
+  return ticks;
+#else
+  qh_fprintf(qh, qh->ferr, 6032, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user_r.h\n");
+  qh_errexit(qh, qh_ERRqhull, NULL, NULL); /* never returns */
+  return 0;
+#endif
+} /* clock */
+
+/*---------------------------------
+
+  qh_freebuffers()
+    free up global memory buffers
+
+  notes:
+    must match qh_initbuffers()
+*/
+void qh_freebuffers(qhT *qh) {
+
+  trace5((qh, qh->ferr, 5001, "qh_freebuffers: freeing up global memory buffers\n"));
+  /* allocated by qh_initqhull_buffers */
+  qh_setfree(qh, &qh->other_points);
+  qh_setfree(qh, &qh->del_vertices);
+  qh_setfree(qh, &qh->coplanarfacetset);
+  qh_memfree(qh, qh->NEARzero, qh->hull_dim * (int)sizeof(realT));
+  qh_memfree(qh, qh->lower_threshold, (qh->input_dim+1) * (int)sizeof(realT));
+  qh_memfree(qh, qh->upper_threshold, (qh->input_dim+1) * (int)sizeof(realT));
+  qh_memfree(qh, qh->lower_bound, (qh->input_dim+1) * (int)sizeof(realT));
+  qh_memfree(qh, qh->upper_bound, (qh->input_dim+1) * (int)sizeof(realT));
+  qh_memfree(qh, qh->gm_matrix, (qh->hull_dim+1) * qh->hull_dim * (int)sizeof(coordT));
+  qh_memfree(qh, qh->gm_row, (qh->hull_dim+1) * (int)sizeof(coordT *));
+  qh->NEARzero= qh->lower_threshold= qh->upper_threshold= NULL;
+  qh->lower_bound= qh->upper_bound= NULL;
+  qh->gm_matrix= NULL;
+  qh->gm_row= NULL;
+
+  if (qh->line)                /* allocated by qh_readinput, freed if no error */
+    qh_free(qh->line);
+  if (qh->half_space)
+    qh_free(qh->half_space);
+  if (qh->temp_malloc)
+    qh_free(qh->temp_malloc);
+  if (qh->feasible_point)      /* allocated by qh_readfeasible */
+    qh_free(qh->feasible_point);
+  if (qh->feasible_string)     /* allocated by qh_initflags */
+    qh_free(qh->feasible_string);
+  qh->line= qh->feasible_string= NULL;
+  qh->half_space= qh->feasible_point= qh->temp_malloc= NULL;
+  /* usually allocated by qh_readinput */
+  if (qh->first_point && qh->POINTSmalloc) {
+    qh_free(qh->first_point);
+    qh->first_point= NULL;
+  }
+  if (qh->input_points && qh->input_malloc) { /* set by qh_joggleinput */
+    qh_free(qh->input_points);
+    qh->input_points= NULL;
+  }
+  trace5((qh, qh->ferr, 5002, "qh_freebuffers: finished\n"));
+} /* freebuffers */
+
+
+/*---------------------------------
+
+  qh_freebuild(qh, allmem )
+    free global memory used by qh_initbuild and qh_buildhull
+    if !allmem,
+      does not free short memory (e.g., facetT, freed by qh_memfreeshort)
+
+  design:
+    free centrums
+    free each vertex
+    for each facet
+      free ridges
+      free outside set, coplanar set, neighbor set, ridge set, vertex set
+      free facet
+    free hash table
+    free interior point
+    free merge sets
+    free temporary sets
+*/
+void qh_freebuild(qhT *qh, boolT allmem) {
+  facetT *facet, *previousfacet= NULL;
+  vertexT *vertex, *previousvertex= NULL;
+  ridgeT *ridge, **ridgep, *previousridge= NULL;
+  mergeT *merge, **mergep;
+  int newsize;
+  boolT freeall;
+
+  /* free qhT global sets first, includes references from qh_buildhull */
+  trace5((qh, qh->ferr, 5004, "qh_freebuild: free global sets\n"));
+  FOREACHmerge_(qh->facet_mergeset)  /* usually empty */
+    qh_memfree(qh, merge, (int)sizeof(mergeT));
+  FOREACHmerge_(qh->degen_mergeset)  /* usually empty */
+    qh_memfree(qh, merge, (int)sizeof(mergeT));
+  FOREACHmerge_(qh->vertex_mergeset)  /* usually empty */
+    qh_memfree(qh, merge, (int)sizeof(mergeT));
+  qh->facet_mergeset= NULL;  /* temp set freed by qh_settempfree_all */
+  qh->degen_mergeset= NULL;  /* temp set freed by qh_settempfree_all */
+  qh->vertex_mergeset= NULL;  /* temp set freed by qh_settempfree_all */
+  qh_setfree(qh, &(qh->hash_table));
+  trace5((qh, qh->ferr, 5003, "qh_freebuild: free temporary sets (qh_settempfree_all)\n"));
+  qh_settempfree_all(qh);
+  trace1((qh, qh->ferr, 1005, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));
+  if (qh->del_vertices)
+    qh_settruncate(qh, qh->del_vertices, 0);
+  if (allmem) {
+    while ((vertex= qh->vertex_list)) {
+      if (vertex->next)
+        qh_delvertex(qh, vertex);
+      else {
+        qh_memfree(qh, vertex, (int)sizeof(vertexT)); /* sentinel */
+        qh->newvertex_list= qh->vertex_list= NULL;
+        break;
+      }
+      previousvertex= vertex; /* in case of memory fault */
+      QHULL_UNUSED(previousvertex)
+    }
+  }else if (qh->VERTEXneighbors) {
+    FORALLvertices
+      qh_setfreelong(qh, &(vertex->neighbors));
+  }
+  qh->VERTEXneighbors= False;
+  qh->GOODclosest= NULL;
+  if (allmem) {
+    FORALLfacets {
+      FOREACHridge_(facet->ridges)
+        ridge->seen= False;
+    }
+    while ((facet= qh->facet_list)) {
+      if (!facet->newfacet || !qh->NEWtentative || qh_setsize(qh, facet->ridges) > 1) { /* skip tentative horizon ridges */
+        trace4((qh, qh->ferr, 4095, "qh_freebuild: delete the previously-seen ridges of f%d\n", facet->id));
+        FOREACHridge_(facet->ridges) {
+          if (ridge->seen)
+            qh_delridge(qh, ridge);
+          else
+            ridge->seen= True;
+          previousridge= ridge; /* in case of memory fault */
+          QHULL_UNUSED(previousridge)
+        }
+      }
+      qh_setfree(qh, &(facet->outsideset));
+      qh_setfree(qh, &(facet->coplanarset));
+      qh_setfree(qh, &(facet->neighbors));
+      qh_setfree(qh, &(facet->ridges));
+      qh_setfree(qh, &(facet->vertices));
+      if (facet->next)
+        qh_delfacet(qh, facet);
+      else {
+        qh_memfree(qh, facet, (int)sizeof(facetT));
+        qh->visible_list= qh->newfacet_list= qh->facet_list= NULL;
+      }
+      previousfacet= facet; /* in case of memory fault */
+      QHULL_UNUSED(previousfacet)
+    }
+  }else {
+    freeall= True;
+    if (qh_setlarger_quick(qh, qh->hull_dim + 1, &newsize))
+      freeall= False;
+    FORALLfacets {
+      qh_setfreelong(qh, &(facet->outsideset));
+      qh_setfreelong(qh, &(facet->coplanarset));
+      if (!facet->simplicial || freeall) {
+        qh_setfreelong(qh, &(facet->neighbors));
+        qh_setfreelong(qh, &(facet->ridges));
+        qh_setfreelong(qh, &(facet->vertices));
+      }
+    }
+  }
+  /* qh internal constants */
+  qh_memfree(qh, qh->interior_point, qh->normal_size);
+  qh->interior_point= NULL;
+} /* freebuild */
+
+/*---------------------------------
+
+  qh_freeqhull(qh, allmem )
+
+  free global memory and set qhT to 0
+  if !allmem,
+    does not free short memory (freed by qh_memfreeshort unless qh_NOmem)
+
+notes:
+  sets qh.NOerrexit in case caller forgets to
+  Does not throw errors
+
+see:
+  see qh_initqhull_start2()
+  For libqhull_r, qhstatT is part of qhT
+
+design:
+  free global and temporary memory from qh_initbuild and qh_buildhull
+  free buffers
+*/
+void qh_freeqhull(qhT *qh, boolT allmem) {
+
+  qh->NOerrexit= True;  /* no more setjmp since called at exit and ~QhullQh */
+  trace1((qh, qh->ferr, 1006, "qh_freeqhull: free global memory\n"));
+  qh_freebuild(qh, allmem);
+  qh_freebuffers(qh);
+  trace1((qh, qh->ferr, 1061, "qh_freeqhull: clear qhT except for qh.qhmem and qh.qhstat\n"));
+  /* memset is the same in qh_freeqhull() and qh_initqhull_start2() */
+  memset((char *)qh, 0, sizeof(qhT)-sizeof(qhmemT)-sizeof(qhstatT));
+  qh->NOerrexit= True;
+} /* freeqhull */
+
+/*---------------------------------
+
+  qh_init_A(qh, infile, outfile, errfile, argc, argv )
+    initialize memory and stdio files
+    convert input options to option string (qh.qhull_command)
+
+  notes:
+    infile may be NULL if qh_readpoints() is not called
+
+    errfile should always be defined.  It is used for reporting
+    errors.  outfile is used for output and format options.
+
+    argc/argv may be 0/NULL
+
+    called before error handling initialized
+    qh_errexit() may not be used
+*/
+void qh_init_A(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) {
+  qh_meminit(qh, errfile);
+  qh_initqhull_start(qh, infile, outfile, errfile);
+  qh_init_qhull_command(qh, argc, argv);
+} /* init_A */
+
+/*---------------------------------
+
+  qh_init_B(qh, points, numpoints, dim, ismalloc )
+    initialize globals for points array
+
+    points has numpoints dim-dimensional points
+      points[0] is the first coordinate of the first point
+      points[1] is the second coordinate of the first point
+      points[dim] is the first coordinate of the second point
+
+    ismalloc=True
+      Qhull will call qh_free(points) on exit or input transformation
+    ismalloc=False
+      Qhull will allocate a new point array if needed for input transformation
+
+    qh.qhull_command
+      is the option string.
+      It is defined by qh_init_B(), qh_qhull_command(), or qh_initflags
+
+  returns:
+    if qh.PROJECTinput or (qh.DELAUNAY and qh.PROJECTdelaunay)
+      projects the input to a new point array
+
+        if qh.DELAUNAY,
+          qh.hull_dim is increased by one
+        if qh.ATinfinity,
+          qh_projectinput adds point-at-infinity for Delaunay tri.
+
+    if qh.SCALEinput
+      changes the upper and lower bounds of the input, see qh_scaleinput
+
+    if qh.ROTATEinput
+      rotates the input by a random rotation, see qh_rotateinput
+      if qh.DELAUNAY
+        rotates about the last coordinate
+
+  notes:
+    called after points are defined
+    qh_errexit() may be used
+*/
+void qh_init_B(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc) {
+  qh_initqhull_globals(qh, points, numpoints, dim, ismalloc);
+  if (qh->qhmem.LASTsize == 0)
+    qh_initqhull_mem(qh);
+  /* mem_r.c and qset_r.c are initialized */
+  qh_initqhull_buffers(qh);
+  qh_initthresholds(qh, qh->qhull_command);
+  if (qh->PROJECTinput || (qh->DELAUNAY && qh->PROJECTdelaunay))
+    qh_projectinput(qh);
+  if (qh->SCALEinput)
+    qh_scaleinput(qh);
+  if (qh->ROTATErandom >= 0) {
+    qh_randommatrix(qh, qh->gm_matrix, qh->hull_dim, qh->gm_row);
+    if (qh->DELAUNAY) {
+      int k, lastk= qh->hull_dim-1;
+      for (k=0; k < lastk; k++) {
+        qh->gm_row[k][lastk]= 0.0;
+        qh->gm_row[lastk][k]= 0.0;
+      }
+      qh->gm_row[lastk][lastk]= 1.0;
+    }
+    qh_gram_schmidt(qh, qh->hull_dim, qh->gm_row);
+    qh_rotateinput(qh, qh->gm_row);
+  }
+} /* init_B */
+
+/*---------------------------------
+
+  qh_init_qhull_command(qh, argc, argv )
+    build qh.qhull_command from argc/argv
+    Calls qh_exit if qhull_command is too short
+
+  returns:
+    a space-delimited string of options (just as typed)
+
+  notes:
+    makes option string easy to input and output
+
+    argc/argv may be 0/NULL
+*/
+void qh_init_qhull_command(qhT *qh, int argc, char *argv[]) {
+
+  if (!qh_argv_to_command(argc, argv, qh->qhull_command, (int)sizeof(qh->qhull_command))){
+    /* Assumes qh.ferr is defined. */
+    qh_fprintf(qh, qh->ferr, 6033, "qhull input error: more than %d characters in command line.\n",
+          (int)sizeof(qh->qhull_command));
+    qh_exit(qh_ERRinput);  /* error reported, can not use qh_errexit */
+  }
+} /* init_qhull_command */
+
+/*---------------------------------
+
+  qh_initflags(qh, commandStr )
+    set flags and initialized constants from commandStr
+    calls qh_exit() if qh.NOerrexit
+
+  returns:
+    sets qh.qhull_command to command if needed
+
+  notes:
+    ignores first word (e.g., 'qhull' in "qhull d")
+    use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
+
+  see:
+    qh_initthresholds() continues processing of 'Pdn' and 'PDn'
+    'prompt' in unix_r.c for documentation
+
+  design:
+    for each space-delimited option group
+      if top-level option
+        check syntax
+        append appropriate option to option string
+        set appropriate global variable or append printFormat to print options
+      else
+        for each sub-option
+          check syntax
+          append appropriate option to option string
+          set appropriate global variable or append printFormat to print options
+*/
+void qh_initflags(qhT *qh, char *command) {
+  int k, i, lastproject;
+  char *s= command, *t, *prev_s, *start, key, *lastwarning= NULL;
+  boolT isgeom= False, wasproject;
+  realT r;
+
+  if(qh->NOerrexit){
+    qh_fprintf(qh, qh->ferr, 6245, "qhull internal error (qh_initflags): qh.NOerrexit was not cleared before calling qh_initflags().  It should be cleared after setjmp().  Exit qhull.\n");
+    qh_exit(qh_ERRqhull);
+  }
+#ifdef qh_RANDOMdist
+  qh->RANDOMfactor= qh_RANDOMdist;
+  qh_option(qh, "Random-qh_RANDOMdist", NULL, &qh->RANDOMfactor);
+  qh->RANDOMdist= True;
+#endif
+  if (command <= &qh->qhull_command[0] || command > &qh->qhull_command[0] + sizeof(qh->qhull_command)) {
+    if (command != &qh->qhull_command[0]) {
+      *qh->qhull_command= '\0';
+      strncat(qh->qhull_command, command, sizeof(qh->qhull_command)-strlen(qh->qhull_command)-1);
+    }
+    while (*s && !isspace(*s))  /* skip program name */
+      s++;
+  }
+  while (*s) {
+    while (*s && isspace(*s))
+      s++;
+    if (*s == '-')
+      s++;
+    if (!*s)
+      break;
+    prev_s= s;
+    switch (*s++) {
+    case 'd':
+      qh_option(qh, "delaunay", NULL, NULL);
+      qh->DELAUNAY= True;
+      break;
+    case 'f':
+      qh_option(qh, "facets", NULL, NULL);
+      qh_appendprint(qh, qh_PRINTfacets);
+      break;
+    case 'i':
+      qh_option(qh, "incidence", NULL, NULL);
+      qh_appendprint(qh, qh_PRINTincidences);
+      break;
+    case 'm':
+      qh_option(qh, "mathematica", NULL, NULL);
+      qh_appendprint(qh, qh_PRINTmathematica);
+      break;
+    case 'n':
+      qh_option(qh, "normals", NULL, NULL);
+      qh_appendprint(qh, qh_PRINTnormals);
+      break;
+    case 'o':
+      qh_option(qh, "offFile", NULL, NULL);
+      qh_appendprint(qh, qh_PRINToff);
+      break;
+    case 'p':
+      qh_option(qh, "points", NULL, NULL);
+      qh_appendprint(qh, qh_PRINTpoints);
+      break;
+    case 's':
+      qh_option(qh, "summary", NULL, NULL);
+      qh->PRINTsummary= True;
+      break;
+    case 'v':
+      qh_option(qh, "voronoi", NULL, NULL);
+      qh->VORONOI= True;
+      qh->DELAUNAY= True;
+      break;
+    case 'A':
+      if (!isdigit(*s) && *s != '.' && *s != '-') {
+        qh_fprintf(qh, qh->ferr, 7002, "qhull input warning: no maximum cosine angle given for option 'An'.  A1.0 is coplanar\n");
+        lastwarning= s-1;
+      }else {
+        if (*s == '-') {
+          qh->premerge_cos= -qh_strtod(s, &s);
+          qh_option(qh, "Angle-premerge-", NULL, &qh->premerge_cos);
+          qh->PREmerge= True;
+        }else {
+          qh->postmerge_cos= qh_strtod(s, &s);
+          qh_option(qh, "Angle-postmerge", NULL, &qh->postmerge_cos);
+          qh->POSTmerge= True;
+        }
+        qh->MERGING= True;
+      }
+      break;
+    case 'C':
+      if (!isdigit(*s) && *s != '.' && *s != '-') {
+        qh_fprintf(qh, qh->ferr, 7003, "qhull input warning: no centrum radius given for option 'Cn'\n");
+        lastwarning= s-1;
+      }else {
+        if (*s == '-') {
+          qh->premerge_centrum= -qh_strtod(s, &s);
+          qh_option(qh, "Centrum-premerge-", NULL, &qh->premerge_centrum);
+          qh->PREmerge= True;
+        }else {
+          qh->postmerge_centrum= qh_strtod(s, &s);
+          qh_option(qh, "Centrum-postmerge", NULL, &qh->postmerge_centrum);
+          qh->POSTmerge= True;
+        }
+        qh->MERGING= True;
+      }
+      break;
+    case 'E':
+      if (*s == '-') {
+        qh_fprintf(qh, qh->ferr, 6363, "qhull option error: expecting a positive number for maximum roundoff 'En'.  Got '%s'\n", s-1);
+        qh_errexit(qh, qh_ERRinput, NULL, NULL);
+      }else if (!isdigit(*s)) {
+        qh_fprintf(qh, qh->ferr, 7005, "qhull option warning: no maximum roundoff given for option 'En'\n");
+        lastwarning= s-1;
+      }else {
+        qh->DISTround= qh_strtod(s, &s);
+        qh_option(qh, "Distance-roundoff", NULL, &qh->DISTround);
+        qh->SETroundoff= True;
+      }
+      break;
+    case 'H':
+      start= s;
+      qh->HALFspace= True;
+      qh_strtod(s, &t);
+      while (t > s)  {
+        if (*t && !isspace(*t)) {
+          if (*t == ',')
+            t++;
+          else {
+            qh_fprintf(qh, qh->ferr, 6364, "qhull option error: expecting 'Hn,n,n,...' for feasible point of halfspace intersection. Got '%s'\n", start-1);
+            qh_errexit(qh, qh_ERRinput, NULL, NULL);
+          }
+        }
+        s= t;
+        qh_strtod(s, &t);
+      }
+      if (start < t) {
+        if (!(qh->feasible_string= (char *)calloc((size_t)(t-start+1), (size_t)1))) {
+          qh_fprintf(qh, qh->ferr, 6034, "qhull error: insufficient memory for 'Hn,n,n'\n");
+          qh_errexit(qh, qh_ERRmem, NULL, NULL);
+        }
+        strncpy(qh->feasible_string, start, (size_t)(t-start));
+        qh_option(qh, "Halfspace-about", NULL, NULL);
+        qh_option(qh, qh->feasible_string, NULL, NULL);
+      }else
+        qh_option(qh, "Halfspace", NULL, NULL);
+      break;
+    case 'R':
+      if (!isdigit(*s)) {
+        qh_fprintf(qh, qh->ferr, 7007, "qhull option warning: missing random perturbation for option 'Rn'\n");
+        lastwarning= s-1;
+      }else {
+        qh->RANDOMfactor= qh_strtod(s, &s);
+        qh_option(qh, "Random-perturb", NULL, &qh->RANDOMfactor);
+        qh->RANDOMdist= True;
+      }
+      break;
+    case 'V':
+      if (!isdigit(*s) && *s != '-') {
+        qh_fprintf(qh, qh->ferr, 7008, "qhull option warning: missing visible distance for option 'Vn'\n");
+        lastwarning= s-1;
+      }else {
+        qh->MINvisible= qh_strtod(s, &s);
+        qh_option(qh, "Visible", NULL, &qh->MINvisible);
+      }
+      break;
+    case 'U':
+      if (!isdigit(*s) && *s != '-') {
+        qh_fprintf(qh, qh->ferr, 7009, "qhull option warning: missing coplanar distance for option 'Un'\n");
+        lastwarning= s-1;
+      }else {
+        qh->MAXcoplanar= qh_strtod(s, &s);
+        qh_option(qh, "U-coplanar", NULL, &qh->MAXcoplanar);
+      }
+      break;
+    case 'W':
+      if (*s == '-') {
+        qh_fprintf(qh, qh->ferr, 6365, "qhull option error: expecting a positive number for outside width 'Wn'.  Got '%s'\n", s-1);
+        qh_errexit(qh, qh_ERRinput, NULL, NULL);
+      }else if (!isdigit(*s)) {
+        qh_fprintf(qh, qh->ferr, 7011, "qhull option warning: missing outside width for option 'Wn'\n");
+        lastwarning= s-1;
+      }else {
+        qh->MINoutside= qh_strtod(s, &s);
+        qh_option(qh, "W-outside", NULL, &qh->MINoutside);
+        qh->APPROXhull= True;
+      }
+      break;
+    /************  sub menus ***************/
+    case 'F':
+      while (*s && !isspace(*s)) {
+        switch (*s++) {
+        case 'a':
+          qh_option(qh, "Farea", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTarea);
+          qh->GETarea= True;
+          break;
+        case 'A':
+          qh_option(qh, "FArea-total", NULL, NULL);
+          qh->GETarea= True;
+          break;
+        case 'c':
+          qh_option(qh, "Fcoplanars", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTcoplanars);
+          break;
+        case 'C':
+          qh_option(qh, "FCentrums", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTcentrums);
+          break;
+        case 'd':
+          qh_option(qh, "Fd-cdd-in", NULL, NULL);
+          qh->CDDinput= True;
+          break;
+        case 'D':
+          qh_option(qh, "FD-cdd-out", NULL, NULL);
+          qh->CDDoutput= True;
+          break;
+        case 'F':
+          qh_option(qh, "FFacets-xridge", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTfacets_xridge);
+          break;
+        case 'i':
+          qh_option(qh, "Finner", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTinner);
+          break;
+        case 'I':
+          qh_option(qh, "FIDs", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTids);
+          break;
+        case 'm':
+          qh_option(qh, "Fmerges", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTmerges);
+          break;
+        case 'M':
+          qh_option(qh, "FMaple", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTmaple);
+          break;
+        case 'n':
+          qh_option(qh, "Fneighbors", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTneighbors);
+          break;
+        case 'N':
+          qh_option(qh, "FNeighbors-vertex", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTvneighbors);
+          break;
+        case 'o':
+          qh_option(qh, "Fouter", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTouter);
+          break;
+        case 'O':
+          if (qh->PRINToptions1st) {
+            qh_option(qh, "FOptions", NULL, NULL);
+            qh_appendprint(qh, qh_PRINToptions);
+          }else
+            qh->PRINToptions1st= True;
+          break;
+        case 'p':
+          qh_option(qh, "Fpoint-intersect", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTpointintersect);
+          break;
+        case 'P':
+          qh_option(qh, "FPoint-nearest", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTpointnearest);
+          break;
+        case 'Q':
+          qh_option(qh, "FQhull", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTqhull);
+          break;
+        case 's':
+          qh_option(qh, "Fsummary", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTsummary);
+          break;
+        case 'S':
+          qh_option(qh, "FSize", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTsize);
+          qh->GETarea= True;
+          break;
+        case 't':
+          qh_option(qh, "Ftriangles", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTtriangles);
+          break;
+        case 'v':
+          /* option set in qh_initqhull_globals */
+          qh_appendprint(qh, qh_PRINTvertices);
+          break;
+        case 'V':
+          qh_option(qh, "FVertex-average", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTaverage);
+          break;
+        case 'x':
+          qh_option(qh, "Fxtremes", NULL, NULL);
+          qh_appendprint(qh, qh_PRINTextremes);
+          break;
+        default:
+          s--;
+          qh_fprintf(qh, qh->ferr, 7012, "qhull option warning: unknown 'F' output option 'F%c', skip to next space\n", (int)s[0]);
+          lastwarning= s-1;
+          while (*++s && !isspace(*s));
+          break;
+        }
+      }
+      break;
+    case 'G':
+      isgeom= True;
+      qh_appendprint(qh, qh_PRINTgeom);
+      while (*s && !isspace(*s)) {
+        switch (*s++) {
+        case 'a':
+          qh_option(qh, "Gall-points", NULL, NULL);
+          qh->PRINTdots= True;
+          break;
+        case 'c':
+          qh_option(qh, "Gcentrums", NULL, NULL);
+          qh->PRINTcentrums= True;
+          break;
+        case 'h':
+          qh_option(qh, "Gintersections", NULL, NULL);
+          qh->DOintersections= True;
+          break;
+        case 'i':
+          qh_option(qh, "Ginner", NULL, NULL);
+          qh->PRINTinner= True;
+          break;
+        case 'n':
+          qh_option(qh, "Gno-planes", NULL, NULL);
+          qh->PRINTnoplanes= True;
+          break;
+        case 'o':
+          qh_option(qh, "Gouter", NULL, NULL);
+          qh->PRINTouter= True;
+          break;
+        case 'p':
+          qh_option(qh, "Gpoints", NULL, NULL);
+          qh->PRINTcoplanar= True;
+          break;
+        case 'r':
+          qh_option(qh, "Gridges", NULL, NULL);
+          qh->PRINTridges= True;
+          break;
+        case 't':
+          qh_option(qh, "Gtransparent", NULL, NULL);
+          qh->PRINTtransparent= True;
+          break;
+        case 'v':
+          qh_option(qh, "Gvertices", NULL, NULL);
+          qh->PRINTspheres= True;
+          break;
+        case 'D':
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7004, "qhull option warning: missing dimension for option 'GDn'\n");
+            lastwarning= s-2;
+          }else {
+            if (qh->DROPdim >= 0) {
+              qh_fprintf(qh, qh->ferr, 7013, "qhull option warning: can only drop one dimension.  Previous 'GD%d' ignored\n",
+                   qh->DROPdim);
+              lastwarning= s-2;
+            }
+            qh->DROPdim= qh_strtol(s, &s);
+            qh_option(qh, "GDrop-dim", &qh->DROPdim, NULL);
+          }
+          break;
+        default:
+          s--;
+          qh_fprintf(qh, qh->ferr, 7014, "qhull option warning: unknown 'G' geomview option 'G%c', skip to next space\n", (int)s[0]);
+          lastwarning= s-1;
+          while (*++s && !isspace(*s));
+          break;
+        }
+      }
+      break;
+    case 'P':
+      while (*s && !isspace(*s)) {
+        switch (*s++) {
+        case 'd': case 'D':  /* see qh_initthresholds() */
+          key= s[-1];
+          i= qh_strtol(s, &s);
+          r= 0;
+          if (*s == ':') {
+            s++;
+            r= qh_strtod(s, &s);
+          }
+          if (key == 'd')
+            qh_option(qh, "Pdrop-facets-dim-less", &i, &r);
+          else
+            qh_option(qh, "PDrop-facets-dim-more", &i, &r);
+          break;
+        case 'g':
+          qh_option(qh, "Pgood-facets", NULL, NULL);
+          qh->PRINTgood= True;
+          break;
+        case 'G':
+          qh_option(qh, "PGood-facet-neighbors", NULL, NULL);
+          qh->PRINTneighbors= True;
+          break;
+        case 'o':
+          qh_option(qh, "Poutput-forced", NULL, NULL);
+          qh->FORCEoutput= True;
+          break;
+        case 'p':
+          qh_option(qh, "Pprecision-ignore", NULL, NULL);
+          qh->PRINTprecision= False;
+          break;
+        case 'A':
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7006, "qhull option warning: missing facet count for keep area option 'PAn'\n");
+            lastwarning= s-2;
+          }else {
+            qh->KEEParea= qh_strtol(s, &s);
+            qh_option(qh, "PArea-keep", &qh->KEEParea, NULL);
+            qh->GETarea= True;
+          }
+          break;
+        case 'F':
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7010, "qhull option warning: missing facet area for option 'PFn'\n");
+            lastwarning= s-2;
+          }else {
+            qh->KEEPminArea= qh_strtod(s, &s);
+            qh_option(qh, "PFacet-area-keep", NULL, &qh->KEEPminArea);
+            qh->GETarea= True;
+          }
+          break;
+        case 'M':
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7090, "qhull option warning: missing merge count for option 'PMn'\n");
+            lastwarning= s-2;
+          }else {
+            qh->KEEPmerge= qh_strtol(s, &s);
+            qh_option(qh, "PMerge-keep", &qh->KEEPmerge, NULL);
+          }
+          break;
+        default:
+          s--;
+          qh_fprintf(qh, qh->ferr, 7015, "qhull option warning: unknown 'P' print option 'P%c', skip to next space\n", (int)s[0]);
+          lastwarning= s-1;
+          while (*++s && !isspace(*s));
+          break;
+        }
+      }
+      break;
+    case 'Q':
+      lastproject= -1;
+      while (*s && !isspace(*s)) {
+        switch (*s++) {
+        case 'a':
+          qh_option(qh, "Qallow-short", NULL, NULL);
+          qh->ALLOWshort= True;
+          break;
+        case 'b': case 'B':  /* handled by qh_initthresholds */
+          key= s[-1];
+          if (key == 'b' && *s == 'B') {
+            s++;
+            r= qh_DEFAULTbox;
+            qh->SCALEinput= True;
+            qh_option(qh, "QbBound-unit-box", NULL, &r);
+            break;
+          }
+          if (key == 'b' && *s == 'b') {
+            s++;
+            qh->SCALElast= True;
+            qh_option(qh, "Qbbound-last", NULL, NULL);
+            break;
+          }
+          k= qh_strtol(s, &s);
+          r= 0.0;
+          wasproject= False;
+          if (*s == ':') {
+            s++;
+            if ((r= qh_strtod(s, &s)) == 0.0) {
+              t= s;            /* need true dimension for memory allocation */
+              while (*t && !isspace(*t)) {
+                if (toupper(*t++) == 'B'
+                 && k == qh_strtol(t, &t)
+                 && *t++ == ':'
+                 && qh_strtod(t, &t) == 0.0) {
+                  qh->PROJECTinput++;
+                  trace2((qh, qh->ferr, 2004, "qh_initflags: project dimension %d\n", k));
+                  qh_option(qh, "Qb-project-dim", &k, NULL);
+                  wasproject= True;
+                  lastproject= k;
+                  break;
+                }
+              }
+            }
+          }
+          if (!wasproject) {
+            if (lastproject == k && r == 0.0)
+              lastproject= -1;  /* doesn't catch all possible sequences */
+            else if (key == 'b') {
+              qh->SCALEinput= True;
+              if (r == 0.0)
+                r= -qh_DEFAULTbox;
+              qh_option(qh, "Qbound-dim-low", &k, &r);
+            }else {
+              qh->SCALEinput= True;
+              if (r == 0.0)
+                r= qh_DEFAULTbox;
+              qh_option(qh, "QBound-dim-high", &k, &r);
+            }
+          }
+          break;
+        case 'c':
+          qh_option(qh, "Qcoplanar-keep", NULL, NULL);
+          qh->KEEPcoplanar= True;
+          break;
+        case 'f':
+          qh_option(qh, "Qfurthest-outside", NULL, NULL);
+          qh->BESToutside= True;
+          break;
+        case 'g':
+          qh_option(qh, "Qgood-facets-only", NULL, NULL);
+          qh->ONLYgood= True;
+          break;
+        case 'i':
+          qh_option(qh, "Qinterior-keep", NULL, NULL);
+          qh->KEEPinside= True;
+          break;
+        case 'm':
+          qh_option(qh, "Qmax-outside-only", NULL, NULL);
+          qh->ONLYmax= True;
+          break;
+        case 'r':
+          qh_option(qh, "Qrandom-outside", NULL, NULL);
+          qh->RANDOMoutside= True;
+          break;
+        case 's':
+          qh_option(qh, "Qsearch-initial-simplex", NULL, NULL);
+          qh->ALLpoints= True;
+          break;
+        case 't':
+          qh_option(qh, "Qtriangulate", NULL, NULL);
+          qh->TRIangulate= True;
+          break;
+        case 'T':
+          qh_option(qh, "QTestPoints", NULL, NULL);
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7091, "qhull option warning: missing number of test points for option 'QTn'\n");
+            lastwarning= s-2;
+          }else {
+            qh->TESTpoints= qh_strtol(s, &s);
+            qh_option(qh, "QTestPoints", &qh->TESTpoints, NULL);
+          }
+          break;
+        case 'u':
+          qh_option(qh, "QupperDelaunay", NULL, NULL);
+          qh->UPPERdelaunay= True;
+          break;
+        case 'v':
+          qh_option(qh, "Qvertex-neighbors-convex", NULL, NULL);
+          qh->TESTvneighbors= True;
+          break;
+        case 'x':
+          qh_option(qh, "Qxact-merge", NULL, NULL);
+          qh->MERGEexact= True;
+          break;
+        case 'z':
+          qh_option(qh, "Qz-infinity-point", NULL, NULL);
+          qh->ATinfinity= True;
+          break;
+        case '0':
+          qh_option(qh, "Q0-no-premerge", NULL, NULL);
+          qh->NOpremerge= True;
+          break;
+        case '1':
+          if (!isdigit(*s)) {
+            qh_option(qh, "Q1-angle-merge", NULL, NULL);
+            qh->ANGLEmerge= True;
+            break;
+          }
+          switch (*s++) {
+          case '0':
+            qh_option(qh, "Q10-no-narrow", NULL, NULL);
+            qh->NOnarrow= True;
+            break;
+          case '1':
+            qh_option(qh, "Q11-trinormals Qtriangulate", NULL, NULL);
+            qh->TRInormals= True;
+            qh->TRIangulate= True;
+            break;
+          case '2':
+            qh_option(qh, "Q12-allow-wide", NULL, NULL);
+            qh->ALLOWwide= True;
+            break;
+          case '4':
+#ifndef qh_NOmerge
+            qh_option(qh, "Q14-merge-pinched-vertices", NULL, NULL);
+            qh->MERGEpinched= True;
+#else
+            /* ignore 'Q14' for q_benchmark testing of difficult cases for Qhull */
+            qh_fprintf(qh, qh->ferr, 7099, "qhull option warning: option 'Q14-merge-pinched' disabled due to qh_NOmerge\n");
+#endif
+            break;
+          case '7':
+            qh_option(qh, "Q17-check-duplicates", NULL, NULL);
+            qh->CHECKduplicates= True;
+            break;
+          default:
+            s--;
+            qh_fprintf(qh, qh->ferr, 7016, "qhull option warning: unknown 'Q' qhull option 'Q1%c', skip to next space\n", (int)s[0]);
+            lastwarning= s-1;
+            while (*++s && !isspace(*s));
+            break;
+          }
+          break;
+        case '2':
+          qh_option(qh, "Q2-no-merge-independent", NULL, NULL);
+          qh->MERGEindependent= False;
+          goto LABELcheckdigit;
+          break; /* no gcc warnings */
+        case '3':
+          qh_option(qh, "Q3-no-merge-vertices", NULL, NULL);
+          qh->MERGEvertices= False;
+        LABELcheckdigit:
+          if (isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7017, "qhull option warning: can not follow '1', '2', or '3' with a digit.  'Q%c%c' skipped\n", *(s-1), *s);
+            lastwarning= s-2;
+            s++;
+          }
+          break;
+        case '4':
+          qh_option(qh, "Q4-avoid-old-into-new", NULL, NULL);
+          qh->AVOIDold= True;
+          break;
+        case '5':
+          qh_option(qh, "Q5-no-check-outer", NULL, NULL);
+          qh->SKIPcheckmax= True;
+          break;
+        case '6':
+          qh_option(qh, "Q6-no-concave-merge", NULL, NULL);
+          qh->SKIPconvex= True;
+          break;
+        case '7':
+          qh_option(qh, "Q7-no-breadth-first", NULL, NULL);
+          qh->VIRTUALmemory= True;
+          break;
+        case '8':
+          qh_option(qh, "Q8-no-near-inside", NULL, NULL);
+          qh->NOnearinside= True;
+          break;
+        case '9':
+          qh_option(qh, "Q9-pick-furthest", NULL, NULL);
+          qh->PICKfurthest= True;
+          break;
+        case 'G':
+          i= qh_strtol(s, &t);
+          if (qh->GOODpoint) {
+            qh_fprintf(qh, qh->ferr, 7018, "qhull option warning: good point already defined for option 'QGn'.  Ignored\n");
+            lastwarning= s-2;
+          }else if (s == t) {
+            qh_fprintf(qh, qh->ferr, 7019, "qhull option warning: missing good point id for option 'QGn'.  Ignored\n");
+            lastwarning= s-2;
+          }else if (i < 0 || *s == '-') {
+            qh->GOODpoint= i-1;
+            qh_option(qh, "QGood-if-dont-see-point", &i, NULL);
+          }else {
+            qh->GOODpoint= i+1;
+            qh_option(qh, "QGood-if-see-point", &i, NULL);
+          }
+          s= t;
+          break;
+        case 'J':
+          if (!isdigit(*s) && *s != '-')
+            qh->JOGGLEmax= 0.0;
+          else {
+            qh->JOGGLEmax= (realT) qh_strtod(s, &s);
+            qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);
+          }
+          break;
+        case 'R':
+          if (!isdigit(*s) && *s != '-') {
+            qh_fprintf(qh, qh->ferr, 7020, "qhull option warning: missing random seed for option 'QRn'\n");
+            lastwarning= s-2;
+          }else {
+            qh->ROTATErandom= i= qh_strtol(s, &s);
+            if (i > 0)
+              qh_option(qh, "QRotate-id", &i, NULL );
+            else if (i < -1)
+              qh_option(qh, "QRandom-seed", &i, NULL );
+          }
+          break;
+        case 'V':
+          i= qh_strtol(s, &t);
+          if (qh->GOODvertex) {
+            qh_fprintf(qh, qh->ferr, 7021, "qhull option warning: good vertex already defined for option 'QVn'.  Ignored\n");
+            lastwarning= s-2;
+          }else if (s == t) {
+            qh_fprintf(qh, qh->ferr, 7022, "qhull option warning: no good point id given for option 'QVn'.  Ignored\n");
+            lastwarning= s-2;
+          }else if (i < 0) {
+            qh->GOODvertex= i - 1;
+            qh_option(qh, "QV-good-facets-not-point", &i, NULL);
+          }else {
+            qh_option(qh, "QV-good-facets-point", &i, NULL);
+            qh->GOODvertex= i + 1;
+          }
+          s= t;
+          break;
+        case 'w':
+          qh_option(qh, "Qwarn-allow", NULL, NULL);
+          qh->ALLOWwarning= True;
+          break;
+        default:
+          s--;
+          qh_fprintf(qh, qh->ferr, 7023, "qhull option warning: unknown 'Q' qhull option 'Q%c', skip to next space\n", (int)s[0]);
+          lastwarning= s-1;
+          while (*++s && !isspace(*s));
+          break;
+        }
+      }
+      break;
+    case 'T':
+      while (*s && !isspace(*s)) {
+        if (isdigit(*s) || *s == '-')
+          qh->IStracing= qh_strtol(s, &s);
+        else switch (*s++) {
+        case 'a':
+          qh_option(qh, "Tannotate-output", NULL, NULL);
+          qh->ANNOTATEoutput= True;
+          break;
+        case 'c':
+          qh_option(qh, "Tcheck-frequently", NULL, NULL);
+          qh->CHECKfrequently= True;
+          break;
+        case 'f':
+          qh_option(qh, "Tflush", NULL, NULL);
+          qh->FLUSHprint= True;
+          break;
+        case 's':
+          qh_option(qh, "Tstatistics", NULL, NULL);
+          qh->PRINTstatistics= True;
+          break;
+        case 'v':
+          qh_option(qh, "Tverify", NULL, NULL);
+          qh->VERIFYoutput= True;
+          break;
+        case 'z':
+          if (qh->ferr == qh_FILEstderr) {
+            /* The C++ interface captures the output in qh_fprint_qhull() */
+            qh_option(qh, "Tz-stdout", NULL, NULL);
+            qh->USEstdout= True;
+          }else if (!qh->fout) {
+            qh_fprintf(qh, qh->ferr, 7024, "qhull option warning: output file undefined(stdout).  Option 'Tz' ignored.\n");
+            lastwarning= s-2;
+          }else {
+            qh_option(qh, "Tz-stdout", NULL, NULL);
+            qh->USEstdout= True;
+            qh->ferr= qh->fout;
+            qh->qhmem.ferr= qh->fout;
+          }
+          break;
+        case 'C':
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7025, "qhull option warning: missing point id for cone for trace option 'TCn'\n");
+            lastwarning= s-2;
+          }else {
+            i= qh_strtol(s, &s);
+            qh_option(qh, "TCone-stop", &i, NULL);
+            qh->STOPcone= i + 1;
+          }
+          break;
+        case 'F':
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7026, "qhull option warning: missing frequency count for trace option 'TFn'\n");
+            lastwarning= s-2;
+          }else {
+            qh->REPORTfreq= qh_strtol(s, &s);
+            qh_option(qh, "TFacet-log", &qh->REPORTfreq, NULL);
+            qh->REPORTfreq2= qh->REPORTfreq/2;  /* for tracemerging() */
+          }
+          break;
+        case 'I':
+          while (isspace(*s))
+            s++;
+          t= qh_skipfilename(qh, s);
+          {
+            char filename[qh_FILENAMElen];
+
+            qh_copyfilename(qh, filename, (int)sizeof(filename), s, (int)(t-s));   /* WARN64 */
+            s= t;
+            if (!freopen(filename, "r", stdin)) {
+              qh_fprintf(qh, qh->ferr, 6041, "qhull option error: cannot open 'TI' file \"%s\"\n", filename);
+              qh_errexit(qh, qh_ERRinput, NULL, NULL);
+            }else {
+              qh_option(qh, "TInput-file", NULL, NULL);
+              qh_option(qh, filename, NULL, NULL);
+            }
+          }
+          break;
+        case 'O':
+          while (isspace(*s))
+            s++;
+          t= qh_skipfilename(qh, s);
+          {
+            char filename[qh_FILENAMElen];
+
+            qh_copyfilename(qh, filename, (int)sizeof(filename), s, (int)(t-s));  /* WARN64 */
+            if (!qh->fout) {
+              qh_fprintf(qh, qh->ferr, 7092, "qhull option warning: qh.fout was not set by caller of qh_initflags.  Cannot use option 'TO' to redirect output.  Ignoring option 'TO'\n");
+              lastwarning= s-2;
+            }else if (!freopen(filename, "w", qh->fout)) {
+              qh_fprintf(qh, qh->ferr, 6044, "qhull option error: cannot open file \"%s\" for writing as option 'TO'.  It is already in use or read-only\n", filename);
+              qh_errexit(qh, qh_ERRinput, NULL, NULL);
+            }else {
+              qh_option(qh, "TOutput-file", NULL, NULL);
+              qh_option(qh, filename, NULL, NULL);
+            }
+            s= t;
+          }
+          break;
+        case 'A':
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7093, "qhull option warning: missing count of added points for trace option 'TAn'\n");
+            lastwarning= s-2;
+          }else {
+            i= qh_strtol(s, &t);
+            qh->STOPadd= i + 1;
+            qh_option(qh, "TA-stop-add", &i, NULL);
+          }
+          s= t;
+          break;
+        case 'P':
+          if (*s == '-') {
+            if (s[1] == '1' && !isdigit(s[2])) {
+              s += 2;
+              qh->TRACEpoint= qh_IDunknown; /* qh_buildhull done */
+              qh_option(qh, "Trace-point", &qh->TRACEpoint, NULL);
+            }else {
+              qh_fprintf(qh, qh->ferr, 7100, "qhull option warning: negative point id for trace option 'TPn'.  Expecting 'TP-1' for tracing after qh_buildhull and qh_postmerge\n");
+              lastwarning= s-2;
+              while (isdigit(*(++s)))
+                ; /* skip digits */
+            }
+          }else if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7029, "qhull option warning: missing point id or -1 for trace option 'TPn'\n");
+            lastwarning= s-2;
+          }else {
+            qh->TRACEpoint= qh_strtol(s, &s);
+            qh_option(qh, "Trace-point", &qh->TRACEpoint, NULL);
+          }
+          break;
+        case 'M':
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7030, "qhull option warning: missing merge id for trace option 'TMn'\n");
+            lastwarning= s-2;
+          }else {
+            qh->TRACEmerge= qh_strtol(s, &s);
+            qh_option(qh, "Trace-merge", &qh->TRACEmerge, NULL);
+          }
+          break;
+        case 'R':
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7031, "qhull option warning: missing rerun count for trace option 'TRn'\n");
+            lastwarning= s-2;
+          }else {
+            qh->RERUN= qh_strtol(s, &s);
+            qh_option(qh, "TRerun", &qh->RERUN, NULL);
+          }
+          break;
+        case 'V':
+          i= qh_strtol(s, &t);
+          if (s == t) {
+            qh_fprintf(qh, qh->ferr, 7032, "qhull option warning: missing furthest point id for trace option 'TVn'\n");
+            lastwarning= s-2;
+          }else if (i < 0) {
+            qh->STOPpoint= i - 1;
+            qh_option(qh, "TV-stop-before-point", &i, NULL);
+          }else {
+            qh->STOPpoint= i + 1;
+            qh_option(qh, "TV-stop-after-point", &i, NULL);
+          }
+          s= t;
+          break;
+        case 'W':
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7033, "qhull option warning: missing max width for trace option 'TWn'\n");
+            lastwarning= s-2;
+          }else {
+            qh->TRACEdist= (realT) qh_strtod(s, &s);
+            qh_option(qh, "TWide-trace", NULL, &qh->TRACEdist);
+          }
+          break;
+        default:
+          s--;
+          qh_fprintf(qh, qh->ferr, 7034, "qhull option warning: unknown 'T' trace option 'T%c', skip to next space\n", (int)s[0]);
+          lastwarning= s-2;
+          while (*++s && !isspace(*s));
+          break;
+        }
+      }
+      break;
+    default:
+      qh_fprintf(qh, qh->ferr, 7094, "qhull option warning: unknown option '%c'(%x)\n",
+        (int)s[-1], (int)s[-1]);
+      lastwarning= s-2;
+      break;
+    }
+    if (s-1 == prev_s && *s && !isspace(*s)) {
+      qh_fprintf(qh, qh->ferr, 7036, "qhull option warning: missing space after option '%c'(%x), reserved for sub-options, ignoring '%c' options to next space\n",
+               (int)*prev_s, (int)*prev_s, (int)*prev_s);
+      lastwarning= s-1;
+      while (*s && !isspace(*s))
+        s++;
+    }
+  }
+  if (qh->STOPcone && qh->JOGGLEmax < REALmax/2) {
+    qh_fprintf(qh, qh->ferr, 7078, "qhull option warning: 'TCn' (stopCone) ignored when used with 'QJn' (joggle)\n");
+    lastwarning= command;
+  }
+  if (isgeom && !qh->FORCEoutput && qh->PRINTout[1]) {
+    qh_fprintf(qh, qh->ferr, 7037, "qhull option warning: additional output formats ('Fc',etc.) are not compatible with Geomview ('G').  Use option 'Po' to override\n");
+    lastwarning= command;
+  }
+  if (lastwarning && !qh->ALLOWwarning) {
+    qh_fprintf(qh, qh->ferr, 6035, "qhull option error: see previous warnings, use 'Qw' to override: '%s' (last offset %d)\n",
+          command, (int)(lastwarning-command));
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  trace4((qh, qh->ferr, 4093, "qh_initflags: option flags initialized\n"));
+  /* set derived values in qh_initqhull_globals */
+} /* initflags */
+
+
+/*---------------------------------
+
+  qh_initqhull_buffers(qh)
+    initialize global memory buffers
+
+  notes:
+    must match qh_freebuffers()
+*/
+void qh_initqhull_buffers(qhT *qh) {
+  int k;
+
+  qh->TEMPsize= (qh->qhmem.LASTsize - SETbasesize)/SETelemsize;
+  if (qh->TEMPsize <= 0 || qh->TEMPsize > qh->qhmem.LASTsize)
+    qh->TEMPsize= 8;  /* e.g., if qh_NOmem */
+  qh->other_points= qh_setnew(qh, qh->TEMPsize);
+  qh->del_vertices= qh_setnew(qh, qh->TEMPsize);
+  qh->coplanarfacetset= qh_setnew(qh, qh->TEMPsize);
+  qh->NEARzero= (realT *)qh_memalloc(qh, qh->hull_dim * (int)sizeof(realT));
+  qh->lower_threshold= (realT *)qh_memalloc(qh, (qh->input_dim+1) * (int)sizeof(realT));
+  qh->upper_threshold= (realT *)qh_memalloc(qh, (qh->input_dim+1) * (int)sizeof(realT));
+  qh->lower_bound= (realT *)qh_memalloc(qh, (qh->input_dim+1) * (int)sizeof(realT));
+  qh->upper_bound= (realT *)qh_memalloc(qh, (qh->input_dim+1) * (int)sizeof(realT));
+  for (k=qh->input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */
+    qh->lower_threshold[k]= -REALmax;
+    qh->upper_threshold[k]= REALmax;
+    qh->lower_bound[k]= -REALmax;
+    qh->upper_bound[k]= REALmax;
+  }
+  qh->gm_matrix= (coordT *)qh_memalloc(qh, (qh->hull_dim+1) * qh->hull_dim * (int)sizeof(coordT));
+  qh->gm_row= (coordT **)qh_memalloc(qh, (qh->hull_dim+1) * (int)sizeof(coordT *));
+} /* initqhull_buffers */
+
+/*---------------------------------
+
+  qh_initqhull_globals(qh, points, numpoints, dim, ismalloc )
+    initialize globals
+    if ismalloc
+      points were malloc'd and qhull should free at end
+
+  returns:
+    sets qh.first_point, num_points, input_dim, hull_dim and others
+    seeds random number generator (seed=1 if tracing)
+    modifies qh.hull_dim if ((qh.DELAUNAY and qh.PROJECTdelaunay) or qh.PROJECTinput)
+    adjust user flags as needed
+    also checks DIM3 dependencies and constants
+
+  notes:
+    do not use qh_point() since an input transformation may move them elsewhere
+    qh_initqhull_start() sets default values for non-zero globals
+    consider duplicate error checks in qh_readpoints.  It is called before qh_initqhull_globals
+
+  design:
+    initialize points array from input arguments
+    test for qh.ZEROcentrum
+      (i.e., use opposite vertex instead of cetrum for convexity testing)
+    initialize qh.CENTERtype, qh.normal_size,
+      qh.center_size, qh.TRACEpoint/level,
+    initialize and test random numbers
+    qh_initqhull_outputflags() -- adjust and test output flags
+*/
+void qh_initqhull_globals(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc) {
+  int seed, pointsneeded, extra= 0, i, randi, k;
+  realT randr;
+  realT factorial;
+
+  time_t timedata;
+
+  trace0((qh, qh->ferr, 13, "qh_initqhull_globals: for %s | %s\n", qh->rbox_command,
+      qh->qhull_command));
+  if (numpoints < 1 || numpoints > qh_POINTSmax) {
+    qh_fprintf(qh, qh->ferr, 6412, "qhull input error (qh_initqhull_globals): expecting between 1 and %d points.  Got %d %d-d points\n",
+      qh_POINTSmax, numpoints, dim);
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    /* same error message in qh_readpoints */
+  }
+  qh->POINTSmalloc= ismalloc;
+  qh->first_point= points;
+  qh->num_points= numpoints;
+  qh->hull_dim= qh->input_dim= dim;
+  if (!qh->NOpremerge && !qh->MERGEexact && !qh->PREmerge && qh->JOGGLEmax > REALmax/2) {
+    qh->MERGING= True;
+    if (qh->hull_dim <= 4) {
+      qh->PREmerge= True;
+      qh_option(qh, "_pre-merge", NULL, NULL);
+    }else {
+      qh->MERGEexact= True;
+      qh_option(qh, "Qxact-merge", NULL, NULL);
+    }
+  }else if (qh->MERGEexact)
+    qh->MERGING= True;
+  if (qh->NOpremerge && (qh->MERGEexact || qh->PREmerge))
+    qh_fprintf(qh, qh->ferr, 7095, "qhull option warning: 'Q0-no-premerge' ignored due to exact merge ('Qx') or pre-merge ('C-n' or 'A-n')\n");
+  if (!qh->NOpremerge && qh->JOGGLEmax > REALmax/2) {
+#ifdef qh_NOmerge
+    qh->JOGGLEmax= 0.0;
+#endif
+  }
+  if (qh->TRIangulate && qh->JOGGLEmax < REALmax/2 && !qh->PREmerge && !qh->POSTmerge && qh->PRINTprecision)
+    qh_fprintf(qh, qh->ferr, 7038, "qhull option warning: joggle ('QJ') produces simplicial output (i.e., triangles in 2-D).  Unless merging is requested, option 'Qt' has no effect\n");
+  if (qh->JOGGLEmax < REALmax/2 && qh->DELAUNAY && !qh->SCALEinput && !qh->SCALElast) {
+    qh->SCALElast= True;
+    qh_option(qh, "Qbbound-last-qj", NULL, NULL);
+  }
+  if (qh->MERGING && !qh->POSTmerge && qh->premerge_cos > REALmax/2
+  && qh->premerge_centrum == 0.0) {
+    qh->ZEROcentrum= True;
+    qh->ZEROall_ok= True;
+    qh_option(qh, "_zero-centrum", NULL, NULL);
+  }
+  if (qh->JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh->PRINTprecision)
+    qh_fprintf(qh, qh->ferr, 7039, "qhull warning: real epsilon, %2.2g, is probably too large for joggle('QJn')\nRecompile with double precision reals(see user_r.h).\n",
+          REALepsilon);
+#ifdef qh_NOmerge
+  if (qh->MERGING) {
+    qh_fprintf(qh, qh->ferr, 6045, "qhull option error: merging not installed (qh_NOmerge) for 'Qx', 'Cn' or 'An')\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+#endif
+  if (qh->DELAUNAY && qh->KEEPcoplanar && !qh->KEEPinside) {
+    qh->KEEPinside= True;
+    qh_option(qh, "Qinterior-keep", NULL, NULL);
+  }
+  if (qh->VORONOI && !qh->DELAUNAY) {
+    qh_fprintf(qh, qh->ferr, 6038, "qhull internal error (qh_initqhull_globals): if qh.VORONOI is set, qh.DELAUNAY must be set.  Qhull constructs the Delaunay triangulation in order to compute the Voronoi diagram\n");
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  if (qh->DELAUNAY && qh->HALFspace) {
+    qh_fprintf(qh, qh->ferr, 6046, "qhull option error: can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    /* same error message in qh_readpoints */
+  }
+  if (!qh->DELAUNAY && (qh->UPPERdelaunay || qh->ATinfinity)) {
+    qh_fprintf(qh, qh->ferr, 6047, "qhull option error: use upper-Delaunay('Qu') or infinity-point('Qz') with Delaunay('d') or Voronoi('v')\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  if (qh->UPPERdelaunay && qh->ATinfinity) {
+    qh_fprintf(qh, qh->ferr, 6048, "qhull option error: can not use infinity-point('Qz') with upper-Delaunay('Qu')\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  if (qh->MERGEpinched && qh->ONLYgood) {
+    qh_fprintf(qh, qh->ferr, 6362, "qhull option error: can not use merge-pinched-vertices ('Q14') with good-facets-only ('Qg')\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  if (qh->MERGEpinched && qh->hull_dim == 2) {
+    trace2((qh, qh->ferr, 2108, "qh_initqhull_globals: disable qh.MERGEpinched for 2-d.  It has no effect"))
+    qh->MERGEpinched= False;
+  }
+  if (qh->SCALElast && !qh->DELAUNAY && qh->PRINTprecision)
+    qh_fprintf(qh, qh->ferr, 7040, "qhull option warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v'\n");
+  qh->DOcheckmax= (!qh->SKIPcheckmax && (qh->MERGING || qh->APPROXhull));
+  qh->KEEPnearinside= (qh->DOcheckmax && !(qh->KEEPinside && qh->KEEPcoplanar)
+                          && !qh->NOnearinside);
+  if (qh->MERGING)
+    qh->CENTERtype= qh_AScentrum;
+  else if (qh->VORONOI)
+    qh->CENTERtype= qh_ASvoronoi;
+  if (qh->TESTvneighbors && !qh->MERGING) {
+    qh_fprintf(qh, qh->ferr, 6049, "qhull option error: test vertex neighbors('Qv') needs a merge option\n");
+    qh_errexit(qh, qh_ERRinput, NULL ,NULL);
+  }
+  if (qh->PROJECTinput || (qh->DELAUNAY && qh->PROJECTdelaunay)) {
+    qh->hull_dim -= qh->PROJECTinput;
+    if (qh->DELAUNAY) {
+      qh->hull_dim++;
+      if (qh->ATinfinity)
+        extra= 1;
+    }
+  }
+  if (qh->hull_dim <= 1) {
+    qh_fprintf(qh, qh->ferr, 6050, "qhull error: dimension %d must be > 1\n", qh->hull_dim);
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  for (k=2, factorial=1.0; k < qh->hull_dim; k++)
+    factorial *= k;
+  qh->AREAfactor= 1.0 / factorial;
+  trace2((qh, qh->ferr, 2005, "qh_initqhull_globals: initialize globals.  input_dim %d, numpoints %d, malloc? %d, projected %d to hull_dim %d\n",
+        qh->input_dim, numpoints, ismalloc, qh->PROJECTinput, qh->hull_dim));
+  qh->normal_size= qh->hull_dim * (int)sizeof(coordT);
+  qh->center_size= qh->normal_size - (int)sizeof(coordT);
+  pointsneeded= qh->hull_dim+1;
+  if (qh->hull_dim > qh_DIMmergeVertex) {
+    qh->MERGEvertices= False;
+    qh_option(qh, "Q3-no-merge-vertices-dim-high", NULL, NULL);
+  }
+  if (qh->GOODpoint)
+    pointsneeded++;
+#ifdef qh_NOtrace
+  if (qh->IStracing || qh->TRACEmerge || qh->TRACEpoint != qh_IDnone || qh->TRACEdist < REALmax/2) {
+      qh_fprintf(qh, qh->ferr, 6051, "qhull option error: tracing is not installed (qh_NOtrace in user_r.h).  Trace options 'Tn', 'TMn', 'TPn' and 'TWn' mostly removed.  Continue with 'Qw' (allow warning)\n");
+      if (!qh->ALLOWwarning)
+        qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+#endif
+  if (qh->RERUN > 1) {
+    qh->TRACElastrun= qh->IStracing; /* qh_build_withrestart duplicates next conditional */
+    if (qh->IStracing && qh->IStracing != -1) {
+      qh_fprintf(qh, qh->ferr, 8162, "qh_initqhull_globals: trace last of TR%d runs at level %d\n", qh->RERUN, qh->IStracing);
+      qh->IStracing= 0;
+    }
+  }else if (qh->TRACEpoint != qh_IDnone || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {
+    qh->TRACElevel= (qh->IStracing ? qh->IStracing : 3);
+    qh->IStracing= 0;
+  }
+  if (qh->ROTATErandom == 0 || qh->ROTATErandom == -1) {
+    seed= (int)time(&timedata);
+    if (qh->ROTATErandom  == -1) {
+      seed= -seed;
+      qh_option(qh, "QRandom-seed", &seed, NULL );
+    }else
+      qh_option(qh, "QRotate-random", &seed, NULL);
+    qh->ROTATErandom= seed;
+  }
+  seed= qh->ROTATErandom;
+  if (seed == INT_MIN)    /* default value */
+    seed= 1;
+  else if (seed < 0)
+    seed= -seed;
+  qh_RANDOMseed_(qh, seed);
+  randr= 0.0;
+  for (i=1000; i--; ) {
+    randi= qh_RANDOMint;
+    randr += randi;
+    if (randi > qh_RANDOMmax) {
+      qh_fprintf(qh, qh->ferr, 8036, "\
+qhull configuration error (qh_RANDOMmax in user_r.h): random integer %d > qh_RANDOMmax (%.8g)\n",
+               randi, qh_RANDOMmax);
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+  }
+  qh_RANDOMseed_(qh, seed);
+  randr= randr/1000;
+  if (randr < qh_RANDOMmax * 0.1
+  || randr > qh_RANDOMmax * 0.9)
+    qh_fprintf(qh, qh->ferr, 8037, "\
+qhull configuration warning (qh_RANDOMmax in user_r.h): average of 1000 random integers (%.2g) is much different than expected (%.2g).  Is qh_RANDOMmax (%.2g) wrong?\n",
+             randr, qh_RANDOMmax * 0.5, qh_RANDOMmax);
+  qh->RANDOMa= 2.0 * qh->RANDOMfactor/qh_RANDOMmax;
+  qh->RANDOMb= 1.0 - qh->RANDOMfactor;
+  if (qh_HASHfactor < 1.1) {
+    qh_fprintf(qh, qh->ferr, 6052, "qhull internal error (qh_initqhull_globals): qh_HASHfactor %d must be at least 1.1.  Qhull uses linear hash probing\n",
+      qh_HASHfactor);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  if (numpoints+extra < pointsneeded) {
+    qh_fprintf(qh, qh->ferr, 6214, "qhull input error: not enough points(%d) to construct initial simplex (need %d)\n",
+            numpoints, pointsneeded);
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  qh_initqhull_outputflags(qh);
+} /* initqhull_globals */
+
+/*---------------------------------
+
+  qh_initqhull_mem(qh )
+    initialize mem_r.c for qhull
+    qh.hull_dim and qh.normal_size determine some of the allocation sizes
+    if qh.MERGING,
+      includes ridgeT
+    calls qh_user_memsizes (user_r.c) to add up to 10 additional sizes for quick allocation
+      (see numsizes below)
+
+  returns:
+    mem_r.c already for qh_memalloc/qh_memfree (errors if called beforehand)
+
+  notes:
+    qh_produceoutput() prints memsizes
+
+*/
+void qh_initqhull_mem(qhT *qh) {
+  int numsizes;
+  int i;
+
+  numsizes= 8+10;
+  qh_meminitbuffers(qh, qh->IStracing, qh_MEMalign, numsizes,
+                     qh_MEMbufsize, qh_MEMinitbuf);
+  qh_memsize(qh, (int)sizeof(vertexT));
+  if (qh->MERGING) {
+    qh_memsize(qh, (int)sizeof(ridgeT));
+    qh_memsize(qh, (int)sizeof(mergeT));
+  }
+  qh_memsize(qh, (int)sizeof(facetT));
+  i= SETbasesize + (qh->hull_dim - 1) * SETelemsize;  /* ridge.vertices */
+  qh_memsize(qh, i);
+  qh_memsize(qh, qh->normal_size);        /* normal */
+  i += SETelemsize;                 /* facet.vertices, .ridges, .neighbors */
+  qh_memsize(qh, i);
+  qh_user_memsizes(qh);
+  qh_memsetup(qh);
+} /* initqhull_mem */
+
+/*---------------------------------
+
+  qh_initqhull_outputflags
+    initialize flags concerned with output
+
+  returns:
+    adjust user flags as needed
+
+  see:
+    qh_clear_outputflags() resets the flags
+
+  design:
+    test for qh.PRINTgood (i.e., only print 'good' facets)
+    check for conflicting print output options
+*/
+void qh_initqhull_outputflags(qhT *qh) {
+  boolT printgeom= False, printmath= False, printcoplanar= False;
+  int i;
+
+  trace3((qh, qh->ferr, 3024, "qh_initqhull_outputflags: %s\n", qh->qhull_command));
+  if (!(qh->PRINTgood || qh->PRINTneighbors)) {
+    if (qh->DELAUNAY || qh->KEEParea || qh->KEEPminArea < REALmax/2 || qh->KEEPmerge
+        || (!qh->ONLYgood && (qh->GOODvertex || qh->GOODpoint))) {
+      qh->PRINTgood= True;
+      qh_option(qh, "Pgood", NULL, NULL);
+    }
+  }
+  if (qh->PRINTtransparent) {
+    if (qh->hull_dim != 4 || !qh->DELAUNAY || qh->VORONOI || qh->DROPdim >= 0) {
+      qh_fprintf(qh, qh->ferr, 6215, "qhull option error: transparent Delaunay('Gt') needs 3-d Delaunay('d') w/o 'GDn'\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    qh->DROPdim= 3;
+    qh->PRINTridges= True;
+  }
+  for (i=qh_PRINTEND; i--; ) {
+    if (qh->PRINTout[i] == qh_PRINTgeom)
+      printgeom= True;
+    else if (qh->PRINTout[i] == qh_PRINTmathematica || qh->PRINTout[i] == qh_PRINTmaple)
+      printmath= True;
+    else if (qh->PRINTout[i] == qh_PRINTcoplanars)
+      printcoplanar= True;
+    else if (qh->PRINTout[i] == qh_PRINTpointnearest)
+      printcoplanar= True;
+    else if (qh->PRINTout[i] == qh_PRINTpointintersect && !qh->HALFspace) {
+      qh_fprintf(qh, qh->ferr, 6053, "qhull option error: option 'Fp' is only used for \nhalfspace intersection('Hn,n,n').\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }else if (qh->PRINTout[i] == qh_PRINTtriangles && (qh->HALFspace || qh->VORONOI)) {
+      qh_fprintf(qh, qh->ferr, 6054, "qhull option error: option 'Ft' is not available for Voronoi vertices ('v') or halfspace intersection ('H')\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }else if (qh->PRINTout[i] == qh_PRINTcentrums && qh->VORONOI) {
+      qh_fprintf(qh, qh->ferr, 6055, "qhull option error: option 'FC' is not available for Voronoi vertices('v')\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }else if (qh->PRINTout[i] == qh_PRINTvertices) {
+      if (qh->VORONOI)
+        qh_option(qh, "Fvoronoi", NULL, NULL);
+      else
+        qh_option(qh, "Fvertices", NULL, NULL);
+    }
+  }
+  if (printcoplanar && qh->DELAUNAY && qh->JOGGLEmax < REALmax/2) {
+    if (qh->PRINTprecision)
+      qh_fprintf(qh, qh->ferr, 7041, "qhull option warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");
+  }
+  if (printmath && (qh->hull_dim > 3 || qh->VORONOI)) {
+    qh_fprintf(qh, qh->ferr, 6056, "qhull option error: Mathematica and Maple output is only available for 2-d and 3-d convex hulls and 2-d Delaunay triangulations\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  if (printgeom) {
+    if (qh->hull_dim > 4) {
+      qh_fprintf(qh, qh->ferr, 6057, "qhull option error: Geomview output is only available for 2-d, 3-d and 4-d\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    if (qh->PRINTnoplanes && !(qh->PRINTcoplanar + qh->PRINTcentrums
+     + qh->PRINTdots + qh->PRINTspheres + qh->DOintersections + qh->PRINTridges)) {
+      qh_fprintf(qh, qh->ferr, 6058, "qhull option error: no output specified for Geomview\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    if (qh->VORONOI && (qh->hull_dim > 3 || qh->DROPdim >= 0)) {
+      qh_fprintf(qh, qh->ferr, 6059, "qhull option error: Geomview output for Voronoi diagrams only for 2-d\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    /* can not warn about furthest-site Geomview output: no lower_threshold */
+    if (qh->hull_dim == 4 && qh->DROPdim == -1 &&
+        (qh->PRINTcoplanar || qh->PRINTspheres || qh->PRINTcentrums)) {
+      qh_fprintf(qh, qh->ferr, 7042, "qhull option warning: coplanars, vertices, and centrums output not available for 4-d output(ignored).  Could use 'GDn' instead.\n");
+      qh->PRINTcoplanar= qh->PRINTspheres= qh->PRINTcentrums= False;
+    }
+  }
+  if (!qh->KEEPcoplanar && !qh->KEEPinside && !qh->ONLYgood) {
+    if ((qh->PRINTcoplanar && qh->PRINTspheres) || printcoplanar) {
+      if (qh->QHULLfinished) {
+        qh_fprintf(qh, qh->ferr, 7072, "qhull output warning: ignoring coplanar points, option 'Qc' was not set for the first run of qhull.\n");
+      }else {
+        qh->KEEPcoplanar= True;
+        qh_option(qh, "Qcoplanar", NULL, NULL);
+      }
+    }
+  }
+  qh->PRINTdim= qh->hull_dim;
+  if (qh->DROPdim >=0) {    /* after Geomview checks */
+    if (qh->DROPdim < qh->hull_dim) {
+      qh->PRINTdim--;
+      if (!printgeom || qh->hull_dim < 3)
+        qh_fprintf(qh, qh->ferr, 7043, "qhull option warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh->DROPdim);
+    }else
+      qh->DROPdim= -1;
+  }else if (qh->VORONOI) {
+    qh->DROPdim= qh->hull_dim-1;
+    qh->PRINTdim= qh->hull_dim-1;
+  }
+} /* qh_initqhull_outputflags */
+
+/*---------------------------------
+
+  qh_initqhull_start(qh, infile, outfile, errfile )
+    allocate memory if needed and call qh_initqhull_start2()
+*/
+void qh_initqhull_start(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile) {
+
+  qh_initstatistics(qh);
+  qh_initqhull_start2(qh, infile, outfile, errfile);
+} /* initqhull_start */
+
+/*---------------------------------
+
+  qh_initqhull_start2(qh, infile, outfile, errfile )
+    start initialization of qhull
+    initialize statistics, stdio, default values for global variables
+    assumes qh is allocated
+  notes:
+    report errors elsewhere, error handling and g_qhull_output [Qhull.cpp, QhullQh()] not in initialized
+  see:
+    qh_maxmin() determines the precision constants
+    qh_freeqhull()
+*/
+void qh_initqhull_start2(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile) {
+  time_t timedata;
+  int seed;
+
+  qh_CPUclock; /* start the clock(for qh_clock).  One-shot. */
+  /* memset is the same in qh_freeqhull() and qh_initqhull_start2() */
+  memset((char *)qh, 0, sizeof(qhT)-sizeof(qhmemT)-sizeof(qhstatT));   /* every field is 0, FALSE, NULL */
+  qh->NOerrexit= True;
+  qh->DROPdim= -1;
+  qh->ferr= errfile;
+  qh->fin= infile;
+  qh->fout= outfile;
+  qh->furthest_id= qh_IDunknown;
+#ifndef qh_NOmerge
+  qh->JOGGLEmax= REALmax;
+#else
+  qh->JOGGLEmax= 0.0;  /* Joggle ('QJ') if qh_NOmerge */
+#endif
+  qh->KEEPminArea= REALmax;
+  qh->last_low= REALmax;
+  qh->last_high= REALmax;
+  qh->last_newhigh= REALmax;
+  qh->last_random= 1; /* reentrant only */
+  qh->lastcpu= 0.0;
+  qh->max_outside= 0.0;
+  qh->max_vertex= 0.0;
+  qh->MAXabs_coord= 0.0;
+  qh->MAXsumcoord= 0.0;
+  qh->MAXwidth= -REALmax;
+  qh->MERGEindependent= True;
+  qh->MINdenom_1= fmax_(1.0/REALmax, REALmin); /* used by qh_scalepoints */
+  qh->MINoutside= 0.0;
+  qh->MINvisible= REALmax;
+  qh->MAXcoplanar= REALmax;
+  qh->outside_err= REALmax;
+  qh->premerge_centrum= 0.0;
+  qh->premerge_cos= REALmax;
+  qh->PRINTprecision= True;
+  qh->PRINTradius= 0.0;
+  qh->postmerge_cos= REALmax;
+  qh->postmerge_centrum= 0.0;
+  qh->ROTATErandom= INT_MIN;
+  qh->MERGEvertices= True;
+  qh->totarea= 0.0;
+  qh->totvol= 0.0;
+  qh->TRACEdist= REALmax;
+  qh->TRACEpoint= qh_IDnone;    /* recompile to trace a point, or use 'TPn' */
+  qh->tracefacet_id= UINT_MAX;  /* recompile to trace a facet, set to UINT_MAX when done, see userprintf_r.c/qh_fprintf */
+  qh->traceridge_id= UINT_MAX;  /* recompile to trace a ridge, set to UINT_MAX when done, see userprintf_r.c/qh_fprintf */
+  qh->tracevertex_id= UINT_MAX; /* recompile to trace a vertex, set to UINT_MAX when done, see userprintf_r.c/qh_fprintf */
+  seed= (int)time(&timedata);
+  qh_RANDOMseed_(qh, seed);
+  qh->run_id= qh_RANDOMint;
+  if(!qh->run_id)
+      qh->run_id++;  /* guarantee non-zero */
+  qh_option(qh, "run-id", &qh->run_id, NULL);
+  strcat(qh->qhull, "qhull");
+} /* initqhull_start2 */
+
+/*---------------------------------
+
+  qh_initthresholds(qh, commandString )
+    set thresholds for printing and scaling from commandString
+
+  returns:
+    sets qh.GOODthreshold or qh.SPLITthreshold if 'Pd0D1' used
+
+  see:
+    qh_initflags(), 'Qbk' 'QBk' 'Pdk' and 'PDk'
+    qh_inthresholds()
+
+  design:
+    for each 'Pdn' or 'PDn' option
+      check syntax
+      set qh.lower_threshold or qh.upper_threshold
+    set qh.GOODthreshold if an unbounded threshold is used
+    set qh.SPLITthreshold if a bounded threshold is used
+*/
+void qh_initthresholds(qhT *qh, char *command) {
+  realT value;
+  int idx, maxdim, k;
+  char *s= command; /* non-const due to strtol */
+  char *lastoption, *lastwarning= NULL;
+  char key;
+
+  maxdim= qh->input_dim;
+  if (qh->DELAUNAY && (qh->PROJECTdelaunay || qh->PROJECTinput))
+    maxdim++;
+  while (*s) {
+    if (*s == '-')
+      s++;
+    if (*s == 'P') {
+      lastoption= s++;
+      while (*s && !isspace(key= *s++)) {
+        if (key == 'd' || key == 'D') {
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7044, "qhull option warning: no dimension given for Print option 'P%c' at: %s.  Ignored\n",
+                    key, s-1);
+            lastwarning= lastoption;
+            continue;
+          }
+          idx= qh_strtol(s, &s);
+          if (idx >= qh->hull_dim) {
+            qh_fprintf(qh, qh->ferr, 7045, "qhull option warning: dimension %d for Print option 'P%c' is >= %d.  Ignored\n",
+                idx, key, qh->hull_dim);
+            lastwarning= lastoption;
+            continue;
+          }
+          if (*s == ':') {
+            s++;
+            value= qh_strtod(s, &s);
+            if (fabs((double)value) > 1.0) {
+              qh_fprintf(qh, qh->ferr, 7046, "qhull option warning: value %2.4g for Print option 'P%c' is > +1 or < -1.  Ignored\n",
+                      value, key);
+              lastwarning= lastoption;
+              continue;
+            }
+          }else
+            value= 0.0;
+          if (key == 'd')
+            qh->lower_threshold[idx]= value;
+          else
+            qh->upper_threshold[idx]= value;
+        }
+      }
+    }else if (*s == 'Q') {
+      lastoption= s++;
+      while (*s && !isspace(key= *s++)) {
+        if (key == 'b' && *s == 'B') {
+          s++;
+          for (k=maxdim; k--; ) {
+            qh->lower_bound[k]= -qh_DEFAULTbox;
+            qh->upper_bound[k]= qh_DEFAULTbox;
+          }
+        }else if (key == 'b' && *s == 'b')
+          s++;
+        else if (key == 'b' || key == 'B') {
+          if (!isdigit(*s)) {
+            qh_fprintf(qh, qh->ferr, 7047, "qhull option warning: no dimension given for Qhull option 'Q%c'\n",
+                    key);
+            lastwarning= lastoption;
+            continue;
+          }
+          idx= qh_strtol(s, &s);
+          if (idx >= maxdim) {
+            qh_fprintf(qh, qh->ferr, 7048, "qhull option warning: dimension %d for Qhull option 'Q%c' is >= %d.  Ignored\n",
+                idx, key, maxdim);
+            lastwarning= lastoption;
+            continue;
+          }
+          if (*s == ':') {
+            s++;
+            value= qh_strtod(s, &s);
+          }else if (key == 'b')
+            value= -qh_DEFAULTbox;
+          else
+            value= qh_DEFAULTbox;
+          if (key == 'b')
+            qh->lower_bound[idx]= value;
+          else
+            qh->upper_bound[idx]= value;
+        }
+      }
+    }else {
+      while (*s && !isspace(*s))
+        s++;
+    }
+    while (isspace(*s))
+      s++;
+  }
+  for (k=qh->hull_dim; k--; ) {
+    if (qh->lower_threshold[k] > -REALmax/2) {
+      qh->GOODthreshold= True;
+      if (qh->upper_threshold[k] < REALmax/2) {
+        qh->SPLITthresholds= True;
+        qh->GOODthreshold= False;
+        break;
+      }
+    }else if (qh->upper_threshold[k] < REALmax/2)
+      qh->GOODthreshold= True;
+  }
+  if (lastwarning && !qh->ALLOWwarning) {
+    qh_fprintf(qh, qh->ferr, 6036, "qhull option error: see previous warnings, use 'Qw' to override: '%s' (last offset %d)\n",
+      command, (int)(lastwarning-command));
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+} /* initthresholds */
+
+/*---------------------------------
+
+  qh_lib_check( qhullLibraryType, qhTsize, vertexTsize, ridgeTsize, facetTsize, setTsize, qhmemTsize )
+    Report error if library does not agree with caller
+
+  notes:
+    NOerrors -- qh_lib_check can not call qh_errexit()
+*/
+void qh_lib_check(int qhullLibraryType, int qhTsize, int vertexTsize, int ridgeTsize, int facetTsize, int setTsize, int qhmemTsize) {
+    int last_errcode= qh_ERRnone;
+
+#if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG)  /* user_r.h */
+    /*_CrtSetBreakAlloc(744);*/  /* Break at memalloc {744}, or 'watch' _crtBreakAlloc */
+    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) );
+    _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
+    _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
+    _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
+    _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
+    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
+    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
+#endif
+
+    if (qhullLibraryType==QHULL_NON_REENTRANT) { /* 0 */
+      qh_fprintf_stderr(6257, "qh_lib_check: Incorrect qhull library called.  Caller uses non-reentrant Qhull with a static qhT.  Qhull library is reentrant.\n");
+      last_errcode= 6257;
+    }else if (qhullLibraryType==QHULL_QH_POINTER) { /* 1 */
+      qh_fprintf_stderr(6258, "qh_lib_check: Incorrect qhull library called.  Caller uses non-reentrant Qhull with a dynamic qhT via qh_QHpointer.  Qhull library is reentrant.\n");
+      last_errcode= 6258;
+    }else if (qhullLibraryType != QHULL_REENTRANT) { /* 2 */
+      qh_fprintf_stderr(6262, "qh_lib_check: Expecting qhullLibraryType QHULL_NON_REENTRANT(0), QHULL_QH_POINTER(1), or QHULL_REENTRANT(2).  Got %d\n", qhullLibraryType);
+      last_errcode= 6262;
+    }
+    if (qhTsize != (int)sizeof(qhT)) {
+      qh_fprintf_stderr(6249, "qh_lib_check: Incorrect qhull library called.  Size of qhT for caller is %d, but for qhull library is %d.\n", qhTsize, (int)sizeof(qhT));
+      last_errcode= 6249;
+    }
+    if (vertexTsize != (int)sizeof(vertexT)) {
+      qh_fprintf_stderr(6250, "qh_lib_check: Incorrect qhull library called.  Size of vertexT for caller is %d, but for qhull library is %d.\n", vertexTsize, (int)sizeof(vertexT));
+      last_errcode= 6250;
+    }
+    if (ridgeTsize != (int)sizeof(ridgeT)) {
+      qh_fprintf_stderr(6251, "qh_lib_check: Incorrect qhull library called.  Size of ridgeT for caller is %d, but for qhull library is %d.\n", ridgeTsize, (int)sizeof(ridgeT));
+      last_errcode= 6251;
+    }
+    if (facetTsize != (int)sizeof(facetT)) {
+      qh_fprintf_stderr(6252, "qh_lib_check: Incorrect qhull library called.  Size of facetT for caller is %d, but for qhull library is %d.\n", facetTsize, (int)sizeof(facetT));
+      last_errcode= 6252;
+    }
+    if (setTsize && setTsize != SETbasesize) {
+      qh_fprintf_stderr(6253, "qh_lib_check: Incorrect qhull library called.  Size of setT for caller is %d, but for qhull library is %d.\n", setTsize, SETbasesize);
+      last_errcode= 6253;
+    }
+    if (qhmemTsize && qhmemTsize != sizeof(qhmemT)) {
+      qh_fprintf_stderr(6254, "qh_lib_check: Incorrect qhull library called.  Size of qhmemT for caller is %d, but for qhull library is %d.\n", qhmemTsize, (int)sizeof(qhmemT));
+      last_errcode= 6254;
+    }
+    if (last_errcode) {
+      qh_fprintf_stderr(6259, "qhull internal error (qh_lib_check): Cannot continue due to QH%d.  '%s' is not reentrant (e.g., qhull.so) or out-of-date.  Exit with %d\n",
+            last_errcode, qh_version2, last_errcode - 6200);
+      qh_exit(last_errcode - 6200);  /* can not use qh_errexit(), must be less than 255 */
+    }
+} /* lib_check */
+
+/*---------------------------------
+
+  qh_option(qh, option, intVal, realVal )
+    add an option description to qh.qhull_options
+
+  notes:
+    NOerrors -- qh_option can not call qh_errexit() [qh_initqhull_start2]
+    will be printed with statistics ('Ts') and errors
+    strlen(option) < 40
+*/
+void qh_option(qhT *qh, const char *option, int *i, realT *r) {
+  char buf[200];
+  int buflen, remainder;
+
+  if (strlen(option) > sizeof(buf)-30-30) {
+    qh_fprintf(qh, qh->ferr, 6408, "qhull internal error (qh_option): option (%d chars) has more than %d chars.  May overflow temporary buffer.  Option '%s'\n",
+        (int)strlen(option), (int)sizeof(buf)-30-30, option);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  buflen = 0;
+  buflen += snprintf(buf, sizeof(buf) / sizeof(buf[0]), "  %s", option);
+  if (i)
+    buflen += snprintf(buf+buflen, sizeof(buf) / sizeof(buf[0]) - buflen, " %d", *i);
+  if (r)
+    buflen += snprintf(buf+buflen, sizeof(buf) / sizeof(buf[0]) - buflen, " %2.2g", *r);
+  qh->qhull_optionlen += buflen;
+  remainder= (int)(sizeof(qh->qhull_options) - strlen(qh->qhull_options)) - 1;    /* WARN64 */
+  maximize_(remainder, 0);
+  if (qh->qhull_optionlen >= qh_OPTIONline && remainder > 0) {
+    strncat(qh->qhull_options, "\n", (unsigned int)remainder);
+    --remainder;
+    qh->qhull_optionlen= buflen;
+  }
+  if (buflen > remainder) {
+    trace1((qh, qh->ferr, 1058, "qh_option: option would overflow qh.qhull_options. Truncated '%s'\n", buf));
+  }
+  strncat(qh->qhull_options, buf, (unsigned int)remainder);
+} /* option */
+
+/*---------------------------------
+
+  qh_zero( qh, errfile )
+    Initialize and zero Qhull's memory for qh_new_qhull()
+
+  notes:
+    Not needed in global_r.c because static variables are initialized to zero
+*/
+void qh_zero(qhT *qh, FILE *errfile) {
+    memset((char *)qh, 0, sizeof(qhT));   /* every field is 0, FALSE, NULL */
+    qh->NOerrexit= True;
+    qh_meminit(qh, errfile);
+} /* zero */
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/io_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/io_r.c
new file mode 100644
index 00000000000..148d31254b8
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/io_r.c
@@ -0,0 +1,4128 @@
+/*
  ---------------------------------
+
+   io_r.c
+   Input/Output routines of qhull application
+
+   see qh-io_r.htm and io_r.h
+
+   see user_r.c for qh_errprint and qh_printfacetlist
+
+   unix_r.c calls qh_readpoints and qh_produce_output
+
+   unix_r.c and user_r.c are the only callers of io_r.c functions
+   This allows the user to avoid loading io_r.o from qhull.a
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/io_r.c#12 $$Change: 2965 $
+   $DateTime: 2020/06/04 15:37:41 $$Author: bbarber $
+*/
+
+#include "qhull_ra.h"
+
+/*========= -functions in alphabetical order after qh_produce_output(qh)  =====*/
+
+/*---------------------------------
+
+  qh_produce_output(qh )
+  qh_produce_output2(qh )
+    prints out the result of qhull in desired format
+    qh_produce_output2 does not call qh_prepare_output
+      qh_checkpolygon is valid for qh_prepare_output
+    if qh.GETarea
+      computes and prints area and volume
+    qh.PRINTout[] is an array of output formats
+
+  notes:
+    prints output in qh.PRINTout order
+*/
+void qh_produce_output(qhT *qh) {
+    int tempsize= qh_setsize(qh, qh->qhmem.tempstack);
+
+    qh_prepare_output(qh);
+    qh_produce_output2(qh);
+    if (qh_setsize(qh, qh->qhmem.tempstack) != tempsize) {
+        qh_fprintf(qh, qh->ferr, 6206, "qhull internal error (qh_produce_output): temporary sets not empty(%d)\n",
+            qh_setsize(qh, qh->qhmem.tempstack));
+        qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }
+} /* produce_output */
+
+
+void qh_produce_output2(qhT *qh) {
+  int i, tempsize= qh_setsize(qh, qh->qhmem.tempstack), d_1;
+
+  fflush(NULL);
+  if (qh->PRINTsummary)
+    qh_printsummary(qh, qh->ferr);
+  else if (qh->PRINTout[0] == qh_PRINTnone)
+    qh_printsummary(qh, qh->fout);
+  for (i=0; i < qh_PRINTEND; i++)
+    qh_printfacets(qh, qh->fout, qh->PRINTout[i], qh->facet_list, NULL, !qh_ALL);
+  fflush(NULL);
+
+  qh_allstatistics(qh);
+  if (qh->PRINTprecision && !qh->MERGING && (qh->JOGGLEmax > REALmax/2 || qh->RERUN))
+    qh_printstats(qh, qh->ferr, qh->qhstat.precision, NULL);
+  if (qh->VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0))
+    qh_printstats(qh, qh->ferr, qh->qhstat.vridges, NULL);
+  if (qh->PRINTstatistics) {
+    qh_printstatistics(qh, qh->ferr, "");
+    qh_memstatistics(qh, qh->ferr);
+    d_1= SETbasesize + (qh->hull_dim - 1) * SETelemsize;
+    qh_fprintf(qh, qh->ferr, 8040, "\
+    size in bytes: merge %d ridge %d vertex %d facet %d\n\
+         normal %d ridge vertices %d facet vertices or neighbors %d\n",
+            (int)sizeof(mergeT), (int)sizeof(ridgeT),
+            (int)sizeof(vertexT), (int)sizeof(facetT),
+            qh->normal_size, d_1, d_1 + SETelemsize);
+  }
+  if (qh_setsize(qh, qh->qhmem.tempstack) != tempsize) {
+    qh_fprintf(qh, qh->ferr, 6065, "qhull internal error (qh_produce_output2): temporary sets not empty(%d)\n",
+             qh_setsize(qh, qh->qhmem.tempstack));
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+} /* produce_output2 */
+
+/*---------------------------------
+
+  qh_dfacet(qh, id )
+    print facet by id, for debugging
+
+*/
+void qh_dfacet(qhT *qh, unsigned int id) {
+  facetT *facet;
+
+  FORALLfacets {
+    if (facet->id == id) {
+      qh_printfacet(qh, qh->fout, facet);
+      break;
+    }
+  }
+} /* dfacet */
+
+
+/*---------------------------------
+
+  qh_dvertex(qh, id )
+    print vertex by id, for debugging
+*/
+void qh_dvertex(qhT *qh, unsigned int id) {
+  vertexT *vertex;
+
+  FORALLvertices {
+    if (vertex->id == id) {
+      qh_printvertex(qh, qh->fout, vertex);
+      break;
+    }
+  }
+} /* dvertex */
+
+
+/*---------------------------------
+
+  qh_compare_facetarea( p1, p2 )
+    used by qsort() to order facets by area
+*/
+int qh_compare_facetarea(const void *p1, const void *p2) {
+  const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
+
+  if (!a->isarea)
+    return -1;
+  if (!b->isarea)
+    return 1;
+  if (a->f.area > b->f.area)
+    return 1;
+  else if (a->f.area == b->f.area)
+    return 0;
+  return -1;
+} /* compare_facetarea */
+
+/*---------------------------------
+
+  qh_compare_facetvisit( p1, p2 )
+    used by qsort() to order facets by visit id or id
+*/
+int qh_compare_facetvisit(const void *p1, const void *p2) {
+  const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
+  int i,j;
+
+  if (!(i= (int)a->visitid))
+    i= (int)(0 - a->id); /* sign distinguishes id from visitid */
+  if (!(j= (int)b->visitid))
+    j= (int)(0 - b->id);
+  return(i - j);
+} /* compare_facetvisit */
+
+/*---------------------------------
+
+  qh_compare_nummerge( p1, p2 )
+    used by qsort() to order facets by number of merges
+
+notes:
+    called by qh_markkeep ('PMerge-keep')
+*/
+int qh_compare_nummerge(const void *p1, const void *p2) {
+  const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);
+
+  return(a->nummerge - b->nummerge);
+} /* compare_nummerge */
+
+/*---------------------------------
+
+  qh_copyfilename(qh, dest, size, source, length )
+    copy filename identified by qh_skipfilename()
+
+  notes:
+    see qh_skipfilename() for syntax
+*/
+void qh_copyfilename(qhT *qh, char *filename, int size, const char* source, int length) {
+  char c= *source;
+
+  if (length > size + 1) {
+      qh_fprintf(qh, qh->ferr, 6040, "qhull error: filename is more than %d characters, %s\n",  size-1, source);
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  strncpy(filename, source, (size_t)length);
+  filename[length]= '\0';
+  if (c == '\'' || c == '"') {
+    char *s= filename + 1;
+    char *t= filename;
+    while (*s) {
+      if (*s == c) {
+          if (s[-1] == '\\')
+              t[-1]= c;
+      }else
+          *t++= *s;
+      s++;
+    }
+    *t= '\0';
+  }
+} /* copyfilename */
+
+/*---------------------------------
+
+  qh_countfacets(qh, facetlist, facets, printall,
+          numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars  )
+    count good facets for printing and set visitid
+    if allfacets, ignores qh_skipfacet()
+
+  notes:
+    qh_printsummary and qh_countfacets must match counts
+
+  returns:
+    numfacets, numsimplicial, total neighbors, numridges, coplanars
+    each facet with ->visitid indicating 1-relative position
+      ->visitid==0 indicates not good
+
+  notes
+    numfacets >= numsimplicial
+    if qh.NEWfacets,
+      does not count visible facets (matches qh_printafacet)
+
+  design:
+    for all facets on facetlist and in facets set
+      unless facet is skipped or visible (i.e., will be deleted)
+        mark facet->visitid
+        update counts
+*/
+void qh_countfacets(qhT *qh, facetT *facetlist, setT *facets, boolT printall,
+    int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {
+  facetT *facet, **facetp;
+  int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;
+
+  FORALLfacet_(facetlist) {
+    if ((facet->visible && qh->NEWfacets)
+    || (!printall && qh_skipfacet(qh, facet)))
+      facet->visitid= 0;
+    else {
+      facet->visitid= (unsigned int)(++numfacets);
+      totneighbors += qh_setsize(qh, facet->neighbors);
+      if (facet->simplicial) {
+        numsimplicial++;
+        if (facet->keepcentrum && facet->tricoplanar)
+          numtricoplanars++;
+      }else
+        numridges += qh_setsize(qh, facet->ridges);
+      if (facet->coplanarset)
+        numcoplanars += qh_setsize(qh, facet->coplanarset);
+    }
+  }
+
+  FOREACHfacet_(facets) {
+    if ((facet->visible && qh->NEWfacets)
+    || (!printall && qh_skipfacet(qh, facet)))
+      facet->visitid= 0;
+    else {
+      facet->visitid= (unsigned int)(++numfacets);
+      totneighbors += qh_setsize(qh, facet->neighbors);
+      if (facet->simplicial){
+        numsimplicial++;
+        if (facet->keepcentrum && facet->tricoplanar)
+          numtricoplanars++;
+      }else
+        numridges += qh_setsize(qh, facet->ridges);
+      if (facet->coplanarset)
+        numcoplanars += qh_setsize(qh, facet->coplanarset);
+    }
+  }
+  qh->visit_id += (unsigned int)numfacets + 1;
+  *numfacetsp= numfacets;
+  *numsimplicialp= numsimplicial;
+  *totneighborsp= totneighbors;
+  *numridgesp= numridges;
+  *numcoplanarsp= numcoplanars;
+  *numtricoplanarsp= numtricoplanars;
+} /* countfacets */
+
+/*---------------------------------
+
+  qh_detvnorm(qh, vertex, vertexA, centers, offset )
+    compute separating plane of the Voronoi diagram for a pair of input sites
+    centers= set of facets (i.e., Voronoi vertices)
+      facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)
+
+  assumes:
+    qh_ASvoronoi and qh_vertexneighbors() already set
+
+  returns:
+    norm
+      a pointer into qh.gm_matrix to qh.hull_dim-1 reals
+      copy the data before reusing qh.gm_matrix
+    offset
+      if 'QVn'
+        sign adjusted so that qh.GOODvertexp is inside
+      else
+        sign adjusted so that vertex is inside
+
+    qh.gm_matrix= simplex of points from centers relative to first center
+
+  notes:
+    in io_r.c so that code for 'v Tv' can be removed by removing io_r.c
+    returns pointer into qh.gm_matrix to avoid tracking of temporary memory
+
+  design:
+    determine midpoint of input sites
+    build points as the set of Voronoi vertices
+    select a simplex from points (if necessary)
+      include midpoint if the Voronoi region is unbounded
+    relocate the first vertex of the simplex to the origin
+    compute the normalized hyperplane through the simplex
+    orient the hyperplane toward 'QVn' or 'vertex'
+    if 'Tv' or 'Ts'
+      if bounded
+        test that hyperplane is the perpendicular bisector of the input sites
+      test that Voronoi vertices not in the simplex are still on the hyperplane
+    free up temporary memory
+*/
+pointT *qh_detvnorm(qhT *qh, vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {
+  facetT *facet, **facetp;
+  int  i, k, pointid, pointidA, point_i, point_n;
+  setT *simplex= NULL;
+  pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;
+  coordT *coord, *gmcoord, *normalp;
+  setT *points= qh_settemp(qh, qh->TEMPsize);
+  boolT nearzero= False;
+  boolT unbounded= False;
+  int numcenters= 0;
+  int dim= qh->hull_dim - 1;
+  realT dist, offset, angle, zero= 0.0;
+
+  midpoint= qh->gm_matrix + qh->hull_dim * qh->hull_dim;  /* last row */
+  for (k=0; k < dim; k++)
+    midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;
+  FOREACHfacet_(centers) {
+    numcenters++;
+    if (!facet->visitid)
+      unbounded= True;
+    else {
+      if (!facet->center)
+        facet->center= qh_facetcenter(qh, facet->vertices);
+      qh_setappend(qh, &points, facet->center);
+    }
+  }
+  if (numcenters > dim) {
+    simplex= qh_settemp(qh, qh->TEMPsize);
+    qh_setappend(qh, &simplex, vertex->point);
+    if (unbounded)
+      qh_setappend(qh, &simplex, midpoint);
+    qh_maxsimplex(qh, dim, points, NULL, 0, &simplex);
+    qh_setdelnth(qh, simplex, 0);
+  }else if (numcenters == dim) {
+    if (unbounded)
+      qh_setappend(qh, &points, midpoint);
+    simplex= points;
+  }else {
+    qh_fprintf(qh, qh->ferr, 6216, "qhull internal error (qh_detvnorm): too few points(%d) to compute separating plane\n", numcenters);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  i= 0;
+  gmcoord= qh->gm_matrix;
+  point0= SETfirstt_(simplex, pointT);
+  FOREACHpoint_(simplex) {
+    if (qh->IStracing >= 4)
+      qh_printmatrix(qh, qh->ferr, "qh_detvnorm: Voronoi vertex or midpoint",
+                              &point, 1, dim);
+    if (point != point0) {
+      qh->gm_row[i++]= gmcoord;
+      coord= point0;
+      for (k=dim; k--; )
+        *(gmcoord++)= *point++ - *coord++;
+    }
+  }
+  qh->gm_row[i]= gmcoord;  /* does not overlap midpoint, may be used later for qh_areasimplex */
+  normal= gmcoord;
+  qh_sethyperplane_gauss(qh, dim, qh->gm_row, point0, True,
+                normal, &offset, &nearzero);
+  /* nearzero is true for axis-parallel hyperplanes (e.g., a bounding box).  Should detect degenerate hyperplanes.  See 'Tv' check following */
+  if (qh->GOODvertexp == vertexA->point)
+    inpoint= vertexA->point;
+  else
+    inpoint= vertex->point;
+  zinc_(Zdistio);
+  dist= qh_distnorm(dim, inpoint, normal, &offset);
+  if (dist > 0) {
+    offset= -offset;
+    normalp= normal;
+    for (k=dim; k--; ) {
+      *normalp= -(*normalp);
+      normalp++;
+    }
+  }
+  if (qh->VERIFYoutput || qh->PRINTstatistics) {
+    pointid= qh_pointid(qh, vertex->point);
+    pointidA= qh_pointid(qh, vertexA->point);
+    if (!unbounded) {
+      zinc_(Zdiststat);
+      dist= qh_distnorm(dim, midpoint, normal, &offset);
+      if (dist < 0)
+        dist= -dist;
+      zzinc_(Zridgemid);
+      wwmax_(Wridgemidmax, dist);
+      wwadd_(Wridgemid, dist);
+      trace4((qh, qh->ferr, 4014, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",
+                 pointid, pointidA, dist));
+      for (k=0; k < dim; k++)
+        midpoint[k]= vertexA->point[k] - vertex->point[k];  /* overwrites midpoint! */
+      qh_normalize(qh, midpoint, dim, False);
+      angle= qh_distnorm(dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
+      if (angle < 0.0)
+        angle= angle + 1.0;
+      else
+        angle= angle - 1.0;
+      if (angle < 0.0)
+        angle= -angle;
+      trace4((qh, qh->ferr, 4015, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",
+                 pointid, pointidA, angle, nearzero));
+      if (nearzero) {
+        zzinc_(Zridge0);
+        wwmax_(Wridge0max, angle);
+        wwadd_(Wridge0, angle);
+      }else {
+        zzinc_(Zridgeok)
+        wwmax_(Wridgeokmax, angle);
+        wwadd_(Wridgeok, angle);
+      }
+    }
+    if (simplex != points) {
+      FOREACHpoint_i_(qh, points) {
+        if (!qh_setin(simplex, point)) {
+          facet= SETelemt_(centers, point_i, facetT);
+          zinc_(Zdiststat);
+          dist= qh_distnorm(dim, point, normal, &offset);
+          if (dist < 0)
+            dist= -dist;
+          zzinc_(Zridge);
+          wwmax_(Wridgemax, dist);
+          wwadd_(Wridge, dist);
+          trace4((qh, qh->ferr, 4016, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",
+                             pointid, pointidA, facet->visitid, dist));
+        }
+      }
+    }
+  }
+  *offsetp= offset;
+  if (simplex != points)
+    qh_settempfree(qh, &simplex);
+  qh_settempfree(qh, &points);
+  return normal;
+} /* detvnorm */
+
+/*---------------------------------
+
+  qh_detvridge(qh, vertexA )
+    determine Voronoi ridge from 'seen' neighbors of vertexA
+    include one vertex-at-infinite if an !neighbor->visitid
+
+  returns:
+    temporary set of centers (facets, i.e., Voronoi vertices)
+    sorted by center id
+*/
+setT *qh_detvridge(qhT *qh, vertexT *vertex) {
+  setT *centers= qh_settemp(qh, qh->TEMPsize);
+  setT *tricenters= qh_settemp(qh, qh->TEMPsize);
+  facetT *neighbor, **neighborp;
+  boolT firstinf= True;
+
+  FOREACHneighbor_(vertex) {
+    if (neighbor->seen) {
+      if (neighbor->visitid) {
+        if (!neighbor->tricoplanar || qh_setunique(qh, &tricenters, neighbor->center))
+          qh_setappend(qh, ¢ers, neighbor);
+      }else if (firstinf) {
+        firstinf= False;
+        qh_setappend(qh, ¢ers, neighbor);
+      }
+    }
+  }
+  qsort(SETaddr_(centers, facetT), (size_t)qh_setsize(qh, centers),
+             sizeof(facetT *), qh_compare_facetvisit);
+  qh_settempfree(qh, &tricenters);
+  return centers;
+} /* detvridge */
+
+/*---------------------------------
+
+  qh_detvridge3(qh, atvertex, vertex )
+    determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
+    include one vertex-at-infinite for !neighbor->visitid
+    assumes all facet->seen2= True
+
+  returns:
+    temporary set of centers (facets, i.e., Voronoi vertices)
+    listed in adjacency order (!oriented)
+    all facet->seen2= True
+
+  design:
+    mark all neighbors of atvertex
+    for each adjacent neighbor of both atvertex and vertex
+      if neighbor selected
+        add neighbor to set of Voronoi vertices
+*/
+setT *qh_detvridge3(qhT *qh, vertexT *atvertex, vertexT *vertex) {
+  setT *centers= qh_settemp(qh, qh->TEMPsize);
+  setT *tricenters= qh_settemp(qh, qh->TEMPsize);
+  facetT *neighbor, **neighborp, *facet= NULL;
+  boolT firstinf= True;
+
+  FOREACHneighbor_(atvertex)
+    neighbor->seen2= False;
+  FOREACHneighbor_(vertex) {
+    if (!neighbor->seen2) {
+      facet= neighbor;
+      break;
+    }
+  }
+  while (facet) {
+    facet->seen2= True;
+    if (neighbor->seen) {
+      if (facet->visitid) {
+        if (!facet->tricoplanar || qh_setunique(qh, &tricenters, facet->center))
+          qh_setappend(qh, ¢ers, facet);
+      }else if (firstinf) {
+        firstinf= False;
+        qh_setappend(qh, ¢ers, facet);
+      }
+    }
+    FOREACHneighbor_(facet) {
+      if (!neighbor->seen2) {
+        if (qh_setin(vertex->neighbors, neighbor))
+          break;
+        else
+          neighbor->seen2= True;
+      }
+    }
+    facet= neighbor;
+  }
+  if (qh->CHECKfrequently) {
+    FOREACHneighbor_(vertex) {
+      if (!neighbor->seen2) {
+          qh_fprintf(qh, qh->ferr, 6217, "qhull internal error (qh_detvridge3): neighbors of vertex p%d are not connected at facet %d\n",
+                 qh_pointid(qh, vertex->point), neighbor->id);
+        qh_errexit(qh, qh_ERRqhull, neighbor, NULL);
+      }
+    }
+  }
+  FOREACHneighbor_(atvertex)
+    neighbor->seen2= True;
+  qh_settempfree(qh, &tricenters);
+  return centers;
+} /* detvridge3 */
+
+/*---------------------------------
+
+  qh_eachvoronoi(qh, fp, printvridge, vertex, visitall, innerouter, inorder )
+    if visitall,
+      visit all Voronoi ridges for vertex (i.e., an input site)
+    else
+      visit all unvisited Voronoi ridges for vertex
+      all vertex->seen= False if unvisited
+    assumes
+      all facet->seen= False
+      all facet->seen2= True (for qh_detvridge3)
+      all facet->visitid == 0 if vertex_at_infinity
+                         == index of Voronoi vertex
+                         >= qh.num_facets if ignored
+    innerouter:
+      qh_RIDGEall--  both inner (bounded) and outer(unbounded) ridges
+      qh_RIDGEinner- only inner
+      qh_RIDGEouter- only outer
+
+    if inorder
+      orders vertices for 3-d Voronoi diagrams
+
+  returns:
+    number of visited ridges (does not include previously visited ridges)
+
+    if printvridge,
+      calls printvridge( fp, vertex, vertexA, centers)
+        fp== any pointer (assumes FILE*)
+             fp may be NULL for QhullQh::qh_fprintf which calls appendQhullMessage
+        vertex,vertexA= pair of input sites that define a Voronoi ridge
+        centers= set of facets (i.e., Voronoi vertices)
+                 ->visitid == index or 0 if vertex_at_infinity
+                 ordered for 3-d Voronoi diagram
+  notes:
+    uses qh.vertex_visit
+
+  see:
+    qh_eachvoronoi_all()
+
+  design:
+    mark selected neighbors of atvertex
+    for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
+      for each unvisited vertex
+        if atvertex and vertex share more than d-1 neighbors
+          bump totalcount
+          if printvridge defined
+            build the set of shared neighbors (i.e., Voronoi vertices)
+            call printvridge
+*/
+int qh_eachvoronoi(qhT *qh, FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
+  boolT unbounded;
+  int count;
+  facetT *neighbor, **neighborp, *neighborA, **neighborAp;
+  setT *centers;
+  setT *tricenters= qh_settemp(qh, qh->TEMPsize);
+
+  vertexT *vertex, **vertexp;
+  boolT firstinf;
+  unsigned int numfacets= (unsigned int)qh->num_facets;
+  int totridges= 0;
+
+  qh->vertex_visit++;
+  atvertex->seen= True;
+  if (visitall) {
+    FORALLvertices
+      vertex->seen= False;
+  }
+  FOREACHneighbor_(atvertex) {
+    if (neighbor->visitid < numfacets)
+      neighbor->seen= True;
+  }
+  FOREACHneighbor_(atvertex) {
+    if (neighbor->seen) {
+      FOREACHvertex_(neighbor->vertices) {
+        if (vertex->visitid != qh->vertex_visit && !vertex->seen) {
+          vertex->visitid= qh->vertex_visit;
+          count= 0;
+          firstinf= True;
+          qh_settruncate(qh, tricenters, 0);
+          FOREACHneighborA_(vertex) {
+            if (neighborA->seen) {
+              if (neighborA->visitid) {
+                if (!neighborA->tricoplanar || qh_setunique(qh, &tricenters, neighborA->center))
+                  count++;
+              }else if (firstinf) {
+                count++;
+                firstinf= False;
+              }
+            }
+          }
+          if (count >= qh->hull_dim - 1) {  /* e.g., 3 for 3-d Voronoi */
+            if (firstinf) {
+              if (innerouter == qh_RIDGEouter)
+                continue;
+              unbounded= False;
+            }else {
+              if (innerouter == qh_RIDGEinner)
+                continue;
+              unbounded= True;
+            }
+            totridges++;
+            trace4((qh, qh->ferr, 4017, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",
+                  count, qh_pointid(qh, atvertex->point), qh_pointid(qh, vertex->point)));
+            if (printvridge) {
+              if (inorder && qh->hull_dim == 3+1) /* 3-d Voronoi diagram */
+                centers= qh_detvridge3(qh, atvertex, vertex);
+              else
+                centers= qh_detvridge(qh, vertex);
+              (*printvridge)(qh, fp, atvertex, vertex, centers, unbounded);
+              qh_settempfree(qh, ¢ers);
+            }
+          }
+        }
+      }
+    }
+  }
+  FOREACHneighbor_(atvertex)
+    neighbor->seen= False;
+  qh_settempfree(qh, &tricenters);
+  return totridges;
+} /* eachvoronoi */
+
+
+/*---------------------------------
+
+  qh_eachvoronoi_all(qh, fp, printvridge, isUpper, innerouter, inorder )
+    visit all Voronoi ridges
+
+    innerouter:
+      see qh_eachvoronoi()
+
+    if inorder
+      orders vertices for 3-d Voronoi diagrams
+
+  returns
+    total number of ridges
+
+    if isUpper == facet->upperdelaunay  (i.e., a Vornoi vertex)
+      facet->visitid= Voronoi vertex index(same as 'o' format)
+    else
+      facet->visitid= 0
+
+    if printvridge,
+      calls printvridge( fp, vertex, vertexA, centers)
+      [see qh_eachvoronoi]
+
+  notes:
+    Not used for qhull.exe
+    same effect as qh_printvdiagram but ridges not sorted by point id
+*/
+int qh_eachvoronoi_all(qhT *qh, FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder) {
+  facetT *facet;
+  vertexT *vertex;
+  int numcenters= 1;  /* vertex 0 is vertex-at-infinity */
+  int totridges= 0;
+
+  qh_clearcenters(qh, qh_ASvoronoi);
+  qh_vertexneighbors(qh);
+  maximize_(qh->visit_id, (unsigned int)qh->num_facets);
+  FORALLfacets {
+    facet->visitid= 0;
+    facet->seen= False;
+    facet->seen2= True;
+  }
+  FORALLfacets {
+    if (facet->upperdelaunay == isUpper)
+      facet->visitid= (unsigned int)(numcenters++);
+  }
+  FORALLvertices
+    vertex->seen= False;
+  FORALLvertices {
+    if (qh->GOODvertex > 0 && qh_pointid(qh, vertex->point)+1 != qh->GOODvertex)
+      continue;
+    totridges += qh_eachvoronoi(qh, fp, printvridge, vertex,
+                   !qh_ALL, innerouter, inorder);
+  }
+  return totridges;
+} /* eachvoronoi_all */
+
+/*---------------------------------
+
+  qh_facet2point(qh, facet, point0, point1, mindist )
+    return two projected temporary vertices for a 2-d facet
+    may be non-simplicial
+
+  returns:
+    point0 and point1 oriented and projected to the facet
+    returns mindist (maximum distance below plane)
+*/
+void qh_facet2point(qhT *qh, facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
+  vertexT *vertex0, *vertex1;
+  realT dist;
+
+  if (facet->toporient ^ qh_ORIENTclock) {
+    vertex0= SETfirstt_(facet->vertices, vertexT);
+    vertex1= SETsecondt_(facet->vertices, vertexT);
+  }else {
+    vertex1= SETfirstt_(facet->vertices, vertexT);
+    vertex0= SETsecondt_(facet->vertices, vertexT);
+  }
+  zadd_(Zdistio, 2);
+  qh_distplane(qh, vertex0->point, facet, &dist);
+  *mindist= dist;
+  *point0= qh_projectpoint(qh, vertex0->point, facet, dist);
+  qh_distplane(qh, vertex1->point, facet, &dist);
+  minimize_(*mindist, dist);
+  *point1= qh_projectpoint(qh, vertex1->point, facet, dist);
+} /* facet2point */
+
+
+/*---------------------------------
+
+  qh_facetvertices(qh, facetlist, facets, allfacets )
+    returns temporary set of vertices in a set and/or list of facets
+    if allfacets, ignores qh_skipfacet()
+
+  returns:
+    vertices with qh.vertex_visit
+
+  notes:
+    optimized for allfacets of facet_list
+
+  design:
+    if allfacets of facet_list
+      create vertex set from vertex_list
+    else
+      for each selected facet in facets or facetlist
+        append unvisited vertices to vertex set
+*/
+setT *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets) {
+  setT *vertices;
+  facetT *facet, **facetp;
+  vertexT *vertex, **vertexp;
+
+  qh->vertex_visit++;
+  if (facetlist == qh->facet_list && allfacets && !facets) {
+    vertices= qh_settemp(qh, qh->num_vertices);
+    FORALLvertices {
+      vertex->visitid= qh->vertex_visit;
+      qh_setappend(qh, &vertices, vertex);
+    }
+  }else {
+    vertices= qh_settemp(qh, qh->TEMPsize);
+    FORALLfacet_(facetlist) {
+      if (!allfacets && qh_skipfacet(qh, facet))
+        continue;
+      FOREACHvertex_(facet->vertices) {
+        if (vertex->visitid != qh->vertex_visit) {
+          vertex->visitid= qh->vertex_visit;
+          qh_setappend(qh, &vertices, vertex);
+        }
+      }
+    }
+  }
+  FOREACHfacet_(facets) {
+    if (!allfacets && qh_skipfacet(qh, facet))
+      continue;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh->vertex_visit) {
+        vertex->visitid= qh->vertex_visit;
+        qh_setappend(qh, &vertices, vertex);
+      }
+    }
+  }
+  return vertices;
+} /* facetvertices */
+
+/*---------------------------------
+
+  qh_geomplanes(qh, facet, outerplane, innerplane )
+    return outer and inner planes for Geomview
+    qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)
+
+  notes:
+    assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon
+*/
+void qh_geomplanes(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane) {
+  realT radius;
+
+  if (qh->MERGING || qh->JOGGLEmax < REALmax/2) {
+    qh_outerinner(qh, facet, outerplane, innerplane);
+    radius= qh->PRINTradius;
+    if (qh->JOGGLEmax < REALmax/2)
+      radius -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);  /* already accounted for in qh_outerinner() */
+    *outerplane += radius;
+    *innerplane -= radius;
+    if (qh->PRINTcoplanar || qh->PRINTspheres) {
+      *outerplane += qh->MAXabs_coord * qh_GEOMepsilon;
+      *innerplane -= qh->MAXabs_coord * qh_GEOMepsilon;
+    }
+  }else
+    *innerplane= *outerplane= 0;
+} /* geomplanes */
+
+
+/*---------------------------------
+
+  qh_markkeep(qh, facetlist )
+    restrict good facets for qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
+    ignores visible facets (!part of convex hull)
+
+  returns:
+    may clear facet->good
+    recomputes qh.num_good
+
+  notes:
+    only called by qh_prepare_output after qh_findgood_all
+    does not throw errors except memory/corruption of qset_r.c
+
+  design:
+    get set of good facets
+    if qh.KEEParea
+      sort facets by area
+      clear facet->good for all but n largest facets
+    if qh.KEEPmerge
+      sort facets by merge count
+      clear facet->good for all but n most merged facets
+    if qh.KEEPminarea
+      clear facet->good if area too small
+    update qh.num_good
+*/
+void qh_markkeep(qhT *qh, facetT *facetlist) {
+  facetT *facet, **facetp;
+  setT *facets= qh_settemp(qh, qh->num_facets);
+  int size, count;
+
+  trace2((qh, qh->ferr, 2006, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",
+          qh->KEEParea, qh->KEEPmerge, qh->KEEPminArea));
+  FORALLfacet_(facetlist) {
+    if (!facet->visible && facet->good)
+      qh_setappend(qh, &facets, facet);
+  }
+  size= qh_setsize(qh, facets);
+  if (qh->KEEParea) {
+    qsort(SETaddr_(facets, facetT), (size_t)size,
+             sizeof(facetT *), qh_compare_facetarea);
+    if ((count= size - qh->KEEParea) > 0) {
+      FOREACHfacet_(facets) {
+        facet->good= False;
+        if (--count == 0)
+          break;
+      }
+    }
+  }
+  if (qh->KEEPmerge) {
+    qsort(SETaddr_(facets, facetT), (size_t)size,
+             sizeof(facetT *), qh_compare_nummerge);
+    if ((count= size - qh->KEEPmerge) > 0) {
+      FOREACHfacet_(facets) {
+        facet->good= False;
+        if (--count == 0)
+          break;
+      }
+    }
+  }
+  if (qh->KEEPminArea < REALmax/2) {
+    FOREACHfacet_(facets) {
+      if (!facet->isarea || facet->f.area < qh->KEEPminArea)
+        facet->good= False;
+    }
+  }
+  qh_settempfree(qh, &facets);
+  count= 0;
+  FORALLfacet_(facetlist) {
+    if (facet->good)
+      count++;
+  }
+  qh->num_good= count;
+} /* markkeep */
+
+
+/*---------------------------------
+
+  qh_markvoronoi(qh, facetlist, facets, printall, isLower, numcenters )
+    mark voronoi vertices for printing by site pairs
+
+  returns:
+    temporary set of vertices indexed by pointid
+    isLower set if printing lower hull (i.e., at least one facet is lower hull)
+    numcenters= total number of Voronoi vertices
+    bumps qh.printoutnum for vertex-at-infinity
+    clears all facet->seen and sets facet->seen2
+
+    if selected
+      facet->visitid= Voronoi vertex id
+    else if upper hull (or 'Qu' and lower hull)
+      facet->visitid= 0
+    else
+      facet->visitid >= qh->num_facets
+
+  notes:
+    ignores qh.ATinfinity, if defined
+*/
+setT *qh_markvoronoi(qhT *qh, facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp) {
+  int numcenters=0;
+  facetT *facet, **facetp;
+  setT *vertices;
+  boolT isLower= False;
+
+  qh->printoutnum++;
+  qh_clearcenters(qh, qh_ASvoronoi);  /* in case, qh_printvdiagram2 called by user */
+  qh_vertexneighbors(qh);
+  vertices= qh_pointvertex(qh);
+  if (qh->ATinfinity)
+    SETelem_(vertices, qh->num_points-1)= NULL;
+  qh->visit_id++;
+  maximize_(qh->visit_id, (unsigned int)qh->num_facets);
+  FORALLfacet_(facetlist) {
+    if (printall || !qh_skipfacet(qh, facet)) {
+      if (!facet->upperdelaunay) {
+        isLower= True;
+        break;
+      }
+    }
+  }
+  FOREACHfacet_(facets) {
+    if (printall || !qh_skipfacet(qh, facet)) {
+      if (!facet->upperdelaunay) {
+        isLower= True;
+        break;
+      }
+    }
+  }
+  FORALLfacets {
+    if (facet->normal && (facet->upperdelaunay == isLower))
+      facet->visitid= 0;  /* facetlist or facets may overwrite */
+    else
+      facet->visitid= qh->visit_id;
+    facet->seen= False;
+    facet->seen2= True;
+  }
+  numcenters++;  /* qh_INFINITE */
+  FORALLfacet_(facetlist) {
+    if (printall || !qh_skipfacet(qh, facet))
+      facet->visitid= (unsigned int)(numcenters++);
+  }
+  FOREACHfacet_(facets) {
+    if (printall || !qh_skipfacet(qh, facet))
+      facet->visitid= (unsigned int)(numcenters++);
+  }
+  *isLowerp= isLower;
+  *numcentersp= numcenters;
+  trace2((qh, qh->ferr, 2007, "qh_markvoronoi: isLower %d numcenters %d\n", isLower, numcenters));
+  return vertices;
+} /* markvoronoi */
+
+/*---------------------------------
+
+  qh_order_vertexneighbors(qh, vertex )
+    order facet neighbors of vertex by 2-d (orientation), 3-d (adjacency), or n-d (f.visitid,id)
+
+  notes:
+    error if qh_vertexneighbors not called beforehand
+    only 2-d orients the neighbors
+    for 4-d and higher
+      set or clear f.visitid for qh_compare_facetvisit
+      for example, use qh_markvoronoi (e.g., qh_printvornoi) or qh_countfacets (e.g., qh_printvneighbors)
+
+  design (2-d):
+    see qh_printextremes_2d
+  design (3-d):
+    initialize a new neighbor set with the first facet in vertex->neighbors
+    while vertex->neighbors non-empty
+      select next neighbor in the previous facet's neighbor set
+    set vertex->neighbors to the new neighbor set
+  design (n-d):
+    qsort by f.visitid, or f.facetid (qh_compare_facetvisit)
+    facet_id is negated (sorted before visit_id facets)
+*/
+void qh_order_vertexneighbors(qhT *qh, vertexT *vertex) {
+  setT *newset;
+  facetT *facet, *facetA, *facetB, *neighbor, **neighborp;
+  vertexT *vertexA;
+  int numneighbors;
+
+  trace4((qh, qh->ferr, 4018, "qh_order_vertexneighbors: order facet neighbors of v%d by 2-d (orientation), 3-d (adjacency), or n-d (f.visitid,id)\n", vertex->id));
+  if (!qh->VERTEXneighbors) {
+    qh_fprintf(qh, qh->ferr, 6428, "qhull internal error (qh_order_vertexneighbors): call qh_vertexneighbors before calling qh_order_vertexneighbors\n");
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  if (qh->hull_dim == 2) {
+    facetA= SETfirstt_(vertex->neighbors, facetT);
+    if (facetA->toporient ^ qh_ORIENTclock)
+      vertexA= SETfirstt_(facetA->vertices, vertexT);
+    else
+      vertexA= SETsecondt_(facetA->vertices, vertexT);
+    if (vertexA!=vertex) {
+      facetB= SETsecondt_(vertex->neighbors, facetT);
+      SETfirst_(vertex->neighbors)= facetB;
+      SETsecond_(vertex->neighbors)= facetA;
+    }
+  }else if (qh->hull_dim == 3) {
+    newset= qh_settemp(qh, qh_setsize(qh, vertex->neighbors));
+    facet= (facetT *)qh_setdellast(vertex->neighbors);
+    qh_setappend(qh, &newset, facet);
+    while (qh_setsize(qh, vertex->neighbors)) {
+      FOREACHneighbor_(vertex) {
+        if (qh_setin(facet->neighbors, neighbor)) {
+          qh_setdel(vertex->neighbors, neighbor);
+          qh_setappend(qh, &newset, neighbor);
+          facet= neighbor;
+          break;
+        }
+      }
+      if (!neighbor) {
+        qh_fprintf(qh, qh->ferr, 6066, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
+          vertex->id, facet->id);
+        qh_errexit(qh, qh_ERRqhull, facet, NULL);
+      }
+    }
+    qh_setfree(qh, &vertex->neighbors);
+    qh_settemppop(qh);
+    vertex->neighbors= newset;
+  }else { /* qh.hull_dim >= 4 */
+    numneighbors= qh_setsize(qh, vertex->neighbors);
+    qsort(SETaddr_(vertex->neighbors, facetT), (size_t)numneighbors,
+        sizeof(facetT *), qh_compare_facetvisit);
+  }
+} /* order_vertexneighbors */
+
+/*---------------------------------
+
+  qh_prepare_output(qh )
+    prepare for qh_produce_output2(qh) according to
+      qh.KEEPminArea, KEEParea, KEEPmerge, GOODvertex, GOODthreshold, GOODpoint, ONLYgood, SPLITthresholds
+    does not reset facet->good
+
+  notes
+    called by qh_produce_output, qh_new_qhull, Qhull.outputQhull
+    except for PRINTstatistics, no-op if previously called with same options
+*/
+void qh_prepare_output(qhT *qh) {
+  if (qh->VORONOI) {
+    qh_clearcenters(qh, qh_ASvoronoi);  /* must be before qh_triangulate */
+    qh_vertexneighbors(qh);
+  }
+  if (qh->TRIangulate && !qh->hasTriangulation) {
+    qh_triangulate(qh);
+    if (qh->VERIFYoutput && !qh->CHECKfrequently)
+      qh_checkpolygon(qh, qh->facet_list);
+  }
+  qh_findgood_all(qh, qh->facet_list);
+  if (qh->GETarea)
+    qh_getarea(qh, qh->facet_list);
+  if (qh->KEEParea || qh->KEEPmerge || qh->KEEPminArea < REALmax/2)
+    qh_markkeep(qh, qh->facet_list);
+  if (qh->PRINTstatistics)
+    qh_collectstatistics(qh);
+}
+
+/*---------------------------------
+
+  qh_printafacet(qh, fp, format, facet, printall )
+    print facet to fp in given output format (see qh.PRINTout)
+
+  returns:
+    nop if !printall and qh_skipfacet()
+    nop if visible facet and NEWfacets and format != PRINTfacets
+    must match qh_countfacets
+
+  notes
+    preserves qh.visit_id
+    facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge
+
+  see
+    qh_printbegin() and qh_printend()
+
+  design:
+    test for printing facet
+    call appropriate routine for format
+    or output results directly
+*/
+void qh_printafacet(qhT *qh, FILE *fp, qh_PRINT format, facetT *facet, boolT printall) {
+  realT color[4], offset, dist, outerplane, innerplane;
+  boolT zerodiv;
+  coordT *point, *normp, *coordp, **pointp, *feasiblep;
+  int k;
+  vertexT *vertex, **vertexp;
+  facetT *neighbor, **neighborp;
+
+  if (!printall && qh_skipfacet(qh, facet))
+    return;
+  if (facet->visible && qh->NEWfacets && format != qh_PRINTfacets)
+    return;
+  qh->printoutnum++;
+  switch (format) {
+  case qh_PRINTarea:
+    if (facet->isarea) {
+      qh_fprintf(qh, fp, 9009, qh_REAL_1, facet->f.area);
+      qh_fprintf(qh, fp, 9010, "\n");
+    }else
+      qh_fprintf(qh, fp, 9011, "0\n");
+    break;
+  case qh_PRINTcoplanars:
+    qh_fprintf(qh, fp, 9012, "%d", qh_setsize(qh, facet->coplanarset));
+    FOREACHpoint_(facet->coplanarset)
+      qh_fprintf(qh, fp, 9013, " %d", qh_pointid(qh, point));
+    qh_fprintf(qh, fp, 9014, "\n");
+    break;
+  case qh_PRINTcentrums:
+    qh_printcenter(qh, fp, format, NULL, facet);
+    break;
+  case qh_PRINTfacets:
+    qh_printfacet(qh, fp, facet);
+    break;
+  case qh_PRINTfacets_xridge:
+    qh_printfacetheader(qh, fp, facet);
+    break;
+  case qh_PRINTgeom:  /* either 2 , 3, or 4-d by qh_printbegin */
+    if (!facet->normal)
+      break;
+    for (k=qh->hull_dim; k--; ) {
+      color[k]= (facet->normal[k]+1.0)/2.0;
+      maximize_(color[k], -1.0);
+      minimize_(color[k], +1.0);
+    }
+    qh_projectdim3(qh, color, color);
+    if (qh->PRINTdim != qh->hull_dim)
+      qh_normalize2(qh, color, 3, True, NULL, NULL);
+    if (qh->hull_dim <= 2)
+      qh_printfacet2geom(qh, fp, facet, color);
+    else if (qh->hull_dim == 3) {
+      if (facet->simplicial)
+        qh_printfacet3geom_simplicial(qh, fp, facet, color);
+      else
+        qh_printfacet3geom_nonsimplicial(qh, fp, facet, color);
+    }else {
+      if (facet->simplicial)
+        qh_printfacet4geom_simplicial(qh, fp, facet, color);
+      else
+        qh_printfacet4geom_nonsimplicial(qh, fp, facet, color);
+    }
+    break;
+  case qh_PRINTids:
+    qh_fprintf(qh, fp, 9015, "%d\n", facet->id);
+    break;
+  case qh_PRINTincidences:
+  case qh_PRINToff:
+  case qh_PRINTtriangles:
+    if (qh->hull_dim == 3 && format != qh_PRINTtriangles)
+      qh_printfacet3vertex(qh, fp, facet, format);
+    else if (facet->simplicial || qh->hull_dim == 2 || format == qh_PRINToff)
+      qh_printfacetNvertex_simplicial(qh, fp, facet, format);
+    else
+      qh_printfacetNvertex_nonsimplicial(qh, fp, facet, qh->printoutvar++, format);
+    break;
+  case qh_PRINTinner:
+    qh_outerinner(qh, facet, NULL, &innerplane);
+    offset= facet->offset - innerplane;
+    goto LABELprintnorm;
+    break; /* prevent warning */
+  case qh_PRINTmerges:
+    qh_fprintf(qh, fp, 9016, "%d\n", facet->nummerge);
+    break;
+  case qh_PRINTnormals:
+    offset= facet->offset;
+    goto LABELprintnorm;
+    break; /* prevent warning */
+  case qh_PRINTouter:
+    qh_outerinner(qh, facet, &outerplane, NULL);
+    offset= facet->offset - outerplane;
+  LABELprintnorm:
+    if (!facet->normal) {
+      qh_fprintf(qh, fp, 9017, "no normal for facet f%d\n", facet->id);
+      break;
+    }
+    if (qh->CDDoutput) {
+      qh_fprintf(qh, fp, 9018, qh_REAL_1, -offset);
+      for (k=0; k < qh->hull_dim; k++)
+        qh_fprintf(qh, fp, 9019, qh_REAL_1, -facet->normal[k]);
+    }else {
+      for (k=0; k < qh->hull_dim; k++)
+        qh_fprintf(qh, fp, 9020, qh_REAL_1, facet->normal[k]);
+      qh_fprintf(qh, fp, 9021, qh_REAL_1, offset);
+    }
+    qh_fprintf(qh, fp, 9022, "\n");
+    break;
+  case qh_PRINTmathematica:  /* either 2 or 3-d by qh_printbegin */
+  case qh_PRINTmaple:
+    if (qh->hull_dim == 2)
+      qh_printfacet2math(qh, fp, facet, format, qh->printoutvar++);
+    else
+      qh_printfacet3math(qh, fp, facet, format, qh->printoutvar++);
+    break;
+  case qh_PRINTneighbors:
+    qh_fprintf(qh, fp, 9023, "%d", qh_setsize(qh, facet->neighbors));
+    FOREACHneighbor_(facet)
+      qh_fprintf(qh, fp, 9024, " %d",
+               neighbor->visitid ? neighbor->visitid - 1: 0 - neighbor->id);
+    qh_fprintf(qh, fp, 9025, "\n");
+    break;
+  case qh_PRINTpointintersect:
+    if (!qh->feasible_point) {
+      qh_fprintf(qh, qh->ferr, 6067, "qhull input error (qh_printafacet): option 'Fp' needs qh->feasible_point\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    if (facet->offset > 0)
+      goto LABELprintinfinite;
+    point= coordp= (coordT *)qh_memalloc(qh, qh->normal_size);
+    normp= facet->normal;
+    feasiblep= qh->feasible_point;
+    if (facet->offset < -qh->MINdenom) {
+      for (k=qh->hull_dim; k--; )
+        *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
+    }else {
+      for (k=qh->hull_dim; k--; ) {
+        *(coordp++)= qh_divzero(*(normp++), facet->offset, qh->MINdenom_1,
+                                 &zerodiv) + *(feasiblep++);
+        if (zerodiv) {
+          qh_memfree(qh, point, qh->normal_size);
+          goto LABELprintinfinite;
+        }
+      }
+    }
+    qh_printpoint(qh, fp, NULL, point);
+    qh_memfree(qh, point, qh->normal_size);
+    break;
+  LABELprintinfinite:
+    for (k=qh->hull_dim; k--; )
+      qh_fprintf(qh, fp, 9026, qh_REAL_1, qh_INFINITE);
+    qh_fprintf(qh, fp, 9027, "\n");
+    break;
+  case qh_PRINTpointnearest:
+    FOREACHpoint_(facet->coplanarset) {
+      int id, id2;
+      vertex= qh_nearvertex(qh, facet, point, &dist);
+      id= qh_pointid(qh, vertex->point);
+      id2= qh_pointid(qh, point);
+      qh_fprintf(qh, fp, 9028, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
+    }
+    break;
+  case qh_PRINTpoints:  /* VORONOI only by qh_printbegin */
+    if (qh->CDDoutput)
+      qh_fprintf(qh, fp, 9029, "1 ");
+    qh_printcenter(qh, fp, format, NULL, facet);
+    break;
+  case qh_PRINTvertices:
+    qh_fprintf(qh, fp, 9030, "%d", qh_setsize(qh, facet->vertices));
+    FOREACHvertex_(facet->vertices)
+      qh_fprintf(qh, fp, 9031, " %d", qh_pointid(qh, vertex->point));
+    qh_fprintf(qh, fp, 9032, "\n");
+    break;
+  default:
+    break;
+  }
+} /* printafacet */
+
+/*---------------------------------
+
+  qh_printbegin(qh )
+    prints header for all output formats
+
+  returns:
+    checks for valid format
+
+  notes:
+    uses qh.visit_id for 3/4off
+    changes qh.interior_point if printing centrums
+    qh_countfacets clears facet->visitid for non-good facets
+
+  see
+    qh_printend() and qh_printafacet()
+
+  design:
+    count facets and related statistics
+    print header for format
+*/
+void qh_printbegin(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
+  int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
+  int i, num;
+  facetT *facet, **facetp;
+  vertexT *vertex, **vertexp;
+  setT *vertices;
+  pointT *point, **pointp, *pointtemp;
+
+  qh->printoutnum= 0;
+  qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
+  switch (format) {
+  case qh_PRINTnone:
+    break;
+  case qh_PRINTarea:
+    qh_fprintf(qh, fp, 9033, "%d\n", numfacets);
+    break;
+  case qh_PRINTcoplanars:
+    qh_fprintf(qh, fp, 9034, "%d\n", numfacets);
+    break;
+  case qh_PRINTcentrums:
+    if (qh->CENTERtype == qh_ASnone)
+      qh_clearcenters(qh, qh_AScentrum);
+    qh_fprintf(qh, fp, 9035, "%d\n%d\n", qh->hull_dim, numfacets);
+    break;
+  case qh_PRINTfacets:
+  case qh_PRINTfacets_xridge:
+    if (facetlist)
+      qh_printvertexlist(qh, fp, "Vertices and facets:\n", facetlist, facets, printall);
+    break;
+  case qh_PRINTgeom:
+    if (qh->hull_dim > 4)  /* qh_initqhull_globals also checks */
+      goto LABELnoformat;
+    if (qh->VORONOI && qh->hull_dim > 3)  /* PRINTdim == DROPdim == hull_dim-1 */
+      goto LABELnoformat;
+    if (qh->hull_dim == 2 && (qh->PRINTridges || qh->DOintersections))
+      qh_fprintf(qh, qh->ferr, 7049, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
+    if (qh->hull_dim == 4 && (qh->PRINTinner || qh->PRINTouter ||
+                             (qh->PRINTdim == 4 && qh->PRINTcentrums)))
+      qh_fprintf(qh, qh->ferr, 7050, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
+    if (qh->PRINTdim == 4 && (qh->PRINTspheres))
+      qh_fprintf(qh, qh->ferr, 7051, "qhull warning: output for vertices not implemented in 4-d\n");
+    if (qh->PRINTdim == 4 && qh->DOintersections && qh->PRINTnoplanes)
+      qh_fprintf(qh, qh->ferr, 7052, "qhull warning: 'Gnh' generates no output in 4-d\n");
+    if (qh->PRINTdim == 2) {
+      qh_fprintf(qh, fp, 9036, "{appearance {linewidth 3} LIST # %s | %s\n",
+              qh->rbox_command, qh->qhull_command);
+    }else if (qh->PRINTdim == 3) {
+      qh_fprintf(qh, fp, 9037, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
+              qh->rbox_command, qh->qhull_command);
+    }else if (qh->PRINTdim == 4) {
+      qh->visit_id++;
+      num= 0;
+      FORALLfacet_(facetlist)    /* get number of ridges to be printed */
+        qh_printend4geom(qh, NULL, facet, &num, printall);
+      FOREACHfacet_(facets)
+        qh_printend4geom(qh, NULL, facet, &num, printall);
+      qh->ridgeoutnum= num;
+      qh->printoutvar= 0;  /* counts number of ridges in output */
+      qh_fprintf(qh, fp, 9038, "LIST # %s | %s\n", qh->rbox_command, qh->qhull_command);
+    }
+
+    if (qh->PRINTdots) {
+      qh->printoutnum++;
+      num= qh->num_points + qh_setsize(qh, qh->other_points);
+      if (qh->DELAUNAY && qh->ATinfinity)
+        num--;
+      if (qh->PRINTdim == 4)
+        qh_fprintf(qh, fp, 9039, "4VECT %d %d 1\n", num, num);
+      else
+        qh_fprintf(qh, fp, 9040, "VECT %d %d 1\n", num, num);
+
+      for (i=num; i--; ) {
+        if (i % 20 == 0)
+          qh_fprintf(qh, fp, 9041, "\n");
+        qh_fprintf(qh, fp, 9042, "1 ");
+      }
+      qh_fprintf(qh, fp, 9043, "# 1 point per line\n1 ");
+      for (i=num-1; i--; ) { /* num at least 3 for D2 */
+        if (i % 20 == 0)
+          qh_fprintf(qh, fp, 9044, "\n");
+        qh_fprintf(qh, fp, 9045, "0 ");
+      }
+      qh_fprintf(qh, fp, 9046, "# 1 color for all\n");
+      FORALLpoints {
+        if (!qh->DELAUNAY || !qh->ATinfinity || qh_pointid(qh, point) != qh->num_points-1) {
+          if (qh->PRINTdim == 4)
+            qh_printpoint(qh, fp, NULL, point);
+            else
+              qh_printpoint3(qh, fp, point);
+        }
+      }
+      FOREACHpoint_(qh->other_points) {
+        if (qh->PRINTdim == 4)
+          qh_printpoint(qh, fp, NULL, point);
+        else
+          qh_printpoint3(qh, fp, point);
+      }
+      qh_fprintf(qh, fp, 9047, "0 1 1 1  # color of points\n");
+    }
+
+    if (qh->PRINTdim == 4  && !qh->PRINTnoplanes)
+      /* 4dview loads up multiple 4OFF objects slowly */
+      qh_fprintf(qh, fp, 9048, "4OFF %d %d 1\n", 3*qh->ridgeoutnum, qh->ridgeoutnum);
+    qh->PRINTcradius= 2 * qh->DISTround;  /* include test DISTround */
+    if (qh->PREmerge) {
+      maximize_(qh->PRINTcradius, qh->premerge_centrum + qh->DISTround);
+    }else if (qh->POSTmerge)
+      maximize_(qh->PRINTcradius, qh->postmerge_centrum + qh->DISTround);
+    qh->PRINTradius= qh->PRINTcradius;
+    if (qh->PRINTspheres + qh->PRINTcoplanar)
+      maximize_(qh->PRINTradius, qh->MAXabs_coord * qh_MINradius);
+    if (qh->premerge_cos < REALmax/2) {
+      maximize_(qh->PRINTradius, (1- qh->premerge_cos) * qh->MAXabs_coord);
+    }else if (!qh->PREmerge && qh->POSTmerge && qh->postmerge_cos < REALmax/2) {
+      maximize_(qh->PRINTradius, (1- qh->postmerge_cos) * qh->MAXabs_coord);
+    }
+    maximize_(qh->PRINTradius, qh->MINvisible);
+    if (qh->JOGGLEmax < REALmax/2)
+      qh->PRINTradius += qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
+    if (qh->PRINTdim != 4 &&
+        (qh->PRINTcoplanar || qh->PRINTspheres || qh->PRINTcentrums)) {
+      vertices= qh_facetvertices(qh, facetlist, facets, printall);
+      if (qh->PRINTspheres && qh->PRINTdim <= 3)
+        qh_printspheres(qh, fp, vertices, qh->PRINTradius);
+      if (qh->PRINTcoplanar || qh->PRINTcentrums) {
+        qh->firstcentrum= True;
+        if (qh->PRINTcoplanar&& !qh->PRINTspheres) {
+          FOREACHvertex_(vertices)
+            qh_printpointvect2(qh, fp, vertex->point, NULL, qh->interior_point, qh->PRINTradius);
+        }
+        FORALLfacet_(facetlist) {
+          if (!printall && qh_skipfacet(qh, facet))
+            continue;
+          if (!facet->normal)
+            continue;
+          if (qh->PRINTcentrums && qh->PRINTdim <= 3)
+            qh_printcentrum(qh, fp, facet, qh->PRINTcradius);
+          if (!qh->PRINTcoplanar)
+            continue;
+          FOREACHpoint_(facet->coplanarset)
+            qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
+          FOREACHpoint_(facet->outsideset)
+            qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
+        }
+        FOREACHfacet_(facets) {
+          if (!printall && qh_skipfacet(qh, facet))
+            continue;
+          if (!facet->normal)
+            continue;
+          if (qh->PRINTcentrums && qh->PRINTdim <= 3)
+            qh_printcentrum(qh, fp, facet, qh->PRINTcradius);
+          if (!qh->PRINTcoplanar)
+            continue;
+          FOREACHpoint_(facet->coplanarset)
+            qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
+          FOREACHpoint_(facet->outsideset)
+            qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);
+        }
+      }
+      qh_settempfree(qh, &vertices);
+    }
+    qh->visit_id++; /* for printing hyperplane intersections */
+    break;
+  case qh_PRINTids:
+    qh_fprintf(qh, fp, 9049, "%d\n", numfacets);
+    break;
+  case qh_PRINTincidences:
+    if (qh->VORONOI && qh->PRINTprecision)
+      qh_fprintf(qh, qh->ferr, 7053, "qhull warning: input sites of Delaunay regions (option 'i').  Use option 'p' or 'o' for Voronoi centers.  Disable warning with option 'Pp'\n");
+    qh->printoutvar= (int)qh->vertex_id;  /* centrum id for 4-d+, non-simplicial facets */
+    if (qh->hull_dim <= 3)
+      qh_fprintf(qh, fp, 9050, "%d\n", numfacets);
+    else
+      qh_fprintf(qh, fp, 9051, "%d\n", numsimplicial+numridges);
+    break;
+  case qh_PRINTinner:
+  case qh_PRINTnormals:
+  case qh_PRINTouter:
+    if (qh->CDDoutput)
+      qh_fprintf(qh, fp, 9052, "%s | %s\nbegin\n    %d %d real\n", qh->rbox_command,
+            qh->qhull_command, numfacets, qh->hull_dim+1);
+    else
+      qh_fprintf(qh, fp, 9053, "%d\n%d\n", qh->hull_dim+1, numfacets);
+    break;
+  case qh_PRINTmathematica:
+  case qh_PRINTmaple:
+    if (qh->hull_dim > 3)  /* qh_initbuffers also checks */
+      goto LABELnoformat;
+    if (qh->VORONOI)
+      qh_fprintf(qh, qh->ferr, 7054, "qhull warning: output is the Delaunay triangulation\n");
+    if (format == qh_PRINTmaple) {
+      if (qh->hull_dim == 2)
+        qh_fprintf(qh, fp, 9054, "PLOT(CURVES(\n");
+      else
+        qh_fprintf(qh, fp, 9055, "PLOT3D(POLYGONS(\n");
+    }else
+      qh_fprintf(qh, fp, 9056, "{\n");
+    qh->printoutvar= 0;   /* counts number of facets for notfirst */
+    break;
+  case qh_PRINTmerges:
+    qh_fprintf(qh, fp, 9057, "%d\n", numfacets);
+    break;
+  case qh_PRINTpointintersect:
+    qh_fprintf(qh, fp, 9058, "%d\n%d\n", qh->hull_dim, numfacets);
+    break;
+  case qh_PRINTneighbors:
+    qh_fprintf(qh, fp, 9059, "%d\n", numfacets);
+    break;
+  case qh_PRINToff:
+  case qh_PRINTtriangles:
+    if (qh->VORONOI)
+      goto LABELnoformat;
+    num= qh->hull_dim;
+    if (format == qh_PRINToff || qh->hull_dim == 2)
+      qh_fprintf(qh, fp, 9060, "%d\n%d %d %d\n", num,
+        qh->num_points+qh_setsize(qh, qh->other_points), numfacets, totneighbors/2);
+    else { /* qh_PRINTtriangles */
+      qh->printoutvar= qh->num_points+qh_setsize(qh, qh->other_points); /* first centrum */
+      if (qh->DELAUNAY)
+        num--;  /* drop last dimension */
+      qh_fprintf(qh, fp, 9061, "%d\n%d %d %d\n", num, qh->printoutvar
+        + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
+    }
+    FORALLpoints
+      qh_printpointid(qh, qh->fout, NULL, num, point, qh_IDunknown);
+    FOREACHpoint_(qh->other_points)
+      qh_printpointid(qh, qh->fout, NULL, num, point, qh_IDunknown);
+    if (format == qh_PRINTtriangles && qh->hull_dim > 2) {
+      FORALLfacets {
+        if (!facet->simplicial && facet->visitid)
+          qh_printcenter(qh, qh->fout, format, NULL, facet);
+      }
+    }
+    break;
+  case qh_PRINTpointnearest:
+    qh_fprintf(qh, fp, 9062, "%d\n", numcoplanars);
+    break;
+  case qh_PRINTpoints:
+    if (!qh->VORONOI)
+      goto LABELnoformat;
+    if (qh->CDDoutput)
+      qh_fprintf(qh, fp, 9063, "%s | %s\nbegin\n%d %d real\n", qh->rbox_command,
+           qh->qhull_command, numfacets, qh->hull_dim);
+    else
+      qh_fprintf(qh, fp, 9064, "%d\n%d\n", qh->hull_dim-1, numfacets);
+    break;
+  case qh_PRINTvertices:
+    qh_fprintf(qh, fp, 9065, "%d\n", numfacets);
+    break;
+  case qh_PRINTsummary:
+  default:
+  LABELnoformat:
+    qh_fprintf(qh, qh->ferr, 6068, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
+         qh->hull_dim);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+} /* printbegin */
+
+/*---------------------------------
+
+  qh_printcenter(qh, fp, string, facet )
+    print facet->center as centrum or Voronoi center
+    string may be NULL.  Don't include '%' codes.
+    nop if qh->CENTERtype neither CENTERvoronoi nor CENTERcentrum
+    if upper envelope of Delaunay triangulation and point at-infinity
+      prints qh_INFINITE instead;
+
+  notes:
+    defines facet->center if needed
+    if format=PRINTgeom, adds a 0 if would otherwise be 2-d
+    Same as QhullFacet::printCenter
+*/
+void qh_printcenter(qhT *qh, FILE *fp, qh_PRINT format, const char *string, facetT *facet) {
+  int k, num;
+
+  if (qh->CENTERtype != qh_ASvoronoi && qh->CENTERtype != qh_AScentrum)
+    return;
+  if (string)
+    qh_fprintf(qh, fp, 9066, "%s", string);
+  if (qh->CENTERtype == qh_ASvoronoi) {
+    num= qh->hull_dim-1;
+    if (!facet->normal || !facet->upperdelaunay || !qh->ATinfinity) {
+      if (!facet->center)
+        facet->center= qh_facetcenter(qh, facet->vertices);
+      for (k=0; k < num; k++)
+        qh_fprintf(qh, fp, 9067, qh_REAL_1, facet->center[k]);
+    }else {
+      for (k=0; k < num; k++)
+        qh_fprintf(qh, fp, 9068, qh_REAL_1, qh_INFINITE);
+    }
+  }else /* qh.CENTERtype == qh_AScentrum */ {
+    num= qh->hull_dim;
+    if (format == qh_PRINTtriangles && qh->DELAUNAY)
+      num--;
+    if (!facet->center)
+      facet->center= qh_getcentrum(qh, facet);
+    for (k=0; k < num; k++)
+      qh_fprintf(qh, fp, 9069, qh_REAL_1, facet->center[k]);
+  }
+  if (format == qh_PRINTgeom && num == 2)
+    qh_fprintf(qh, fp, 9070, " 0\n");
+  else
+    qh_fprintf(qh, fp, 9071, "\n");
+} /* printcenter */
+
+/*---------------------------------
+
+  qh_printcentrum(qh, fp, facet, radius )
+    print centrum for a facet in OOGL format
+    radius defines size of centrum
+    2-d or 3-d only
+
+  returns:
+    defines facet->center if needed
+*/
+void qh_printcentrum(qhT *qh, FILE *fp, facetT *facet, realT radius) {
+  pointT *centrum, *projpt;
+  boolT tempcentrum= False;
+  realT xaxis[4], yaxis[4], normal[4], dist;
+  realT green[3]={0, 1, 0};
+  vertexT *apex;
+  int k;
+
+  if (qh->CENTERtype == qh_AScentrum) {
+    if (!facet->center)
+      facet->center= qh_getcentrum(qh, facet);
+    centrum= facet->center;
+  }else {
+    centrum= qh_getcentrum(qh, facet);
+    tempcentrum= True;
+  }
+  qh_fprintf(qh, fp, 9072, "{appearance {-normal -edge normscale 0} ");
+  if (qh->firstcentrum) {
+    qh->firstcentrum= False;
+    qh_fprintf(qh, fp, 9073, "{INST geom { define centrum CQUAD  # f%d\n\
+-0.3 -0.3 0.0001     0 0 1 1\n\
+ 0.3 -0.3 0.0001     0 0 1 1\n\
+ 0.3  0.3 0.0001     0 0 1 1\n\
+-0.3  0.3 0.0001     0 0 1 1 } transform { \n", facet->id);
+  }else
+    qh_fprintf(qh, fp, 9074, "{INST geom { : centrum } transform { # f%d\n", facet->id);
+  apex= SETfirstt_(facet->vertices, vertexT);
+  qh_distplane(qh, apex->point, facet, &dist);
+  projpt= qh_projectpoint(qh, apex->point, facet, dist);
+  for (k=qh->hull_dim; k--; ) {
+    xaxis[k]= projpt[k] - centrum[k];
+    normal[k]= facet->normal[k];
+  }
+  if (qh->hull_dim == 2) {
+    xaxis[2]= 0;
+    normal[2]= 0;
+  }else if (qh->hull_dim == 4) {
+    qh_projectdim3(qh, xaxis, xaxis);
+    qh_projectdim3(qh, normal, normal);
+    qh_normalize2(qh, normal, qh->PRINTdim, True, NULL, NULL);
+  }
+  qh_crossproduct(3, xaxis, normal, yaxis);
+  qh_fprintf(qh, fp, 9075, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
+  qh_fprintf(qh, fp, 9076, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
+  qh_fprintf(qh, fp, 9077, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
+  qh_printpoint3(qh, fp, centrum);
+  qh_fprintf(qh, fp, 9078, "1 }}}\n");
+  qh_memfree(qh, projpt, qh->normal_size);
+  qh_printpointvect(qh, fp, centrum, facet->normal, NULL, radius, green);
+  if (tempcentrum)
+    qh_memfree(qh, centrum, qh->normal_size);
+} /* printcentrum */
+
+/*---------------------------------
+
+  qh_printend(qh, fp, format )
+    prints trailer for all output formats
+
+  see:
+    qh_printbegin() and qh_printafacet()
+
+*/
+void qh_printend(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
+  int num;
+  facetT *facet, **facetp;
+
+  if (!qh->printoutnum)
+    qh_fprintf(qh, qh->ferr, 7055, "qhull warning: no facets printed\n");
+  switch (format) {
+  case qh_PRINTgeom:
+    if (qh->hull_dim == 4 && qh->DROPdim < 0  && !qh->PRINTnoplanes) {
+      qh->visit_id++;
+      num= 0;
+      FORALLfacet_(facetlist)
+        qh_printend4geom(qh, fp, facet,&num, printall);
+      FOREACHfacet_(facets)
+        qh_printend4geom(qh, fp, facet, &num, printall);
+      if (num != qh->ridgeoutnum || qh->printoutvar != qh->ridgeoutnum) {
+        qh_fprintf(qh, qh->ferr, 6069, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh->ridgeoutnum, qh->printoutvar, num);
+        qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+      }
+    }else
+      qh_fprintf(qh, fp, 9079, "}\n");
+    break;
+  case qh_PRINTinner:
+  case qh_PRINTnormals:
+  case qh_PRINTouter:
+    if (qh->CDDoutput)
+      qh_fprintf(qh, fp, 9080, "end\n");
+    break;
+  case qh_PRINTmaple:
+    qh_fprintf(qh, fp, 9081, "));\n");
+    break;
+  case qh_PRINTmathematica:
+    qh_fprintf(qh, fp, 9082, "}\n");
+    break;
+  case qh_PRINTpoints:
+    if (qh->CDDoutput)
+      qh_fprintf(qh, fp, 9083, "end\n");
+    break;
+  default:
+    break;
+  }
+} /* printend */
+
+/*---------------------------------
+
+  qh_printend4geom(qh, fp, facet, numridges, printall )
+    helper function for qh_printbegin/printend
+
+  returns:
+    number of printed ridges
+
+  notes:
+    just counts printed ridges if fp=NULL
+    uses facet->visitid
+    must agree with qh_printfacet4geom...
+
+  design:
+    computes color for facet from its normal
+    prints each ridge of facet
+*/
+void qh_printend4geom(qhT *qh, FILE *fp, facetT *facet, int *nump, boolT printall) {
+  realT color[3];
+  int i, num= *nump;
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+
+  if (!printall && qh_skipfacet(qh, facet))
+    return;
+  if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))
+    return;
+  if (!facet->normal)
+    return;
+  if (fp) {
+    for (i=0; i < 3; i++) {
+      color[i]= (facet->normal[i]+1.0)/2.0;
+      maximize_(color[i], -1.0);
+      minimize_(color[i], +1.0);
+    }
+  }
+  facet->visitid= qh->visit_id;
+  if (facet->simplicial) {
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh->visit_id) {
+        if (fp)
+          qh_fprintf(qh, fp, 9084, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
+                 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
+                 facet->id, neighbor->id);
+        num++;
+      }
+    }
+  }else {
+    FOREACHridge_(facet->ridges) {
+      neighbor= otherfacet_(ridge, facet);
+      if (neighbor->visitid != qh->visit_id) {
+        if (fp)
+          qh_fprintf(qh, fp, 9085, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
+                 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
+                 ridge->id, facet->id, neighbor->id);
+        num++;
+      }
+    }
+  }
+  *nump= num;
+} /* printend4geom */
+
+/*---------------------------------
+
+  qh_printextremes(qh, fp, facetlist, facets, printall )
+    print extreme points for convex hulls or halfspace intersections
+
+  notes:
+    #points, followed by ids, one per line
+
+    sorted by id
+    same order as qh_printpoints_out if no coplanar/interior points
+*/
+void qh_printextremes(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
+  setT *vertices, *points;
+  pointT *point;
+  vertexT *vertex, **vertexp;
+  int id;
+  int numpoints=0, point_i, point_n;
+  int allpoints= qh->num_points + qh_setsize(qh, qh->other_points);
+
+  points= qh_settemp(qh, allpoints);
+  qh_setzero(qh, points, 0, allpoints);
+  vertices= qh_facetvertices(qh, facetlist, facets, printall);
+  FOREACHvertex_(vertices) {
+    id= qh_pointid(qh, vertex->point);
+    if (id >= 0) {
+      SETelem_(points, id)= vertex->point;
+      numpoints++;
+    }
+  }
+  qh_settempfree(qh, &vertices);
+  qh_fprintf(qh, fp, 9086, "%d\n", numpoints);
+  FOREACHpoint_i_(qh, points) {
+    if (point)
+      qh_fprintf(qh, fp, 9087, "%d\n", point_i);
+  }
+  qh_settempfree(qh, &points);
+} /* printextremes */
+
+/*---------------------------------
+
+  qh_printextremes_2d(qh, fp, facetlist, facets, printall )
+    prints point ids for facets in qh_ORIENTclock order
+
+  notes:
+    #points, followed by ids, one per line
+    if facetlist/facets are disjoint than the output includes skips
+    errors if facets form a loop
+    does not print coplanar points
+*/
+void qh_printextremes_2d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
+  int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;
+  setT *vertices;
+  facetT *facet, *startfacet, *nextfacet;
+  vertexT *vertexA, *vertexB;
+
+  qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh->visit_id */
+  vertices= qh_facetvertices(qh, facetlist, facets, printall);
+  qh_fprintf(qh, fp, 9088, "%d\n", qh_setsize(qh, vertices));
+  qh_settempfree(qh, &vertices);
+  if (!numfacets)
+    return;
+  facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
+  qh->vertex_visit++;
+  qh->visit_id++;
+  do {
+    if (facet->toporient ^ qh_ORIENTclock) {
+      vertexA= SETfirstt_(facet->vertices, vertexT);
+      vertexB= SETsecondt_(facet->vertices, vertexT);
+      nextfacet= SETfirstt_(facet->neighbors, facetT);
+    }else {
+      vertexA= SETsecondt_(facet->vertices, vertexT);
+      vertexB= SETfirstt_(facet->vertices, vertexT);
+      nextfacet= SETsecondt_(facet->neighbors, facetT);
+    }
+    if (facet->visitid == qh->visit_id) {
+      qh_fprintf(qh, qh->ferr, 6218, "qhull internal error (qh_printextremes_2d): loop in facet list.  facet %d nextfacet %d\n",
+                 facet->id, nextfacet->id);
+      qh_errexit2(qh, qh_ERRqhull, facet, nextfacet);
+    }
+    if (facet->visitid) {
+      if (vertexA->visitid != qh->vertex_visit) {
+        vertexA->visitid= qh->vertex_visit;
+        qh_fprintf(qh, fp, 9089, "%d\n", qh_pointid(qh, vertexA->point));
+      }
+      if (vertexB->visitid != qh->vertex_visit) {
+        vertexB->visitid= qh->vertex_visit;
+        qh_fprintf(qh, fp, 9090, "%d\n", qh_pointid(qh, vertexB->point));
+      }
+    }
+    facet->visitid= qh->visit_id;
+    facet= nextfacet;
+  }while (facet && facet != startfacet);
+} /* printextremes_2d */
+
+/*---------------------------------
+
+  qh_printextremes_d(qh, fp, facetlist, facets, printall )
+    print extreme points of input sites for Delaunay triangulations
+
+  notes:
+    #points, followed by ids, one per line
+
+    unordered
+*/
+void qh_printextremes_d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
+  setT *vertices;
+  vertexT *vertex, **vertexp;
+  boolT upperseen, lowerseen;
+  facetT *neighbor, **neighborp;
+  int numpoints=0;
+
+  vertices= qh_facetvertices(qh, facetlist, facets, printall);
+  qh_vertexneighbors(qh);
+  FOREACHvertex_(vertices) {
+    upperseen= lowerseen= False;
+    FOREACHneighbor_(vertex) {
+      if (neighbor->upperdelaunay)
+        upperseen= True;
+      else
+        lowerseen= True;
+    }
+    if (upperseen && lowerseen) {
+      vertex->seen= True;
+      numpoints++;
+    }else
+      vertex->seen= False;
+  }
+  qh_fprintf(qh, fp, 9091, "%d\n", numpoints);
+  FOREACHvertex_(vertices) {
+    if (vertex->seen)
+      qh_fprintf(qh, fp, 9092, "%d\n", qh_pointid(qh, vertex->point));
+  }
+  qh_settempfree(qh, &vertices);
+} /* printextremes_d */
+
+/*---------------------------------
+
+  qh_printfacet(qh, fp, facet )
+    prints all fields of a facet to fp
+
+  notes:
+    ridges printed in neighbor order
+*/
+void qh_printfacet(qhT *qh, FILE *fp, facetT *facet) {
+
+  qh_printfacetheader(qh, fp, facet);
+  if (facet->ridges)
+    qh_printfacetridges(qh, fp, facet);
+} /* printfacet */
+
+
+/*---------------------------------
+
+  qh_printfacet2geom(qh, fp, facet, color )
+    print facet as part of a 2-d VECT for Geomview
+
+    notes:
+      assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon
+      mindist is calculated within io_r.c.  maxoutside is calculated elsewhere
+      so a DISTround error may have occurred.
+*/
+void qh_printfacet2geom(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
+  pointT *point0, *point1;
+  realT mindist, innerplane, outerplane;
+  int k;
+
+  qh_facet2point(qh, facet, &point0, &point1, &mindist);
+  qh_geomplanes(qh, facet, &outerplane, &innerplane);
+  if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))
+    qh_printfacet2geom_points(qh, fp, point0, point1, facet, outerplane, color);
+  if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&
+                outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {
+    for (k=3; k--; )
+      color[k]= 1.0 - color[k];
+    qh_printfacet2geom_points(qh, fp, point0, point1, facet, innerplane, color);
+  }
+  qh_memfree(qh, point1, qh->normal_size);
+  qh_memfree(qh, point0, qh->normal_size);
+} /* printfacet2geom */
+
+/*---------------------------------
+
+  qh_printfacet2geom_points(qh, fp, point1, point2, facet, offset, color )
+    prints a 2-d facet as a VECT with 2 points at some offset.
+    The points are on the facet's plane.
+*/
+void qh_printfacet2geom_points(qhT *qh, FILE *fp, pointT *point1, pointT *point2,
+                               facetT *facet, realT offset, realT color[3]) {
+  pointT *p1= point1, *p2= point2;
+
+  qh_fprintf(qh, fp, 9093, "VECT 1 2 1 2 1 # f%d\n", facet->id);
+  if (offset != 0.0) {
+    p1= qh_projectpoint(qh, p1, facet, -offset);
+    p2= qh_projectpoint(qh, p2, facet, -offset);
+  }
+  qh_fprintf(qh, fp, 9094, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
+           p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
+  if (offset != 0.0) {
+    qh_memfree(qh, p1, qh->normal_size);
+    qh_memfree(qh, p2, qh->normal_size);
+  }
+  qh_fprintf(qh, fp, 9095, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
+} /* printfacet2geom_points */
+
+
+/*---------------------------------
+
+  qh_printfacet2math(qh, fp, facet, format, notfirst )
+    print 2-d Maple or Mathematica output for a facet
+    may be non-simplicial
+
+  notes:
+    use %16.8f since Mathematica 2.2 does not handle exponential format
+    see qh_printfacet3math
+*/
+void qh_printfacet2math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {
+  pointT *point0, *point1;
+  realT mindist;
+  const char *pointfmt;
+
+  qh_facet2point(qh, facet, &point0, &point1, &mindist);
+  if (notfirst)
+    qh_fprintf(qh, fp, 9096, ",");
+  if (format == qh_PRINTmaple)
+    pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n";
+  else
+    pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n";
+  qh_fprintf(qh, fp, 9097, pointfmt, point0[0], point0[1], point1[0], point1[1]);
+  qh_memfree(qh, point1, qh->normal_size);
+  qh_memfree(qh, point0, qh->normal_size);
+} /* printfacet2math */
+
+
+/*---------------------------------
+
+  qh_printfacet3geom_nonsimplicial(qh, fp, facet, color )
+    print Geomview OFF for a 3-d nonsimplicial facet.
+    if DOintersections, prints ridges to unvisited neighbors(qh->visit_id)
+
+  notes
+    uses facet->visitid for intersections and ridges
+*/
+void qh_printfacet3geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
+  ridgeT *ridge, **ridgep;
+  setT *projectedpoints, *vertices;
+  vertexT *vertex, **vertexp, *vertexA, *vertexB;
+  pointT *projpt, *point, **pointp;
+  facetT *neighbor;
+  realT dist, outerplane, innerplane;
+  int cntvertices, k;
+  realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
+
+  qh_geomplanes(qh, facet, &outerplane, &innerplane);
+  vertices= qh_facet3vertex(qh, facet); /* oriented */
+  cntvertices= qh_setsize(qh, vertices);
+  projectedpoints= qh_settemp(qh, cntvertices);
+  FOREACHvertex_(vertices) {
+    zinc_(Zdistio);
+    qh_distplane(qh, vertex->point, facet, &dist);
+    projpt= qh_projectpoint(qh, vertex->point, facet, dist);
+    qh_setappend(qh, &projectedpoints, projpt);
+  }
+  if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))
+    qh_printfacet3geom_points(qh, fp, projectedpoints, facet, outerplane, color);
+  if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&
+                outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {
+    for (k=3; k--; )
+      color[k]= 1.0 - color[k];
+    qh_printfacet3geom_points(qh, fp, projectedpoints, facet, innerplane, color);
+  }
+  FOREACHpoint_(projectedpoints)
+    qh_memfree(qh, point, qh->normal_size);
+  qh_settempfree(qh, &projectedpoints);
+  qh_settempfree(qh, &vertices);
+  if ((qh->DOintersections || qh->PRINTridges)
+  && (!facet->visible || !qh->NEWfacets)) {
+    facet->visitid= qh->visit_id;
+    FOREACHridge_(facet->ridges) {
+      neighbor= otherfacet_(ridge, facet);
+      if (neighbor->visitid != qh->visit_id) {
+        if (qh->DOintersections)
+          qh_printhyperplaneintersection(qh, fp, facet, neighbor, ridge->vertices, black);
+        if (qh->PRINTridges) {
+          vertexA= SETfirstt_(ridge->vertices, vertexT);
+          vertexB= SETsecondt_(ridge->vertices, vertexT);
+          qh_printline3geom(qh, fp, vertexA->point, vertexB->point, green);
+        }
+      }
+    }
+  }
+} /* printfacet3geom_nonsimplicial */
+
+/*---------------------------------
+
+  qh_printfacet3geom_points(qh, fp, points, facet, offset )
+    prints a 3-d facet as OFF Geomview object.
+    offset is relative to the facet's hyperplane
+    Facet is determined as a list of points
+*/
+void qh_printfacet3geom_points(qhT *qh, FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
+  int k, n= qh_setsize(qh, points), i;
+  pointT *point, **pointp;
+  setT *printpoints;
+
+  qh_fprintf(qh, fp, 9098, "{ OFF %d 1 1 # f%d\n", n, facet->id);
+  if (offset != 0.0) {
+    printpoints= qh_settemp(qh, n);
+    FOREACHpoint_(points)
+      qh_setappend(qh, &printpoints, qh_projectpoint(qh, point, facet, -offset));
+  }else
+    printpoints= points;
+  FOREACHpoint_(printpoints) {
+    for (k=0; k < qh->hull_dim; k++) {
+      if (k == qh->DROPdim)
+        qh_fprintf(qh, fp, 9099, "0 ");
+      else
+        qh_fprintf(qh, fp, 9100, "%8.4g ", point[k]);
+    }
+    if (printpoints != points)
+      qh_memfree(qh, point, qh->normal_size);
+    qh_fprintf(qh, fp, 9101, "\n");
+  }
+  if (printpoints != points)
+    qh_settempfree(qh, &printpoints);
+  qh_fprintf(qh, fp, 9102, "%d ", n);
+  for (i=0; i < n; i++)
+    qh_fprintf(qh, fp, 9103, "%d ", i);
+  qh_fprintf(qh, fp, 9104, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
+} /* printfacet3geom_points */
+
+
+/*---------------------------------
+
+  qh_printfacet3geom_simplicial(qh )
+    print Geomview OFF for a 3-d simplicial facet.
+
+  notes:
+    may flip color
+    uses facet->visitid for intersections and ridges
+
+    assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon
+    innerplane may be off by qh->DISTround.  Maxoutside is calculated elsewhere
+    so a DISTround error may have occurred.
+*/
+void qh_printfacet3geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
+  setT *points, *vertices;
+  vertexT *vertex, **vertexp, *vertexA, *vertexB;
+  facetT *neighbor, **neighborp;
+  realT outerplane, innerplane;
+  realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
+  int k;
+
+  qh_geomplanes(qh, facet, &outerplane, &innerplane);
+  vertices= qh_facet3vertex(qh, facet);
+  points= qh_settemp(qh, qh->TEMPsize);
+  FOREACHvertex_(vertices)
+    qh_setappend(qh, &points, vertex->point);
+  if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))
+    qh_printfacet3geom_points(qh, fp, points, facet, outerplane, color);
+  if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&
+              outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {
+    for (k=3; k--; )
+      color[k]= 1.0 - color[k];
+    qh_printfacet3geom_points(qh, fp, points, facet, innerplane, color);
+  }
+  qh_settempfree(qh, &points);
+  qh_settempfree(qh, &vertices);
+  if ((qh->DOintersections || qh->PRINTridges)
+  && (!facet->visible || !qh->NEWfacets)) {
+    facet->visitid= qh->visit_id;
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh->visit_id) {
+        vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,
+                          SETindex_(facet->neighbors, neighbor), 0);
+        if (qh->DOintersections)
+           qh_printhyperplaneintersection(qh, fp, facet, neighbor, vertices, black);
+        if (qh->PRINTridges) {
+          vertexA= SETfirstt_(vertices, vertexT);
+          vertexB= SETsecondt_(vertices, vertexT);
+          qh_printline3geom(qh, fp, vertexA->point, vertexB->point, green);
+        }
+        qh_setfree(qh, &vertices);
+      }
+    }
+  }
+} /* printfacet3geom_simplicial */
+
+/*---------------------------------
+
+  qh_printfacet3math(qh, fp, facet, notfirst )
+    print 3-d Maple or Mathematica output for a facet
+
+  notes:
+    may be non-simplicial
+    use %16.8f since Mathematica 2.2 does not handle exponential format
+    see qh_printfacet2math
+*/
+void qh_printfacet3math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {
+  vertexT *vertex, **vertexp;
+  setT *points, *vertices;
+  pointT *point, **pointp;
+  boolT firstpoint= True;
+  realT dist;
+  const char *pointfmt, *endfmt;
+
+  if (notfirst)
+    qh_fprintf(qh, fp, 9105, ",\n");
+  vertices= qh_facet3vertex(qh, facet);
+  points= qh_settemp(qh, qh_setsize(qh, vertices));
+  FOREACHvertex_(vertices) {
+    zinc_(Zdistio);
+    qh_distplane(qh, vertex->point, facet, &dist);
+    point= qh_projectpoint(qh, vertex->point, facet, dist);
+    qh_setappend(qh, &points, point);
+  }
+  if (format == qh_PRINTmaple) {
+    qh_fprintf(qh, fp, 9106, "[");
+    pointfmt= "[%16.8f, %16.8f, %16.8f]";
+    endfmt= "]";
+  }else {
+    qh_fprintf(qh, fp, 9107, "Polygon[{");
+    pointfmt= "{%16.8f, %16.8f, %16.8f}";
+    endfmt= "}]";
+  }
+  FOREACHpoint_(points) {
+    if (firstpoint)
+      firstpoint= False;
+    else
+      qh_fprintf(qh, fp, 9108, ",\n");
+    qh_fprintf(qh, fp, 9109, pointfmt, point[0], point[1], point[2]);
+  }
+  FOREACHpoint_(points)
+    qh_memfree(qh, point, qh->normal_size);
+  qh_settempfree(qh, &points);
+  qh_settempfree(qh, &vertices);
+  qh_fprintf(qh, fp, 9110, "%s", endfmt);
+} /* printfacet3math */
+
+
+/*---------------------------------
+
+  qh_printfacet3vertex(qh, fp, facet, format )
+    print vertices in a 3-d facet as point ids
+
+  notes:
+    prints number of vertices first if format == qh_PRINToff
+    the facet may be non-simplicial
+*/
+void qh_printfacet3vertex(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format) {
+  vertexT *vertex, **vertexp;
+  setT *vertices;
+
+  vertices= qh_facet3vertex(qh, facet);
+  if (format == qh_PRINToff)
+    qh_fprintf(qh, fp, 9111, "%d ", qh_setsize(qh, vertices));
+  FOREACHvertex_(vertices)
+    qh_fprintf(qh, fp, 9112, "%d ", qh_pointid(qh, vertex->point));
+  qh_fprintf(qh, fp, 9113, "\n");
+  qh_settempfree(qh, &vertices);
+} /* printfacet3vertex */
+
+
+/*---------------------------------
+
+  qh_printfacet4geom_nonsimplicial(qh )
+    print Geomview 4OFF file for a 4d nonsimplicial facet
+    prints all ridges to unvisited neighbors (qh.visit_id)
+    if qh.DROPdim
+      prints in OFF format
+
+  notes:
+    must agree with printend4geom()
+*/
+void qh_printfacet4geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
+  facetT *neighbor;
+  ridgeT *ridge, **ridgep;
+  vertexT *vertex, **vertexp;
+  pointT *point;
+  int k;
+  realT dist;
+
+  facet->visitid= qh->visit_id;
+  if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))
+    return;
+  FOREACHridge_(facet->ridges) {
+    neighbor= otherfacet_(ridge, facet);
+    if (neighbor->visitid == qh->visit_id)
+      continue;
+    if (qh->PRINTtransparent && !neighbor->good)
+      continue;
+    if (qh->DOintersections)
+      qh_printhyperplaneintersection(qh, fp, facet, neighbor, ridge->vertices, color);
+    else {
+      if (qh->DROPdim >= 0)
+        qh_fprintf(qh, fp, 9114, "OFF 3 1 1 # f%d\n", facet->id);
+      else {
+        qh->printoutvar++;
+        qh_fprintf(qh, fp, 9115, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
+      }
+      FOREACHvertex_(ridge->vertices) {
+        zinc_(Zdistio);
+        qh_distplane(qh, vertex->point,facet, &dist);
+        point=qh_projectpoint(qh, vertex->point,facet, dist);
+        for (k=0; k < qh->hull_dim; k++) {
+          if (k != qh->DROPdim)
+            qh_fprintf(qh, fp, 9116, "%8.4g ", point[k]);
+        }
+        qh_fprintf(qh, fp, 9117, "\n");
+        qh_memfree(qh, point, qh->normal_size);
+      }
+      if (qh->DROPdim >= 0)
+        qh_fprintf(qh, fp, 9118, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
+    }
+  }
+} /* printfacet4geom_nonsimplicial */
+
+
+/*---------------------------------
+
+  qh_printfacet4geom_simplicial(qh, fp, facet, color )
+    print Geomview 4OFF file for a 4d simplicial facet
+    prints triangles for unvisited neighbors (qh.visit_id)
+
+  notes:
+    must agree with printend4geom()
+*/
+void qh_printfacet4geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {
+  setT *vertices;
+  facetT *neighbor, **neighborp;
+  vertexT *vertex, **vertexp;
+  int k;
+
+  facet->visitid= qh->visit_id;
+  if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))
+    return;
+  FOREACHneighbor_(facet) {
+    if (neighbor->visitid == qh->visit_id)
+      continue;
+    if (qh->PRINTtransparent && !neighbor->good)
+      continue;
+    vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,
+                          SETindex_(facet->neighbors, neighbor), 0);
+    if (qh->DOintersections)
+      qh_printhyperplaneintersection(qh, fp, facet, neighbor, vertices, color);
+    else {
+      if (qh->DROPdim >= 0)
+        qh_fprintf(qh, fp, 9119, "OFF 3 1 1 # ridge between f%d f%d\n",
+                facet->id, neighbor->id);
+      else {
+        qh->printoutvar++;
+        qh_fprintf(qh, fp, 9120, "# ridge between f%d f%d\n", facet->id, neighbor->id);
+      }
+      FOREACHvertex_(vertices) {
+        for (k=0; k < qh->hull_dim; k++) {
+          if (k != qh->DROPdim)
+            qh_fprintf(qh, fp, 9121, "%8.4g ", vertex->point[k]);
+        }
+        qh_fprintf(qh, fp, 9122, "\n");
+      }
+      if (qh->DROPdim >= 0)
+        qh_fprintf(qh, fp, 9123, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
+    }
+    qh_setfree(qh, &vertices);
+  }
+} /* printfacet4geom_simplicial */
+
+
+/*---------------------------------
+
+  qh_printfacetNvertex_nonsimplicial(qh, fp, facet, id, format )
+    print vertices for an N-d non-simplicial facet
+    triangulates each ridge to the id
+*/
+void qh_printfacetNvertex_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, int id, qh_PRINT format) {
+  vertexT *vertex, **vertexp;
+  ridgeT *ridge, **ridgep;
+
+  if (facet->visible && qh->NEWfacets)
+    return;
+  FOREACHridge_(facet->ridges) {
+    if (format == qh_PRINTtriangles)
+      qh_fprintf(qh, fp, 9124, "%d ", qh->hull_dim);
+    qh_fprintf(qh, fp, 9125, "%d ", id);
+    if ((ridge->top == facet) ^ qh_ORIENTclock) {
+      FOREACHvertex_(ridge->vertices)
+        qh_fprintf(qh, fp, 9126, "%d ", qh_pointid(qh, vertex->point));
+    }else {
+      FOREACHvertexreverse12_(ridge->vertices)
+        qh_fprintf(qh, fp, 9127, "%d ", qh_pointid(qh, vertex->point));
+    }
+    qh_fprintf(qh, fp, 9128, "\n");
+  }
+} /* printfacetNvertex_nonsimplicial */
+
+
+/*---------------------------------
+
+  qh_printfacetNvertex_simplicial(qh, fp, facet, format )
+    print vertices for an N-d simplicial facet
+    prints vertices for non-simplicial facets
+      2-d facets (orientation preserved by qh_mergefacet2d)
+      PRINToff ('o') for 4-d and higher
+*/
+void qh_printfacetNvertex_simplicial(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format) {
+  vertexT *vertex, **vertexp;
+
+  if (format == qh_PRINToff || format == qh_PRINTtriangles)
+    qh_fprintf(qh, fp, 9129, "%d ", qh_setsize(qh, facet->vertices));
+  if ((facet->toporient ^ qh_ORIENTclock)
+  || (qh->hull_dim > 2 && !facet->simplicial)) {
+    FOREACHvertex_(facet->vertices)
+      qh_fprintf(qh, fp, 9130, "%d ", qh_pointid(qh, vertex->point));
+  }else {
+    FOREACHvertexreverse12_(facet->vertices)
+      qh_fprintf(qh, fp, 9131, "%d ", qh_pointid(qh, vertex->point));
+  }
+  qh_fprintf(qh, fp, 9132, "\n");
+} /* printfacetNvertex_simplicial */
+
+
+/*---------------------------------
+
+  qh_printfacetheader(qh, fp, facet )
+    prints header fields of a facet to fp
+
+  notes:
+    for 'f' output and debugging
+    Same as QhullFacet::printHeader()
+*/
+void qh_printfacetheader(qhT *qh, FILE *fp, facetT *facet) {
+  pointT *point, **pointp, *furthest;
+  facetT *neighbor, **neighborp;
+  realT dist;
+
+  if (facet == qh_MERGEridge) {
+    qh_fprintf(qh, fp, 9133, " MERGEridge\n");
+    return;
+  }else if (facet == qh_DUPLICATEridge) {
+    qh_fprintf(qh, fp, 9134, " DUPLICATEridge\n");
+    return;
+  }else if (!facet) {
+    qh_fprintf(qh, fp, 9135, " NULLfacet\n");
+    return;
+  }
+  qh->old_randomdist= qh->RANDOMdist;
+  qh->RANDOMdist= False;
+  qh_fprintf(qh, fp, 9136, "- f%d\n", facet->id);
+  qh_fprintf(qh, fp, 9137, "    - flags:");
+  if (facet->toporient)
+    qh_fprintf(qh, fp, 9138, " top");
+  else
+    qh_fprintf(qh, fp, 9139, " bottom");
+  if (facet->simplicial)
+    qh_fprintf(qh, fp, 9140, " simplicial");
+  if (facet->tricoplanar)
+    qh_fprintf(qh, fp, 9141, " tricoplanar");
+  if (facet->upperdelaunay)
+    qh_fprintf(qh, fp, 9142, " upperDelaunay");
+  if (facet->visible)
+    qh_fprintf(qh, fp, 9143, " visible");
+  if (facet->newfacet)
+    qh_fprintf(qh, fp, 9144, " newfacet");
+  if (facet->tested)
+    qh_fprintf(qh, fp, 9145, " tested");
+  if (!facet->good)
+    qh_fprintf(qh, fp, 9146, " notG");
+  if (facet->seen && qh->IStracing)
+    qh_fprintf(qh, fp, 9147, " seen");
+  if (facet->seen2 && qh->IStracing)
+    qh_fprintf(qh, fp, 9418, " seen2");
+  if (facet->isarea)
+    qh_fprintf(qh, fp, 9419, " isarea");
+  if (facet->coplanarhorizon)
+    qh_fprintf(qh, fp, 9148, " coplanarhorizon");
+  if (facet->mergehorizon)
+    qh_fprintf(qh, fp, 9149, " mergehorizon");
+  if (facet->cycledone)
+    qh_fprintf(qh, fp, 9420, " cycledone");
+  if (facet->keepcentrum)
+    qh_fprintf(qh, fp, 9150, " keepcentrum");
+  if (facet->dupridge)
+    qh_fprintf(qh, fp, 9151, " dupridge");
+  if (facet->mergeridge && !facet->mergeridge2)
+    qh_fprintf(qh, fp, 9152, " mergeridge1");
+  if (facet->mergeridge2)
+    qh_fprintf(qh, fp, 9153, " mergeridge2");
+  if (facet->newmerge)
+    qh_fprintf(qh, fp, 9154, " newmerge");
+  if (facet->flipped)
+    qh_fprintf(qh, fp, 9155, " flipped");
+  if (facet->notfurthest)
+    qh_fprintf(qh, fp, 9156, " notfurthest");
+  if (facet->degenerate)
+    qh_fprintf(qh, fp, 9157, " degenerate");
+  if (facet->redundant)
+    qh_fprintf(qh, fp, 9158, " redundant");
+  qh_fprintf(qh, fp, 9159, "\n");
+  if (facet->isarea)
+    qh_fprintf(qh, fp, 9160, "    - area: %2.2g\n", facet->f.area);
+  else if (qh->NEWfacets && facet->visible && facet->f.replace)
+    qh_fprintf(qh, fp, 9161, "    - replacement: f%d\n", facet->f.replace->id);
+  else if (facet->newfacet) {
+    if (facet->f.samecycle && facet->f.samecycle != facet)
+      qh_fprintf(qh, fp, 9162, "    - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
+  }else if (facet->tricoplanar /* !isarea */) {
+    if (facet->f.triowner)
+      qh_fprintf(qh, fp, 9163, "    - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
+  }else if (facet->f.newcycle)
+    qh_fprintf(qh, fp, 9164, "    - was horizon to f%d\n", facet->f.newcycle->id);
+  if (facet->nummerge == qh_MAXnummerge)
+    qh_fprintf(qh, fp, 9427, "    - merges: %dmax\n", qh_MAXnummerge);
+  else if (facet->nummerge)
+    qh_fprintf(qh, fp, 9165, "    - merges: %d\n", facet->nummerge);
+  qh_printpointid(qh, fp, "    - normal: ", qh->hull_dim, facet->normal, qh_IDunknown);
+  qh_fprintf(qh, fp, 9166, "    - offset: %10.7g\n", facet->offset);
+  if (qh->CENTERtype == qh_ASvoronoi || facet->center)
+    qh_printcenter(qh, fp, qh_PRINTfacets, "    - center: ", facet);
+#if qh_MAXoutside
+  if (facet->maxoutside > qh->DISTround) /* initial value */
+    qh_fprintf(qh, fp, 9167, "    - maxoutside: %10.7g\n", facet->maxoutside);
+#endif
+  if (!SETempty_(facet->outsideset)) {
+    furthest= (pointT *)qh_setlast(facet->outsideset);
+    if (qh_setsize(qh, facet->outsideset) < 6) {
+      qh_fprintf(qh, fp, 9168, "    - outside set(furthest p%d):\n", qh_pointid(qh, furthest));
+      FOREACHpoint_(facet->outsideset)
+        qh_printpoint(qh, fp, "     ", point);
+    }else if (qh_setsize(qh, facet->outsideset) < 21) {
+      qh_printpoints(qh, fp, "    - outside set:", facet->outsideset);
+    }else {
+      qh_fprintf(qh, fp, 9169, "    - outside set:  %d points.", qh_setsize(qh, facet->outsideset));
+      qh_printpoint(qh, fp, "  Furthest", furthest);
+    }
+#if !qh_COMPUTEfurthest
+    qh_fprintf(qh, fp, 9170, "    - furthest distance= %2.2g\n", facet->furthestdist);
+#endif
+  }
+  if (!SETempty_(facet->coplanarset)) {
+    furthest= (pointT *)qh_setlast(facet->coplanarset);
+    if (qh_setsize(qh, facet->coplanarset) < 6) {
+      qh_fprintf(qh, fp, 9171, "    - coplanar set(furthest p%d):\n", qh_pointid(qh, furthest));
+      FOREACHpoint_(facet->coplanarset)
+        qh_printpoint(qh, fp, "     ", point);
+    }else if (qh_setsize(qh, facet->coplanarset) < 21) {
+      qh_printpoints(qh, fp, "    - coplanar set:", facet->coplanarset);
+    }else {
+      qh_fprintf(qh, fp, 9172, "    - coplanar set:  %d points.", qh_setsize(qh, facet->coplanarset));
+      qh_printpoint(qh, fp, "  Furthest", furthest);
+    }
+    zinc_(Zdistio);
+    qh_distplane(qh, furthest, facet, &dist);
+    qh_fprintf(qh, fp, 9173, "      furthest distance= %2.2g\n", dist);
+  }
+  qh_printvertices(qh, fp, "    - vertices:", facet->vertices);
+  qh_fprintf(qh, fp, 9174, "    - neighboring facets:");
+  FOREACHneighbor_(facet) {
+    if (neighbor == qh_MERGEridge)
+      qh_fprintf(qh, fp, 9175, " MERGEridge");
+    else if (neighbor == qh_DUPLICATEridge)
+      qh_fprintf(qh, fp, 9176, " DUPLICATEridge");
+    else
+      qh_fprintf(qh, fp, 9177, " f%d", neighbor->id);
+  }
+  qh_fprintf(qh, fp, 9178, "\n");
+  qh->RANDOMdist= qh->old_randomdist;
+} /* printfacetheader */
+
+
+/*---------------------------------
+
+  qh_printfacetridges(qh, fp, facet )
+    prints ridges of a facet to fp
+
+  notes:
+    ridges printed in neighbor order
+    assumes the ridges exist
+    for 'f' output
+    same as QhullFacet::printRidges
+*/
+void qh_printfacetridges(qhT *qh, FILE *fp, facetT *facet) {
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int numridges= 0;
+  int n;
+
+  if (facet->visible && qh->NEWfacets) {
+    qh_fprintf(qh, fp, 9179, "    - ridges (tentative ids):");
+    FOREACHridge_(facet->ridges)
+      qh_fprintf(qh, fp, 9180, " r%d", ridge->id);
+    qh_fprintf(qh, fp, 9181, "\n");
+  }else {
+    qh_fprintf(qh, fp, 9182, "    - ridges:\n");
+    FOREACHridge_(facet->ridges)
+      ridge->seen= False;
+    if (qh->hull_dim == 3) {
+      ridge= SETfirstt_(facet->ridges, ridgeT);
+      while (ridge && !ridge->seen) {
+        ridge->seen= True;
+        qh_printridge(qh, fp, ridge);
+        numridges++;
+        ridge= qh_nextridge3d(ridge, facet, NULL);
+        }
+    }else {
+      FOREACHneighbor_(facet) {
+        FOREACHridge_(facet->ridges) {
+          if (otherfacet_(ridge, facet) == neighbor && !ridge->seen) {
+            ridge->seen= True;
+            qh_printridge(qh, fp, ridge);
+            numridges++;
+          }
+        }
+      }
+    }
+    n= qh_setsize(qh, facet->ridges);
+    if (n == 1 && facet->newfacet && qh->NEWtentative) {
+      qh_fprintf(qh, fp, 9411, "     - horizon ridge to visible facet\n");
+    }
+    if (numridges != n) {
+      qh_fprintf(qh, fp, 9183, "     - all ridges:");
+      FOREACHridge_(facet->ridges)
+        qh_fprintf(qh, fp, 9184, " r%d", ridge->id);
+      qh_fprintf(qh, fp, 9185, "\n");
+    }
+    /* non-3d ridges w/o non-simplicial neighbors */
+    FOREACHridge_(facet->ridges) {
+      if (!ridge->seen)
+        qh_printridge(qh, fp, ridge);
+    }
+  }
+} /* printfacetridges */
+
+/*---------------------------------
+
+  qh_printfacets(qh, fp, format, facetlist, facets, printall )
+    prints facetlist and/or facet set in output format
+
+  notes:
+    also used for specialized formats ('FO' and summary)
+    turns off 'Rn' option since want actual numbers
+*/
+void qh_printfacets(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
+  int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
+  facetT *facet, **facetp;
+  setT *vertices;
+  coordT *center;
+  realT outerplane, innerplane;
+
+  qh->old_randomdist= qh->RANDOMdist;
+  qh->RANDOMdist= False;
+  if (qh->CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
+    qh_fprintf(qh, qh->ferr, 7056, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
+  if (format == qh_PRINTnone)
+    ; /* print nothing */
+  else if (format == qh_PRINTaverage) {
+    vertices= qh_facetvertices(qh, facetlist, facets, printall);
+    center= qh_getcenter(qh, vertices);
+    qh_fprintf(qh, fp, 9186, "%d 1\n", qh->hull_dim);
+    qh_printpointid(qh, fp, NULL, qh->hull_dim, center, qh_IDunknown);
+    qh_memfree(qh, center, qh->normal_size);
+    qh_settempfree(qh, &vertices);
+  }else if (format == qh_PRINTextremes) {
+    if (qh->DELAUNAY)
+      qh_printextremes_d(qh, fp, facetlist, facets, printall);
+    else if (qh->hull_dim == 2)
+      qh_printextremes_2d(qh, fp, facetlist, facets, printall);
+    else
+      qh_printextremes(qh, fp, facetlist, facets, printall);
+  }else if (format == qh_PRINToptions)
+    qh_fprintf(qh, fp, 9187, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);
+  else if (format == qh_PRINTpoints && !qh->VORONOI)
+    qh_printpoints_out(qh, fp, facetlist, facets, printall);
+  else if (format == qh_PRINTqhull)
+    qh_fprintf(qh, fp, 9188, "%s | %s\n", qh->rbox_command, qh->qhull_command);
+  else if (format == qh_PRINTsize) {
+    qh_fprintf(qh, fp, 9189, "0\n2 ");
+    qh_fprintf(qh, fp, 9190, qh_REAL_1, qh->totarea);
+    qh_fprintf(qh, fp, 9191, qh_REAL_1, qh->totvol);
+    qh_fprintf(qh, fp, 9192, "\n");
+  }else if (format == qh_PRINTsummary) {
+    qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
+    vertices= qh_facetvertices(qh, facetlist, facets, printall);
+    qh_fprintf(qh, fp, 9193, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh->hull_dim,
+                qh->num_points + qh_setsize(qh, qh->other_points),
+                qh->num_vertices, qh->num_facets - qh->num_visible,
+                qh_setsize(qh, vertices), numfacets, numcoplanars,
+                numfacets - numsimplicial, zzval_(Zdelvertextot),
+                numtricoplanars);
+    qh_settempfree(qh, &vertices);
+    qh_outerinner(qh, NULL, &outerplane, &innerplane);
+    qh_fprintf(qh, fp, 9194, qh_REAL_2n, outerplane, innerplane);
+  }else if (format == qh_PRINTvneighbors)
+    qh_printvneighbors(qh, fp, facetlist, facets, printall);
+  else if (qh->VORONOI && format == qh_PRINToff)
+    qh_printvoronoi(qh, fp, format, facetlist, facets, printall);
+  else if (qh->VORONOI && format == qh_PRINTgeom) {
+    qh_printbegin(qh, fp, format, facetlist, facets, printall);
+    qh_printvoronoi(qh, fp, format, facetlist, facets, printall);
+    qh_printend(qh, fp, format, facetlist, facets, printall);
+  }else if (qh->VORONOI
+  && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
+    qh_printvdiagram(qh, fp, format, facetlist, facets, printall);
+  else {
+    qh_printbegin(qh, fp, format, facetlist, facets, printall);
+    FORALLfacet_(facetlist)
+      qh_printafacet(qh, fp, format, facet, printall);
+    FOREACHfacet_(facets)
+      qh_printafacet(qh, fp, format, facet, printall);
+    qh_printend(qh, fp, format, facetlist, facets, printall);
+  }
+  qh->RANDOMdist= qh->old_randomdist;
+} /* printfacets */
+
+
+/*---------------------------------
+
+  qh_printhyperplaneintersection(qh, fp, facet1, facet2, vertices, color )
+    print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
+*/
+void qh_printhyperplaneintersection(qhT *qh, FILE *fp, facetT *facet1, facetT *facet2,
+                   setT *vertices, realT color[3]) {
+  realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
+  vertexT *vertex, **vertexp;
+  int i, k;
+  boolT nearzero1, nearzero2;
+
+  costheta= qh_getangle(qh, facet1->normal, facet2->normal);
+  denominator= 1 - costheta * costheta;
+  i= qh_setsize(qh, vertices);
+  if (qh->hull_dim == 3)
+    qh_fprintf(qh, fp, 9195, "VECT 1 %d 1 %d 1 ", i, i);
+  else if (qh->hull_dim == 4 && qh->DROPdim >= 0)
+    qh_fprintf(qh, fp, 9196, "OFF 3 1 1 ");
+  else
+    qh->printoutvar++;
+  qh_fprintf(qh, fp, 9197, "# intersect f%d f%d\n", facet1->id, facet2->id);
+  mindenom= 1 / (10.0 * qh->MAXabs_coord);
+  FOREACHvertex_(vertices) {
+    zadd_(Zdistio, 2);
+    qh_distplane(qh, vertex->point, facet1, &dist1);
+    qh_distplane(qh, vertex->point, facet2, &dist2);
+    s= qh_divzero(-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
+    t= qh_divzero(-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
+    if (nearzero1 || nearzero2)
+      s= t= 0.0;
+    for (k=qh->hull_dim; k--; )
+      p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
+    if (qh->PRINTdim <= 3) {
+      qh_projectdim3(qh, p, p);
+      qh_fprintf(qh, fp, 9198, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
+    }else
+      qh_fprintf(qh, fp, 9199, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
+    if (nearzero1+nearzero2)
+      qh_fprintf(qh, fp, 9200, "p%d(coplanar facets)\n", qh_pointid(qh, vertex->point));
+    else
+      qh_fprintf(qh, fp, 9201, "projected p%d\n", qh_pointid(qh, vertex->point));
+  }
+  if (qh->hull_dim == 3)
+    qh_fprintf(qh, fp, 9202, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
+  else if (qh->hull_dim == 4 && qh->DROPdim >= 0)
+    qh_fprintf(qh, fp, 9203, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
+} /* printhyperplaneintersection */
+
+/*---------------------------------
+
+  qh_printline3geom(qh, fp, pointA, pointB, color )
+    prints a line as a VECT
+    prints 0's for qh.DROPdim
+
+  notes:
+    if pointA == pointB,
+      it's a 1 point VECT
+*/
+void qh_printline3geom(qhT *qh, FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
+  int k;
+  realT pA[4], pB[4];
+
+  qh_projectdim3(qh, pointA, pA);
+  qh_projectdim3(qh, pointB, pB);
+  if ((fabs(pA[0] - pB[0]) > 1e-3) ||
+      (fabs(pA[1] - pB[1]) > 1e-3) ||
+      (fabs(pA[2] - pB[2]) > 1e-3)) {
+    qh_fprintf(qh, fp, 9204, "VECT 1 2 1 2 1\n");
+    for (k=0; k < 3; k++)
+       qh_fprintf(qh, fp, 9205, "%8.4g ", pB[k]);
+    qh_fprintf(qh, fp, 9206, " # p%d\n", qh_pointid(qh, pointB));
+  }else
+    qh_fprintf(qh, fp, 9207, "VECT 1 1 1 1 1\n");
+  for (k=0; k < 3; k++)
+    qh_fprintf(qh, fp, 9208, "%8.4g ", pA[k]);
+  qh_fprintf(qh, fp, 9209, " # p%d\n", qh_pointid(qh, pointA));
+  qh_fprintf(qh, fp, 9210, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
+}
+
+/*---------------------------------
+
+  qh_printneighborhood(qh, fp, format, facetA, facetB, printall )
+    print neighborhood of one or two facets
+
+  notes:
+    calls qh_findgood_all()
+    bumps qh.visit_id
+*/
+void qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall) {
+  facetT *neighbor, **neighborp, *facet;
+  setT *facets;
+
+  if (format == qh_PRINTnone)
+    return;
+  qh_findgood_all(qh, qh->facet_list);
+  if (facetA == facetB)
+    facetB= NULL;
+  facets= qh_settemp(qh, 2*(qh_setsize(qh, facetA->neighbors)+1));
+  qh->visit_id++;
+  for (facet=facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
+    if (facet->visitid != qh->visit_id) {
+      facet->visitid= qh->visit_id;
+      qh_setappend(qh, &facets, facet);
+    }
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid == qh->visit_id)
+        continue;
+      neighbor->visitid= qh->visit_id;
+      if (printall || !qh_skipfacet(qh, neighbor))
+        qh_setappend(qh, &facets, neighbor);
+    }
+  }
+  qh_printfacets(qh, fp, format, NULL, facets, printall);
+  qh_settempfree(qh, &facets);
+} /* printneighborhood */
+
+/*---------------------------------
+
+  qh_printpoint(qh, fp, string, point )
+  qh_printpointid(qh, fp, string, dim, point, id )
+    prints the coordinates of a point
+
+  returns:
+    if string is defined
+      prints 'string p%d'.  Skips p%d if id=qh_IDunknown(-1) or qh_IDnone(-3)
+
+  notes:
+    nop if point is NULL
+    Same as QhullPoint's printPoint
+*/
+void qh_printpoint(qhT *qh, FILE *fp, const char *string, pointT *point) {
+  int id= qh_pointid(qh, point);
+
+  qh_printpointid(qh, fp, string, qh->hull_dim, point, id);
+} /* printpoint */
+
+void qh_printpointid(qhT *qh, FILE *fp, const char *string, int dim, pointT *point, int id) {
+  int k;
+  realT r; /*bug fix*/
+
+  if (!point)
+    return;
+  if (string) {
+    qh_fprintf(qh, fp, 9211, "%s", string);
+    if (id != qh_IDunknown && id != qh_IDnone)
+      qh_fprintf(qh, fp, 9212, " p%d: ", id);
+  }
+  for (k=dim; k--; ) {
+    r= *point++;
+    if (string)
+      qh_fprintf(qh, fp, 9213, " %8.4g", r);
+    else
+      qh_fprintf(qh, fp, 9214, qh_REAL_1, r);
+  }
+  qh_fprintf(qh, fp, 9215, "\n");
+} /* printpointid */
+
+/*---------------------------------
+
+  qh_printpoint3(qh, fp, point )
+    prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
+*/
+void qh_printpoint3(qhT *qh, FILE *fp, pointT *point) {
+  int k;
+  realT p[4];
+
+  qh_projectdim3(qh, point, p);
+  for (k=0; k < 3; k++)
+    qh_fprintf(qh, fp, 9216, "%8.4g ", p[k]);
+  qh_fprintf(qh, fp, 9217, " # p%d\n", qh_pointid(qh, point));
+} /* printpoint3 */
+
+/*----------------------------------------
+-printpoints- print pointids for a set of points starting at index
+   see geom_r.c
+*/
+
+/*---------------------------------
+
+  qh_printpoints_out(qh, fp, facetlist, facets, printall )
+    prints vertices, coplanar/inside points, for facets by their point coordinates
+    allows qh.CDDoutput
+
+  notes:
+    same format as qhull input
+    if no coplanar/interior points,
+      same order as qh_printextremes
+*/
+void qh_printpoints_out(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {
+  int allpoints= qh->num_points + qh_setsize(qh, qh->other_points);
+  int numpoints=0, point_i, point_n;
+  setT *vertices, *points;
+  facetT *facet, **facetp;
+  pointT *point, **pointp;
+  vertexT *vertex, **vertexp;
+  int id;
+
+  points= qh_settemp(qh, allpoints);
+  qh_setzero(qh, points, 0, allpoints);
+  vertices= qh_facetvertices(qh, facetlist, facets, printall);
+  FOREACHvertex_(vertices) {
+    id= qh_pointid(qh, vertex->point);
+    if (id >= 0)
+      SETelem_(points, id)= vertex->point;
+  }
+  if (qh->KEEPinside || qh->KEEPcoplanar || qh->KEEPnearinside) {
+    FORALLfacet_(facetlist) {
+      if (!printall && qh_skipfacet(qh, facet))
+        continue;
+      FOREACHpoint_(facet->coplanarset) {
+        id= qh_pointid(qh, point);
+        if (id >= 0)
+          SETelem_(points, id)= point;
+      }
+    }
+    FOREACHfacet_(facets) {
+      if (!printall && qh_skipfacet(qh, facet))
+        continue;
+      FOREACHpoint_(facet->coplanarset) {
+        id= qh_pointid(qh, point);
+        if (id >= 0)
+          SETelem_(points, id)= point;
+      }
+    }
+  }
+  qh_settempfree(qh, &vertices);
+  FOREACHpoint_i_(qh, points) {
+    if (point)
+      numpoints++;
+  }
+  if (qh->CDDoutput)
+    qh_fprintf(qh, fp, 9218, "%s | %s\nbegin\n%d %d real\n", qh->rbox_command,
+             qh->qhull_command, numpoints, qh->hull_dim + 1);
+  else
+    qh_fprintf(qh, fp, 9219, "%d\n%d\n", qh->hull_dim, numpoints);
+  FOREACHpoint_i_(qh, points) {
+    if (point) {
+      if (qh->CDDoutput)
+        qh_fprintf(qh, fp, 9220, "1 ");
+      qh_printpoint(qh, fp, NULL, point);
+    }
+  }
+  if (qh->CDDoutput)
+    qh_fprintf(qh, fp, 9221, "end\n");
+  qh_settempfree(qh, &points);
+} /* printpoints_out */
+
+
+/*---------------------------------
+
+  qh_printpointvect(qh, fp, point, normal, center, radius, color )
+    prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
+*/
+void qh_printpointvect(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
+  realT diff[4], pointA[4];
+  int k;
+
+  for (k=qh->hull_dim; k--; ) {
+    if (center)
+      diff[k]= point[k]-center[k];
+    else if (normal)
+      diff[k]= normal[k];
+    else
+      diff[k]= 0;
+  }
+  if (center)
+    qh_normalize2(qh, diff, qh->hull_dim, True, NULL, NULL);
+  for (k=qh->hull_dim; k--; )
+    pointA[k]= point[k]+diff[k] * radius;
+  qh_printline3geom(qh, fp, point, pointA, color);
+} /* printpointvect */
+
+/*---------------------------------
+
+  qh_printpointvect2(qh, fp, point, normal, center, radius )
+    prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
+*/
+void qh_printpointvect2(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
+  realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};
+
+  qh_printpointvect(qh, fp, point, normal, center, radius, red);
+  qh_printpointvect(qh, fp, point, normal, center, -radius, yellow);
+} /* printpointvect2 */
+
+/*---------------------------------
+
+  qh_printridge(qh, fp, ridge )
+    prints the information in a ridge
+
+  notes:
+    for qh_printfacetridges()
+    same as operator<< [QhullRidge.cpp]
+*/
+void qh_printridge(qhT *qh, FILE *fp, ridgeT *ridge) {
+
+  qh_fprintf(qh, fp, 9222, "     - r%d", ridge->id);
+  if (ridge->tested)
+    qh_fprintf(qh, fp, 9223, " tested");
+  if (ridge->nonconvex)
+    qh_fprintf(qh, fp, 9224, " nonconvex");
+  if (ridge->mergevertex)
+    qh_fprintf(qh, fp, 9421, " mergevertex");
+  if (ridge->mergevertex2)
+    qh_fprintf(qh, fp, 9422, " mergevertex2");
+  if (ridge->simplicialtop)
+    qh_fprintf(qh, fp, 9425, " simplicialtop");
+  if (ridge->simplicialbot)
+    qh_fprintf(qh, fp, 9423, " simplicialbot");
+  qh_fprintf(qh, fp, 9225, "\n");
+  qh_printvertices(qh, fp, "           vertices:", ridge->vertices);
+  if (ridge->top && ridge->bottom)
+    qh_fprintf(qh, fp, 9226, "           between f%d and f%d\n",
+            ridge->top->id, ridge->bottom->id);
+} /* printridge */
+
+/*---------------------------------
+
+  qh_printspheres(qh, fp, vertices, radius )
+    prints 3-d vertices as OFF spheres
+
+  notes:
+    inflated octahedron from Stuart Levy earth/mksphere2
+*/
+void qh_printspheres(qhT *qh, FILE *fp, setT *vertices, realT radius) {
+  vertexT *vertex, **vertexp;
+
+  qh->printoutnum++;
+  qh_fprintf(qh, fp, 9227, "{appearance {-edge -normal normscale 0} {\n\
+INST geom {define vsphere OFF\n\
+18 32 48\n\
+\n\
+0 0 1\n\
+1 0 0\n\
+0 1 0\n\
+-1 0 0\n\
+0 -1 0\n\
+0 0 -1\n\
+0.707107 0 0.707107\n\
+0 -0.707107 0.707107\n\
+0.707107 -0.707107 0\n\
+-0.707107 0 0.707107\n\
+-0.707107 -0.707107 0\n\
+0 0.707107 0.707107\n\
+-0.707107 0.707107 0\n\
+0.707107 0.707107 0\n\
+0.707107 0 -0.707107\n\
+0 0.707107 -0.707107\n\
+-0.707107 0 -0.707107\n\
+0 -0.707107 -0.707107\n\
+\n\
+3 0 6 11\n\
+3 0 7 6 \n\
+3 0 9 7 \n\
+3 0 11 9\n\
+3 1 6 8 \n\
+3 1 8 14\n\
+3 1 13 6\n\
+3 1 14 13\n\
+3 2 11 13\n\
+3 2 12 11\n\
+3 2 13 15\n\
+3 2 15 12\n\
+3 3 9 12\n\
+3 3 10 9\n\
+3 3 12 16\n\
+3 3 16 10\n\
+3 4 7 10\n\
+3 4 8 7\n\
+3 4 10 17\n\
+3 4 17 8\n\
+3 5 14 17\n\
+3 5 15 14\n\
+3 5 16 15\n\
+3 5 17 16\n\
+3 6 13 11\n\
+3 7 8 6\n\
+3 9 10 7\n\
+3 11 12 9\n\
+3 14 8 17\n\
+3 15 13 14\n\
+3 16 12 15\n\
+3 17 10 16\n} transforms { TLIST\n");
+  FOREACHvertex_(vertices) {
+    qh_fprintf(qh, fp, 9228, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
+      radius, vertex->id, radius, radius);
+    qh_printpoint3(qh, fp, vertex->point);
+    qh_fprintf(qh, fp, 9229, "1\n");
+  }
+  qh_fprintf(qh, fp, 9230, "}}}\n");
+} /* printspheres */
+
+
+/*----------------------------------------------
+-printsummary-
+                see libqhull_r.c
+*/
+
+/*---------------------------------
+
+  qh_printvdiagram(qh, fp, format, facetlist, facets, printall )
+    print voronoi diagram
+      # of pairs of input sites
+      #indices site1 site2 vertex1 ...
+
+    sites indexed by input point id
+      point 0 is the first input point
+    vertices indexed by 'o' and 'p' order
+      vertex 0 is the 'vertex-at-infinity'
+      vertex 1 is the first Voronoi vertex
+
+  see:
+    qh_printvoronoi()
+    qh_eachvoronoi_all()
+
+  notes:
+    if all facets are upperdelaunay,
+      prints upper hull (furthest-site Voronoi diagram)
+*/
+void qh_printvdiagram(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
+  setT *vertices;
+  int totcount, numcenters;
+  boolT isLower;
+  qh_RIDGE innerouter= qh_RIDGEall;
+  printvridgeT printvridge= NULL;
+
+  if (format == qh_PRINTvertices) {
+    innerouter= qh_RIDGEall;
+    printvridge= qh_printvridge;
+  }else if (format == qh_PRINTinner) {
+    innerouter= qh_RIDGEinner;
+    printvridge= qh_printvnorm;
+  }else if (format == qh_PRINTouter) {
+    innerouter= qh_RIDGEouter;
+    printvridge= qh_printvnorm;
+  }else {
+    qh_fprintf(qh, qh->ferr, 6219, "qhull internal error (qh_printvdiagram): unknown print format %d.\n", format);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  vertices= qh_markvoronoi(qh, facetlist, facets, printall, &isLower, &numcenters);
+  totcount= qh_printvdiagram2(qh, NULL, NULL, vertices, innerouter, False);
+  qh_fprintf(qh, fp, 9231, "%d\n", totcount);
+  totcount= qh_printvdiagram2(qh, fp, printvridge, vertices, innerouter, True /* inorder*/);
+  qh_settempfree(qh, &vertices);
+#if 0  /* for testing qh_eachvoronoi_all */
+  qh_fprintf(qh, fp, 9232, "\n");
+  totcount= qh_eachvoronoi_all(qh, fp, printvridge, qh->UPPERdelaunay, innerouter, True /* inorder*/);
+  qh_fprintf(qh, fp, 9233, "%d\n", totcount);
+#endif
+} /* printvdiagram */
+
+/*---------------------------------
+
+  qh_printvdiagram2(qh, fp, printvridge, vertices, innerouter, inorder )
+    visit all pairs of input sites (vertices) for selected Voronoi vertices
+    vertices may include NULLs
+
+  innerouter:
+    qh_RIDGEall   print inner ridges(bounded) and outer ridges(unbounded)
+    qh_RIDGEinner print only inner ridges
+    qh_RIDGEouter print only outer ridges
+
+  inorder:
+    print 3-d Voronoi vertices in order
+
+  assumes:
+    qh_markvoronoi marked facet->visitid for Voronoi vertices
+    all facet->seen= False
+    all facet->seen2= True
+
+  returns:
+    total number of Voronoi ridges
+    if printvridge,
+      calls printvridge( fp, vertex, vertexA, centers) for each ridge
+      [see qh_eachvoronoi()]
+
+  see:
+    qh_eachvoronoi_all()
+*/
+int qh_printvdiagram2(qhT *qh, FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
+  int totcount= 0;
+  int vertex_i, vertex_n;
+  vertexT *vertex;
+
+  FORALLvertices
+    vertex->seen= False;
+  FOREACHvertex_i_(qh, vertices) {
+    if (vertex) {
+      if (qh->GOODvertex > 0 && qh_pointid(qh, vertex->point)+1 != qh->GOODvertex)
+        continue;
+      totcount += qh_eachvoronoi(qh, fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
+    }
+  }
+  return totcount;
+} /* printvdiagram2 */
+
+/*---------------------------------
+
+  qh_printvertex(qh, fp, vertex )
+    prints the information in a vertex
+    Duplicated as operator<< [QhullVertex.cpp]
+*/
+void qh_printvertex(qhT *qh, FILE *fp, vertexT *vertex) {
+  pointT *point;
+  int k, count= 0;
+  facetT *neighbor, **neighborp;
+  realT r; /*bug fix*/
+
+  if (!vertex) {
+    qh_fprintf(qh, fp, 9234, "  NULLvertex\n");
+    return;
+  }
+  qh_fprintf(qh, fp, 9235, "- p%d(v%d):", qh_pointid(qh, vertex->point), vertex->id);
+  point= vertex->point;
+  if (point) {
+    for (k=qh->hull_dim; k--; ) {
+      r= *point++;
+      qh_fprintf(qh, fp, 9236, " %5.2g", r);
+    }
+  }
+  if (vertex->deleted)
+    qh_fprintf(qh, fp, 9237, " deleted");
+  if (vertex->delridge)
+    qh_fprintf(qh, fp, 9238, " delridge");
+  if (vertex->newfacet)
+    qh_fprintf(qh, fp, 9415, " newfacet");
+  if (vertex->seen && qh->IStracing)
+    qh_fprintf(qh, fp, 9416, " seen");
+  if (vertex->seen2 && qh->IStracing)
+    qh_fprintf(qh, fp, 9417, " seen2");
+  qh_fprintf(qh, fp, 9239, "\n");
+  if (vertex->neighbors) {
+    qh_fprintf(qh, fp, 9240, "  neighbors:");
+    FOREACHneighbor_(vertex) {
+      if (++count % 100 == 0)
+        qh_fprintf(qh, fp, 9241, "\n     ");
+      qh_fprintf(qh, fp, 9242, " f%d", neighbor->id);
+    }
+    qh_fprintf(qh, fp, 9243, "\n");
+  }
+} /* printvertex */
+
+
+/*---------------------------------
+
+  qh_printvertexlist(qh, fp, string, facetlist, facets, printall )
+    prints vertices used by a facetlist or facet set
+    tests qh_skipfacet() if !printall
+*/
+void qh_printvertexlist(qhT *qh, FILE *fp, const char* string, facetT *facetlist,
+                         setT *facets, boolT printall) {
+  vertexT *vertex, **vertexp;
+  setT *vertices;
+
+  vertices= qh_facetvertices(qh, facetlist, facets, printall);
+  qh_fprintf(qh, fp, 9244, "%s", string);
+  FOREACHvertex_(vertices)
+    qh_printvertex(qh, fp, vertex);
+  qh_settempfree(qh, &vertices);
+} /* printvertexlist */
+
+
+/*---------------------------------
+
+  qh_printvertices(qh, fp, string, vertices )
+    prints vertices in a set
+    duplicated as printVertexSet [QhullVertex.cpp]
+*/
+void qh_printvertices(qhT *qh, FILE *fp, const char* string, setT *vertices) {
+  vertexT *vertex, **vertexp;
+
+  qh_fprintf(qh, fp, 9245, "%s", string);
+  FOREACHvertex_(vertices)
+    qh_fprintf(qh, fp, 9246, " p%d(v%d)", qh_pointid(qh, vertex->point), vertex->id);
+  qh_fprintf(qh, fp, 9247, "\n");
+} /* printvertices */
+
+/*---------------------------------
+
+  qh_printvneighbors(qh, fp, facetlist, facets, printall )
+    print vertex neighbors of vertices in facetlist and facets ('FN')
+
+  notes:
+    qh_countfacets clears facet->visitid for non-printed facets
+
+  design:
+    collect facet count and related statistics
+    if necessary, build neighbor sets for each vertex
+    collect vertices in facetlist and facets
+    build a point array for point->vertex and point->coplanar facet
+    for each point
+      list vertex neighbors or coplanar facet
+*/
+void qh_printvneighbors(qhT *qh, FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
+  int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;
+  setT *vertices, *vertex_points, *coplanar_points;
+  int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
+  vertexT *vertex, **vertexp;
+  int vertex_i, vertex_n;
+  facetT *facet, **facetp, *neighbor, **neighborp;
+  pointT *point, **pointp;
+
+  qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);  /* sets facet->visitid */
+  qh_fprintf(qh, fp, 9248, "%d\n", numpoints);
+  qh_vertexneighbors(qh);
+  vertices= qh_facetvertices(qh, facetlist, facets, printall);
+  vertex_points= qh_settemp(qh, numpoints);
+  coplanar_points= qh_settemp(qh, numpoints);
+  qh_setzero(qh, vertex_points, 0, numpoints);
+  qh_setzero(qh, coplanar_points, 0, numpoints);
+  FOREACHvertex_(vertices)
+    qh_point_add(qh, vertex_points, vertex->point, vertex);
+  FORALLfacet_(facetlist) {
+    FOREACHpoint_(facet->coplanarset)
+      qh_point_add(qh, coplanar_points, point, facet);
+  }
+  FOREACHfacet_(facets) {
+    FOREACHpoint_(facet->coplanarset)
+      qh_point_add(qh, coplanar_points, point, facet);
+  }
+  FOREACHvertex_i_(qh, vertex_points) {
+    if (vertex) {
+      numneighbors= qh_setsize(qh, vertex->neighbors);
+      qh_fprintf(qh, fp, 9249, "%d", numneighbors);
+      qh_order_vertexneighbors(qh, vertex);
+      FOREACHneighbor_(vertex)
+        qh_fprintf(qh, fp, 9250, " %d",
+                 neighbor->visitid ? neighbor->visitid - 1 : 0 - neighbor->id);
+      qh_fprintf(qh, fp, 9251, "\n");
+    }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
+      qh_fprintf(qh, fp, 9252, "1 %d\n",
+                  facet->visitid ? facet->visitid - 1 : 0 - facet->id);
+    else
+      qh_fprintf(qh, fp, 9253, "0\n");
+  }
+  qh_settempfree(qh, &coplanar_points);
+  qh_settempfree(qh, &vertex_points);
+  qh_settempfree(qh, &vertices);
+} /* printvneighbors */
+
+/*---------------------------------
+
+  qh_printvoronoi(qh, fp, format, facetlist, facets, printall )
+    print voronoi diagram in 'o' or 'G' format
+    for 'o' format
+      prints voronoi centers for each facet and for infinity
+      for each vertex, lists ids of printed facets or infinity
+      assumes facetlist and facets are disjoint
+    for 'G' format
+      prints an OFF object
+      adds a 0 coordinate to center
+      prints infinity but does not list in vertices
+
+  see:
+    qh_printvdiagram()
+
+  notes:
+    if 'o',
+      prints a line for each point except "at-infinity"
+    if all facets are upperdelaunay,
+      reverses lower and upper hull
+*/
+void qh_printvoronoi(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {
+  int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
+  facetT *facet, **facetp, *neighbor, **neighborp;
+  setT *vertices;
+  vertexT *vertex;
+  boolT isLower;
+  unsigned int numfacets= (unsigned int)qh->num_facets;
+
+  vertices= qh_markvoronoi(qh, facetlist, facets, printall, &isLower, &numcenters);
+  FOREACHvertex_i_(qh, vertices) {
+    if (vertex) {
+      numvertices++;
+      numneighbors= numinf= 0;
+      FOREACHneighbor_(vertex) {
+        if (neighbor->visitid == 0)
+          numinf= 1;
+        else if (neighbor->visitid < numfacets)
+          numneighbors++;
+      }
+      if (numinf && !numneighbors) {
+        SETelem_(vertices, vertex_i)= NULL;
+        numvertices--;
+      }
+    }
+  }
+  if (format == qh_PRINTgeom)
+    qh_fprintf(qh, fp, 9254, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",
+                numcenters, numvertices);
+  else
+    qh_fprintf(qh, fp, 9255, "%d\n%d %d 1\n", qh->hull_dim-1, numcenters, qh_setsize(qh, vertices));
+  if (format == qh_PRINTgeom) {
+    for (k=qh->hull_dim-1; k--; )
+      qh_fprintf(qh, fp, 9256, qh_REAL_1, 0.0);
+    qh_fprintf(qh, fp, 9257, " 0 # infinity not used\n");
+  }else {
+    for (k=qh->hull_dim-1; k--; )
+      qh_fprintf(qh, fp, 9258, qh_REAL_1, qh_INFINITE);
+    qh_fprintf(qh, fp, 9259, "\n");
+  }
+  FORALLfacet_(facetlist) {
+    if (facet->visitid && facet->visitid < numfacets) {
+      if (format == qh_PRINTgeom)
+        qh_fprintf(qh, fp, 9260, "# %d f%d\n", vid++, facet->id);
+      qh_printcenter(qh, fp, format, NULL, facet);
+    }
+  }
+  FOREACHfacet_(facets) {
+    if (facet->visitid && facet->visitid < numfacets) {
+      if (format == qh_PRINTgeom)
+        qh_fprintf(qh, fp, 9261, "# %d f%d\n", vid++, facet->id);
+      qh_printcenter(qh, fp, format, NULL, facet);
+    }
+  }
+  FOREACHvertex_i_(qh, vertices) {
+    numneighbors= 0;
+    numinf=0;
+    if (vertex) {
+      qh_order_vertexneighbors(qh, vertex);
+      FOREACHneighbor_(vertex) {
+        if (neighbor->visitid == 0)
+          numinf= 1;
+        else if (neighbor->visitid < numfacets)
+          numneighbors++;
+      }
+    }
+    if (format == qh_PRINTgeom) {
+      if (vertex) {
+        qh_fprintf(qh, fp, 9262, "%d", numneighbors);
+        FOREACHneighbor_(vertex) {
+          if (neighbor->visitid && neighbor->visitid < numfacets)
+            qh_fprintf(qh, fp, 9263, " %d", neighbor->visitid);
+        }
+        qh_fprintf(qh, fp, 9264, " # p%d(v%d)\n", vertex_i, vertex->id);
+      }else
+        qh_fprintf(qh, fp, 9265, " # p%d is coplanar or isolated\n", vertex_i);
+    }else {
+      if (numinf)
+        numneighbors++;
+      qh_fprintf(qh, fp, 9266, "%d", numneighbors);
+      if (vertex) {
+        FOREACHneighbor_(vertex) {
+          if (neighbor->visitid == 0) {
+            if (numinf) {
+              numinf= 0;
+              qh_fprintf(qh, fp, 9267, " %d", neighbor->visitid);
+            }
+          }else if (neighbor->visitid < numfacets)
+            qh_fprintf(qh, fp, 9268, " %d", neighbor->visitid);
+        }
+      }
+      qh_fprintf(qh, fp, 9269, "\n");
+    }
+  }
+  if (format == qh_PRINTgeom)
+    qh_fprintf(qh, fp, 9270, "}\n");
+  qh_settempfree(qh, &vertices);
+} /* printvoronoi */
+
+/*---------------------------------
+
+  qh_printvnorm(qh, fp, vertex, vertexA, centers, unbounded )
+    print one separating plane of the Voronoi diagram for a pair of input sites
+    unbounded==True if centers includes vertex-at-infinity
+
+  assumes:
+    qh_ASvoronoi and qh_vertexneighbors() already set
+
+  note:
+    parameter unbounded is UNUSED by this callback
+
+  see:
+    qh_printvdiagram()
+    qh_eachvoronoi()
+*/
+void qh_printvnorm(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
+  pointT *normal;
+  realT offset;
+  int k;
+  QHULL_UNUSED(unbounded);
+
+  normal= qh_detvnorm(qh, vertex, vertexA, centers, &offset);
+  qh_fprintf(qh, fp, 9271, "%d %d %d ",
+      2+qh->hull_dim, qh_pointid(qh, vertex->point), qh_pointid(qh, vertexA->point));
+  for (k=0; k< qh->hull_dim-1; k++)
+    qh_fprintf(qh, fp, 9272, qh_REAL_1, normal[k]);
+  qh_fprintf(qh, fp, 9273, qh_REAL_1, offset);
+  qh_fprintf(qh, fp, 9274, "\n");
+} /* printvnorm */
+
+/*---------------------------------
+
+  qh_printvridge(qh, fp, vertex, vertexA, centers, unbounded )
+    print one ridge of the Voronoi diagram for a pair of input sites
+    unbounded==True if centers includes vertex-at-infinity
+
+  see:
+    qh_printvdiagram()
+
+  notes:
+    the user may use a different function
+    parameter unbounded is UNUSED
+*/
+void qh_printvridge(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
+  facetT *facet, **facetp;
+  QHULL_UNUSED(unbounded);
+
+  qh_fprintf(qh, fp, 9275, "%d %d %d", qh_setsize(qh, centers)+2,
+       qh_pointid(qh, vertex->point), qh_pointid(qh, vertexA->point));
+  FOREACHfacet_(centers)
+    qh_fprintf(qh, fp, 9276, " %d", facet->visitid);
+  qh_fprintf(qh, fp, 9277, "\n");
+} /* printvridge */
+
+/*---------------------------------
+
+  qh_projectdim3(qh, source, destination )
+    project 2-d 3-d or 4-d point to a 3-d point
+    uses qh.DROPdim and qh.hull_dim
+    source and destination may be the same
+
+  notes:
+    allocate 4 elements to destination just in case
+*/
+void qh_projectdim3(qhT *qh, pointT *source, pointT *destination) {
+  int i,k;
+
+  for (k=0, i=0; k < qh->hull_dim; k++) {
+    if (qh->hull_dim == 4) {
+      if (k != qh->DROPdim)
+        destination[i++]= source[k];
+    }else if (k == qh->DROPdim)
+      destination[i++]= 0;
+    else
+      destination[i++]= source[k];
+  }
+  while (i < 3)
+    destination[i++]= 0.0;
+} /* projectdim3 */
+
+/*---------------------------------
+
+  qh_readfeasible(qh, dim, curline )
+    read feasible point from current line and qh.fin
+
+  returns:
+    number of lines read from qh.fin
+    sets qh.feasible_point with malloc'd coordinates
+
+  notes:
+    checks for qh.HALFspace
+    assumes dim > 1
+
+  see:
+    qh_setfeasible
+*/
+int qh_readfeasible(qhT *qh, int dim, const char *curline) {
+  boolT isfirst= True;
+  int linecount= 0, tokcount= 0;
+  const char *s;
+  char *t, firstline[qh_MAXfirst+1];
+  coordT *coords, value;
+
+  if (!qh->HALFspace) {
+    qh_fprintf(qh, qh->ferr, 6070, "qhull input error: feasible point(dim 1 coords) is only valid for halfspace intersection\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  if (qh->feasible_string)
+    qh_fprintf(qh, qh->ferr, 7057, "qhull input warning: feasible point(dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
+  if (!(qh->feasible_point= (coordT *)qh_malloc((size_t)dim * sizeof(coordT)))) {
+    qh_fprintf(qh, qh->ferr, 6071, "qhull error: insufficient memory for feasible point\n");
+    qh_errexit(qh, qh_ERRmem, NULL, NULL);
+  }
+  coords= qh->feasible_point;
+  while ((s= (isfirst ?  curline : fgets(firstline, qh_MAXfirst, qh->fin)))) {
+    if (isfirst)
+      isfirst= False;
+    else
+      linecount++;
+    while (*s) {
+      while (isspace(*s))
+        s++;
+      value= qh_strtod(s, &t);
+      if (s == t)
+        break;
+      s= t;
+      *(coords++)= value;
+      if (++tokcount == dim) {
+        while (isspace(*s))
+          s++;
+        qh_strtod(s, &t);
+        if (s != t) {
+          qh_fprintf(qh, qh->ferr, 6072, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
+               s);
+          qh_errexit(qh, qh_ERRinput, NULL, NULL);
+        }
+        return linecount;
+      }
+    }
+  }
+  qh_fprintf(qh, qh->ferr, 6073, "qhull input error: only %d coordinates.  Could not read %d-d feasible point.\n",
+           tokcount, dim);
+  qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  return 0;
+} /* readfeasible */
+
+/*---------------------------------
+
+  qh_readpoints(qh, numpoints, dimension, ismalloc )
+    read points from qh.fin into qh.first_point, qh.num_points
+    qh.fin is lines of coordinates, one per vertex, first line number of points
+    if 'rbox D4',
+      gives message
+    if qh.ATinfinity,
+      adds point-at-infinity for Delaunay triangulations
+
+  returns:
+    number of points, array of point coordinates, dimension, ismalloc True
+    if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
+        and clears qh.PROJECTdelaunay
+    if qh.HALFspace, reads optional feasible point, reads halfspaces,
+        converts to dual.
+
+  for feasible point in "cdd format" in 3-d:
+    3 1
+    coordinates
+    comments
+    begin
+    n 4 real/integer
+    ...
+    end
+
+  notes:
+    dimension will change in qh_initqhull_globals if qh.PROJECTinput
+    uses malloc() since qh_mem not initialized
+    QH11012 FIX: qh_readpoints needs rewriting, too long
+*/
+coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc) {
+  coordT *points, *coords, *infinity= NULL;
+  realT paraboloid, maxboloid= -REALmax, value;
+  realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
+  char *s= 0, *t, firstline[qh_MAXfirst+1];
+  int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
+  int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
+  int tokcount= 0, linecount=0, maxcount, coordcount=0;
+  boolT islong, isfirst= True, wasbegin= False;
+  boolT isdelaunay= qh->DELAUNAY && !qh->PROJECTinput;
+
+  if (qh->CDDinput) {
+    while ((s= fgets(firstline, qh_MAXfirst, qh->fin))) {
+      linecount++;
+      if (qh->HALFspace && linecount == 1 && isdigit(*s)) {
+        dimfeasible= qh_strtol(s, &s);
+        while (isspace(*s))
+          s++;
+        if (qh_strtol(s, &s) == 1)
+          linecount += qh_readfeasible(qh, dimfeasible, s);
+        else
+          dimfeasible= 0;
+      }else if (!memcmp(firstline, "begin", (size_t)5) || !memcmp(firstline, "BEGIN", (size_t)5))
+        break;
+      else if (!*qh->rbox_command)
+        strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);
+    }
+    if (!s) {
+      qh_fprintf(qh, qh->ferr, 6074, "qhull input error: missing \"begin\" for cdd-formated input\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+  }
+  while (!numinput && (s= fgets(firstline, qh_MAXfirst, qh->fin))) {
+    linecount++;
+    if (!memcmp(s, "begin", (size_t)5) || !memcmp(s, "BEGIN", (size_t)5))
+      wasbegin= True;
+    while (*s) {
+      while (isspace(*s))
+        s++;
+      if (!*s)
+        break;
+      if (!isdigit(*s)) {
+        if (!*qh->rbox_command) {
+          strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);
+          firsttext= linecount;
+        }
+        break;
+      }
+      if (!diminput)
+        diminput= qh_strtol(s, &s);
+      else {
+        numinput= qh_strtol(s, &s);
+        if (numinput == 1 && diminput >= 2 && qh->HALFspace && !qh->CDDinput) {
+          linecount += qh_readfeasible(qh, diminput, s); /* checks if ok */
+          dimfeasible= diminput;
+          diminput= numinput= 0;
+        }else
+          break;
+      }
+    }
+  }
+  if (!s) {
+    qh_fprintf(qh, qh->ferr, 6075, "qhull input error: short input file.  Did not find dimension and number of points\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  if (diminput > numinput) {
+    tempi= diminput;    /* exchange dim and n, e.g., for cdd input format */
+    diminput= numinput;
+    numinput= tempi;
+  }
+  if (diminput < 2) {
+    qh_fprintf(qh, qh->ferr, 6220, "qhull input error: dimension %d (first or smaller number) should be at least 2\n",
+            diminput);
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  if (numinput < 1 || numinput > qh_POINTSmax) {
+    qh_fprintf(qh, qh->ferr, 6411, "qhull input error: expecting between 1 and %d points.  Got %d %d-d points\n",
+      qh_POINTSmax, numinput, diminput);
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    /* same error message in qh_initqhull_globals */
+  }
+
+  if (isdelaunay && qh->HALFspace) {
+    qh_fprintf(qh, qh->ferr, 6037, "qhull option error (qh_readpoints): can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    /* otherwise corrupted memory allocations, same error message as in qh_initqhull_globals */
+  }else if (isdelaunay) {
+    qh->PROJECTdelaunay= False;
+    if (qh->CDDinput)
+      *dimension= diminput;
+    else
+      *dimension= diminput+1;
+    *numpoints= numinput;
+    if (qh->ATinfinity)
+      (*numpoints)++;
+  }else if (qh->HALFspace) {
+    *dimension= diminput - 1;
+    *numpoints= numinput;
+    if (diminput < 3) {
+      qh_fprintf(qh, qh->ferr, 6221, "qhull input error: dimension %d (first number, includes offset) should be at least 3 for halfspaces\n",
+            diminput);
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    if (dimfeasible) {
+      if (dimfeasible != *dimension) {
+        qh_fprintf(qh, qh->ferr, 6222, "qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
+          dimfeasible, diminput);
+        qh_errexit(qh, qh_ERRinput, NULL, NULL);
+      }
+    }else
+      qh_setfeasible(qh, *dimension);
+  }else {
+    if (qh->CDDinput)
+      *dimension= diminput-1;
+    else
+      *dimension= diminput;
+    *numpoints= numinput;
+  }
+  qh->normal_size= *dimension * (int)sizeof(coordT); /* for tracing with qh_printpoint */
+  if (qh->HALFspace) {
+    qh->half_space= coordp= (coordT *)qh_malloc((size_t)qh->normal_size + sizeof(coordT));
+    if (qh->CDDinput) {
+      offsetp= qh->half_space;
+      normalp= offsetp + 1;
+    }else {
+      normalp= qh->half_space;
+      offsetp= normalp + *dimension;
+    }
+  }
+  qh->maxline= diminput * (qh_REALdigits + 5);
+  maximize_(qh->maxline, 500);
+  qh->line= (char *)qh_malloc((size_t)(qh->maxline+1) * sizeof(char));
+  *ismalloc= True;  /* use malloc since memory not setup */
+  coords= points= qh->temp_malloc=  /* numinput and diminput >=2 by QH6220 */
+        (coordT *)qh_malloc((size_t)((*numpoints)*(*dimension))*sizeof(coordT));
+  if (!coords || !qh->line || (qh->HALFspace && !qh->half_space)) {
+    qh_fprintf(qh, qh->ferr, 6076, "qhull error: insufficient memory to read %d points\n",
+            numinput);
+    qh_errexit(qh, qh_ERRmem, NULL, NULL);
+  }
+  if (isdelaunay && qh->ATinfinity) {
+    infinity= points + numinput * (*dimension);
+    for (k= (*dimension) - 1; k--; )
+      infinity[k]= 0.0;
+  }
+  maxcount= numinput * diminput;
+  paraboloid= 0.0;
+  while ((s= (isfirst ?  s : fgets(qh->line, qh->maxline, qh->fin)))) {
+    if (!isfirst) {
+      linecount++;
+      if (*s == 'e' || *s == 'E') {
+        if (!memcmp(s, "end", (size_t)3) || !memcmp(s, "END", (size_t)3)) {
+          if (qh->CDDinput )
+            break;
+          else if (wasbegin)
+            qh_fprintf(qh, qh->ferr, 7058, "qhull input warning: the input appears to be in cdd format.  If so, use 'Fd'\n");
+        }
+      }
+    }
+    islong= False;
+    while (*s) {
+      while (isspace(*s))
+        s++;
+      value= qh_strtod(s, &t);
+      if (s == t) {
+        if (!*qh->rbox_command)
+         strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);
+        if (*s && !firsttext)
+          firsttext= linecount;
+        if (!islong && !firstshort && coordcount)
+          firstshort= linecount;
+        break;
+      }
+      if (!firstpoint)
+        firstpoint= linecount;
+      s= t;
+      if (++tokcount > maxcount)
+        continue;
+      if (qh->HALFspace) {
+        if (qh->CDDinput)
+          *(coordp++)= -value; /* both coefficients and offset */
+        else
+          *(coordp++)= value;
+      }else {
+        *(coords++)= value;
+        if (qh->CDDinput && !coordcount) {
+          if (value != 1.0) {
+            qh_fprintf(qh, qh->ferr, 6077, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
+                   linecount);
+            qh_errexit(qh, qh_ERRinput, NULL, NULL);
+          }
+          coords--;
+        }else if (isdelaunay) {
+          paraboloid += value * value;
+          if (qh->ATinfinity) {
+            if (qh->CDDinput)
+              infinity[coordcount-1] += value;
+            else
+              infinity[coordcount] += value;
+          }
+        }
+      }
+      if (++coordcount == diminput) {
+        coordcount= 0;
+        if (isdelaunay) {
+          *(coords++)= paraboloid;
+          maximize_(maxboloid, paraboloid);
+          paraboloid= 0.0;
+        }else if (qh->HALFspace) {
+          if (!qh_sethalfspace(qh, *dimension, coords, &coords, normalp, offsetp, qh->feasible_point)) {
+            qh_fprintf(qh, qh->ferr, 8048, "The halfspace was on line %d\n", linecount);
+            if (wasbegin)
+              qh_fprintf(qh, qh->ferr, 8049, "The input appears to be in cdd format.  If so, you should use option 'Fd'\n");
+            qh_errexit(qh, qh_ERRinput, NULL, NULL);
+          }
+          coordp= qh->half_space;
+        }
+        while (isspace(*s))
+          s++;
+        if (*s) {
+          islong= True;
+          if (!firstlong)
+            firstlong= linecount;
+        }
+      }
+    }
+    if (!islong && !firstshort && coordcount)
+      firstshort= linecount;
+    if (!isfirst && s - qh->line >= qh->maxline) {
+      qh_fprintf(qh, qh->ferr, 6078, "qhull input error: line %d contained more than %d characters\n",
+              linecount, (int) (s - qh->line));   /* WARN64 */
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    isfirst= False;
+  }
+  if (qh->rbox_command[0])
+    qh->rbox_command[strlen(qh->rbox_command)-1]= '\0'; /* remove \n, previous qh_errexit's display command as two lines */
+  if (tokcount != maxcount) {
+    newnum= fmin_(numinput, tokcount/diminput);
+    if (qh->ALLOWshort)
+      qh_fprintf(qh, qh->ferr, 7073, "qhull warning: instead of %d points in %d-d, input contains %d points and %d extra coordinates.\n",
+          numinput, diminput, tokcount/diminput, tokcount % diminput);
+    else
+      qh_fprintf(qh, qh->ferr, 6410, "qhull error: instead of %d points in %d-d, input contains %d points and %d extra coordinates.\n",
+          numinput, diminput, tokcount/diminput, tokcount % diminput);
+    if (firsttext)
+      qh_fprintf(qh, qh->ferr, 8051, "    Line %d is the first comment.\n", firsttext);
+    qh_fprintf(qh, qh->ferr, 8033,   "    Line %d is the first point.\n", firstpoint);
+    if (firstshort)
+      qh_fprintf(qh, qh->ferr, 8052, "    Line %d is the first short line.\n", firstshort);
+    if (firstlong)
+      qh_fprintf(qh, qh->ferr, 8053, "    Line %d is the first long line.\n", firstlong);
+    if (qh->ALLOWshort)
+      qh_fprintf(qh, qh->ferr, 8054, "    Continuing with %d points.\n", newnum);
+    else {
+      qh_fprintf(qh, qh->ferr, 8077, "    Override with option 'Qa' (allow-short)\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    numinput= newnum;
+    if (isdelaunay && qh->ATinfinity) {
+      for (k= tokcount % diminput; k--; )
+        infinity[k] -= *(--coords);
+      *numpoints= newnum+1;
+    }else {
+      coords -= tokcount % diminput;
+      *numpoints= newnum;
+    }
+  }
+  if (isdelaunay && qh->ATinfinity) {
+    for (k= (*dimension) - 1; k--; )
+      infinity[k] /= numinput;
+    if (coords == infinity)
+      coords += (*dimension) -1;
+    else {
+      for (k=0; k < (*dimension) - 1; k++)
+        *(coords++)= infinity[k];
+    }
+    *(coords++)= maxboloid * 1.1;
+  }
+  if (!strcmp(qh->rbox_command, "./rbox D4"))
+    qh_fprintf(qh, qh->ferr, 8055, "\n\
+This is the qhull test case.  If any errors or core dumps occur,\n\
+recompile qhull with 'make new'.  If errors still occur, there is\n\
+an incompatibility.  You should try a different compiler.  You can also\n\
+change the choices in user_r.h.  If you discover the source of the problem,\n\
+please send mail to qhull_bug@qhull.org.\n\
+\n\
+Type 'qhull' for a short list of options.\n");
+  qh_free(qh->line);
+  qh->line= NULL;
+  if (qh->half_space) {
+    qh_free(qh->half_space);
+    qh->half_space= NULL;
+  }
+  qh->temp_malloc= NULL;
+  trace1((qh, qh->ferr, 1008,"qh_readpoints: read in %d %d-dimensional points\n",
+          numinput, diminput));
+  return(points);
+} /* readpoints */
+
+
+/*---------------------------------
+
+  qh_setfeasible(qh, dim )
+    set qh.feasible_point from qh.feasible_string in "n,n,n" or "n n n" format
+
+  notes:
+    "n,n,n" already checked by qh_initflags()
+    see qh_readfeasible()
+    called only once from qh_new_qhull, otherwise leaks memory
+*/
+void qh_setfeasible(qhT *qh, int dim) {
+  int tokcount= 0;
+  char *s;
+  coordT *coords, value;
+
+  if (!(s= qh->feasible_string)) {
+    qh_fprintf(qh, qh->ferr, 6223, "qhull input error: halfspace intersection needs a feasible point.  Either prepend the input with 1 point or use 'Hn,n,n'.  See manual.\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  if (!(qh->feasible_point= (pointT *)qh_malloc((size_t)dim * sizeof(coordT)))) {
+    qh_fprintf(qh, qh->ferr, 6079, "qhull error: insufficient memory for 'Hn,n,n'\n");
+    qh_errexit(qh, qh_ERRmem, NULL, NULL);
+  }
+  coords= qh->feasible_point;
+  while (*s) {
+    value= qh_strtod(s, &s);
+    if (++tokcount > dim) {
+      qh_fprintf(qh, qh->ferr, 7059, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
+          qh->feasible_string, dim);
+      break;
+    }
+    *(coords++)= value;
+    if (*s)
+      s++;
+  }
+  while (++tokcount <= dim)
+    *(coords++)= 0.0;
+} /* setfeasible */
+
+/*---------------------------------
+
+  qh_skipfacet(qh, facet )
+    returns 'True' if this facet is not to be printed
+
+  notes:
+    based on the user provided slice thresholds and 'good' specifications
+*/
+boolT qh_skipfacet(qhT *qh, facetT *facet) {
+  facetT *neighbor, **neighborp;
+
+  if (qh->PRINTneighbors) {
+    if (facet->good)
+      return !qh->PRINTgood;
+    FOREACHneighbor_(facet) {
+      if (neighbor->good)
+        return False;
+    }
+    return True;
+  }else if (qh->PRINTgood)
+    return !facet->good;
+  else if (!facet->normal)
+    return True;
+  return(!qh_inthresholds(qh, facet->normal, NULL));
+} /* skipfacet */
+
+/*---------------------------------
+
+  qh_skipfilename(qh, string )
+    returns pointer to character after filename
+
+  notes:
+    skips leading spaces
+    ends with spacing or eol
+    if starts with ' or " ends with the same, skipping \' or \"
+    For qhull, qh_argv_to_command() only uses double quotes
+*/
+char *qh_skipfilename(qhT *qh, char *filename) {
+  char *s= filename;  /* non-const due to return */
+  char c;
+
+  while (*s && isspace(*s))
+    s++;
+  c= *s++;
+  if (c == '\0') {
+    qh_fprintf(qh, qh->ferr, 6204, "qhull input error: filename expected, none found.\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  if (c == '\'' || c == '"') {
+    while (*s !=c || s[-1] == '\\') {
+      if (!*s) {
+        qh_fprintf(qh, qh->ferr, 6203, "qhull input error: missing quote after filename -- %s\n", filename);
+        qh_errexit(qh, qh_ERRinput, NULL, NULL);
+      }
+      s++;
+    }
+    s++;
+  }
+  else while (*s && !isspace(*s))
+      s++;
+  return s;
+} /* skipfilename */
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/io_r.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/io_r.h
new file mode 100644
index 00000000000..eb3c7514923
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/io_r.h
@@ -0,0 +1,166 @@
+/*
  ---------------------------------
+
+   io_r.h
+   declarations of Input/Output functions
+
+   see README, libqhull_r.h and io_r.c
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/io_r.h#3 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+*/
+
+#ifndef qhDEFio
+#define qhDEFio 1
+
+#include "libqhull_r.h"
+
+/*============ constants and flags ==================*/
+
+/*----------------------------------
+
+  qh_MAXfirst
+    maximum length of first two lines of stdin
+*/
+#define qh_MAXfirst  200
+
+/*----------------------------------
+
+  qh_MINradius
+    min radius for Gp and Gv, fraction of maxcoord
+*/
+#define qh_MINradius 0.02
+
+/*----------------------------------
+
+  qh_GEOMepsilon
+    adjust outer planes for 'lines closer' and geomview roundoff.
+    This prevents bleed through.
+*/
+#define qh_GEOMepsilon 2e-3
+
+/*----------------------------------
+
+  qh_WHITESPACE
+    possible values of white space
+*/
+#define qh_WHITESPACE " \n\t\v\r\f"
+
+
+/*----------------------------------
+
+  qh_RIDGE
+    to select which ridges to print in qh_eachvoronoi
+*/
+typedef enum
+{
+    qh_RIDGEall= 0, qh_RIDGEinner, qh_RIDGEouter
+}
+qh_RIDGE;
+
+/*----------------------------------
+
+  printvridgeT
+    prints results of qh_printvdiagram
+
+  see:
+    qh_printvridge for an example
+*/
+typedef void (*printvridgeT)(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+
+/*============== -prototypes in alphabetical order =========*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void    qh_dfacet(qhT *qh, unsigned int id);
+void    qh_dvertex(qhT *qh, unsigned int id);
+int     qh_compare_facetarea(const void *p1, const void *p2);
+int     qh_compare_facetvisit(const void *p1, const void *p2);
+int     qh_compare_nummerge(const void *p1, const void *p2);
+void    qh_copyfilename(qhT *qh, char *filename, int size, const char* source, int length);
+void    qh_countfacets(qhT *qh, facetT *facetlist, setT *facets, boolT printall,
+              int *numfacetsp, int *numsimplicialp, int *totneighborsp,
+              int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp);
+pointT *qh_detvnorm(qhT *qh, vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp);
+setT   *qh_detvridge(qhT *qh, vertexT *vertex);
+setT   *qh_detvridge3(qhT *qh, vertexT *atvertex, vertexT *vertex);
+int     qh_eachvoronoi(qhT *qh, FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder);
+int     qh_eachvoronoi_all(qhT *qh, FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder);
+void    qh_facet2point(qhT *qh, facetT *facet, pointT **point0, pointT **point1, realT *mindist);
+setT   *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets);
+void    qh_geomplanes(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane);
+void    qh_markkeep(qhT *qh, facetT *facetlist);
+setT   *qh_markvoronoi(qhT *qh, facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp);
+void    qh_order_vertexneighbors(qhT *qh, vertexT *vertex);
+void    qh_prepare_output(qhT *qh);
+void    qh_printafacet(qhT *qh, FILE *fp, qh_PRINT format, facetT *facet, boolT printall);
+void    qh_printbegin(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printcenter(qhT *qh, FILE *fp, qh_PRINT format, const char *string, facetT *facet);
+void    qh_printcentrum(qhT *qh, FILE *fp, facetT *facet, realT radius);
+void    qh_printend(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printend4geom(qhT *qh, FILE *fp, facetT *facet, int *num, boolT printall);
+void    qh_printextremes(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printextremes_2d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printextremes_d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printfacet(qhT *qh, FILE *fp, facetT *facet);
+void    qh_printfacet2math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
+void    qh_printfacet2geom(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
+void    qh_printfacet2geom_points(qhT *qh, FILE *fp, pointT *point1, pointT *point2,
+                               facetT *facet, realT offset, realT color[3]);
+void    qh_printfacet3math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
+void    qh_printfacet3geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
+void    qh_printfacet3geom_points(qhT *qh, FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]);
+void    qh_printfacet3geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
+void    qh_printfacet3vertex(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format);
+void    qh_printfacet4geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
+void    qh_printfacet4geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]);
+void    qh_printfacetNvertex_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, int id, qh_PRINT format);
+void    qh_printfacetNvertex_simplicial(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format);
+void    qh_printfacetheader(qhT *qh, FILE *fp, facetT *facet);
+void    qh_printfacetridges(qhT *qh, FILE *fp, facetT *facet);
+void    qh_printfacets(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printhyperplaneintersection(qhT *qh, FILE *fp, facetT *facet1, facetT *facet2,
+                   setT *vertices, realT color[3]);
+void    qh_printline3geom(qhT *qh, FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
+void    qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
+void    qh_printpoint(qhT *qh, FILE *fp, const char *string, pointT *point);
+void    qh_printpointid(qhT *qh, FILE *fp, const char *string, int dim, pointT *point, int id);
+void    qh_printpoint3(qhT *qh, FILE *fp, pointT *point);
+void    qh_printpoints_out(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printpointvect(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]);
+void    qh_printpointvect2(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius);
+void    qh_printridge(qhT *qh, FILE *fp, ridgeT *ridge);
+void    qh_printspheres(qhT *qh, FILE *fp, setT *vertices, realT radius);
+void    qh_printvdiagram(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
+int     qh_printvdiagram2(qhT *qh, FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder);
+void    qh_printvertex(qhT *qh, FILE *fp, vertexT *vertex);
+void    qh_printvertexlist(qhT *qh, FILE *fp, const char* string, facetT *facetlist,
+                         setT *facets, boolT printall);
+void    qh_printvertices(qhT *qh, FILE *fp, const char* string, setT *vertices);
+void    qh_printvneighbors(qhT *qh, FILE *fp, facetT* facetlist, setT *facets, boolT printall);
+void    qh_printvoronoi(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printvnorm(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+void    qh_printvridge(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+void    qh_produce_output(qhT *qh);
+void    qh_produce_output2(qhT *qh);
+void    qh_projectdim3(qhT *qh, pointT *source, pointT *destination);
+int     qh_readfeasible(qhT *qh, int dim, const char *curline);
+coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc);
+void    qh_setfeasible(qhT *qh, int dim);
+boolT   qh_skipfacet(qhT *qh, facetT *facet);
+char   *qh_skipfilename(qhT *qh, char *filename);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* qhDEFio */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/libqhull_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/libqhull_r.c
new file mode 100644
index 00000000000..0d41d7be053
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/libqhull_r.c
@@ -0,0 +1,1754 @@
+/*
  ---------------------------------
+
+   libqhull_r.c
+   Quickhull algorithm for convex hulls
+
+   qhull() and top-level routines
+
+   see qh-qhull_r.htm, libqhull_r.h, unix_r.c
+
+   see qhull_ra.h for internal functions
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/libqhull_r.c#17 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+*/
+
+#include "qhull_ra.h"
+
+/*============= functions in alphabetic order after qhull() =======*/
+
+/*---------------------------------
+
+  qh_qhull(qh)
+    compute DIM3 convex hull of qh.num_points starting at qh.first_point
+    qh->contains all global options and variables
+
+  returns:
+    returns polyhedron
+      qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices,
+
+    returns global variables
+      qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex
+
+    returns precision constants
+      qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge
+
+  notes:
+    unless needed for output
+      qh.max_vertex and qh.min_vertex are max/min due to merges
+
+  see:
+    to add individual points to either qh.num_points
+      use qh_addpoint()
+
+    if qh.GETarea
+      qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea()
+
+  design:
+    record starting time
+    initialize hull and partition points
+    build convex hull
+    unless early termination
+      update facet->maxoutside for vertices, coplanar, and near-inside points
+    error if temporary sets exist
+    record end time
+*/
+
+void qh_qhull(qhT *qh) {
+  int numoutside;
+
+  qh->hulltime= qh_CPUclock;
+  if (qh->RERUN || qh->JOGGLEmax < REALmax/2)
+    qh_build_withrestart(qh);
+  else {
+    qh_initbuild(qh);
+    qh_buildhull(qh);
+  }
+  if (!qh->STOPadd && !qh->STOPcone && !qh->STOPpoint) {
+    if (qh->ZEROall_ok && !qh->TESTvneighbors && qh->MERGEexact)
+      qh_checkzero(qh, qh_ALL);
+    if (qh->ZEROall_ok && !qh->TESTvneighbors && !qh->WAScoplanar) {
+      trace2((qh, qh->ferr, 2055, "qh_qhull: all facets are clearly convex and no coplanar points.  Post-merging and check of maxout not needed.\n"));
+      qh->DOcheckmax= False;
+    }else {
+      qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
+      if (qh->MERGEexact || (qh->hull_dim > qh_DIMreduceBuild && qh->PREmerge))
+        qh_postmerge(qh, "First post-merge", qh->premerge_centrum, qh->premerge_cos,
+             (qh->POSTmerge ? False : qh->TESTvneighbors)); /* calls qh_reducevertices */
+      else if (!qh->POSTmerge && qh->TESTvneighbors)
+        qh_postmerge(qh, "For testing vertex neighbors", qh->premerge_centrum,
+             qh->premerge_cos, True);                       /* calls qh_test_vneighbors */
+      if (qh->POSTmerge)
+        qh_postmerge(qh, "For post-merging", qh->postmerge_centrum,
+             qh->postmerge_cos, qh->TESTvneighbors);
+      if (qh->visible_list == qh->facet_list) {            /* qh_postmerge was called */
+        qh->findbestnew= True;
+        qh_partitionvisible(qh, !qh_ALL, &numoutside /* qh.visible_list */);
+        qh->findbestnew= False;
+        qh_deletevisible(qh /* qh.visible_list */);        /* stops at first !f.visible */
+        qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
+      }
+      qh_all_vertexmerges(qh, -1, NULL, NULL);
+      qh_freemergesets(qh);
+    }
+    if (qh->TRACEpoint == qh_IDunknown && qh->TRACElevel > qh->IStracing) {
+      qh->IStracing= qh->TRACElevel;
+      qh_fprintf(qh, qh->ferr, 2112, "qh_qhull: finished qh_buildhull and qh_postmerge, start tracing (TP-1)\n");
+    }
+    if (qh->DOcheckmax){
+      if (qh->REPORTfreq) {
+        qh_buildtracing(qh, NULL, NULL);
+        qh_fprintf(qh, qh->ferr, 8115, "\nTesting all coplanar points.\n");
+      }
+      qh_check_maxout(qh);
+    }
+    if (qh->KEEPnearinside && !qh->maxoutdone)
+      qh_nearcoplanar(qh);
+  }
+  if (qh_setsize(qh, qh->qhmem.tempstack) != 0) {
+    qh_fprintf(qh, qh->ferr, 6164, "qhull internal error (qh_qhull): temporary sets not empty(%d) at end of Qhull\n",
+             qh_setsize(qh, qh->qhmem.tempstack));
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh->hulltime= qh_CPUclock - qh->hulltime;
+  qh->QHULLfinished= True;
+  trace1((qh, qh->ferr, 1036, "Qhull: algorithm completed\n"));
+} /* qhull */
+
+/*---------------------------------
+
+  qh_addpoint(qh, furthest, facet, checkdist )
+    add point (usually furthest point) above facet to hull
+    if checkdist,
+      check that point is above facet.
+      if point is not outside of the hull, uses qh_partitioncoplanar()
+      assumes that facet is defined by qh_findbestfacet()
+    else if facet specified,
+      assumes that point is above facet (major damage if below)
+    for Delaunay triangulations,
+      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
+      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
+
+  returns:
+    returns False if user requested an early termination
+      qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined
+    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
+    clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)
+    if unknown point, adds a pointer to qh.other_points
+      do not deallocate the point's coordinates
+
+  notes:
+    called from qh_initbuild, qh_buildhull, and qh_addpoint
+    tail recursive call if merged a pinchedvertex due to a duplicated ridge
+      no more than qh.num_vertices calls (QH6296)
+    assumes point is near its best facet and not at a local minimum of a lens
+      distributions.  Use qh_findbestfacet to avoid this case.
+    uses qh.visible_list, qh.newfacet_list, qh.delvertex_list, qh.NEWfacets
+    if called from a user application after qh_qhull and 'QJ' (joggle),
+      facet merging for precision problems is disabled by default
+
+  design:
+    exit if qh.STOPadd vertices 'TAn'
+    add point to other_points if needed
+    if checkdist
+      if point not above facet
+        partition coplanar point
+        exit
+    exit if pre STOPpoint requested
+    find horizon and visible facets for point
+    build cone of new facets to the horizon
+    exit if build cone fails due to qh.ONLYgood
+    tail recursive call if build cone fails due to pinched vertices
+    exit if STOPcone requested
+    merge non-convex new facets
+    if merge found, many merges, or 'Qf'
+       use qh_findbestnew() instead of qh_findbest()
+    partition outside points from visible facets
+    delete visible facets
+    check polyhedron if requested
+    exit if post STOPpoint requested
+    reset working lists of facets and vertices
+*/
+boolT qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist) {
+  realT dist, pbalance;
+  facetT *replacefacet, *newfacet;
+  vertexT *apex;
+  boolT isoutside= False;
+  int numpart, numpoints, goodvisible, goodhorizon, apexpointid;
+
+  qh->maxoutdone= False;
+  if (qh_pointid(qh, furthest) == qh_IDunknown)
+    qh_setappend(qh, &qh->other_points, furthest);
+  if (!facet) {
+    qh_fprintf(qh, qh->ferr, 6213, "qhull internal error (qh_addpoint): NULL facet.  Need to call qh_findbestfacet first\n");
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh_detmaxoutside(qh);
+  if (checkdist) {
+    facet= qh_findbest(qh, furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper,
+                        &dist, &isoutside, &numpart);
+    zzadd_(Zpartition, numpart);
+    if (!isoutside) {
+      zinc_(Znotmax);  /* last point of outsideset is no longer furthest. */
+      facet->notfurthest= True;
+      qh_partitioncoplanar(qh, furthest, facet, &dist, qh->findbestnew);
+      return True;
+    }
+  }
+  qh_buildtracing(qh, furthest, facet);
+  if (qh->STOPpoint < 0 && qh->furthest_id == -qh->STOPpoint-1) {
+    facet->notfurthest= True;
+    return False;
+  }
+  qh_findhorizon(qh, furthest, facet, &goodvisible, &goodhorizon);
+  if (qh->ONLYgood && !qh->GOODclosest && !(goodvisible+goodhorizon)) {
+    zinc_(Znotgood);
+    facet->notfurthest= True;
+    /* last point of outsideset is no longer furthest.  This is ok
+        since all points of the outside are likely to be bad */
+    qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
+    return True;
+  }
+  apex= qh_buildcone(qh, furthest, facet, goodhorizon, &replacefacet);
+  /* qh.newfacet_list, visible_list, newvertex_list */
+  if (!apex) {
+    if (qh->ONLYgood)
+      return True; /* ignore this furthest point, a good new facet was not found */
+    if (replacefacet) {
+      if (qh->retry_addpoint++ >= qh->num_vertices) {
+        qh_fprintf(qh, qh->ferr, 6296, "qhull internal error (qh_addpoint): infinite loop (%d retries) of merging pinched vertices due to dupridge for point p%d, facet f%d, and %d vertices\n",
+          qh->retry_addpoint, qh_pointid(qh, furthest), facet->id, qh->num_vertices);
+        qh_errexit(qh, qh_ERRqhull, facet, NULL);
+      }
+      /* retry qh_addpoint after resolving a dupridge via qh_merge_pinchedvertices */
+      return qh_addpoint(qh, furthest, replacefacet, True /* checkdisk */);
+    }
+    qh->retry_addpoint= 0;
+    return True; /* ignore this furthest point, resolved a dupridge by making furthest a coplanar point */
+  }
+  if (qh->retry_addpoint) {
+    zinc_(Zretryadd);
+    zadd_(Zretryaddtot, qh->retry_addpoint);
+    zmax_(Zretryaddmax, qh->retry_addpoint);
+    qh->retry_addpoint= 0;
+  }
+  apexpointid= qh_pointid(qh, apex->point);
+  zzinc_(Zprocessed);
+  if (qh->STOPcone && qh->furthest_id == qh->STOPcone-1) {
+    facet->notfurthest= True;
+    return False;  /* visible_list etc. still defined */
+  }
+  qh->findbestnew= False;
+  if (qh->PREmerge || qh->MERGEexact) {
+    qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
+    qh_premerge(qh, apexpointid, qh->premerge_centrum, qh->premerge_cos /* qh.newfacet_list */);
+    if (qh_USEfindbestnew)
+      qh->findbestnew= True;
+    else {
+      FORALLnew_facets {
+        if (!newfacet->simplicial) {
+          qh->findbestnew= True;  /* use qh_findbestnew instead of qh_findbest*/
+          break;
+        }
+      }
+    }
+  }else if (qh->BESToutside)
+    qh->findbestnew= True;
+  if (qh->IStracing >= 4)
+    qh_checkpolygon(qh, qh->visible_list);
+  qh_partitionvisible(qh, !qh_ALL, &numpoints /* qh.visible_list */);
+  qh->findbestnew= False;
+  qh->findbest_notsharp= False;
+  zinc_(Zpbalance);
+  pbalance= numpoints - (realT) qh->hull_dim /* assumes all points extreme */
+                * (qh->num_points - qh->num_vertices)/qh->num_vertices;
+  wadd_(Wpbalance, pbalance);
+  wadd_(Wpbalance2, pbalance * pbalance);
+  qh_deletevisible(qh /* qh.visible_list */);
+  zmax_(Zmaxvertex, qh->num_vertices);
+  qh->NEWfacets= False;
+  if (qh->IStracing >= 4) {
+    if (qh->num_facets < 200)
+      qh_printlists(qh);
+    qh_printfacetlist(qh, qh->newfacet_list, NULL, True);
+    qh_checkpolygon(qh, qh->facet_list);
+  }else if (qh->CHECKfrequently) {
+    if (qh->num_facets < 1000)
+      qh_checkpolygon(qh, qh->facet_list);
+    else
+      qh_checkpolygon(qh, qh->newfacet_list);
+  }
+  if (qh->STOPpoint > 0 && qh->furthest_id == qh->STOPpoint-1 && qh_setsize(qh, qh->vertex_mergeset) > 0)
+    return False;
+  qh_resetlists(qh, True, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
+  if (qh->facet_mergeset) {
+    /* vertex merges occur after facet merges (qh_premerge) and qh_resetlists */
+    qh_all_vertexmerges(qh, apexpointid, NULL, NULL);
+    qh_freemergesets(qh);
+  }
+  /* qh_triangulate(qh); to test qh.TRInormals */
+  if (qh->STOPpoint > 0 && qh->furthest_id == qh->STOPpoint-1)
+    return False;
+  trace2((qh, qh->ferr, 2056, "qh_addpoint: added p%d to convex hull with point balance %2.2g\n",
+    qh_pointid(qh, furthest), pbalance));
+  return True;
+} /* addpoint */
+
+/*---------------------------------
+
+  qh_build_withrestart(qh)
+    allow restarts due to qh.JOGGLEmax while calling qh_buildhull()
+       qh_errexit always undoes qh_build_withrestart()
+    qh.FIRSTpoint/qh.NUMpoints is point array
+       it may be moved by qh_joggleinput
+*/
+void qh_build_withrestart(qhT *qh) {
+  int restart;
+  vertexT *vertex, **vertexp;
+
+  qh->ALLOWrestart= True;
+  while (True) {
+    restart= setjmp(qh->restartexit); /* simple statement for CRAY J916 */
+    if (restart) {       /* only from qh_joggle_restart() */
+      qh->last_errcode= qh_ERRnone;
+      zzinc_(Zretry);
+      wmax_(Wretrymax, qh->JOGGLEmax);
+      /* QH7078 warns about using 'TCn' with 'QJn' */
+      qh->STOPcone= qh_IDunknown; /* if break from joggle, prevents normal output */
+      FOREACHvertex_(qh->del_vertices) {
+        if (vertex->point && !vertex->partitioned)
+          vertex->partitioned= True; /* avoid error in qh_freebuild -> qh_delvertex */
+      }
+    }
+    if (!qh->RERUN && qh->JOGGLEmax < REALmax/2) {
+      if (qh->build_cnt > qh_JOGGLEmaxretry) {
+        qh_fprintf(qh, qh->ferr, 6229, "qhull input error: %d attempts to construct a convex hull with joggled input.  Increase joggle above 'QJ%2.2g' or modify qh_JOGGLE... parameters in user_r.h\n",
+           qh->build_cnt, qh->JOGGLEmax);
+        qh_errexit(qh, qh_ERRinput, NULL, NULL);
+      }
+      if (qh->build_cnt && !restart)
+        break;
+    }else if (qh->build_cnt && qh->build_cnt >= qh->RERUN)
+      break;
+    qh->STOPcone= 0;
+    qh_freebuild(qh, True);  /* first call is a nop */
+    qh->build_cnt++;
+    if (!qh->qhull_optionsiz)
+      qh->qhull_optionsiz= (int)strlen(qh->qhull_options);   /* WARN64 */
+    else {
+      qh->qhull_options[qh->qhull_optionsiz]= '\0';
+      qh->qhull_optionlen= qh_OPTIONline;  /* starts a new line */
+    }
+    qh_option(qh, "_run", &qh->build_cnt, NULL);
+    if (qh->build_cnt == qh->RERUN) {
+      qh->IStracing= qh->TRACElastrun;  /* duplicated from qh_initqhull_globals */
+      if (qh->TRACEpoint != qh_IDnone || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {
+        qh->TRACElevel= (qh->IStracing? qh->IStracing : 3);
+        qh->IStracing= 0;
+      }
+      qh->qhmem.IStracing= qh->IStracing;
+    }
+    if (qh->JOGGLEmax < REALmax/2)
+      qh_joggleinput(qh);
+    qh_initbuild(qh);
+    qh_buildhull(qh);
+    if (qh->JOGGLEmax < REALmax/2 && !qh->MERGING)
+      qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
+  }
+  qh->ALLOWrestart= False;
+} /* qh_build_withrestart */
+
+/*---------------------------------
+
+  qh_buildcone(qh, furthest, facet, goodhorizon, &replacefacet )
+    build cone of new facets from furthest to the horizon
+    goodhorizon is count of good, horizon facets from qh_find_horizon
+
+  returns:
+    returns apex of cone with qh.newfacet_list and qh.first_newfacet (f.id)
+    returns NULL if qh.ONLYgood and no good facets
+    returns NULL and retryfacet if merging pinched vertices will resolve a dupridge
+      a horizon vertex was nearly adjacent to another vertex
+      will retry qh_addpoint
+    returns NULL if resolve a dupridge by making furthest a coplanar point
+      furthest was nearly adjacent to an existing vertex
+    updates qh.degen_mergeset (MRGridge) if resolve a dupridge by merging facets
+    updates qh.newfacet_list, visible_list, newvertex_list
+    updates qh.facet_list, vertex_list, num_facets, num_vertices
+
+  notes:
+    called by qh_addpoint
+    see qh_triangulate, it triangulates non-simplicial facets in post-processing
+
+  design:
+    make new facets for point to horizon
+    compute balance statistics
+    make hyperplanes for point
+    exit if qh.ONLYgood and not good (qh_buildcone_onlygood)
+    match neighboring new facets
+    if dupridges
+      exit if !qh.IGNOREpinched and dupridge resolved by coplanar furthest
+      retry qh_buildcone if !qh.IGNOREpinched and dupridge resolved by qh_buildcone_mergepinched
+      otherwise dupridges resolved by merging facets
+    update vertex neighbors and delete interior vertices
+*/
+vertexT *qh_buildcone(qhT *qh, pointT *furthest, facetT *facet, int goodhorizon, facetT **retryfacet) {
+  vertexT *apex;
+  realT newbalance;
+  int numnew;
+
+  *retryfacet= NULL;
+  qh->first_newfacet= qh->facet_id;
+  qh->NEWtentative= (qh->MERGEpinched || qh->ONLYgood); /* cleared by qh_attachnewfacets or qh_resetlists */
+  apex= qh_makenewfacets(qh, furthest /* qh.newfacet_list visible_list, attaches new facets if !qh.NEWtentative */);
+  numnew= (int)(qh->facet_id - qh->first_newfacet);
+  newbalance= numnew - (realT)(qh->num_facets - qh->num_visible) * qh->hull_dim / qh->num_vertices;
+  /* newbalance statistics updated below if the new facets are accepted */
+  if (qh->ONLYgood) { /* qh.MERGEpinched is false by QH6362 */
+    if (!qh_buildcone_onlygood(qh, apex, goodhorizon /* qh.newfacet_list */)) {
+      facet->notfurthest= True;
+      return NULL;
+    }
+  }else if(qh->MERGEpinched) {
+#ifndef qh_NOmerge
+    if (qh_buildcone_mergepinched(qh, apex, facet, retryfacet /* qh.newfacet_list */))
+      return NULL;
+#else
+    qh_fprintf(qh, qh->ferr, 6375, "qhull option error (qh_buildcone): option 'Q14' (qh.MERGEpinched) is not available due to qh_NOmerge\n");
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+#endif
+  }else {
+    /* qh_makenewfacets attached new facets to the horizon */
+    qh_matchnewfacets(qh); /* ignore returned value.  qh_forcedmerges will merge dupridges if any */
+    qh_makenewplanes(qh /* qh.newfacet_list */);
+    qh_update_vertexneighbors_cone(qh);
+  }
+  wadd_(Wnewbalance, newbalance);
+  wadd_(Wnewbalance2, newbalance * newbalance);
+  trace2((qh, qh->ferr, 2067, "qh_buildcone: created %d newfacets for p%d(v%d) new facet balance %2.2g\n",
+    numnew, qh_pointid(qh, furthest), apex->id, newbalance));
+  return apex;
+} /* buildcone */
+
+#ifndef qh_NOmerge
+/*---------------------------------
+
+  qh_buildcone_mergepinched(qh, apex, facet, maxdupdist, &retryfacet )
+    build cone of new facets from furthest to the horizon
+    maxdupdist>0.0 for merging dupridges (qh_matchdupridge)
+
+  returns:
+    returns True if merged a pinched vertex and deleted the cone of new facets
+      if retryfacet is set
+        a dupridge was resolved by qh_merge_pinchedvertices
+        retry qh_addpoint
+      otherwise
+        apex/furthest was partitioned as a coplanar point
+        ignore this furthest point
+    returns False if no dupridges or if dupridges will be resolved by MRGridge
+    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
+
+  notes:
+    only called from qh_buildcone with qh.MERGEpinched
+
+  design:
+    match neighboring new facets
+    if matching detected dupridges with a wide merge (qh_RATIOtrypinched)
+      if pinched vertices (i.e., nearly adjacent)
+        delete the cone of new facets
+        delete the apex and reset the facet lists
+        if coplanar, pinched apex
+          partition the apex as a coplanar point
+        else
+           repeatedly merge the nearest pair of pinched vertices and subsequent facet merges
+        return True
+      otherwise
+        MRGridge are better than vertex merge, but may report an error
+    attach new facets
+    make hyperplanes for point
+    update vertex neighbors and delete interior vertices
+*/
+boolT qh_buildcone_mergepinched(qhT *qh, vertexT *apex, facetT *facet, facetT **retryfacet) {
+  facetT *newfacet, *nextfacet;
+  pointT *apexpoint;
+  coordT maxdupdist;
+  int apexpointid;
+  boolT iscoplanar;
+
+  *retryfacet= NULL;
+  maxdupdist= qh_matchnewfacets(qh);
+  if (maxdupdist > qh_RATIOtrypinched * qh->ONEmerge) { /* one or more dupridges with a wide merge */
+    if (qh->IStracing >= 4 && qh->num_facets < 1000)
+      qh_printlists(qh);
+    qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
+    if (qh_getpinchedmerges(qh, apex, maxdupdist, &iscoplanar /* qh.newfacet_list, qh.vertex_mergeset */)) {
+      for (newfacet=qh->newfacet_list; newfacet && newfacet->next; newfacet= nextfacet) {
+        nextfacet= newfacet->next;
+        qh_delfacet(qh, newfacet);
+      }
+      apexpoint= apex->point;
+      apexpointid= qh_pointid(qh, apexpoint);
+      qh_delvertex(qh, apex);
+      qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
+      if (iscoplanar) {
+        zinc_(Zpinchedapex);
+        facet->notfurthest= True;
+        qh_partitioncoplanar(qh, apexpoint, facet, NULL, qh->findbestnew);
+      }else {
+        qh_all_vertexmerges(qh, apexpointid, facet, retryfacet);
+      }
+      qh_freemergesets(qh); /* errors if not empty */
+      return True;
+    }
+    /* MRGridge are better than vertex merge, but may report an error */
+    qh_freemergesets(qh);
+  }
+  qh_attachnewfacets(qh /* qh.visible_list */);
+  qh_makenewplanes(qh /* qh.newfacet_list */);
+  qh_update_vertexneighbors_cone(qh);
+  return False;
+} /* buildcone_mergepinched */
+#endif /* !qh_NOmerge */
+
+/*---------------------------------
+
+  qh_buildcone_onlygood(qh, apex, goodhorizon )
+    build cone of good, new facets from apex and its qh.newfacet_list to the horizon
+    goodhorizon is count of good, horizon facets from qh_find_horizon
+
+  returns:
+    False if a f.good facet or a qh.GOODclosest facet is not found
+    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
+
+  notes:
+    called from qh_buildcone
+    QH11030 FIX: Review effect of qh.GOODclosest on qh_buildcone_onlygood ('Qg').  qh_findgood preserves old value if didn't find a good facet.  See qh_findgood_all for disabling
+
+  design:
+    make hyperplanes for point
+    if qh_findgood fails to find a f.good facet or a qh.GOODclosest facet
+      delete cone of new facets
+      return NULL (ignores apex)
+    else
+      attach cone to horizon
+      match neighboring new facets
+*/
+boolT qh_buildcone_onlygood(qhT *qh, vertexT *apex, int goodhorizon) {
+  facetT *newfacet, *nextfacet;
+
+  qh_makenewplanes(qh /* qh.newfacet_list */);
+  if(qh_findgood(qh, qh->newfacet_list, goodhorizon) == 0) {
+    if (!qh->GOODclosest) {
+      for (newfacet=qh->newfacet_list; newfacet && newfacet->next; newfacet= nextfacet) {
+        nextfacet= newfacet->next;
+        qh_delfacet(qh, newfacet);
+      }
+      qh_delvertex(qh, apex);
+      qh_resetlists(qh, False /*no stats*/, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
+      zinc_(Znotgoodnew);
+      /* !good outside points dropped from hull */
+      return False;
+    }
+  }
+  qh_attachnewfacets(qh /* qh.visible_list */);
+  qh_matchnewfacets(qh); /* ignore returned value.  qh_forcedmerges will merge dupridges if any */
+  qh_update_vertexneighbors_cone(qh);
+  return True;
+} /* buildcone_onlygood */
+
+/*---------------------------------
+
+  qh_buildhull(qh)
+    construct a convex hull by adding outside points one at a time
+
+  returns:
+
+  notes:
+    may be called multiple times
+    checks facet and vertex lists for incorrect flags
+    to recover from STOPcone, call qh_deletevisible and qh_resetlists
+
+  design:
+    check visible facet and newfacet flags
+    check newfacet vertex flags and qh.STOPcone/STOPpoint
+    for each facet with a furthest outside point
+      add point to facet
+      exit if qh.STOPcone or qh.STOPpoint requested
+    if qh.NARROWhull for initial simplex
+      partition remaining outside points to coplanar sets
+*/
+void qh_buildhull(qhT *qh) {
+  facetT *facet;
+  pointT *furthest;
+  vertexT *vertex;
+  int id;
+
+  trace1((qh, qh->ferr, 1037, "qh_buildhull: start build hull\n"));
+  FORALLfacets {
+    if (facet->visible || facet->newfacet) {
+      qh_fprintf(qh, qh->ferr, 6165, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",
+                   facet->id);
+      qh_errexit(qh, qh_ERRqhull, facet, NULL);
+    }
+  }
+  FORALLvertices {
+    if (vertex->newfacet) {
+      qh_fprintf(qh, qh->ferr, 6166, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",
+                   vertex->id);
+      qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }
+    id= qh_pointid(qh, vertex->point);
+    if ((qh->STOPpoint>0 && id == qh->STOPpoint-1) ||
+        (qh->STOPpoint<0 && id == -qh->STOPpoint-1) ||
+        (qh->STOPcone>0 && id == qh->STOPcone-1)) {
+      trace1((qh, qh->ferr, 1038,"qh_buildhull: stop point or cone P%d in initial hull\n", id));
+      return;
+    }
+  }
+  qh->facet_next= qh->facet_list;      /* advance facet when processed */
+  while ((furthest= qh_nextfurthest(qh, &facet))) {
+    qh->num_outside--;  /* if ONLYmax, furthest may not be outside */
+    if (qh->STOPadd>0 && (qh->num_vertices - qh->hull_dim - 1 >= qh->STOPadd - 1)) {
+      trace1((qh, qh->ferr, 1059, "qh_buildhull: stop after adding %d vertices\n", qh->STOPadd-1));
+      return;
+    }
+    if (!qh_addpoint(qh, furthest, facet, qh->ONLYmax))
+      break;
+  }
+  if (qh->NARROWhull) /* move points from outsideset to coplanarset */
+    qh_outcoplanar(qh /* facet_list */ );
+  if (qh->num_outside && !furthest) {
+    qh_fprintf(qh, qh->ferr, 6167, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh->num_outside);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  trace1((qh, qh->ferr, 1039, "qh_buildhull: completed the hull construction\n"));
+} /* buildhull */
+
+
+/*---------------------------------
+
+  qh_buildtracing(qh, furthest, facet )
+    trace an iteration of qh_buildhull() for furthest point and facet
+    if !furthest, prints progress message
+
+  returns:
+    tracks progress with qh.lastreport, lastcpu, lastfacets, lastmerges, lastplanes, lastdist
+    updates qh.furthest_id (-3 if furthest is NULL)
+    also resets visit_id, vertext_visit on wrap around
+
+  see:
+    qh_tracemerging()
+
+  design:
+    if !furthest
+      print progress message
+      exit
+    if 'TFn' iteration
+      print progress message
+    else if tracing
+      trace furthest point and facet
+    reset qh.visit_id and qh.vertex_visit if overflow may occur
+    set qh.furthest_id for tracing
+*/
+void qh_buildtracing(qhT *qh, pointT *furthest, facetT *facet) {
+  realT dist= 0;
+  double cpu;
+  int total, furthestid;
+  time_t timedata;
+  struct tm *tp;
+  vertexT *vertex;
+
+  qh->old_randomdist= qh->RANDOMdist;
+  qh->RANDOMdist= False;
+  if (!furthest) {
+    time(&timedata);
+    tp= localtime(&timedata);
+    cpu= (double)qh_CPUclock - (double)qh->hulltime;
+    cpu /= (double)qh_SECticks;
+    total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+    qh_fprintf(qh, qh->ferr, 8118, "\n\
+At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
+ The current hull contains %d facets and %d vertices.  Last point was p%d\n",
+      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,
+      total, qh->num_facets, qh->num_vertices, qh->furthest_id);
+    return;
+  }
+  furthestid= qh_pointid(qh, furthest);
+#ifndef qh_NOtrace
+  if (qh->TRACEpoint == furthestid) {
+    trace1((qh, qh->ferr, 1053, "qh_buildtracing: start trace T%d for point TP%d above facet f%d\n", qh->TRACElevel, furthestid, facet->id));
+    qh->IStracing= qh->TRACElevel;
+    qh->qhmem.IStracing= qh->TRACElevel;
+  }else if (qh->TRACEpoint != qh_IDnone && qh->TRACEdist < REALmax/2) {
+    qh->IStracing= 0;
+    qh->qhmem.IStracing= 0;
+  }
+#endif
+  if (qh->REPORTfreq && (qh->facet_id-1 > qh->lastreport + (unsigned int)qh->REPORTfreq)) {
+    qh->lastreport= qh->facet_id-1;
+    time(&timedata);
+    tp= localtime(&timedata);
+    cpu= (double)qh_CPUclock - (double)qh->hulltime;
+    cpu /= (double)qh_SECticks;
+    total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+    zinc_(Zdistio);
+    qh_distplane(qh, furthest, facet, &dist);
+    qh_fprintf(qh, qh->ferr, 8119, "\n\
+At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
+ The current hull contains %d facets and %d vertices.  There are %d\n\
+ outside points.  Next is point p%d(v%d), %2.2g above f%d.\n",
+      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,
+      total, qh->num_facets, qh->num_vertices, qh->num_outside+1,
+      furthestid, qh->vertex_id, dist, getid_(facet));
+  }else if (qh->IStracing >=1) {
+    cpu= (double)qh_CPUclock - (double)qh->hulltime;
+    cpu /= (double)qh_SECticks;
+    qh_distplane(qh, furthest, facet, &dist);
+    qh_fprintf(qh, qh->ferr, 1049, "qh_addpoint: add p%d(v%d) %2.2g above f%d to hull of %d facets, %d merges, %d outside at %4.4g CPU secs.  Previous p%d(v%d) delta %4.4g CPU, %d facets, %d merges, %d hyperplanes, %d distplanes, %d retries\n",
+      furthestid, qh->vertex_id, dist, getid_(facet), qh->num_facets, zzval_(Ztotmerge), qh->num_outside+1, cpu, qh->furthest_id, qh->vertex_id - 1,
+      cpu - qh->lastcpu, qh->num_facets - qh->lastfacets,  zzval_(Ztotmerge) - qh->lastmerges, zzval_(Zsetplane) - qh->lastplanes, zzval_(Zdistplane) - qh->lastdist, qh->retry_addpoint);
+    qh->lastcpu= cpu;
+    qh->lastfacets= qh->num_facets;
+    qh->lastmerges= zzval_(Ztotmerge);
+    qh->lastplanes= zzval_(Zsetplane);
+    qh->lastdist= zzval_(Zdistplane);
+  }
+  zmax_(Zvisit2max, (int)qh->visit_id/2);
+  if (qh->visit_id > (unsigned int) INT_MAX) { /* 31 bits */
+    zinc_(Zvisit);
+    if (!qh_checklists(qh, qh->facet_list)) {
+      qh_fprintf(qh, qh->ferr, 6370, "qhull internal error: qh_checklists failed on reset of qh.visit_id %u\n", qh->visit_id);
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }
+    qh->visit_id= 0;
+    FORALLfacets
+      facet->visitid= 0;
+  }
+  zmax_(Zvvisit2max, (int)qh->vertex_visit/2);
+  if (qh->vertex_visit > (unsigned int) INT_MAX) { /* 31 bits */
+    zinc_(Zvvisit);
+    if (qh->visit_id && !qh_checklists(qh, qh->facet_list)) {
+      qh_fprintf(qh, qh->ferr, 6371, "qhull internal error: qh_checklists failed on reset of qh.vertex_visit %u\n", qh->vertex_visit);
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }
+    qh->vertex_visit= 0;
+    FORALLvertices
+      vertex->visitid= 0;
+  }
+  qh->furthest_id= furthestid;
+  qh->RANDOMdist= qh->old_randomdist;
+} /* buildtracing */
+
+/*---------------------------------
+
+  qh_errexit2(qh, exitcode, facet, otherfacet )
+    return exitcode to system after an error
+    report two facets
+
+  returns:
+    assumes exitcode non-zero
+
+  see:
+    normally use qh_errexit() in user_r.c(reports a facet and a ridge)
+*/
+void qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet) {
+  qh->tracefacet= NULL;  /* avoid infinite recursion through qh_fprintf */
+  qh->traceridge= NULL;
+  qh->tracevertex= NULL;
+  qh_errprint(qh, "ERRONEOUS", facet, otherfacet, NULL, NULL);
+  qh_errexit(qh, exitcode, NULL, NULL);
+} /* errexit2 */
+
+
+/*---------------------------------
+
+  qh_findhorizon(qh, point, facet, goodvisible, goodhorizon )
+    given a visible facet, find the point's horizon and visible facets
+    for all facets, !facet-visible
+
+  returns:
+    returns qh.visible_list/num_visible with all visible facets
+      marks visible facets with ->visible
+    updates count of good visible and good horizon facets
+    updates qh.max_outside, qh.max_vertex, facet->maxoutside
+
+  see:
+    similar to qh_delpoint()
+
+  design:
+    move facet to qh.visible_list at end of qh.facet_list
+    for all visible facets
+     for each unvisited neighbor of a visible facet
+       compute distance of point to neighbor
+       if point above neighbor
+         move neighbor to end of qh.visible_list
+       else if point is coplanar with neighbor
+         update qh.max_outside, qh.max_vertex, neighbor->maxoutside
+         mark neighbor coplanar (will create a samecycle later)
+         update horizon statistics
+*/
+void qh_findhorizon(qhT *qh, pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {
+  facetT *neighbor, **neighborp, *visible;
+  int numhorizon= 0, coplanar= 0;
+  realT dist;
+
+  trace1((qh, qh->ferr, 1040, "qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(qh, point),facet->id));
+  *goodvisible= *goodhorizon= 0;
+  zinc_(Ztotvisible);
+  qh_removefacet(qh, facet);  /* visible_list at end of qh->facet_list */
+  qh_appendfacet(qh, facet);
+  qh->num_visible= 1;
+  if (facet->good)
+    (*goodvisible)++;
+  qh->visible_list= facet;
+  facet->visible= True;
+  facet->f.replace= NULL;
+  if (qh->IStracing >=4)
+    qh_errprint(qh, "visible", facet, NULL, NULL, NULL);
+  qh->visit_id++;
+  FORALLvisible_facets {
+    if (visible->tricoplanar && !qh->TRInormals) {
+      qh_fprintf(qh, qh->ferr, 6230, "qhull internal error (qh_findhorizon): does not work for tricoplanar facets.  Use option 'Q11'\n");
+      qh_errexit(qh, qh_ERRqhull, visible, NULL);
+    }
+    if (qh_setsize(qh, visible->neighbors) == 0) {
+      qh_fprintf(qh, qh->ferr, 6295, "qhull internal error (qh_findhorizon): visible facet f%d does not have neighbors\n", visible->id);
+      qh_errexit(qh, qh_ERRqhull, visible, NULL);
+    }
+    visible->visitid= qh->visit_id;
+    FOREACHneighbor_(visible) {
+      if (neighbor->visitid == qh->visit_id)
+        continue;
+      neighbor->visitid= qh->visit_id;
+      zzinc_(Znumvisibility);
+      qh_distplane(qh, point, neighbor, &dist);
+      if (dist > qh->MINvisible) {
+        zinc_(Ztotvisible);
+        qh_removefacet(qh, neighbor);  /* append to end of qh->visible_list */
+        qh_appendfacet(qh, neighbor);
+        neighbor->visible= True;
+        neighbor->f.replace= NULL;
+        qh->num_visible++;
+        if (neighbor->good)
+          (*goodvisible)++;
+        if (qh->IStracing >=4)
+          qh_errprint(qh, "visible", neighbor, NULL, NULL, NULL);
+      }else {
+        if (dist >= -qh->MAXcoplanar) {
+          neighbor->coplanarhorizon= True;
+          zzinc_(Zcoplanarhorizon);
+          qh_joggle_restart(qh, "coplanar horizon");
+          coplanar++;
+          if (qh->MERGING) {
+            if (dist > 0) {
+              maximize_(qh->max_outside, dist);
+              maximize_(qh->max_vertex, dist);
+#if qh_MAXoutside
+              maximize_(neighbor->maxoutside, dist);
+#endif
+            }else
+              minimize_(qh->min_vertex, dist);  /* due to merge later */
+          }
+          trace2((qh, qh->ferr, 2057, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh->MINvisible(%2.7g)\n",
+              qh_pointid(qh, point), neighbor->id, dist, qh->MINvisible));
+        }else
+          neighbor->coplanarhorizon= False;
+        zinc_(Ztothorizon);
+        numhorizon++;
+        if (neighbor->good)
+          (*goodhorizon)++;
+        if (qh->IStracing >=4)
+          qh_errprint(qh, "horizon", neighbor, NULL, NULL, NULL);
+      }
+    }
+  }
+  if (!numhorizon) {
+    qh_joggle_restart(qh, "empty horizon");
+    qh_fprintf(qh, qh->ferr, 6168, "qhull topology error (qh_findhorizon): empty horizon for p%d.  It was above all facets.\n", qh_pointid(qh, point));
+    if (qh->num_facets < 100) {
+      qh_printfacetlist(qh, qh->facet_list, NULL, True);
+    }
+    qh_errexit(qh, qh_ERRtopology, NULL, NULL);
+  }
+  trace1((qh, qh->ferr, 1041, "qh_findhorizon: %d horizon facets(good %d), %d visible(good %d), %d coplanar\n",
+       numhorizon, *goodhorizon, qh->num_visible, *goodvisible, coplanar));
+  if (qh->IStracing >= 4 && qh->num_facets < 100)
+    qh_printlists(qh);
+} /* findhorizon */
+
+/*---------------------------------
+
+  qh_joggle_restart(qh, reason )
+    if joggle ('QJn') and not merging, restart on precision and topology errors
+*/
+void qh_joggle_restart(qhT *qh, const char *reason) {
+
+  if (qh->JOGGLEmax < REALmax/2) {
+    if (qh->ALLOWrestart && !qh->PREmerge && !qh->MERGEexact) {
+      trace0((qh, qh->ferr, 26, "qh_joggle_restart: qhull restart because of %s\n", reason));
+      /* May be called repeatedly if qh->ALLOWrestart */
+      longjmp(qh->restartexit, qh_ERRprec);
+    }
+  }
+} /* qh_joggle_restart */
+
+/*---------------------------------
+
+  qh_nextfurthest(qh, visible )
+    returns next furthest point and visible facet for qh_addpoint()
+    starts search at qh.facet_next
+
+  returns:
+    removes furthest point from outside set
+    NULL if none available
+    advances qh.facet_next over facets with empty outside sets
+
+  design:
+    for each facet from qh.facet_next
+      if empty outside set
+        advance qh.facet_next
+      else if qh.NARROWhull
+        determine furthest outside point
+        if furthest point is not outside
+          advance qh.facet_next(point will be coplanar)
+    remove furthest point from outside set
+*/
+pointT *qh_nextfurthest(qhT *qh, facetT **visible) {
+  facetT *facet;
+  int size, idx, loopcount= 0;
+  realT randr, dist;
+  pointT *furthest;
+
+  while ((facet= qh->facet_next) != qh->facet_tail) {
+    if (!facet || loopcount++ > qh->num_facets) {
+      qh_fprintf(qh, qh->ferr, 6406, "qhull internal error (qh_nextfurthest): null facet or infinite loop detected for qh.facet_next f%d facet_tail f%d\n",
+        getid_(facet), getid_(qh->facet_tail));
+      qh_printlists(qh);
+      qh_errexit2(qh, qh_ERRqhull, facet, qh->facet_tail);
+    }
+    if (!facet->outsideset) {
+      qh->facet_next= facet->next;
+      continue;
+    }
+    SETreturnsize_(facet->outsideset, size);
+    if (!size) {
+      qh_setfree(qh, &facet->outsideset);
+      qh->facet_next= facet->next;
+      continue;
+    }
+    if (qh->NARROWhull) {
+      if (facet->notfurthest)
+        qh_furthestout(qh, facet);
+      furthest= (pointT *)qh_setlast(facet->outsideset);
+#if qh_COMPUTEfurthest
+      qh_distplane(qh, furthest, facet, &dist);
+      zinc_(Zcomputefurthest);
+#else
+      dist= facet->furthestdist;
+#endif
+      if (dist < qh->MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */
+        qh->facet_next= facet->next;
+        continue;
+      }
+    }
+    if (!qh->RANDOMoutside && !qh->VIRTUALmemory) {
+      if (qh->PICKfurthest) {
+        qh_furthestnext(qh /* qh.facet_list */);
+        facet= qh->facet_next;
+      }
+      *visible= facet;
+      return ((pointT *)qh_setdellast(facet->outsideset));
+    }
+    if (qh->RANDOMoutside) {
+      int outcoplanar= 0;
+      if (qh->NARROWhull) {
+        FORALLfacets {
+          if (facet == qh->facet_next)
+            break;
+          if (facet->outsideset)
+            outcoplanar += qh_setsize(qh, facet->outsideset);
+        }
+      }
+      randr= qh_RANDOMint;
+      randr= randr/(qh_RANDOMmax+1);
+      randr= floor((qh->num_outside - outcoplanar) * randr);
+      idx= (int)randr;
+      FORALLfacet_(qh->facet_next) {
+        if (facet->outsideset) {
+          SETreturnsize_(facet->outsideset, size);
+          if (!size)
+            qh_setfree(qh, &facet->outsideset);
+          else if (size > idx) {
+            *visible= facet;
+            return ((pointT *)qh_setdelnth(qh, facet->outsideset, idx));
+          }else
+            idx -= size;
+        }
+      }
+      qh_fprintf(qh, qh->ferr, 6169, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n",
+              qh->num_outside, idx+1, randr);
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }else { /* VIRTUALmemory */
+      facet= qh->facet_tail->previous;
+      if (!(furthest= (pointT *)qh_setdellast(facet->outsideset))) {
+        if (facet->outsideset)
+          qh_setfree(qh, &facet->outsideset);
+        qh_removefacet(qh, facet);
+        qh_prependfacet(qh, facet, &qh->facet_list);
+        continue;
+      }
+      *visible= facet;
+      return furthest;
+    }
+  }
+  return NULL;
+} /* nextfurthest */
+
+/*---------------------------------
+
+  qh_partitionall(qh, vertices, points, numpoints )
+    partitions all points in points/numpoints to the outsidesets of facets
+    vertices= vertices in qh.facet_list(!partitioned)
+
+  returns:
+    builds facet->outsideset
+    does not partition qh.GOODpoint
+    if qh.ONLYgood && !qh.MERGING,
+      does not partition qh.GOODvertex
+
+  notes:
+    faster if qh.facet_list sorted by anticipated size of outside set
+
+  design:
+    initialize pointset with all points
+    remove vertices from pointset
+    remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)
+    for all facets
+      for all remaining points in pointset
+        compute distance from point to facet
+        if point is outside facet
+          remove point from pointset (by not reappending)
+          update bestpoint
+          append point or old bestpoint to facet's outside set
+      append bestpoint to facet's outside set (furthest)
+    for all points remaining in pointset
+      partition point into facets' outside sets and coplanar sets
+*/
+void qh_partitionall(qhT *qh, setT *vertices, pointT *points, int numpoints){
+  setT *pointset;
+  vertexT *vertex, **vertexp;
+  pointT *point, **pointp, *bestpoint;
+  int size, point_i, point_n, point_end, remaining, i, id;
+  facetT *facet;
+  realT bestdist= -REALmax, dist, distoutside;
+
+  trace1((qh, qh->ferr, 1042, "qh_partitionall: partition all points into outside sets\n"));
+  pointset= qh_settemp(qh, numpoints);
+  qh->num_outside= 0;
+  pointp= SETaddr_(pointset, pointT);
+  for (i=numpoints, point= points; i--; point += qh->hull_dim)
+    *(pointp++)= point;
+  qh_settruncate(qh, pointset, numpoints);
+  FOREACHvertex_(vertices) {
+    if ((id= qh_pointid(qh, vertex->point)) >= 0)
+      SETelem_(pointset, id)= NULL;
+  }
+  id= qh_pointid(qh, qh->GOODpointp);
+  if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)
+    SETelem_(pointset, id)= NULL;
+  if (qh->GOODvertexp && qh->ONLYgood && !qh->MERGING) { /* matches qhull()*/
+    if ((id= qh_pointid(qh, qh->GOODvertexp)) >= 0)
+      SETelem_(pointset, id)= NULL;
+  }
+  if (!qh->BESToutside) {  /* matches conditional for qh_partitionpoint below */
+    distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user_r.h */
+    zval_(Ztotpartition)= qh->num_points - qh->hull_dim - 1; /*misses GOOD... */
+    remaining= qh->num_facets;
+    point_end= numpoints;
+    FORALLfacets {
+      size= point_end/(remaining--) + 100;
+      facet->outsideset= qh_setnew(qh, size);
+      bestpoint= NULL;
+      point_end= 0;
+      FOREACHpoint_i_(qh, pointset) {
+        if (point) {
+          zzinc_(Zpartitionall);
+          qh_distplane(qh, point, facet, &dist);
+          if (dist < distoutside)
+            SETelem_(pointset, point_end++)= point;
+          else {
+            qh->num_outside++;
+            if (!bestpoint) {
+              bestpoint= point;
+              bestdist= dist;
+            }else if (dist > bestdist) {
+              qh_setappend(qh, &facet->outsideset, bestpoint);
+              bestpoint= point;
+              bestdist= dist;
+            }else
+              qh_setappend(qh, &facet->outsideset, point);
+          }
+        }
+      }
+      if (bestpoint) {
+        qh_setappend(qh, &facet->outsideset, bestpoint);
+#if !qh_COMPUTEfurthest
+        facet->furthestdist= bestdist;
+#endif
+      }else
+        qh_setfree(qh, &facet->outsideset);
+      qh_settruncate(qh, pointset, point_end);
+    }
+  }
+  /* if !qh->BESToutside, pointset contains points not assigned to outsideset */
+  if (qh->BESToutside || qh->MERGING || qh->KEEPcoplanar || qh->KEEPinside || qh->KEEPnearinside) {
+    qh->findbestnew= True;
+    FOREACHpoint_i_(qh, pointset) {
+      if (point)
+        qh_partitionpoint(qh, point, qh->facet_list);
+    }
+    qh->findbestnew= False;
+  }
+  zzadd_(Zpartitionall, zzval_(Zpartition));
+  zzval_(Zpartition)= 0;
+  qh_settempfree(qh, &pointset);
+  if (qh->IStracing >= 4)
+    qh_printfacetlist(qh, qh->facet_list, NULL, True);
+} /* partitionall */
+
+
+/*---------------------------------
+
+  qh_partitioncoplanar(qh, point, facet, dist, allnew )
+    partition coplanar point to a facet
+    dist is distance from point to facet
+    if dist NULL,
+      searches for bestfacet and does nothing if inside
+    if allnew (qh.findbestnew)
+      searches new facets instead of using qh_findbest()
+
+  returns:
+    qh.max_ouside updated
+    if qh.KEEPcoplanar or qh.KEEPinside
+      point assigned to best coplanarset
+    qh.repart_facetid==0 (for detecting infinite recursion via qh_partitionpoint)
+
+  notes:
+    facet->maxoutside is updated at end by qh_check_maxout
+
+  design:
+    if dist undefined
+      find best facet for point
+      if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside)
+        exit
+    if keeping coplanar/nearinside/inside points
+      if point is above furthest coplanar point
+        append point to coplanar set (it is the new furthest)
+        update qh.max_outside
+      else
+        append point one before end of coplanar set
+    else if point is clearly outside of qh.max_outside and bestfacet->coplanarset
+    and bestfacet is more than perpendicular to facet
+      repartition the point using qh_findbest() -- it may be put on an outsideset
+    else
+      update qh.max_outside
+*/
+void qh_partitioncoplanar(qhT *qh, pointT *point, facetT *facet, realT *dist, boolT allnew) {
+  facetT *bestfacet;
+  pointT *oldfurthest;
+  realT bestdist, angle, nearest, dist2= 0.0;
+  int numpart= 0;
+  boolT isoutside, oldfindbest, repartition= False;
+
+  trace4((qh, qh->ferr, 4090, "qh_partitioncoplanar: partition coplanar point p%d starting with f%d dist? %2.2g, allnew? %d, gh.repart_facetid f%d\n",
+    qh_pointid(qh, point), facet->id, (dist ? *dist : 0.0), allnew, qh->repart_facetid));
+  qh->WAScoplanar= True;
+  if (!dist) {
+    if (allnew)
+      bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh_ALL, &isoutside, &numpart);
+    else
+      bestfacet= qh_findbest(qh, point, facet, qh_ALL, !qh_ISnewfacets, qh->DELAUNAY,
+                          &bestdist, &isoutside, &numpart);
+    zinc_(Ztotpartcoplanar);
+    zzadd_(Zpartcoplanar, numpart);
+    if (!qh->DELAUNAY && !qh->KEEPinside) { /*  for 'd', bestdist skips upperDelaunay facets */
+      if (qh->KEEPnearinside) {
+        if (bestdist < -qh->NEARinside) {
+          zinc_(Zcoplanarinside);
+          trace4((qh, qh->ferr, 4062, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g allnew? %d\n",
+                  qh_pointid(qh, point), bestfacet->id, bestdist, allnew));
+          qh->repart_facetid= 0;
+          return;
+        }
+      }else if (bestdist < -qh->MAXcoplanar) {
+          trace4((qh, qh->ferr, 4063, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g allnew? %d\n",
+                  qh_pointid(qh, point), bestfacet->id, bestdist, allnew));
+        zinc_(Zcoplanarinside);
+        qh->repart_facetid= 0;
+        return;
+      }
+    }
+  }else {
+    bestfacet= facet;
+    bestdist= *dist;
+  }
+  if(bestfacet->visible){
+    qh_fprintf(qh, qh->ferr, 6405, "qhull internal error (qh_partitioncoplanar): cannot partition coplanar p%d of f%d into visible facet f%d\n",
+        qh_pointid(qh, point), facet->id, bestfacet->id);
+    qh_errexit2(qh, qh_ERRqhull, facet, bestfacet);
+  }
+  if (bestdist > qh->max_outside) {
+    if (!dist && facet != bestfacet) { /* can't be recursive from qh_partitionpoint since facet != bestfacet */
+      zinc_(Zpartangle);
+      angle= qh_getangle(qh, facet->normal, bestfacet->normal);
+      if (angle < 0) {
+        nearest= qh_vertex_bestdist(qh, bestfacet->vertices);
+        /* typically due to deleted vertex and coplanar facets, e.g.,
+        RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */
+        zinc_(Zpartcorner);
+        trace2((qh, qh->ferr, 2058, "qh_partitioncoplanar: repartition coplanar point p%d from f%d as an outside point above corner facet f%d dist %2.2g with angle %2.2g\n",
+          qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, angle));
+        repartition= True;
+      }
+    }
+    if (!repartition) {
+      if (bestdist > qh->MAXoutside * qh_RATIOcoplanaroutside) {
+        nearest= qh_vertex_bestdist(qh, bestfacet->vertices);
+        if (facet->id == bestfacet->id) {
+          if (facet->id == qh->repart_facetid) {
+            qh_fprintf(qh, qh->ferr, 6404, "Qhull internal error (qh_partitioncoplanar): infinite loop due to recursive call to qh_partitionpoint.  Repartition point p%d from f%d as a outside point dist %2.2g nearest vertices %2.2g\n",
+              qh_pointid(qh, point), facet->id, bestdist, nearest);
+            qh_errexit(qh, qh_ERRqhull, facet, NULL);
+          }
+          qh->repart_facetid= facet->id; /* reset after call to qh_partitionpoint */
+        }
+        if (point == qh->coplanar_apex) {
+          /* otherwise may loop indefinitely, the point is well above a facet, yet near a vertex */
+          qh_fprintf(qh, qh->ferr, 6425, "Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p%d from f%d as outside point above f%d.  It previously failed to form a cone of facets, dist %2.2g, nearest vertices %2.2g\n",
+            qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, nearest);
+          qh_errexit(qh, qh_ERRtopology, facet, NULL);
+        }
+        if (nearest < 2 * qh->MAXoutside * qh_RATIOcoplanaroutside) {
+          zinc_(Zparttwisted);
+          qh_fprintf(qh, qh->ferr, 7085, "Qhull precision warning: repartition coplanar point p%d from f%d as an outside point above twisted facet f%d dist %2.2g nearest vertices %2.2g\n",
+            qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, nearest);
+        }else {
+          zinc_(Zparthidden);
+          qh_fprintf(qh, qh->ferr, 7086, "Qhull precision warning: repartition coplanar point p%d from f%d as an outside point above hidden facet f%d dist %2.2g nearest vertices %2.2g\n",
+            qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, nearest);
+        }
+        repartition= True;
+      }
+    }
+    if (repartition) {
+      oldfindbest= qh->findbestnew;
+      qh->findbestnew= False;
+      qh_partitionpoint(qh, point, bestfacet);
+      qh->findbestnew= oldfindbest;
+      qh->repart_facetid= 0;
+      return;
+    }
+    qh->repart_facetid= 0;
+    qh->max_outside= bestdist;
+    if (bestdist > qh->TRACEdist || qh->IStracing >= 3) {
+      qh_fprintf(qh, qh->ferr, 3041, "qh_partitioncoplanar: == p%d from f%d increases qh.max_outside to %2.2g of f%d last p%d\n",
+                     qh_pointid(qh, point), facet->id, bestdist, bestfacet->id, qh->furthest_id);
+      qh_errprint(qh, "DISTANT", facet, bestfacet, NULL, NULL);
+    }
+  }
+  if (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside) {
+    oldfurthest= (pointT *)qh_setlast(bestfacet->coplanarset);
+    if (oldfurthest) {
+      zinc_(Zcomputefurthest);
+      qh_distplane(qh, oldfurthest, bestfacet, &dist2);
+    }
+    if (!oldfurthest || dist2 < bestdist)
+      qh_setappend(qh, &bestfacet->coplanarset, point);
+    else
+      qh_setappend2ndlast(qh, &bestfacet->coplanarset, point);
+  }
+  trace4((qh, qh->ferr, 4064, "qh_partitioncoplanar: point p%d is coplanar with facet f%d (or inside) dist %2.2g\n",
+          qh_pointid(qh, point), bestfacet->id, bestdist));
+} /* partitioncoplanar */
+
+/*---------------------------------
+
+  qh_partitionpoint(qh, point, facet )
+    assigns point to an outside set, coplanar set, or inside set (i.e., dropt)
+    if qh.findbestnew
+      uses qh_findbestnew() to search all new facets
+    else
+      uses qh_findbest()
+
+  notes:
+    after qh_distplane(), this and qh_findbest() are most expensive in 3-d
+
+  design:
+    find best facet for point
+      (either exhaustive search of new facets or directed search from facet)
+    if qh.NARROWhull
+      retain coplanar and nearinside points as outside points
+    if point is outside bestfacet
+      if point above furthest point for bestfacet
+        append point to outside set (it becomes the new furthest)
+        if outside set was empty
+          move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)
+        update bestfacet->furthestdist
+      else
+        append point one before end of outside set
+    else if point is coplanar to bestfacet
+      if keeping coplanar points or need to update qh.max_outside
+        partition coplanar point into bestfacet
+    else if near-inside point
+      partition as coplanar point into bestfacet
+    else is an inside point
+      if keeping inside points
+        partition as coplanar point into bestfacet
+*/
+void qh_partitionpoint(qhT *qh, pointT *point, facetT *facet) {
+  realT bestdist, previousdist;
+  boolT isoutside, isnewoutside= False;
+  facetT *bestfacet;
+  int numpart;
+
+  if (qh->findbestnew)
+    bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh->BESToutside, &isoutside, &numpart);
+  else
+    bestfacet= qh_findbest(qh, point, facet, qh->BESToutside, qh_ISnewfacets, !qh_NOupper,
+                          &bestdist, &isoutside, &numpart);
+  zinc_(Ztotpartition);
+  zzadd_(Zpartition, numpart);
+  if(bestfacet->visible){
+    qh_fprintf(qh, qh->ferr, 6293, "qhull internal error (qh_partitionpoint): cannot partition p%d of f%d into visible facet f%d\n",
+      qh_pointid(qh, point), facet->id, bestfacet->id);
+    qh_errexit2(qh, qh_ERRqhull, facet, bestfacet);
+  }
+  if (qh->NARROWhull) {
+    if (qh->DELAUNAY && !isoutside && bestdist >= -qh->MAXcoplanar)
+      qh_joggle_restart(qh, "nearly incident point (narrow hull)");
+    if (qh->KEEPnearinside) {
+      if (bestdist >= -qh->NEARinside)
+        isoutside= True;
+    }else if (bestdist >= -qh->MAXcoplanar)
+      isoutside= True;
+  }
+
+  if (isoutside) {
+    if (!bestfacet->outsideset
+    || !qh_setlast(bestfacet->outsideset)) { /* empty outside set */
+      qh_setappend(qh, &(bestfacet->outsideset), point);
+      if (!qh->NARROWhull || bestdist > qh->MINoutside)
+        isnewoutside= True;
+#if !qh_COMPUTEfurthest
+      bestfacet->furthestdist= bestdist;
+#endif
+    }else {
+#if qh_COMPUTEfurthest
+      zinc_(Zcomputefurthest);
+      qh_distplane(qh, oldfurthest, bestfacet, &previousdist);
+      if (previousdist < bestdist)
+        qh_setappend(qh, &(bestfacet->outsideset), point);
+      else
+        qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);
+#else
+      previousdist= bestfacet->furthestdist;
+      if (previousdist < bestdist) {
+        qh_setappend(qh, &(bestfacet->outsideset), point);
+        bestfacet->furthestdist= bestdist;
+        if (qh->NARROWhull && previousdist < qh->MINoutside && bestdist >= qh->MINoutside)
+          isnewoutside= True;
+      }else
+        qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);
+#endif
+    }
+    if (isnewoutside && qh->facet_next != bestfacet) {
+      if (bestfacet->newfacet) {
+        if (qh->facet_next->newfacet)
+          qh->facet_next= qh->newfacet_list; /* make sure it's after qh.facet_next */
+      }else {
+        qh_removefacet(qh, bestfacet);  /* make sure it's after qh.facet_next */
+        qh_appendfacet(qh, bestfacet);
+        if(qh->newfacet_list){
+          bestfacet->newfacet= True;
+        }
+      }
+    }
+    qh->num_outside++;
+    trace4((qh, qh->ferr, 4065, "qh_partitionpoint: point p%d is outside facet f%d newfacet? %d, newoutside? %d (or narrowhull)\n",
+          qh_pointid(qh, point), bestfacet->id, bestfacet->newfacet, isnewoutside));
+  }else if (qh->DELAUNAY || bestdist >= -qh->MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */
+    if (qh->DELAUNAY)
+      qh_joggle_restart(qh, "nearly incident point");
+    /* allow coplanar points with joggle, may be interior */
+    zzinc_(Zcoplanarpart);
+    if ((qh->KEEPcoplanar + qh->KEEPnearinside) || bestdist > qh->max_outside)
+      qh_partitioncoplanar(qh, point, bestfacet, &bestdist, qh->findbestnew);
+    else {
+      trace4((qh, qh->ferr, 4066, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n",
+          qh_pointid(qh, point), bestfacet->id));
+    }
+  }else if (qh->KEEPnearinside && bestdist >= -qh->NEARinside) {
+    zinc_(Zpartnear);
+    qh_partitioncoplanar(qh, point, bestfacet, &bestdist, qh->findbestnew);
+  }else {
+    zinc_(Zpartinside);
+    trace4((qh, qh->ferr, 4067, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",
+          qh_pointid(qh, point), bestfacet->id, bestdist));
+    if (qh->KEEPinside)
+      qh_partitioncoplanar(qh, point, bestfacet, &bestdist, qh->findbestnew);
+  }
+} /* partitionpoint */
+
+/*---------------------------------
+
+  qh_partitionvisible(qh, allpoints, numoutside )
+    partitions outside points in visible facets (qh.visible_list) to qh.newfacet_list
+    if keeping coplanar/near-inside/inside points
+      partitions coplanar points; repartitions if 'allpoints' (not used)
+    1st neighbor (if any) of visible facets points to a horizon facet or a new facet
+
+  returns:
+    updates outside sets and coplanar sets of qh.newfacet_list
+    updates qh.num_outside (count of outside points)
+    does not truncate f.outsideset, f.coplanarset, or qh.del_vertices (see qh_deletevisible)
+
+  notes:
+    called by qh_qhull, qh_addpoint, and qh_all_vertexmerges
+    qh.findbest_notsharp should be clear (extra work if set)
+
+  design:
+    for all visible facets with outside set or coplanar set
+      select a newfacet for visible facet
+      if outside set
+        partition outside set into new facets
+      if coplanar set and keeping coplanar/near-inside/inside points
+        if allpoints
+          partition coplanar set into new facets, may be assigned outside
+        else
+          partition coplanar set into coplanar sets of new facets
+    for each deleted vertex
+      if allpoints
+        partition vertex into new facets, may be assigned outside
+      else
+        partition vertex into coplanar sets of new facets
+*/
+void qh_partitionvisible(qhT *qh, boolT allpoints, int *numoutside /* qh.visible_list */) {
+  facetT *visible, *newfacet;
+  pointT *point, **pointp;
+  int delsize, coplanar=0, size;
+  vertexT *vertex, **vertexp;
+
+  trace3((qh, qh->ferr, 3042, "qh_partitionvisible: partition outside and coplanar points of visible and merged facets f%d into new facets f%d\n",
+    qh->visible_list->id, qh->newfacet_list->id));
+  if (qh->ONLYmax)
+    maximize_(qh->MINoutside, qh->max_vertex);
+  *numoutside= 0;
+  FORALLvisible_facets {
+    if (!visible->outsideset && !visible->coplanarset)
+      continue;
+    newfacet= qh_getreplacement(qh, visible);
+    if (!newfacet)
+      newfacet= qh->newfacet_list;
+    if (!newfacet->next) {
+      qh_fprintf(qh, qh->ferr, 6170, "qhull topology error (qh_partitionvisible): all new facets deleted as\n       degenerate facets. Can not continue.\n");
+      qh_errexit(qh, qh_ERRtopology, NULL, NULL);
+    }
+    if (visible->outsideset) {
+      size= qh_setsize(qh, visible->outsideset);
+      *numoutside += size;
+      qh->num_outside -= size;
+      FOREACHpoint_(visible->outsideset)
+        qh_partitionpoint(qh, point, newfacet);
+    }
+    if (visible->coplanarset && (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside)) {
+      size= qh_setsize(qh, visible->coplanarset);
+      coplanar += size;
+      FOREACHpoint_(visible->coplanarset) {
+        if (allpoints) /* not used */
+          qh_partitionpoint(qh, point, newfacet);
+        else
+          qh_partitioncoplanar(qh, point, newfacet, NULL, qh->findbestnew);
+      }
+    }
+  }
+  delsize= qh_setsize(qh, qh->del_vertices);
+  if (delsize > 0) {
+    trace3((qh, qh->ferr, 3049, "qh_partitionvisible: partition %d deleted vertices as coplanar? %d points into new facets f%d\n",
+      delsize, !allpoints, qh->newfacet_list->id));
+    FOREACHvertex_(qh->del_vertices) {
+      if (vertex->point && !vertex->partitioned) {
+        if (!qh->newfacet_list || qh->newfacet_list == qh->facet_tail) {
+          qh_fprintf(qh, qh->ferr, 6284, "qhull internal error (qh_partitionvisible): all new facets deleted or none defined.  Can not partition deleted v%d.\n", vertex->id);
+          qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+        }
+        if (allpoints) /* not used */
+          /* [apr'2019] infinite loop if vertex recreates the same facets from the same horizon
+             e.g., qh_partitionpoint if qh.DELAUNAY with qh.MERGEindependent for all mergetype, ../eg/qtest.sh t427764 '1000 s W1e-13 D3' 'd' */
+          qh_partitionpoint(qh, vertex->point, qh->newfacet_list);
+        else
+          qh_partitioncoplanar(qh, vertex->point, qh->newfacet_list, NULL, qh_ALL); /* search all new facets */
+        vertex->partitioned= True;
+      }
+    }
+  }
+  trace1((qh, qh->ferr, 1043,"qh_partitionvisible: partitioned %d points from outsidesets, %d points from coplanarsets, and %d deleted vertices\n", *numoutside, coplanar, delsize));
+} /* partitionvisible */
+
+/*---------------------------------
+
+  qh_printsummary(qh, fp )
+    prints summary to fp
+
+  notes:
+    not in io_r.c so that user_eg.c can prevent io_r.c from loading
+    qh_printsummary and qh_countfacets must match counts
+    updates qh.facet_visit to detect infinite loop
+
+  design:
+    determine number of points, vertices, and coplanar points
+    print summary
+*/
+void qh_printsummary(qhT *qh, FILE *fp) {
+  realT ratio, outerplane, innerplane;
+  double cpu;
+  int size, id, nummerged, numpinched, numvertices, numcoplanars= 0, nonsimplicial=0, numdelaunay= 0;
+  facetT *facet;
+  const char *s;
+  int numdel= zzval_(Zdelvertextot);
+  int numtricoplanars= 0;
+  boolT goodused;
+
+  size= qh->num_points + qh_setsize(qh, qh->other_points);
+  numvertices= qh->num_vertices - qh_setsize(qh, qh->del_vertices);
+  id= qh_pointid(qh, qh->GOODpointp);
+  if (!qh_checklists(qh, qh->facet_list) && !qh->ERREXITcalled) {
+    qh_fprintf(qh, fp, 6372, "qhull internal error: qh_checklists failed at qh_printsummary\n");
+    if (qh->num_facets < 4000)
+      qh_printlists(qh);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  if (qh->DELAUNAY && qh->ERREXITcalled) {
+    /* update f.good and determine qh.num_good as in qh_findgood_all */
+    FORALLfacets {
+      if (facet->visible)
+        facet->good= False; /* will be deleted */
+      else if (facet->good) {
+        if (facet->normal && !qh_inthresholds(qh, facet->normal, NULL))
+          facet->good= False;
+        else
+          numdelaunay++;
+      }
+    }
+    qh->num_good= numdelaunay;
+  }
+  FORALLfacets {
+    if (facet->coplanarset)
+      numcoplanars += qh_setsize(qh, facet->coplanarset);
+    if (facet->good) {
+      if (facet->simplicial) {
+        if (facet->keepcentrum && facet->tricoplanar)
+          numtricoplanars++;
+      }else if (qh_setsize(qh, facet->vertices) != qh->hull_dim)
+        nonsimplicial++;
+    }
+  }
+  if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)
+    size--;
+  if (qh->STOPadd || qh->STOPcone || qh->STOPpoint)
+    qh_fprintf(qh, fp, 9288, "\nEarly exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'.");
+  goodused= False;
+  if (qh->ERREXITcalled)
+    ; /* qh_findgood_all not called */
+  else if (qh->UPPERdelaunay) {
+    if (qh->GOODvertex || qh->GOODpoint || qh->SPLITthresholds)
+      goodused= True;
+  }else if (qh->DELAUNAY) {
+    if (qh->GOODvertex || qh->GOODpoint || qh->GOODthreshold)
+      goodused= True;
+  }else if (qh->num_good > 0 || qh->GOODthreshold)
+    goodused= True;
+  nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+  if (qh->VORONOI) {
+    if (qh->UPPERdelaunay)
+      qh_fprintf(qh, fp, 9289, "\n\
+Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
+    else
+      qh_fprintf(qh, fp, 9290, "\n\
+Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
+    qh_fprintf(qh, fp, 9291, "  Number of Voronoi regions%s: %d\n",
+              qh->ATinfinity ? " and at-infinity" : "", numvertices);
+    if (numdel)
+      qh_fprintf(qh, fp, 9292, "  Total number of deleted points due to merging: %d\n", numdel);
+    if (numcoplanars - numdel > 0)
+      qh_fprintf(qh, fp, 9293, "  Number of nearly incident points: %d\n", numcoplanars - numdel);
+    else if (size - numvertices - numdel > 0)
+      qh_fprintf(qh, fp, 9294, "  Total number of nearly incident points: %d\n", size - numvertices - numdel);
+    qh_fprintf(qh, fp, 9295, "  Number of%s Voronoi vertices: %d\n",
+              goodused ? " 'good'" : "", qh->num_good);
+    if (nonsimplicial)
+      qh_fprintf(qh, fp, 9296, "  Number of%s non-simplicial Voronoi vertices: %d\n",
+              goodused ? " 'good'" : "", nonsimplicial);
+  }else if (qh->DELAUNAY) {
+    if (qh->UPPERdelaunay)
+      qh_fprintf(qh, fp, 9297, "\n\
+Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
+    else
+      qh_fprintf(qh, fp, 9298, "\n\
+Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
+    qh_fprintf(qh, fp, 9299, "  Number of input sites%s: %d\n",
+              qh->ATinfinity ? " and at-infinity" : "", numvertices);
+    if (numdel)
+      qh_fprintf(qh, fp, 9300, "  Total number of deleted points due to merging: %d\n", numdel);
+    if (numcoplanars - numdel > 0)
+      qh_fprintf(qh, fp, 9301, "  Number of nearly incident points: %d\n", numcoplanars - numdel);
+    else if (size - numvertices - numdel > 0)
+      qh_fprintf(qh, fp, 9302, "  Total number of nearly incident points: %d\n", size - numvertices - numdel);
+    qh_fprintf(qh, fp, 9303, "  Number of%s Delaunay regions: %d\n",
+              goodused ? " 'good'" : "", qh->num_good);
+    if (nonsimplicial)
+      qh_fprintf(qh, fp, 9304, "  Number of%s non-simplicial Delaunay regions: %d\n",
+              goodused ? " 'good'" : "", nonsimplicial);
+  }else if (qh->HALFspace) {
+    qh_fprintf(qh, fp, 9305, "\n\
+Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
+    qh_fprintf(qh, fp, 9306, "  Number of halfspaces: %d\n", size);
+    qh_fprintf(qh, fp, 9307, "  Number of non-redundant halfspaces: %d\n", numvertices);
+    if (numcoplanars) {
+      if (qh->KEEPinside && qh->KEEPcoplanar)
+        s= "similar and redundant";
+      else if (qh->KEEPinside)
+        s= "redundant";
+      else
+        s= "similar";
+      qh_fprintf(qh, fp, 9308, "  Number of %s halfspaces: %d\n", s, numcoplanars);
+    }
+    qh_fprintf(qh, fp, 9309, "  Number of intersection points: %d\n", qh->num_facets - qh->num_visible);
+    if (goodused)
+      qh_fprintf(qh, fp, 9310, "  Number of 'good' intersection points: %d\n", qh->num_good);
+    if (nonsimplicial)
+      qh_fprintf(qh, fp, 9311, "  Number of%s non-simplicial intersection points: %d\n",
+              goodused ? " 'good'" : "", nonsimplicial);
+  }else {
+    qh_fprintf(qh, fp, 9312, "\n\
+Convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
+    qh_fprintf(qh, fp, 9313, "  Number of vertices: %d\n", numvertices);
+    if (numcoplanars) {
+      if (qh->KEEPinside && qh->KEEPcoplanar)
+        s= "coplanar and interior";
+      else if (qh->KEEPinside)
+        s= "interior";
+      else
+        s= "coplanar";
+      qh_fprintf(qh, fp, 9314, "  Number of %s points: %d\n", s, numcoplanars);
+    }
+    qh_fprintf(qh, fp, 9315, "  Number of facets: %d\n", qh->num_facets - qh->num_visible);
+    if (goodused)
+      qh_fprintf(qh, fp, 9316, "  Number of 'good' facets: %d\n", qh->num_good);
+    if (nonsimplicial)
+      qh_fprintf(qh, fp, 9317, "  Number of%s non-simplicial facets: %d\n",
+              goodused ? " 'good'" : "", nonsimplicial);
+  }
+  if (numtricoplanars)
+      qh_fprintf(qh, fp, 9318, "  Number of triangulated facets: %d\n", numtricoplanars);
+  qh_fprintf(qh, fp, 9319, "\nStatistics for: %s | %s",
+                      qh->rbox_command, qh->qhull_command);
+  if (qh->ROTATErandom != INT_MIN)
+    qh_fprintf(qh, fp, 9320, " QR%d\n\n", qh->ROTATErandom);
+  else
+    qh_fprintf(qh, fp, 9321, "\n\n");
+  qh_fprintf(qh, fp, 9322, "  Number of points processed: %d\n", zzval_(Zprocessed));
+  qh_fprintf(qh, fp, 9323, "  Number of hyperplanes created: %d\n", zzval_(Zsetplane));
+  if (qh->DELAUNAY)
+    qh_fprintf(qh, fp, 9324, "  Number of facets in hull: %d\n", qh->num_facets - qh->num_visible);
+  qh_fprintf(qh, fp, 9325, "  Number of distance tests for qhull: %d\n", zzval_(Zpartition)+
+      zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));
+#if 0  /* NOTE: must print before printstatistics() */
+  {realT stddev, ave;
+  qh_fprintf(qh, fp, 9326, "  average new facet balance: %2.2g\n",
+          wval_(Wnewbalance)/zval_(Zprocessed));
+  stddev= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),
+                                 wval_(Wnewbalance2), &ave);
+  qh_fprintf(qh, fp, 9327, "  new facet standard deviation: %2.2g\n", stddev);
+  qh_fprintf(qh, fp, 9328, "  average partition balance: %2.2g\n",
+          wval_(Wpbalance)/zval_(Zpbalance));
+  stddev= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),
+                                 wval_(Wpbalance2), &ave);
+  qh_fprintf(qh, fp, 9329, "  partition standard deviation: %2.2g\n", stddev);
+  }
+#endif
+  if (nummerged) {
+    qh_fprintf(qh, fp, 9330,"  Number of distance tests for merging: %d\n",zzval_(Zbestdist)+
+          zzval_(Zcentrumtests)+zzval_(Zvertextests)+zzval_(Zdistcheck)+zzval_(Zdistzero));
+    qh_fprintf(qh, fp, 9331,"  Number of distance tests for checking: %d\n",zzval_(Zcheckpart)+zzval_(Zdistconvex));
+    qh_fprintf(qh, fp, 9332,"  Number of merged facets: %d\n", nummerged);
+  }
+  numpinched= zzval_(Zpinchduplicate) + zzval_(Zpinchedvertex);
+  if (numpinched)
+    qh_fprintf(qh, fp, 9375,"  Number of merged pinched vertices: %d\n", numpinched);
+  if (!qh->RANDOMoutside && qh->QHULLfinished) {
+    cpu= (double)qh->hulltime;
+    cpu /= (double)qh_SECticks;
+    wval_(Wcpu)= cpu;
+    qh_fprintf(qh, fp, 9333, "  CPU seconds to compute hull (after input): %2.4g\n", cpu);
+  }
+  if (qh->RERUN) {
+    if (!qh->PREmerge && !qh->MERGEexact)
+      qh_fprintf(qh, fp, 9334, "  Percentage of runs with precision errors: %4.1f\n",
+           zzval_(Zretry)*100.0/qh->build_cnt);  /* careful of order */
+  }else if (qh->JOGGLEmax < REALmax/2) {
+    if (zzval_(Zretry))
+      qh_fprintf(qh, fp, 9335, "  After %d retries, input joggled by: %2.2g\n",
+         zzval_(Zretry), qh->JOGGLEmax);
+    else
+      qh_fprintf(qh, fp, 9336, "  Input joggled by: %2.2g\n", qh->JOGGLEmax);
+  }
+  if (qh->totarea != 0.0)
+    qh_fprintf(qh, fp, 9337, "  %s facet area:   %2.8g\n",
+            zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totarea);
+  if (qh->totvol != 0.0)
+    qh_fprintf(qh, fp, 9338, "  %s volume:       %2.8g\n",
+            zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totvol);
+  if (qh->MERGING) {
+    qh_outerinner(qh, NULL, &outerplane, &innerplane);
+    if (outerplane > 2 * qh->DISTround) {
+      qh_fprintf(qh, fp, 9339, "  Maximum distance of point above facet: %2.2g", outerplane);
+      ratio= outerplane/(qh->ONEmerge + qh->DISTround);
+      /* don't report ratio if MINoutside is large */
+      if (ratio > 0.05 && 2* qh->ONEmerge > qh->MINoutside && qh->JOGGLEmax > REALmax/2)
+        qh_fprintf(qh, fp, 9340, " (%.1fx)\n", ratio);
+      else
+        qh_fprintf(qh, fp, 9341, "\n");
+    }
+    if (innerplane < -2 * qh->DISTround) {
+      qh_fprintf(qh, fp, 9342, "  Maximum distance of vertex below facet: %2.2g", innerplane);
+      ratio= -innerplane/(qh->ONEmerge+qh->DISTround);
+      if (ratio > 0.05 && qh->JOGGLEmax > REALmax/2)
+        qh_fprintf(qh, fp, 9343, " (%.1fx)\n", ratio);
+      else
+        qh_fprintf(qh, fp, 9344, "\n");
+    }
+  }
+  qh_fprintf(qh, fp, 9345, "\n");
+} /* printsummary */
+
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/libqhull_r.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/libqhull_r.h
new file mode 100644
index 00000000000..7193e2a5bed
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/libqhull_r.h
@@ -0,0 +1,1281 @@
+/*
  ---------------------------------
+
+   libqhull_r.h
+   user-level header file for using qhull.a library
+
+   see qh-qhull_r.htm, qhull_ra.h
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/libqhull_r.h#18 $$Change: 3664 $
+   $DateTime: 2024/07/22 23:55:01 $$Author: bbarber $
+
+   includes function prototypes for libqhull_r.c, geom_r.c, global_r.c, io_r.c, user_r.c
+
+   use mem_r.h for mem_r.c
+   use qset_r.h for qset_r.c
+
+   see unix_r.c for an example of using libqhull_r.h
+
+   recompile qhull if you change this file
+*/
+
+#ifndef qhDEFlibqhull
+#define qhDEFlibqhull 1
+
+/*=========================== -included files ==============*/
+
+/* user_r.h first for QHULL_CRTDBG */
+#include "user_r.h"      /* user definable constants (e.g., realT). */
+
+#include "mem_r.h"   /* Needed for qhT in libqhull_r.h */
+#include "qset_r.h"   /* Needed for QHULL_LIB_CHECK */
+/* include stat_r.h after defining boolT.  Needed for qhT in libqhull_r.h */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifndef __STDC__
+#ifndef __cplusplus
+#if     !defined(_MSC_VER)
+#error  Neither __STDC__ nor __cplusplus is defined.  Please use strict ANSI C or C++ to compile
+#error  Qhull.  You may need to turn off compiler extensions in your project configuration.  If
+#error  your compiler is a standard C compiler, you can delete this warning from libqhull_r.h
+#endif
+#endif
+#endif
+
+#if defined(__GNUC__)
+/* See https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-format-function-attribute */
+#define QH_PRINTF_LIKE(string_index, first_to_check) __attribute__((format(printf, string_index, first_to_check)))
+#else
+#define QH_PRINTF_LIKE(string_index, first_to_check)
+#endif
+
+/* QH_NORETURN marks as a function as never returning. This is primarily
+   beneficial for aiding static analyzers and reducing compiler warnings.
+   It must come before function declarations, as MSVC only supports this syntax. */
+#if defined(__GNUC__)
+/* Compilers that support the GNU C syntax. Use __noreturn__ instead of 'noreturn' as the latter is a macro in C11. */
+#define QH_NORETURN __attribute__((__noreturn__))
+#elif defined(_MSC_VER)
+/* Compilers that support the MSVC syntax. */
+#define QH_NORETURN __declspec(noreturn)
+#else
+#define QH_NORETURN /* empty */
+#endif
+
+/*============ constants and basic types ====================*/
+
+extern const char qh_version[]; /* defined in global_r.c */
+extern const char qh_version2[]; /* defined in global_r.c */
+
+/*----------------------------------
+
+  coordT
+    coordinates and coefficients are stored as realT (i.e., double)
+
+  notes:
+    Qhull works well if realT is 'float'.  If so joggle (QJ) is not effective.
+
+    Could use 'float' for data and 'double' for calculations (realT vs. coordT)
+      This requires many type casts, and adjusted error bounds.
+      Also C compilers may do expressions in double anyway.
+*/
+#define coordT realT
+
+/*----------------------------------
+
+  pointT
+    a point is an array of coordinates, usually qh.hull_dim
+    qh_pointid returns
+      qh_IDnone if point==0 or qh is undefined
+      qh_IDinterior for qh.interior_point
+      qh_IDunknown if point is neither in qh.first_point... nor qh.other_points
+
+  notes:
+    qh.STOPcone and qh.STOPpoint assume that qh_IDunknown==-1 (other negative numbers indicate points)
+    qh_IDunknown is also returned by getid_() for unknown facet, ridge, or vertex
+*/
+#define pointT coordT
+typedef enum
+{
+    qh_IDnone= -3, qh_IDinterior= -2, qh_IDunknown= -1
+}
+qh_pointT;
+
+/*----------------------------------
+
+  flagT
+    Boolean flag as a bit
+*/
+#define flagT unsigned int
+
+/*----------------------------------
+
+  boolT
+    boolean value, either True or False
+
+  notes:
+    needed for portability
+    Use qh_False/qh_True as synonyms
+*/
+#define boolT unsigned int
+#ifdef False
+#undef False
+#endif
+#ifdef True
+#undef True
+#endif
+#define False 0
+#define True 1
+#define qh_False 0
+#define qh_True 1
+
+#include "stat_r.h"  /* needs boolT */
+
+/*----------------------------------
+
+  qh_CENTER
+    to distinguish facet->center
+*/
+typedef enum
+{
+    qh_ASnone= 0,    /* If not MERGING and not VORONOI */
+    qh_ASvoronoi,    /* Set by qh_clearcenters on qh_prepare_output, or if not MERGING and VORONOI */
+    qh_AScentrum     /* If MERGING (assumed during merging) */
+}
+qh_CENTER;
+
+/*----------------------------------
+
+  qh_PRINT
+    output formats for printing (qh.PRINTout).
+    'Fa' 'FV' 'Fc' 'FC'
+
+
+   notes:
+   some of these names are similar to qhT names.  The similar names are only
+   used in switch statements in qh_printbegin() etc.
+*/
+typedef enum {qh_PRINTnone= 0,
+  qh_PRINTarea, qh_PRINTaverage,           /* 'Fa' 'FV' 'Fc' 'FC' */
+  qh_PRINTcoplanars, qh_PRINTcentrums,
+  qh_PRINTfacets, qh_PRINTfacets_xridge,   /* 'f' 'FF' 'G' 'FI' 'Fi' 'Fn' */
+  qh_PRINTgeom, qh_PRINTids, qh_PRINTinner, qh_PRINTneighbors,
+  qh_PRINTnormals, qh_PRINTouter, qh_PRINTmaple, /* 'n' 'Fo' 'i' 'm' 'Fm' 'FM', 'o' */
+  qh_PRINTincidences, qh_PRINTmathematica, qh_PRINTmerges, qh_PRINToff,
+  qh_PRINToptions, qh_PRINTpointintersect, /* 'FO' 'Fp' 'FP' 'p' 'FQ' 'FS' */
+  qh_PRINTpointnearest, qh_PRINTpoints, qh_PRINTqhull, qh_PRINTsize,
+  qh_PRINTsummary, qh_PRINTtriangles,      /* 'Fs' 'Ft' 'Fv' 'FN' 'Fx' */
+  qh_PRINTvertices, qh_PRINTvneighbors, qh_PRINTextremes,
+  qh_PRINTEND} qh_PRINT;
+
+/*----------------------------------
+
+  qh_ALL
+    argument flag for selecting everything
+*/
+#define qh_ALL      True
+#define qh_NOupper  True      /* argument for qh_findbest */
+#define qh_IScheckmax  True   /* argument for qh_findbesthorizon */
+#define qh_ISnewfacets  True  /* argument for qh_findbest */
+#define qh_RESETvisible  True /* argument for qh_resetlists */
+
+/*----------------------------------
+
+  qh_ERR...
+    Qhull exit status codes, for indicating errors
+    See: MSG_ERROR (6000) and MSG_WARNING (7000) [user_r.h]
+*/
+#define qh_ERRnone  0    /* no error occurred during qhull */
+#define qh_ERRinput 1    /* input inconsistency */
+#define qh_ERRsingular 2 /* singular input data, calls qh_printhelp_singular */
+#define qh_ERRprec  3    /* precision error, calls qh_printhelp_degenerate */
+#define qh_ERRmem   4    /* insufficient memory, matches mem_r.h */
+#define qh_ERRqhull 5    /* internal error detected, matches mem_r.h, calls qh_printhelp_internal */
+#define qh_ERRother 6    /* other error detected */
+#define qh_ERRtopology 7 /* topology error, maybe due to nearly adjacent vertices, calls qh_printhelp_topology */
+#define qh_ERRwide 8     /* wide facet error, maybe due to nearly adjacent vertices, calls qh_printhelp_wide */
+#define qh_ERRdebug 9    /* qh_errexit from debugging code */
+
+/*----------------------------------
+
+qh_FILEstderr
+Fake stderr to distinguish error output from normal output
+For C++ interface.  Must redefine qh_fprintf_qhull
+*/
+#define qh_FILEstderr ((FILE *)1)
+
+/* ============ -structures- ====================
+   each of the following structures is defined by a typedef
+   all realT and coordT fields occur at the beginning of a structure
+        (otherwise space may be wasted due to alignment)
+   define all flags together and pack into 32-bit number
+
+   DEFqhT and DEFsetT are likewise defined in mem_r.h, qset_r.h, and stat_r.h
+*/
+
+typedef struct vertexT vertexT;
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+
+#ifndef DEFqhT
+#define DEFqhT 1
+typedef struct qhT qhT;          /* defined below */
+#endif
+
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;        /* defined in qset_r.h */
+#endif
+
+/*----------------------------------
+
+  facetT
+    defines a facet
+
+  notes:
+   qhull() generates the hull as a list of facets.
+
+  topological information:
+    f.previous,next     doubly-linked list of facets, next is always defined
+    f.vertices          set of vertices
+    f.ridges            set of ridges
+    f.neighbors         set of neighbors
+    f.toporient         True if facet has top-orientation (else bottom)
+
+  geometric information:
+    f.offset,normal     hyperplane equation
+    f.maxoutside        offset to outer plane -- all points inside
+    f.center            centrum for testing convexity or Voronoi center for output
+    f.simplicial        True if facet is simplicial
+    f.flipped           True if facet does not include qh.interior_point
+
+  for constructing hull:
+    f.visible           True if facet on list of visible facets (will be deleted)
+    f.newfacet          True if facet on list of newly created facets
+    f.coplanarset       set of points coplanar with this facet
+                        (includes near-inside points for later testing)
+    f.outsideset        set of points outside of this facet
+    f.furthestdist      distance to furthest point of outside set
+    f.visitid           marks visited facets during a loop
+    f.replace           replacement facet for to-be-deleted, visible facets
+    f.samecycle,newcycle cycle of facets for merging into horizon facet
+
+  see below for other flags and fields
+*/
+/* QhullFacet.cpp -- Update static initializer list for s_empty_facet if add or remove fields */
+struct facetT {
+#if !qh_COMPUTEfurthest
+  coordT   furthestdist;/* distance to furthest point of outsideset */
+#endif
+#if qh_MAXoutside
+  coordT   maxoutside;  /* max computed distance of point to facet
+                        Before QHULLfinished this is an approximation
+                        since maxdist not always set for qh_mergefacet
+                        Actual outer plane is +DISTround and
+                        computed outer plane is +2*DISTround.
+                        Initial maxoutside is qh.DISTround, otherwise distance tests need to account for DISTround */
+#endif
+  coordT   offset;      /* exact offset of hyperplane from origin */
+  coordT  *normal;      /* normal of hyperplane, hull_dim coefficients */
+                        /*   if f.tricoplanar, shared with a neighbor */
+  union {               /* in order of testing */
+   realT   area;        /* area of facet, only in io_r.c if  f.isarea */
+   facetT *replace;     /* replacement facet for qh.NEWfacets with f.visible
+                             NULL if qh_mergedegen_redundant, interior, or !NEWfacets */
+   facetT *samecycle;   /* cycle of facets from the same visible/horizon intersection,
+                             if ->newfacet */
+   facetT *newcycle;    /*  in horizon facet, current samecycle of new facets */
+   facetT *trivisible;  /* visible facet for ->tricoplanar facets during qh_triangulate() */
+   facetT *triowner;    /* owner facet for ->tricoplanar, !isarea facets w/ ->keepcentrum */
+  }f;
+  coordT  *center;      /* set according to qh.CENTERtype */
+                        /*   qh_ASnone:    no center (not MERGING) */
+                        /*   qh_AScentrum: centrum for testing convexity (qh_getcentrum) */
+                        /*                 assumed qh_AScentrum while merging */
+                        /*   qh_ASvoronoi: Voronoi center (qh_facetcenter) */
+                        /* after constructing the hull, it may be changed (qh_clearcenter) */
+                        /* if tricoplanar and !keepcentrum, shared with a neighbor */
+  facetT  *previous;    /* previous facet in the facet_list or NULL, for C++ interface */
+  facetT  *next;        /* next facet in the facet_list or facet_tail */
+  setT    *vertices;    /* vertices for this facet, inverse sorted by ID
+                           if simplicial, 1st vertex was apex/furthest
+                           qh_reduce_vertices removes extraneous vertices via qh_remove_extravertices
+                           if f.visible, vertices may be on qh.del_vertices */
+  setT    *ridges;      /* explicit ridges for nonsimplicial facets or nonsimplicial neighbors.
+                           For simplicial facets, neighbors define the ridges
+                           qh_makeridges() converts simplicial facets by creating ridges prior to merging
+                           If qh.NEWtentative, new facets have horizon ridge, but not vice versa
+                           if f.visible && qh.NEWfacets, ridges is empty */
+  setT    *neighbors;   /* neighbors of the facet.  Neighbors may be f.visible
+                           If simplicial, the kth neighbor is opposite the kth vertex and the
+                           first neighbor is the horizon facet for the first vertex.
+                           dupridges marked by qh_DUPLICATEridge (0x01) and qh_MERGEridge (0x02)
+                           if f.visible && qh.NEWfacets, neighbors is empty */
+  setT    *outsideset;  /* set of points outside this facet
+                           if non-empty, last point is furthest
+                           if NARROWhull, includes coplanars (less than qh.MINoutside) for partitioning*/
+  setT    *coplanarset; /* set of points coplanar with this facet
+                           >= qh.min_vertex and <= facet->max_outside
+                           a point is assigned to the furthest facet
+                           if non-empty, last point is furthest away */
+  unsigned int visitid; /* visit_id, for visiting all neighbors,
+                           all uses are independent */
+  unsigned int id;      /* unique identifier from qh.facet_id, 1..qh.facet_id, 0 is sentinel, printed as 'f%d' */
+  unsigned int nummerge:9; /* number of merges */
+#define qh_MAXnummerge 511 /* 2^9-1 */
+                        /* 23 flags (at most 23 due to nummerge), printed by "flags:" in io_r.c */
+  flagT    tricoplanar:1; /* True if TRIangulate and simplicial and coplanar with a neighbor */
+                          /*   all tricoplanars share the same apex */
+                          /*   all tricoplanars share the same ->center, ->normal, ->offset, ->maxoutside */
+                          /*     ->keepcentrum is true for the owner.  It has the ->coplanareset */
+                          /*   if ->degenerate, does not span facet (one logical ridge) */
+                          /*   during qh_triangulate, f.trivisible points to original facet */
+  flagT    newfacet:1;  /* True if facet on qh.newfacet_list (new/qh.first_newfacet or merged) */
+  flagT    visible:1;   /* True if visible facet (will be deleted) */
+  flagT    toporient:1; /* True if created with top orientation
+                           after merging, use ridge orientation */
+  flagT    simplicial:1;/* True if simplicial facet, ->ridges may be implicit */
+  flagT    seen:1;      /* used to perform operations only once, like visitid */
+  flagT    seen2:1;     /* used to perform operations only once, like visitid */
+  flagT    flipped:1;   /* True if facet is flipped */
+  flagT    upperdelaunay:1; /* True if facet is upper envelope of Delaunay triangulation */
+  flagT    notfurthest:1; /* True if last point of outsideset is not furthest */
+
+/*-------- flags primarily for output ---------*/
+  flagT    good:1;      /* True if a facet marked good for output */
+  flagT    isarea:1;    /* True if facet->f.area is defined */
+
+/*-------- flags for merging ------------------*/
+  flagT    dupridge:1;  /* True if facet has one or more dupridge in a new facet (qh_matchneighbor),
+                             a dupridge has a subridge shared by more than one new facet */
+  flagT    mergeridge:1; /* True if facet or neighbor has a qh_MERGEridge (qh_mark_dupridges)
+                            ->normal defined for mergeridge and mergeridge2 */
+  flagT    mergeridge2:1; /* True if neighbor has a qh_MERGEridge (qh_mark_dupridges) */
+  flagT    coplanarhorizon:1;  /* True if horizon facet is coplanar at last use */
+  flagT     mergehorizon:1; /* True if will merge into horizon (its first neighbor w/ f.coplanarhorizon). */
+  flagT     cycledone:1;/* True if mergecycle_all already done */
+  flagT    tested:1;    /* True if facet convexity has been tested (false after merge */
+  flagT    keepcentrum:1; /* True if keep old centrum after a merge, or marks owner for ->tricoplanar
+                             Set by qh_updatetested if more than qh_MAXnewcentrum extra vertices
+                             Set by qh_mergefacet if |maxdist| > qh.WIDEfacet */
+  flagT    newmerge:1;  /* True if facet is newly merged for reducevertices */
+  flagT    degenerate:1; /* True if facet is degenerate (degen_mergeset or ->tricoplanar) */
+  flagT    redundant:1;  /* True if facet is redundant (degen_mergeset)
+                         Maybe merge degenerate and redundant to gain another flag */
+};
+
+
+/*----------------------------------
+
+  ridgeT
+    defines a ridge
+
+  notes:
+  a ridge is hull_dim-1 simplex between two neighboring facets.  If the
+  facets are non-simplicial, there may be more than one ridge between
+  two facets.  E.G. a 4-d hypercube has two triangles between each pair
+  of neighboring facets.
+
+  topological information:
+    vertices            a set of vertices
+    top,bottom          neighboring facets with orientation
+
+  geometric information:
+    tested              True if ridge is clearly convex
+    nonconvex           True if ridge is non-convex
+*/
+/* QhullRidge.cpp -- Update static initializer list for s_empty_ridge if add or remove fields */
+struct ridgeT {
+  setT    *vertices;    /* vertices belonging to this ridge, inverse sorted by ID
+                           NULL if a degen ridge (matchsame) */
+  facetT  *top;         /* top facet for this ridge */
+  facetT  *bottom;      /* bottom facet for this ridge
+                        ridge oriented by odd/even vertex order and top/bottom */
+  unsigned int id;      /* unique identifier.  Same size as vertex_id, printed as 'r%d' */
+  flagT    seen:1;      /* used to perform operations only once */
+  flagT    tested:1;    /* True when ridge is tested for convexity by centrum or opposite vertices */
+  flagT    nonconvex:1; /* True if getmergeset detected a non-convex neighbor
+                           only one ridge between neighbors may have nonconvex */
+  flagT    mergevertex:1; /* True if pending qh_appendvertexmerge due to
+                             qh_maybe_duplicateridge or qh_maybe_duplicateridges
+                             disables check for duplicate vertices in qh_checkfacet */
+  flagT    mergevertex2:1; /* True if qh_drop_mergevertex of MRGvertices, printed but not used */
+  flagT    simplicialtop:1; /* True if top was simplicial (original vertices) */
+  flagT    simplicialbot:1; /* True if bottom was simplicial (original vertices)
+                             use qh_test_centrum_merge if top and bot, need to retest since centrum may change */
+};
+
+/*----------------------------------
+
+  vertexT
+     defines a vertex
+
+  topological information:
+    next,previous       doubly-linked list of all vertices
+    neighbors           set of adjacent facets (only if qh.VERTEXneighbors)
+
+  geometric information:
+    point               array of DIM3 coordinates
+*/
+/* QhullVertex.cpp -- Update static initializer list for s_empty_vertex if add or remove fields */
+struct vertexT {
+  vertexT *next;        /* next vertex in vertex_list or vertex_tail */
+  vertexT *previous;    /* previous vertex in vertex_list or NULL, for C++ interface */
+  pointT  *point;       /* hull_dim coordinates (coordT) */
+  setT    *neighbors;   /* neighboring facets of vertex, qh_vertexneighbors()
+                           initialized in io_r.c or after first merge
+                           qh_update_vertices for qh_addpoint or qh_triangulate
+                           updated by merges
+                           qh_order_vertexneighbors by 2-d (orientation) 3-d (adjacency), n-d (f.visitid,id) */
+  unsigned int id;      /* unique identifier, 1..qh.vertex_id,  0 for sentinel, printed as 'r%d' */
+  unsigned int visitid; /* for use with qh.vertex_visit, size must match */
+  flagT    seen:1;      /* used to perform operations only once */
+  flagT    seen2:1;     /* another seen flag */
+  flagT    deleted:1;   /* vertex will be deleted via qh.del_vertices */
+  flagT    delridge:1;  /* vertex belonged to a deleted ridge, cleared by qh_reducevertices */
+  flagT    newfacet:1;  /* true if vertex is in a new facet
+                           vertex is on qh.newvertex_list and it has a facet on qh.newfacet_list
+                           or vertex is on qh.newvertex_list due to qh_newvertices while merging
+                           cleared by qh_resetlists */
+  flagT    partitioned:1; /* true if deleted vertex has been partitioned */
+};
+
+/*======= -global variables -qh ============================*/
+
+/*----------------------------------
+
+  qhT
+   All global variables for qhull are in qhT.  It includes qhmemT, qhstatT, and rbox globals
+
+   This version of Qhull is reentrant, but it is not thread-safe.
+
+   Do not run separate threads on the same instance of qhT.
+
+   QHULL_LIB_CHECK checks that a program and the corresponding
+   qhull library were built with the same type of header files.
+
+   QHULL_LIB_TYPE is QHULL_NON_REENTRANT, QHULL_QH_POINTER, or QHULL_REENTRANT
+*/
+
+#define QHULL_NON_REENTRANT 0
+#define QHULL_QH_POINTER 1
+#define QHULL_REENTRANT 2
+
+#define QHULL_LIB_TYPE QHULL_REENTRANT
+
+#define QHULL_LIB_CHECK qh_lib_check(QHULL_LIB_TYPE, sizeof(qhT), sizeof(vertexT), sizeof(ridgeT), sizeof(facetT), SETbasesize, sizeof(qhmemT));
+#define QHULL_LIB_CHECK_RBOX qh_lib_check(QHULL_LIB_TYPE, sizeof(qhT), sizeof(vertexT), sizeof(ridgeT), sizeof(facetT), 0, 0);
+
+struct qhT {
+
+/*----------------------------------
+
+  qh constants
+    configuration flags and constants for Qhull
+
+  notes:
+    The user configures Qhull by defining flags.  They are
+    copied into qh by qh_setflags().  qh-quick_r.htm#options defines the flags.
+*/
+  boolT ALLpoints;        /* true 'Qs' if search all points for initial simplex */
+  boolT ALLOWshort;       /* true 'Qa' allow input with fewer or more points than coordinates */
+  boolT ALLOWwarning;     /* true 'Qw' if allow option warnings */
+  boolT ALLOWwide;        /* true 'Q12' if allow wide facets and wide dupridges, c.f. qh_WIDEmaxoutside */
+  boolT ANGLEmerge;       /* true 'Q1' if sort potential merges by type/angle instead of type/distance  */
+  boolT APPROXhull;       /* true 'Wn' if MINoutside set */
+  realT MINoutside;       /*   Minimum distance for an outside point ('Wn' or 2*qh.MINvisible) */
+  boolT ANNOTATEoutput;   /* true 'Ta' if annotate output with message codes */
+  boolT ATinfinity;       /* true 'Qz' if point num_points-1 is "at-infinity"
+                             for improving precision in Delaunay triangulations */
+  boolT AVOIDold;         /* true 'Q4' if avoid old->new merges */
+  boolT BESToutside;      /* true 'Qf' if partition points into best outsideset */
+  boolT CDDinput;         /* true 'Pc' if input uses CDD format (1.0/offset first) */
+  boolT CDDoutput;        /* true 'PC' if print normals in CDD format (offset first) */
+  boolT CHECKduplicates;  /* true 'Q17' if qh_maybe_duplicateridges after each qh_mergefacet */
+  boolT CHECKfrequently;  /* true 'Tc' if checking frequently */
+  realT premerge_cos;     /*   'A-n'   cos_max when pre merging */
+  realT postmerge_cos;    /*   'An'    cos_max when post merging */
+  boolT DELAUNAY;         /* true 'd' or 'v' if computing DELAUNAY triangulation */
+  boolT DOintersections;  /* true 'Gh' if print hyperplane intersections */
+  int   DROPdim;          /* drops dim 'GDn' for 4-d -> 3-d output */
+  boolT FLUSHprint;       /* true 'Tf' if flush after qh_fprintf for segfaults */
+  boolT FORCEoutput;      /* true 'Po' if forcing output despite degeneracies */
+  int   GOODpoint;        /* 'QGn' or 'QG-n' (n+1, n-1), good facet if visible from point n (or not) */
+  pointT *GOODpointp;     /*   the actual point */
+  boolT GOODthreshold;    /* true 'Pd/PD' if qh.lower_threshold/upper_threshold defined
+                             set if qh.UPPERdelaunay (qh_initbuild)
+                             false if qh.SPLITthreshold */
+  int   GOODvertex;       /* 'QVn' or 'QV-n' (n+1, n-1), good facet if vertex for point n (or not) */
+  pointT *GOODvertexp;     /*   the actual point */
+  boolT HALFspace;        /* true 'Hn,n,n' if halfspace intersection */
+  boolT ISqhullQh;        /* Set by Qhull.cpp on initialization */
+  int   IStracing;        /* 'Tn' trace execution, 0=none, 1=least, 4=most, -1=events */
+  int   KEEParea;         /* 'PAn' number of largest facets to keep */
+  boolT KEEPcoplanar;     /* true 'Qc' if keeping nearest facet for coplanar points */
+  boolT KEEPinside;       /* true 'Qi' if keeping nearest facet for inside points
+                              set automatically if 'd Qc' */
+  int   KEEPmerge;        /* 'PMn' number of facets to keep with most merges */
+  realT KEEPminArea;      /* 'PFn' minimum facet area to keep */
+  realT MAXcoplanar;      /* 'Un' max distance below a facet to be coplanar*/
+  int   MAXwide;          /* 'QWn' max ratio for wide facet, otherwise error unless Q12-allow-wide */
+  boolT MERGEexact;       /* true 'Qx' if exact merges (concave, degen, dupridge, flipped)
+                             tested by qh_checkzero and qh_test_*_merge */
+  boolT MERGEindependent; /* true if merging independent sets of coplanar facets. 'Q2' disables */
+  boolT MERGING;          /* true if exact-, pre- or post-merging, with angle and centrum tests */
+  realT   premerge_centrum;  /*   'C-n' centrum_radius when pre merging.  Default is round-off */
+  realT   postmerge_centrum; /*   'Cn' centrum_radius when post merging.  Default is round-off */
+  boolT MERGEpinched;     /* true 'Q14' if merging pinched vertices due to dupridge */
+  boolT MERGEvertices;    /* true if merging redundant vertices, 'Q3' disables or qh.hull_dim > qh_DIMmergeVertex */
+  realT MINvisible;       /* 'Vn' min. distance for a facet to be visible */
+  boolT NOnarrow;         /* true 'Q10' if no special processing for narrow distributions */
+  boolT NOnearinside;     /* true 'Q8' if ignore near-inside points when partitioning, qh_check_points may fail */
+  boolT NOpremerge;       /* true 'Q0' if no defaults for C-0 or Qx */
+  boolT ONLYgood;         /* true 'Qg' if process points with good visible or horizon facets */
+  boolT ONLYmax;          /* true 'Qm' if only process points that increase max_outside */
+  boolT PICKfurthest;     /* true 'Q9' if process furthest of furthest points*/
+  boolT POSTmerge;        /* true if merging after buildhull ('Cn' or 'An') */
+  boolT PREmerge;         /* true if merging during buildhull ('C-n' or 'A-n') */
+                        /* NOTE: some of these names are similar to qh_PRINT names */
+  boolT PRINTcentrums;    /* true 'Gc' if printing centrums */
+  boolT PRINTcoplanar;    /* true 'Gp' if printing coplanar points */
+  int   PRINTdim;         /* print dimension for Geomview output */
+  boolT PRINTdots;        /* true 'Ga' if printing all points as dots */
+  boolT PRINTgood;        /* true 'Pg' if printing good facets
+                             PGood set if 'd', 'PAn', 'PFn', 'PMn', 'QGn', 'QG-n', 'QVn', or 'QV-n' */
+  boolT PRINTinner;       /* true 'Gi' if printing inner planes */
+  boolT PRINTneighbors;   /* true 'PG' if printing neighbors of good facets */
+  boolT PRINTnoplanes;    /* true 'Gn' if printing no planes */
+  boolT PRINToptions1st;  /* true 'FO' if printing options to stderr */
+  boolT PRINTouter;       /* true 'Go' if printing outer planes */
+  boolT PRINTprecision;   /* false 'Pp' if not reporting precision problems */
+  qh_PRINT PRINTout[qh_PRINTEND]; /* list of output formats to print */
+  boolT PRINTridges;      /* true 'Gr' if print ridges */
+  boolT PRINTspheres;     /* true 'Gv' if print vertices as spheres */
+  boolT PRINTstatistics;  /* true 'Ts' if printing statistics to stderr */
+  boolT PRINTsummary;     /* true 's' if printing summary to stderr */
+  boolT PRINTtransparent; /* true 'Gt' if print transparent outer ridges */
+  boolT PROJECTdelaunay;  /* true if DELAUNAY, no readpoints() and
+                             need projectinput() for Delaunay in qh_init_B */
+  int   PROJECTinput;     /* number of projected dimensions 'bn:0Bn:0' */
+  boolT RANDOMdist;       /* true 'Rn' if randomly change distplane and setfacetplane */
+  realT RANDOMfactor;     /*    maximum random perturbation */
+  realT RANDOMa;          /*    qh_randomfactor is randr * RANDOMa + RANDOMb */
+  realT RANDOMb;
+  boolT RANDOMoutside;    /* true 'Qr' if select a random outside point */
+  int   REPORTfreq;       /* 'TFn' buildtracing reports every n facets */
+  int   REPORTfreq2;      /* tracemerging reports every REPORTfreq/2 facets */
+  int   RERUN;            /* 'TRn' rerun qhull n times (qh.build_cnt) */
+  int   ROTATErandom;     /* 'QRn' n<-1 random seed, n==-1 time is seed, n==0 random rotation by time, n>0 rotate input */
+  boolT SCALEinput;       /* true 'Qbk' if scaling input */
+  boolT SCALElast;        /* true 'Qbb' if scale last coord to max prev coord */
+  boolT SETroundoff;      /* true 'En' if qh.DISTround is predefined */
+  boolT SKIPcheckmax;     /* true 'Q5' if skip qh_check_maxout, qh_check_points may fail */
+  boolT SKIPconvex;       /* true 'Q6' if skip convexity testing during pre-merge */
+  boolT SPLITthresholds;  /* true 'Pd/PD' if upper_/lower_threshold defines a region
+                               else qh.GOODthresholds
+                               set if qh.DELAUNAY (qh_initbuild)
+                               used only for printing (!for qh.ONLYgood) */
+  int   STOPadd;          /* 'TAn' 1+n for stop after adding n vertices */
+  int   STOPcone;         /* 'TCn' 1+n for stopping after cone for point n */
+                          /*       also used by qh_build_withresart for err exit*/
+  int   STOPpoint;        /* 'TVn' 'TV-n' 1+n for stopping after/before(-)
+                                        adding point n */
+  int   TESTpoints;       /* 'QTn' num of test points after qh.num_points.  Test points always coplanar. */
+  boolT TESTvneighbors;   /*  true 'Qv' if test vertex neighbors at end */
+  int   TRACElevel;       /* 'Tn' conditional IStracing level */
+  int   TRACElastrun;     /*  qh.TRACElevel applies to last qh.RERUN */
+  int   TRACEpoint;       /* 'TPn' start tracing when point n is a vertex, use qh_IDunknown (-1) after qh_buildhull and qh_postmerge */
+  realT TRACEdist;        /* 'TWn' start tracing when merge distance too big */
+  int   TRACEmerge;       /* 'TMn' start tracing before this merge */
+  boolT TRIangulate;      /* true 'Qt' if triangulate non-simplicial facets */
+  boolT TRInormals;       /* true 'Q11' if triangulate duplicates ->normal and ->center (sets Qt) */
+  boolT UPPERdelaunay;    /* true 'Qu' if computing furthest-site Delaunay */
+  boolT USEstdout;        /* true 'Tz' if using stdout instead of stderr */
+  boolT VERIFYoutput;     /* true 'Tv' if verify output at end of qhull */
+  boolT VIRTUALmemory;    /* true 'Q7' if depth-first processing in buildhull */
+  boolT VORONOI;          /* true 'v' if computing Voronoi diagram, also sets qh.DELAUNAY */
+
+  /*--------input constants ---------*/
+  realT AREAfactor;       /* 1/(hull_dim-1)! for converting det's to area */
+  boolT DOcheckmax;       /* true if calling qh_check_maxout (!qh.SKIPcheckmax && qh.MERGING) */
+  char  *feasible_string;  /* feasible point 'Hn,n,n' for halfspace intersection */
+  coordT *feasible_point;  /*    as coordinates, both malloc'd */
+  boolT GETarea;          /* true 'Fa', 'FA', 'FS', 'PAn', 'PFn' if compute facet area/Voronoi volume in io_r.c */
+  boolT KEEPnearinside;   /* true if near-inside points in coplanarset */
+  int   hull_dim;         /* dimension of hull, set by initbuffers */
+  int   input_dim;        /* dimension of input, set by initbuffers */
+  int   num_points;       /* number of input points */
+  pointT *first_point;    /* array of input points, see POINTSmalloc */
+  boolT POINTSmalloc;     /*   true if qh.first_point/num_points allocated */
+  pointT *input_points;   /* copy of original qh.first_point for input points for qh_joggleinput */
+  boolT input_malloc;     /* true if qh.input_points malloc'd */
+  char  qhull_command[256];/* command line that invoked this program */
+  int   qhull_commandsiz2; /*    size of qhull_command at qh_clear_outputflags */
+  char  rbox_command[256]; /* command line that produced the input points */
+  char  qhull_options[512];/* descriptive list of options */
+  int   qhull_optionlen;  /*    length of last line */
+  int   qhull_optionsiz;  /*    size of qhull_options at qh_build_withrestart */
+  int   qhull_optionsiz2; /*    size of qhull_options at qh_clear_outputflags */
+  int   run_id;           /* non-zero, random identifier for this instance of qhull */
+  boolT VERTEXneighbors;  /* true if maintaining vertex neighbors */
+  boolT ZEROcentrum;      /* true if 'C-0' or 'C-0 Qx' and not post-merging or 'A-n'.  Sets ZEROall_ok */
+  realT *upper_threshold; /* don't print if facet->normal[k]>=upper_threshold[k]
+                             must set either GOODthreshold or SPLITthreshold
+                             if qh.DELAUNAY, default is 0.0 for upper envelope (qh_initbuild) */
+  realT *lower_threshold; /* don't print if facet->normal[k] <=lower_threshold[k] */
+  realT *upper_bound;     /* scale point[k] to new upper bound */
+  realT *lower_bound;     /* scale point[k] to new lower bound
+                             project if both upper_ and lower_bound == 0 */
+
+/*----------------------------------
+
+  qh precision constants
+    precision constants for Qhull
+
+  notes:
+    qh_detroundoff [geom2_r.c] computes the maximum roundoff error for distance
+    and other computations.  It also sets default values for the
+    qh constants above.
+*/
+  realT ANGLEround;       /* max round off error for angles */
+  realT centrum_radius;   /* max centrum radius for convexity ('Cn' + 2*qh.DISTround) */
+  realT cos_max;          /* max cosine for convexity (roundoff added) */
+  realT DISTround;        /* max round off error for distances, qh.SETroundoff ('En') overrides qh_distround */
+  realT MAXabs_coord;     /* max absolute coordinate */
+  realT MAXlastcoord;     /* max last coordinate for qh_scalelast */
+  realT MAXoutside;       /* max target for qh.max_outside/f.maxoutside, base for qh_RATIO...
+                             recomputed at qh_addpoint, unrelated to qh_MAXoutside */
+  realT MAXsumcoord;      /* max sum of coordinates */
+  realT MAXwidth;         /* max rectilinear width of point coordinates */
+  realT MINdenom_1;       /* min. abs. value for 1/x */
+  realT MINdenom;         /*    use divzero if denominator < MINdenom */
+  realT MINdenom_1_2;     /* min. abs. val for 1/x that allows normalization */
+  realT MINdenom_2;       /*    use divzero if denominator < MINdenom_2 */
+  realT MINlastcoord;     /* min. last coordinate for qh_scalelast */
+  realT *NEARzero;        /* hull_dim array for near zero in gausselim */
+  realT NEARinside;       /* keep points for qh_check_maxout if close to facet */
+  realT ONEmerge;         /* max distance for merging simplicial facets */
+  realT outside_err;      /* application's epsilon for coplanar points
+                             qh_check_bestdist() qh_check_points() reports error if point outside */
+  realT WIDEfacet;        /* size of wide facet for skipping ridge in
+                             area computation and locking centrum */
+  boolT NARROWhull;       /* set in qh_initialhull if angle < qh_MAXnarrow */
+
+/*----------------------------------
+
+  qh internal constants
+    internal constants for Qhull
+*/
+  char qhull[sizeof("qhull")]; /* "qhull" for checking ownership while debugging */
+  jmp_buf errexit;        /* exit label for qh_errexit, defined by setjmp() and NOerrexit */
+  char    jmpXtra[40];    /* extra bytes in case jmp_buf is defined wrong by compiler */
+  jmp_buf restartexit;    /* restart label for qh_errexit, defined by setjmp() and ALLOWrestart */
+  char    jmpXtra2[40];   /* extra bytes in case jmp_buf is defined wrong by compiler*/
+  FILE *  fin;            /* pointer to input file, init by qh_initqhull_start2 */
+  FILE *  fout;           /* pointer to output file */
+  FILE *  ferr;           /* pointer to error file */
+  pointT *interior_point; /* center point of the initial simplex*/
+  int     normal_size;    /* size in bytes for facet normals and point coords */
+  int     center_size;    /* size in bytes for Voronoi centers */
+  int     TEMPsize;       /* size for small, temporary sets (in quick mem) */
+
+/*----------------------------------
+
+  qh facet and vertex lists
+    defines lists of facets, new facets, visible facets, vertices, and
+    new vertices.  Includes counts, next ids, and trace ids.
+  see:
+    qh_resetlists()
+*/
+  facetT *facet_list;     /* first facet */
+  facetT *facet_tail;     /* end of facet_list (dummy facet with id 0 and next==NULL) */
+  facetT *facet_next;     /* next facet for buildhull()
+                             previous facets do not have outside sets
+                             NARROWhull: previous facets may have coplanar outside sets for qh_outcoplanar */
+  facetT *newfacet_list;  /* list of new facets to end of facet_list
+                             qh_postmerge sets newfacet_list to facet_list */
+  facetT *visible_list;   /* list of visible facets preceding newfacet_list,
+                             end of visible list if !facet->visible, same as newfacet_list
+                             qh_findhorizon sets visible_list at end of facet_list
+                             qh_willdelete prepends to visible_list
+                             qh_triangulate appends mirror facets to visible_list at end of facet_list
+                             qh_postmerge sets visible_list to facet_list
+                             qh_deletevisible deletes the visible facets */
+  int       num_visible;  /* current number of visible facets */
+  unsigned int tracefacet_id; /* set at init, then can print whenever */
+  facetT  *tracefacet;    /*   set in newfacet/mergefacet, undone in delfacet and qh_errexit */
+  unsigned int traceridge_id; /* set at init, then can print whenever */
+  ridgeT  *traceridge;    /*   set in newridge, undone in delridge, errexit, errexit2, makenew_nonsimplicial, mergecycle_ridges */
+  unsigned int tracevertex_id; /* set at buildtracing, can print whenever */
+  vertexT *tracevertex;   /*   set in newvertex, undone in delvertex and qh_errexit */
+  vertexT *vertex_list;   /* list of all vertices, to vertex_tail */
+  vertexT *vertex_tail;   /*      end of vertex_list (dummy vertex with ID 0, next NULL) */
+  vertexT *newvertex_list; /* list of vertices in newfacet_list, to vertex_tail
+                             all vertices have 'newfacet' set */
+  int   num_facets;       /* number of facets in facet_list
+                             includes visible faces (num_visible) */
+  int   num_vertices;     /* number of vertices in facet_list */
+  int   num_outside;      /* number of points in outsidesets (for tracing and RANDOMoutside)
+                               includes coplanar outsideset points for NARROWhull/qh_outcoplanar() */
+  int   num_good;         /* number of good facets (after qh_findgood_all or qh_markkeep) */
+  unsigned int facet_id;  /* ID of next, new facet from newfacet() */
+  unsigned int ridge_id;  /* ID of next, new ridge from newridge() */
+  unsigned int vertex_id; /* ID of next, new vertex from newvertex() */
+  unsigned int first_newfacet; /* ID of first_newfacet for qh_buildcone, or 0 if none */
+
+/*----------------------------------
+
+  qh global variables
+    defines minimum and maximum distances, next visit ids, several flags,
+    and other global variables.
+    initialize in qh_initbuild or qh_maxmin if used in qh_buildhull
+*/
+  unsigned long hulltime; /* ignore time to set up input and randomize */
+                          /*   use 'unsigned long' to avoid wrap-around errors */
+  boolT ALLOWrestart;     /* true if qh_joggle_restart can use qh.restartexit */
+  int   build_cnt;        /* number of calls to qh_initbuild */
+  qh_CENTER CENTERtype;   /* current type of facet->center, qh_CENTER */
+  int   furthest_id;      /* pointid of furthest point, for tracing */
+  int   last_errcode;     /* last errcode from qh_fprintf, reset in qh_build_withrestart */
+  facetT *GOODclosest;    /* closest facet to GOODthreshold in qh_findgood */
+  pointT *coplanar_apex;  /* last apex declared a coplanar point by qh_getpinchedmerges, prevents infinite loop */
+  boolT hasAreaVolume;    /* true if totarea, totvol was defined by qh_getarea */
+  boolT hasTriangulation; /* true if triangulation created by qh_triangulate */
+  boolT isRenameVertex;   /* true during qh_merge_pinchedvertices, disables duplicate ridge vertices in qh_checkfacet */
+  realT JOGGLEmax;        /* set 'QJn' if randomly joggle input. 'QJ'/'QJ0.0' sets default (qh_detjoggle) */
+  boolT maxoutdone;       /* set qh_check_maxout(), cleared by qh_addpoint() */
+  realT max_outside;      /* maximum distance from a point to a facet,
+                               before roundoff, not simplicial vertices
+                               actual outer plane is +DISTround and
+                               computed outer plane is +2*DISTround */
+  realT max_vertex;       /* maximum distance (>0) from vertex to a facet,
+                               before roundoff, due to a merge */
+  realT min_vertex;       /* minimum distance (<0) from vertex to a facet,
+                               before roundoff, due to a merge
+                               if qh.JOGGLEmax, qh_makenewplanes sets it
+                               recomputed if qh.DOcheckmax, default -qh.DISTround */
+  boolT NEWfacets;        /* true while visible facets invalid due to new or merge
+                              from qh_makecone/qh_attachnewfacets to qh_resetlists */
+  boolT NEWtentative;     /* true while new facets are tentative due to !qh.IGNOREpinched or qh.ONLYgood
+                              from qh_makecone to qh_attachnewfacets */
+  boolT findbestnew;      /* true if partitioning calls qh_findbestnew */
+  boolT findbest_notsharp; /* true if new facets are at least 90 degrees */
+  boolT NOerrexit;        /* true if qh.errexit is not available, cleared after setjmp.  See qh.ERREXITcalled */
+  realT PRINTcradius;     /* radius for printing centrums */
+  realT PRINTradius;      /* radius for printing vertex spheres and points */
+  boolT POSTmerging;      /* true when post merging */
+  int   printoutvar;      /* temporary variable for qh_printbegin, etc. */
+  int   printoutnum;      /* number of facets printed */
+  unsigned int repart_facetid; /* previous facetid to prevent recursive qh_partitioncoplanar+qh_partitionpoint */
+  int   retry_addpoint;   /* number of retries of qh_addpoint due to merging pinched vertices */
+  boolT QHULLfinished;    /* True after qhull() is finished */
+  realT totarea;          /* 'FA': total facet area computed by qh_getarea, hasAreaVolume */
+  realT totvol;           /* 'FA': total volume computed by qh_getarea, hasAreaVolume */
+  unsigned int visit_id;  /* unique ID for searching neighborhoods, */
+  unsigned int vertex_visit; /* unique ID for searching vertices, reset with qh_buildtracing */
+  boolT WAScoplanar;      /* True if qh_partitioncoplanar (qh_check_maxout) */
+  boolT ZEROall_ok;       /* True if qh_checkzero always succeeds */
+
+/*----------------------------------
+
+  qh global sets
+    defines sets for merging, initial simplex, hashing, extra input points,
+    and deleted vertices
+*/
+  setT *facet_mergeset;   /* temporary set of merges to be done */
+  setT *degen_mergeset;   /* temporary set of degenerate and redundant merges */
+  setT *vertex_mergeset;  /* temporary set of vertex merges */
+  setT *hash_table;       /* hash table for matching ridges in qh_matchfacets
+                             size is setsize() */
+  setT *other_points;     /* additional points */
+  setT *del_vertices;     /* vertices to partition and delete with visible
+                             facets.  v.deleted is set for checkfacet */
+
+/*----------------------------------
+
+  qh global buffers
+    defines buffers for maxtrix operations, input, and error messages
+*/
+  coordT *gm_matrix;      /* (dim+1)Xdim matrix for geom_r.c */
+  coordT **gm_row;        /* array of gm_matrix rows */
+  char* line;             /* malloc'd input line of maxline+1 chars */
+  int maxline;
+  coordT *half_space;     /* malloc'd input array for halfspace (qh.normal_size+coordT) */
+  coordT *temp_malloc;    /* malloc'd input array for points */
+
+/*----------------------------------
+
+  qh static variables
+    defines static variables for individual functions
+
+  notes:
+    do not use 'static' within a function.  Multiple instances of qhull
+    may exist.
+
+    do not assume zero initialization, 'QPn' may cause a restart
+*/
+  boolT ERREXITcalled;    /* true during qh_errexit (prevents duplicate calls).  see qh.NOerrexit */
+  boolT firstcentrum;     /* for qh_printcentrum */
+  boolT old_randomdist;   /* save RANDOMdist flag during io, tracing, or statistics */
+  setT *coplanarfacetset; /* set of coplanar facets for searching qh_findbesthorizon() */
+  realT last_low;         /* qh_scalelast parameters for qh_setdelaunay */
+  realT last_high;
+  realT last_newhigh;
+  realT lastcpu;          /* for qh_buildtracing */
+  int   lastfacets;       /*   last qh.num_facets */
+  int   lastmerges;       /*   last zzval_(Ztotmerge) */
+  int   lastplanes;       /*   last zzval_(Zsetplane) */
+  int   lastdist;         /*   last zzval_(Zdistplane) */
+  unsigned int lastreport; /*  last qh.facet_id */
+  int mergereport;        /* for qh_tracemerging */
+  setT *old_tempstack;    /* for saving qh->qhmem.tempstack in save_qhull */
+  int   ridgeoutnum;      /* number of ridges for 4OFF output (qh_printbegin,etc) */
+
+/*----------------------------------
+
+  qh memory management, rbox globals, and statistics
+
+  Replaces global data structures defined for libqhull
+*/
+  int     last_random;    /* Last random number from qh_rand (random_r.c) */
+  jmp_buf rbox_errexit;   /* errexit from rboxlib_r.c, defined by qh_rboxpoints() only */
+  char    jmpXtra3[40];   /* extra bytes in case jmp_buf is defined wrong by compiler */
+  int     rbox_isinteger;
+  double  rbox_out_offset;
+  void *  cpp_object;     /* C++ pointer.  Currently used by RboxPoints.qh_fprintf_rbox */
+  void *  cpp_other;      /* C++ pointer.  Reserved for other users */
+  void *  cpp_user;       /* C++ pointer.  Currently used by QhullUser.qh_fprintf */
+
+  /* Last, otherwise zero'd by qh_initqhull_start2 (global_r.c */
+  qhmemT  qhmem;          /* Qhull managed memory (mem_r.h) */
+  /* After qhmem because its size depends on the number of statistics */
+  qhstatT qhstat;         /* Qhull statistics (stat_r.h) */
+};
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+
+  otherfacet_(ridge, facet)
+    return neighboring facet for a ridge in facet
+*/
+#define otherfacet_(ridge, facet) \
+                        (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)
+
+/*----------------------------------
+
+  getid_(p)
+    return int ID for facet, ridge, or vertex
+    return qh_IDunknown(-1) if NULL
+    return 0 if facet_tail or vertex_tail
+*/
+#define getid_(p)       ((p) ? (int)((p)->id) : qh_IDunknown)
+
+/*============== FORALL macros ===================*/
+
+/*----------------------------------
+
+  FORALLfacets { ... }
+    assign 'facet' to each facet in qh.facet_list
+
+  notes:
+    uses 'facetT *facet;'
+    assumes last facet is a sentinel
+    assumes qh defined
+
+  see:
+    FORALLfacet_( facetlist )
+*/
+#define FORALLfacets for (facet=qh->facet_list;facet && facet->next;facet=facet->next)
+
+/*----------------------------------
+
+  FORALLpoints { ... }
+    assign 'point' to each point in qh.first_point, qh.num_points
+
+  notes:
+    assumes qh defined
+
+  declare:
+    coordT *point, *pointtemp;
+*/
+#define FORALLpoints FORALLpoint_(qh, qh->first_point, qh->num_points)
+
+/*----------------------------------
+
+  FORALLpoint_(qh, points, num) { ... }
+    assign 'point' to each point in points array of num points
+
+  declare:
+    coordT *point, *pointtemp;
+*/
+#define FORALLpoint_(qh, points, num) for (point=(points), \
+      pointtemp= (points)+qh->hull_dim*(num); point < pointtemp; point += qh->hull_dim)
+
+/*----------------------------------
+
+  FORALLvertices { ... }
+    assign 'vertex' to each vertex in qh.vertex_list
+
+  declare:
+    vertexT *vertex;
+
+  notes:
+    assumes qh.vertex_list terminated by NULL or a sentinel (v.next==NULL)
+    assumes qh defined
+*/
+#define FORALLvertices for (vertex=qh->vertex_list;vertex && vertex->next;vertex= vertex->next)
+
+/*----------------------------------
+
+  FOREACHfacet_( facets ) { ... }
+    assign 'facet' to each facet in facets
+
+  declare:
+    facetT *facet, **facetp;
+
+  notes:
+    assumes set is not modified
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHfacet_(facets)    FOREACHsetelement_(facetT, facets, facet)
+
+/*----------------------------------
+
+  FOREACHneighbor_( facet ) { ... }
+    assign 'neighbor' to each neighbor in facet->neighbors
+
+  FOREACHneighbor_( vertex ) { ... }
+    assign 'neighbor' to each neighbor in vertex->neighbors
+
+  declare:
+    facetT *neighbor, **neighborp;
+
+  notes:
+    assumes set is not modified
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHneighbor_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighbor)
+
+/*----------------------------------
+
+  FOREACHpoint_( points ) { ... }
+    assign 'point' to each point in points set
+
+  declare:
+    pointT *point, **pointp;
+
+  notes:
+    assumes set is not modified
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHpoint_(points)    FOREACHsetelement_(pointT, points, point)
+
+/*----------------------------------
+
+  FOREACHridge_( ridges ) { ... }
+    assign 'ridge' to each ridge in ridges set
+
+  declare:
+    ridgeT *ridge, **ridgep;
+
+  notes:
+    assumes set is not modified
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHridge_(ridges)    FOREACHsetelement_(ridgeT, ridges, ridge)
+
+/*----------------------------------
+
+  FOREACHvertex_( vertices ) { ... }
+    assign 'vertex' to each vertex in vertices set
+
+  declare:
+    vertexT *vertex, **vertexp;
+
+  notes:
+    assumes set is not modified
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)
+
+/*----------------------------------
+
+  FOREACHfacet_i_(qh, facets ) { ... }
+    assign 'facet' and 'facet_i' for each facet in facets set
+
+  declare:
+    facetT *facet;
+    int     facet_n, facet_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHfacet_i_(qh, facets)    FOREACHsetelement_i_(qh, facetT, facets, facet)
+
+/*----------------------------------
+
+  FOREACHneighbor_i_(qh, facet ) { ... }
+    assign 'neighbor' and 'neighbor_i' for each neighbor in facet->neighbors
+
+  declare:
+    facetT *neighbor;
+    int     neighbor_n, neighbor_i;
+
+  notes:
+    see FOREACHsetelement_i_
+    for facet neighbors of vertex, need to define a new macro
+*/
+#define FOREACHneighbor_i_(qh, facet)  FOREACHsetelement_i_(qh, facetT, facet->neighbors, neighbor)
+
+/*----------------------------------
+
+  FOREACHpoint_i_(qh, points ) { ... }
+    assign 'point' and 'point_i' for each point in points set
+
+  declare:
+    pointT *point;
+    int     point_n, point_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHpoint_i_(qh, points)    FOREACHsetelement_i_(qh, pointT, points, point)
+
+/*----------------------------------
+
+  FOREACHridge_i_(qh, ridges ) { ... }
+    assign 'ridge' and 'ridge_i' for each ridge in ridges set
+
+  declare:
+    ridgeT *ridge;
+    int     ridge_n, ridge_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHridge_i_(qh, ridges)    FOREACHsetelement_i_(qh, ridgeT, ridges, ridge)
+
+/*----------------------------------
+
+  FOREACHvertex_i_(qh, vertices ) { ... }
+    assign 'vertex' and 'vertex_i' for each vertex in vertices set
+
+  declare:
+    vertexT *vertex;
+    int     vertex_n, vertex_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHvertex_i_(qh, vertices) FOREACHsetelement_i_(qh, vertexT, vertices, vertex)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/********* -libqhull_r.c prototypes (duplicated from qhull_ra.h) **********************/
+
+void    qh_qhull(qhT *qh);
+boolT   qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist);
+void    QH_NORETURN qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet);
+void    qh_printsummary(qhT *qh, FILE *fp);
+
+/********* -user_r.c prototypes (alphabetical) **********************/
+
+void    QH_NORETURN qh_errexit(qhT *qh, int exitcode, facetT *facet, ridgeT *ridge);
+void    qh_errprint(qhT *qh, const char* string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex);
+int     qh_new_qhull(qhT *qh, int dim, int numpoints, coordT *points, boolT ismalloc,
+                char *qhull_cmd, FILE *outfile, FILE *errfile);
+void    qh_printfacetlist(qhT *qh, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printhelp_degenerate(qhT *qh, FILE *fp);
+void    qh_printhelp_internal(qhT *qh, FILE *fp);
+void    qh_printhelp_narrowhull(qhT *qh, FILE *fp, realT minangle);
+void    qh_printhelp_singular(qhT *qh, FILE *fp);
+void    qh_printhelp_topology(qhT *qh, FILE *fp);
+void    qh_printhelp_wide(qhT *qh, FILE *fp);
+void    qh_user_memsizes(qhT *qh);
+
+/********* -usermem_r.c prototypes (alphabetical) **********************/
+void    QH_NORETURN qh_exit(int exitcode);
+void    qh_fprintf_stderr(int msgcode, const char *fmt, ... ) QH_PRINTF_LIKE(2, 3);
+void    qh_free(void *mem);
+void   *qh_malloc(size_t size);
+
+/********* -userprintf_r.c and userprintf_rbox_r.c prototypes **********************/
+void    qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... ) QH_PRINTF_LIKE(4, 5);
+void    qh_fprintf_rbox(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... ) QH_PRINTF_LIKE(4, 5);
+
+/***** -geom_r.c/geom2_r.c/random_r.c prototypes (duplicated from geom_r.h, random_r.h) ****************/
+
+facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,
+                     boolT bestoutside, boolT newfacets, boolT noupper,
+                     realT *dist, boolT *isoutside, int *numpart);
+facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet,
+                     realT *dist, boolT bestoutside, boolT *isoutside, int *numpart);
+boolT   qh_gram_schmidt(qhT *qh, int dim, realT **rows);
+void    qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane);
+void    qh_projectinput(qhT *qh);
+void    qh_randommatrix(qhT *qh, realT *buffer, int dim, realT **row);
+void    qh_rotateinput(qhT *qh, realT **rows);
+void    qh_scaleinput(qhT *qh);
+void    qh_setdelaunay(qhT *qh, int dim, int count, pointT *points);
+coordT  *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible);
+
+/***** -global_r.c prototypes (alphabetical) ***********************/
+
+unsigned long qh_clock(qhT *qh);
+void    qh_checkflags(qhT *qh, char *command, char *hiddenflags);
+void    qh_clear_outputflags(qhT *qh);
+void    qh_freebuffers(qhT *qh);
+void    qh_freeqhull(qhT *qh, boolT allmem);
+void    qh_init_A(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]);
+void    qh_init_B(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
+void    qh_init_qhull_command(qhT *qh, int argc, char *argv[]);
+void    qh_initbuffers(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
+void    qh_initflags(qhT *qh, char *command);
+void    qh_initqhull_buffers(qhT *qh);
+void    qh_initqhull_globals(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
+void    qh_initqhull_mem(qhT *qh);
+void    qh_initqhull_outputflags(qhT *qh);
+void    qh_initqhull_start(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile);
+void    qh_initqhull_start2(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile);
+void    qh_initthresholds(qhT *qh, char *command);
+void    qh_lib_check(int qhullLibraryType, int qhTsize, int vertexTsize, int ridgeTsize, int facetTsize, int setTsize, int qhmemTsize);
+void    qh_option(qhT *qh, const char *option, int *i, realT *r);
+void    qh_zero(qhT *qh, FILE *errfile);
+
+/***** -io_r.c prototypes (duplicated from io_r.h) ***********************/
+
+void    qh_dfacet(qhT *qh, unsigned int id);
+void    qh_dvertex(qhT *qh, unsigned int id);
+void    qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
+void    qh_produce_output(qhT *qh);
+coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc);
+
+
+/********* -poly_r.c/poly2_r.c prototypes (duplicated from poly_r.h) **********************/
+
+void    qh_check_output(qhT *qh);
+void    qh_check_points(qhT *qh);
+setT   *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets);
+facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside);
+vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp);
+pointT *qh_point(qhT *qh, int id);
+setT   *qh_pointfacet(qhT *qh /* qh.facet_list */);
+int     qh_pointid(qhT *qh, pointT *point);
+setT   *qh_pointvertex(qhT *qh /* qh.facet_list */);
+void    qh_setvoronoi_all(qhT *qh);
+void    qh_triangulate(qhT *qh /* qh.facet_list */);
+
+/********* -rboxlib_r.c prototypes **********************/
+int     qh_rboxpoints(qhT *qh, char* rbox_command);
+void    QH_NORETURN qh_errexit_rbox(qhT *qh, int exitcode);
+
+/************************** accessors.c prototypes ******************************/
+
+#define QH_GETTER(TYPE, FIELD) TYPE qh_get_##FIELD(const qhT *qh)
+#define QH_SETTER(TYPE, FIELD) void qh_set_##FIELD(qhT *qh, TYPE _val_)
+QH_GETTER(facetT*, facet_list);
+QH_GETTER(pointT*, first_point);
+QH_GETTER(int, hull_dim);
+QH_GETTER(int, num_facets);
+QH_GETTER(int, num_points);
+QH_GETTER(int, num_vertices);
+QH_GETTER(vertexT*, vertex_list);
+QH_GETTER(realT, totarea);
+QH_GETTER(realT, totvol);
+QH_GETTER(boolT, hasAreaVolume);
+QH_SETTER(boolT, hasAreaVolume);
+QH_GETTER(boolT, hasTriangulation);
+QH_SETTER(boolT, hasTriangulation);
+QH_GETTER(int, num_good);
+QH_GETTER(setT*, del_vertices);
+QH_GETTER(int, input_dim);
+QH_GETTER(boolT, DELAUNAY);
+QH_GETTER(boolT, SCALElast);
+QH_GETTER(boolT, KEEPcoplanar);
+QH_GETTER(boolT, MERGEexact);
+QH_GETTER(boolT, NOerrexit);
+QH_GETTER(boolT, PROJECTdelaunay);
+QH_GETTER(boolT, ATinfinity);
+QH_GETTER(boolT, UPPERdelaunay);
+QH_GETTER(int, normal_size);
+QH_GETTER(int, num_visible);
+QH_GETTER(int, center_size);
+QH_GETTER(const char *, qhull_command);
+QH_GETTER(facetT*, facet_tail);
+QH_GETTER(vertexT*, vertex_tail);
+QH_GETTER(unsigned int, facet_id);
+QH_GETTER(unsigned int, visit_id);
+QH_GETTER(unsigned int, vertex_visit);
+QH_GETTER(pointT*, input_points);
+QH_GETTER(coordT*, feasible_point);
+QH_GETTER(realT, last_low);
+QH_GETTER(realT, last_high);
+QH_GETTER(realT, last_newhigh);
+QH_GETTER(realT, max_outside);
+QH_GETTER(realT, MINoutside);
+QH_GETTER(realT, DISTround);
+QH_GETTER(setT*, other_points);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* qhDEFlibqhull */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/mem_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/mem_r.c
new file mode 100644
index 00000000000..57e80edda9b
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/mem_r.c
@@ -0,0 +1,566 @@
+/*
  ---------------------------------
+
+  mem_r.c
+    memory management routines for qhull
+
+  See libqhull/mem.c for a standalone program.
+
+  To initialize memory:
+
+    qh_meminit(qh, stderr);
+    qh_meminitbuffers(qh, qh->IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
+    qh_memsize(qh, (int)sizeof(facetT));
+    qh_memsize(qh, (int)sizeof(facetT));
+    ...
+    qh_memsetup(qh);
+
+  To free up all memory buffers:
+    qh_memfreeshort(qh, &curlong, &totlong);
+
+  if qh_NOmem,
+    malloc/free is used instead of mem_r.c
+
+  notes:
+    uses Quickfit algorithm (freelists for commonly allocated sizes)
+    assumes small sizes for freelists (it discards the tail of memory buffers)
+
+  see:
+    qh-mem_r.htm and mem_r.h
+    global_r.c (qh_initbuffers) for an example of using mem_r.c
+
+  Copyright (c) 1993-2020 The Geometry Center.
+  $Id: //main/2019/qhull/src/libqhull_r/mem_r.c#7 $$Change: 2953 $
+  $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+*/
+
+#include "libqhull_r.h"  /* includes user_r.h and mem_r.h */
+
+#include 
+#include 
+#include 
+
+#ifndef qh_NOmem
+
+/*============= internal functions ==============*/
+
+static int qh_intcompare(const void *i, const void *j);
+
+/*========== functions in alphabetical order ======== */
+
+/*---------------------------------
+
+  qh_intcompare( i, j )
+    used by qsort and bsearch to compare two integers
+*/
+static int qh_intcompare(const void *i, const void *j) {
+  return(*((const int *)i) - *((const int *)j));
+} /* intcompare */
+
+
+/*----------------------------------
+
+  qh_memalloc(qh, insize )
+    returns object of insize bytes
+    qhmem is the global memory structure
+
+  returns:
+    pointer to allocated memory
+    errors if insufficient memory
+
+  notes:
+    use explicit type conversion to avoid type warnings on some compilers
+    actual object may be larger than insize
+    use qh_memalloc_() for inline code for quick allocations
+    logs allocations if 'T5'
+    caller is responsible for freeing the memory.
+    short memory is freed on shutdown by qh_memfreeshort unless qh_NOmem
+
+  design:
+    if size < qh->qhmem.LASTsize
+      if qh->qhmem.freelists[size] non-empty
+        return first object on freelist
+      else
+        round up request to size of qh->qhmem.freelists[size]
+        allocate new allocation buffer if necessary
+        allocate object from allocation buffer
+    else
+      allocate object with qh_malloc() in user_r.c
+*/
+void *qh_memalloc(qhT *qh, int insize) {
+  void **freelistp, *newbuffer;
+  int idx, size, n;
+  int outsize, bufsize;
+  void *object;
+
+  if (insize<0) {
+      qh_fprintf(qh, qh->qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d).  Did int overflow due to high-D?\n", insize); /* WARN64 */
+      qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
+  }
+  if (insize>=0 && insize <= qh->qhmem.LASTsize) {
+    idx= qh->qhmem.indextable[insize];
+    outsize= qh->qhmem.sizetable[idx];
+    qh->qhmem.totshort += outsize;
+    freelistp= qh->qhmem.freelists+idx;
+    if ((object= *freelistp)) {
+      qh->qhmem.cntquick++;
+      qh->qhmem.totfree -= outsize;
+      *freelistp= *((void **)*freelistp);  /* replace freelist with next object */
+#ifdef qh_TRACEshort
+      n= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;
+      if (qh->qhmem.IStracing >= 5)
+          qh_fprintf(qh, qh->qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);
+#endif
+      return(object);
+    }else {
+      qh->qhmem.cntshort++;
+      if (outsize > qh->qhmem.freesize) {
+        qh->qhmem.totdropped += qh->qhmem.freesize;
+        if (!qh->qhmem.curbuffer)
+          bufsize= qh->qhmem.BUFinit;
+        else
+          bufsize= qh->qhmem.BUFsize;
+        if (!(newbuffer= qh_malloc((size_t)bufsize))) {
+          qh_fprintf(qh, qh->qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize);
+          qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
+        }
+        *((void **)newbuffer)= qh->qhmem.curbuffer;  /* prepend newbuffer to curbuffer
+                                                    list.  newbuffer!=0 by QH6080 */
+        qh->qhmem.curbuffer= newbuffer;
+        size= ((int)sizeof(void **) + qh->qhmem.ALIGNmask) & ~qh->qhmem.ALIGNmask;
+        qh->qhmem.freemem= (void *)((char *)newbuffer+size);
+        qh->qhmem.freesize= bufsize - size;
+        qh->qhmem.totbuffer += bufsize - size; /* easier to check */
+        /* Periodically test totbuffer.  It matches at beginning and exit of every call */
+        n= qh->qhmem.totshort + qh->qhmem.totfree + qh->qhmem.totdropped + qh->qhmem.freesize - outsize;
+        if (qh->qhmem.totbuffer != n) {
+            qh_fprintf(qh, qh->qhmem.ferr, 6212, "qhull internal error (qh_memalloc): short totbuffer %d != totshort+totfree... %d\n", qh->qhmem.totbuffer, n);
+            qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
+        }
+      }
+      object= qh->qhmem.freemem;
+      qh->qhmem.freemem= (void *)((char *)qh->qhmem.freemem + outsize);
+      qh->qhmem.freesize -= outsize;
+      qh->qhmem.totunused += outsize - insize;
+#ifdef qh_TRACEshort
+      n= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;
+      if (qh->qhmem.IStracing >= 5)
+          qh_fprintf(qh, qh->qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);
+#endif
+      return object;
+    }
+  }else {                     /* long allocation */
+    if (!qh->qhmem.indextable) {
+      qh_fprintf(qh, qh->qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
+      qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+    }
+    outsize= insize;
+    qh->qhmem.cntlong++;
+    qh->qhmem.totlong += outsize;
+    if (qh->qhmem.maxlong < qh->qhmem.totlong)
+      qh->qhmem.maxlong= qh->qhmem.totlong;
+    if (!(object= qh_malloc((size_t)outsize))) {
+      qh_fprintf(qh, qh->qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize);
+      qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
+    }
+    if (qh->qhmem.IStracing >= 5)
+      qh_fprintf(qh, qh->qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, outsize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
+  }
+  return(object);
+} /* memalloc */
+
+
+/*----------------------------------
+
+  qh_memcheck(qh)
+*/
+void qh_memcheck(qhT *qh) {
+  int i, count, totfree= 0;
+  void *object;
+
+  if (!qh) {
+    qh_fprintf_stderr(6243, "qhull internal error (qh_memcheck): qh is 0.  It does not point to a qhT\n");
+    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
+  }
+  if (qh->qhmem.ferr == 0 || qh->qhmem.IStracing < 0 || qh->qhmem.IStracing > 10 || (((qh->qhmem.ALIGNmask+1) & qh->qhmem.ALIGNmask) != 0)) {
+    qh_fprintf_stderr(6244, "qhull internal error (qh_memcheck): either qh->qhmem is overwritten or qh->qhmem is not initialized.  Call qh_meminit or qh_new_qhull before calling qh_mem routines.  ferr %p, IsTracing %d, ALIGNmask 0x%x\n",
+          (void *) qh->qhmem.ferr, qh->qhmem.IStracing, qh->qhmem.ALIGNmask);
+    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
+  }
+  if (qh->qhmem.IStracing != 0)
+    qh_fprintf(qh, qh->qhmem.ferr, 8143, "qh_memcheck: check size of freelists on qh->qhmem\nqh_memcheck: A segmentation fault indicates an overwrite of qh->qhmem\n");
+  for (i=0; i < qh->qhmem.TABLEsize; i++) {
+    count=0;
+    for (object= qh->qhmem.freelists[i]; object; object= *((void **)object))
+      count++;
+    totfree += qh->qhmem.sizetable[i] * count;
+  }
+  if (totfree != qh->qhmem.totfree) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6211, "qhull internal error (qh_memcheck): totfree %d not equal to freelist total %d\n", qh->qhmem.totfree, totfree);
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  if (qh->qhmem.IStracing != 0)
+    qh_fprintf(qh, qh->qhmem.ferr, 8144, "qh_memcheck: total size of freelists totfree (%d) is the same as qh->qhmem.totfree\n", totfree);
+} /* memcheck */
+
+/*----------------------------------
+
+  qh_memfree(qh, object, insize )
+    free up an object of size bytes
+    size is insize from qh_memalloc
+
+  notes:
+    object may be NULL
+    type checking warns if using (void **)object
+    use qh_memfree_() for quick free's of small objects
+
+  design:
+    if size <= qh->qhmem.LASTsize
+      append object to corresponding freelist
+    else
+      call qh_free(object)
+*/
+void qh_memfree(qhT *qh, void *object, int insize) {
+  void **freelistp;
+  int idx, outsize;
+
+  if (!object)
+    return;
+  if (insize <= qh->qhmem.LASTsize) {
+    qh->qhmem.freeshort++;
+    idx= qh->qhmem.indextable[insize];
+    outsize= qh->qhmem.sizetable[idx];
+    qh->qhmem.totfree += outsize;
+    qh->qhmem.totshort -= outsize;
+    freelistp= qh->qhmem.freelists + idx;
+    *((void **)object)= *freelistp;
+    *freelistp= object;
+#ifdef qh_TRACEshort
+    idx= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;
+    if (qh->qhmem.IStracing >= 5)
+        qh_fprintf(qh, qh->qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);
+#endif
+  }else {
+    qh->qhmem.freelong++;
+    qh->qhmem.totlong -= insize;
+    if (qh->qhmem.IStracing >= 5)
+      qh_fprintf(qh, qh->qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
+    qh_free(object);
+  }
+} /* memfree */
+
+
+/*---------------------------------
+
+  qh_memfreeshort(qh, curlong, totlong )
+    frees up all short and qhmem memory allocations
+
+  returns:
+    number and size of current long allocations
+
+  notes:
+    if qh_NOmem (qh_malloc() for all allocations),
+       short objects (e.g., facetT) are not recovered.
+       use qh_freeqhull(qh, qh_ALL) instead.
+
+  see:
+    qh_freeqhull(qh, allMem)
+    qh_memtotal(qh, curlong, totlong, curshort, totshort, maxlong, totbuffer);
+*/
+void qh_memfreeshort(qhT *qh, int *curlong, int *totlong) {
+  void *buffer, *nextbuffer;
+  FILE *ferr;
+
+  *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;
+  *totlong= qh->qhmem.totlong;
+  for (buffer=qh->qhmem.curbuffer; buffer; buffer= nextbuffer) {
+    nextbuffer= *((void **) buffer);
+    qh_free(buffer);
+  }
+  qh->qhmem.curbuffer= NULL;
+  if (qh->qhmem.LASTsize) {
+    qh_free(qh->qhmem.indextable);
+    qh_free(qh->qhmem.freelists);
+    qh_free(qh->qhmem.sizetable);
+  }
+  ferr= qh->qhmem.ferr;
+  memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
+  qh->qhmem.ferr= ferr;
+} /* memfreeshort */
+
+
+/*----------------------------------
+
+  qh_meminit(qh, ferr )
+    initialize qhmem and test sizeof(void *)
+    Does not throw errors.  qh_exit on failure
+*/
+void qh_meminit(qhT *qh, FILE *ferr) {
+
+  memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
+  if (ferr)
+    qh->qhmem.ferr= ferr;
+  else
+    qh->qhmem.ferr= stderr;
+  if (sizeof(void *) < sizeof(int)) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6083, "qhull internal error (qh_meminit): sizeof(void *) %d < sizeof(int) %d.  qset_r.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
+    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
+  }
+  if (sizeof(void *) > sizeof(ptr_intT)) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6084, "qhull internal error (qh_meminit): sizeof(void *) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem_r.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT));
+    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
+  }
+  qh_memcheck(qh);
+} /* meminit */
+
+/*---------------------------------
+
+  qh_meminitbuffers(qh, tracelevel, alignment, numsizes, bufsize, bufinit )
+    initialize qhmem
+    if tracelevel >= 5, trace memory allocations
+    alignment= desired address alignment for memory allocations
+    numsizes= number of freelists
+    bufsize=  size of additional memory buffers for short allocations
+    bufinit=  size of initial memory buffer for short allocations
+*/
+void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
+
+  qh->qhmem.IStracing= tracelevel;
+  qh->qhmem.NUMsizes= numsizes;
+  qh->qhmem.BUFsize= bufsize;
+  qh->qhmem.BUFinit= bufinit;
+  qh->qhmem.ALIGNmask= alignment-1;
+  if (qh->qhmem.ALIGNmask & ~qh->qhmem.ALIGNmask) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  qh->qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int));
+  qh->qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *));
+  if (!qh->qhmem.sizetable || !qh->qhmem.freelists) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n");
+    qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
+  }
+  if (qh->qhmem.IStracing >= 1)
+    qh_fprintf(qh, qh->qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
+} /* meminitbuffers */
+
+/*---------------------------------
+
+  qh_memsetup(qh)
+    set up memory after running memsize()
+*/
+void qh_memsetup(qhT *qh) {
+  int k,i;
+
+  qsort(qh->qhmem.sizetable, (size_t)qh->qhmem.TABLEsize, sizeof(int), qh_intcompare);
+  qh->qhmem.LASTsize= qh->qhmem.sizetable[qh->qhmem.TABLEsize-1];
+  if (qh->qhmem.LASTsize >= qh->qhmem.BUFsize || qh->qhmem.LASTsize >= qh->qhmem.BUFinit) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",
+            qh->qhmem.LASTsize, qh->qhmem.BUFsize, qh->qhmem.BUFinit);
+    qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
+  }
+  if (!(qh->qhmem.indextable= (int *)qh_malloc((size_t)(qh->qhmem.LASTsize+1) * sizeof(int)))) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n");
+    qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
+  }
+  for (k=qh->qhmem.LASTsize+1; k--; )
+    qh->qhmem.indextable[k]= k;
+  i= 0;
+  for (k=0; k <= qh->qhmem.LASTsize; k++) {
+    if (qh->qhmem.indextable[k] <= qh->qhmem.sizetable[i])
+      qh->qhmem.indextable[k]= i;
+    else
+      qh->qhmem.indextable[k]= ++i;
+  }
+} /* memsetup */
+
+/*---------------------------------
+
+  qh_memsize(qh, size )
+    define a free list for this size
+*/
+void qh_memsize(qhT *qh, int size) {
+  int k;
+
+  if (qh->qhmem.LASTsize) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6089, "qhull internal error (qh_memsize): qh_memsize called after qh_memsetup\n");
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  size= (size + qh->qhmem.ALIGNmask) & ~qh->qhmem.ALIGNmask;
+  if (qh->qhmem.IStracing >= 3)
+    qh_fprintf(qh, qh->qhmem.ferr, 3078, "qh_memsize: quick memory of %d bytes\n", size);
+  for (k=qh->qhmem.TABLEsize; k--; ) {
+    if (qh->qhmem.sizetable[k] == size)
+      return;
+  }
+  if (qh->qhmem.TABLEsize < qh->qhmem.NUMsizes)
+    qh->qhmem.sizetable[qh->qhmem.TABLEsize++]= size;
+  else
+    qh_fprintf(qh, qh->qhmem.ferr, 7060, "qhull warning (qh_memsize): free list table has room for only %d sizes\n", qh->qhmem.NUMsizes);
+} /* memsize */
+
+
+/*---------------------------------
+
+  qh_memstatistics(qh, fp )
+    print out memory statistics
+
+    Verifies that qh->qhmem.totfree == sum of freelists
+*/
+void qh_memstatistics(qhT *qh, FILE *fp) {
+  int i;
+  int count;
+  void *object;
+
+  qh_memcheck(qh);
+  qh_fprintf(qh, fp, 9278, "\nmemory statistics:\n\
+%7d quick allocations\n\
+%7d short allocations\n\
+%7d long allocations\n\
+%7d short frees\n\
+%7d long frees\n\
+%7d bytes of short memory in use\n\
+%7d bytes of short memory in freelists\n\
+%7d bytes of dropped short memory\n\
+%7d bytes of unused short memory (estimated)\n\
+%7d bytes of long memory allocated (max, except for input)\n\
+%7d bytes of long memory in use (in %d pieces)\n\
+%7d bytes of short memory buffers (minus links)\n\
+%7d bytes per short memory buffer (initially %d bytes)\n",
+           qh->qhmem.cntquick, qh->qhmem.cntshort, qh->qhmem.cntlong,
+           qh->qhmem.freeshort, qh->qhmem.freelong,
+           qh->qhmem.totshort, qh->qhmem.totfree,
+           qh->qhmem.totdropped + qh->qhmem.freesize, qh->qhmem.totunused,
+           qh->qhmem.maxlong, qh->qhmem.totlong, qh->qhmem.cntlong - qh->qhmem.freelong,
+           qh->qhmem.totbuffer, qh->qhmem.BUFsize, qh->qhmem.BUFinit);
+  if (qh->qhmem.cntlarger) {
+    qh_fprintf(qh, fp, 9279, "%7d calls to qh_setlarger\n%7.2g     average copy size\n",
+           qh->qhmem.cntlarger, ((double)qh->qhmem.totlarger)/(double)qh->qhmem.cntlarger);
+    qh_fprintf(qh, fp, 9280, "  freelists(bytes->count):");
+  }
+  for (i=0; i < qh->qhmem.TABLEsize; i++) {
+    count=0;
+    for (object= qh->qhmem.freelists[i]; object; object= *((void **)object))
+      count++;
+    qh_fprintf(qh, fp, 9281, " %d->%d", qh->qhmem.sizetable[i], count);
+  }
+  qh_fprintf(qh, fp, 9282, "\n\n");
+} /* memstatistics */
+
+
+/*---------------------------------
+
+  qh_NOmem
+    turn off quick-fit memory allocation
+
+  notes:
+    uses qh_malloc() and qh_free() instead
+*/
+#else /* qh_NOmem */
+
+void *qh_memalloc(qhT *qh, int insize) {
+  void *object;
+
+  if (!(object= qh_malloc((size_t)insize))) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n");
+    qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
+  }
+  qh->qhmem.cntlong++;
+  qh->qhmem.totlong += insize;
+  if (qh->qhmem.maxlong < qh->qhmem.totlong)
+      qh->qhmem.maxlong= qh->qhmem.totlong;
+  if (qh->qhmem.IStracing >= 5)
+    qh_fprintf(qh, qh->qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
+  return object;
+}
+
+void qh_memcheck(qhT *qh) {
+}
+
+void qh_memfree(qhT *qh, void *object, int insize) {
+
+  if (!object)
+    return;
+  qh_free(object);
+  qh->qhmem.freelong++;
+  qh->qhmem.totlong -= insize;
+  if (qh->qhmem.IStracing >= 5)
+    qh_fprintf(qh, qh->qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);
+}
+
+void qh_memfreeshort(qhT *qh, int *curlong, int *totlong) {
+  *totlong= qh->qhmem.totlong;
+  *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;
+  memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
+}
+
+void qh_meminit(qhT *qh, FILE *ferr) {
+
+  memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem));  /* every field is 0, FALSE, NULL */
+  if (ferr)
+      qh->qhmem.ferr= ferr;
+  else
+      qh->qhmem.ferr= stderr;
+  if (sizeof(void *) < sizeof(int)) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6091, "qhull internal error (qh_meminit): sizeof(void *) %d < sizeof(int) %d.  qset_r.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+}
+
+void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
+
+  qh->qhmem.IStracing= tracelevel;
+}
+
+void qh_memsetup(qhT *qh) {
+}
+
+void qh_memsize(qhT *qh, int size) {
+}
+
+void qh_memstatistics(qhT *qh, FILE *fp) {
+
+  qh_fprintf(qh, fp, 9409, "\nmemory statistics:\n\
+%7d long allocations\n\
+%7d long frees\n\
+%7d bytes of long memory allocated (max, except for input)\n\
+%7d bytes of long memory in use (in %d pieces)\n",
+           qh->qhmem.cntlong,
+           qh->qhmem.freelong,
+           qh->qhmem.maxlong, qh->qhmem.totlong, qh->qhmem.cntlong - qh->qhmem.freelong);
+}
+
+#endif /* qh_NOmem */
+
+/*---------------------------------
+
+  qh_memtotal(qh, totlong, curlong, totshort, curshort, maxlong, totbuffer )
+    Return the total, allocated long and short memory
+
+  returns:
+    Returns the total current bytes of long and short allocations
+    Returns the current count of long and short allocations
+    Returns the maximum long memory and total short buffer (minus one link per buffer)
+    Does not error (for deprecated UsingLibQhull.cpp in libqhullpcpp)
+*/
+void qh_memtotal(qhT *qh, int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer) {
+    *totlong= qh->qhmem.totlong;
+    *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;
+    *totshort= qh->qhmem.totshort;
+    *curshort= qh->qhmem.cntshort + qh->qhmem.cntquick - qh->qhmem.freeshort;
+    *maxlong= qh->qhmem.maxlong;
+    *totbuffer= qh->qhmem.totbuffer;
+} /* memtotlong */
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/mem_r.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/mem_r.h
new file mode 100644
index 00000000000..aeb761b100e
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/mem_r.h
@@ -0,0 +1,235 @@
+/*
  ---------------------------------
+
+   mem_r.h
+     prototypes for memory management functions
+
+   see qh-mem_r.htm, mem_r.c and qset_r.h
+
+   for error handling, writes message and calls
+     qh_errexit(qhT *qh, qhmem_ERRmem, NULL, NULL) if insufficient memory
+       and
+     qh_errexit(qhT *qh, qhmem_ERRqhull, NULL, NULL) otherwise
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/mem_r.h#6 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+*/
+
+#ifndef qhDEFmem
+#define qhDEFmem 1
+
+#include 
+
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;          /* defined in qset_r.h */
+#endif
+
+#ifndef DEFqhT
+#define DEFqhT 1
+typedef struct qhT qhT;          /* defined in libqhull_r.h */
+#endif
+
+/*---------------------------------
+
+  qh_NOmem
+    turn off quick-fit memory allocation
+
+  notes:
+    mem_r.c implements Quickfit memory allocation for about 20% time
+    savings.  If it fails on your machine, try to locate the
+    problem, and send the answer to qhull@qhull.org.  If this can
+    not be done, define qh_NOmem to use malloc/free instead.
+
+    #define qh_NOmem
+*/
+
+/*---------------------------------
+
+qh_TRACEshort
+Trace short and quick memory allocations at T5
+
+*/
+#define qh_TRACEshort
+
+/*-------------------------------------------
+    to avoid bus errors, memory allocation must consider alignment requirements.
+    malloc() automatically takes care of alignment.   Since mem_r.c manages
+    its own memory, we need to explicitly specify alignment in
+    qh_meminitbuffers().
+
+    A safe choice is sizeof(double).  sizeof(float) may be used if doubles
+    do not occur in data structures and pointers are the same size.  Be careful
+    of machines (e.g., DEC Alpha) with large pointers.  If gcc is available,
+    use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)).
+
+   see qh_MEMalign in user_r.h for qhull's alignment
+*/
+
+#define qhmem_ERRmem 4    /* matches qh_ERRmem in libqhull_r.h */
+#define qhmem_ERRqhull 5  /* matches qh_ERRqhull in libqhull_r.h */
+
+/*----------------------------------
+
+  ptr_intT
+    for casting a void * to an integer-type that holds a pointer
+    Used for integer expressions (e.g., computing qh_gethash() in poly_r.c)
+
+  notes:
+    WARN64 -- these notes indicate 64-bit issues
+    On 64-bit machines, a pointer may be larger than an 'int'.
+    qh_meminit()/mem_r.c checks that 'ptr_intT' holds a 'void*'
+    ptr_intT is typically a signed value, but not necessarily so
+    size_t is typically unsigned, but should match the parameter type
+    Qhull uses int instead of size_t except for system calls such as malloc, qsort, qh_malloc, etc.
+    This matches Qt convention and is easier to work with.
+*/
+#if (defined(__MINGW64__)) && defined(_WIN64)
+typedef long long ptr_intT;
+#elif defined(_MSC_VER) && defined(_WIN64)
+typedef long long ptr_intT;
+#else
+typedef long ptr_intT;
+#endif
+
+/*----------------------------------
+
+  qhmemT
+    global memory structure for mem_r.c
+
+ notes:
+   users should ignore qhmem except for writing extensions
+   qhmem is allocated in mem_r.c
+
+   qhmem could be swapable like qh and qhstat, but then
+   multiple qh's and qhmem's would need to keep in synch.
+   A swapable qhmem would also waste memory buffers.  As long
+   as memory operations are atomic, there is no problem with
+   multiple qh structures being active at the same time.
+   If you need separate address spaces, you can swap the
+   contents of qh->qhmem.
+*/
+typedef struct qhmemT qhmemT;
+
+struct qhmemT {               /* global memory management variables */
+  int      BUFsize;           /* size of memory allocation buffer */
+  int      BUFinit;           /* initial size of memory allocation buffer */
+  int      TABLEsize;         /* actual number of sizes in free list table */
+  int      NUMsizes;          /* maximum number of sizes in free list table */
+  int      LASTsize;          /* last size in free list table */
+  int      ALIGNmask;         /* worst-case alignment, must be 2^n-1 */
+  void   **freelists;          /* free list table, linked by offset 0 */
+  int     *sizetable;         /* size of each freelist */
+  int     *indextable;        /* size->index table */
+  void    *curbuffer;         /* current buffer, linked by offset 0 */
+  void    *freemem;           /*   free memory in curbuffer */
+  int      freesize;          /*   size of freemem in bytes */
+  setT    *tempstack;         /* stack of temporary memory, managed by users */
+  FILE    *ferr;              /* file for reporting errors when 'qh' may be undefined */
+  int      IStracing;         /* =5 if tracing memory allocations */
+  int      cntquick;          /* count of quick allocations */
+                              /* Note: removing statistics doesn't effect speed */
+  int      cntshort;          /* count of short allocations */
+  int      cntlong;           /* count of long allocations */
+  int      freeshort;         /* count of short memfrees */
+  int      freelong;          /* count of long memfrees */
+  int      totbuffer;         /* total short memory buffers minus buffer links */
+  int      totdropped;        /* total dropped memory at end of short memory buffers (e.g., freesize) */
+  int      totfree;           /* total size of free, short memory on freelists */
+  int      totlong;           /* total size of long memory in use */
+  int      maxlong;           /*   maximum totlong */
+  int      totshort;          /* total size of short memory in use */
+  int      totunused;         /* total unused short memory (estimated, short size - request size of first allocations) */
+  int      cntlarger;         /* count of setlarger's */
+  int      totlarger;         /* total copied by setlarger */
+};
+
+
+/*==================== -macros ====================*/
+
+/*----------------------------------
+
+  qh_memalloc_(qh, insize, freelistp, object, type)
+    returns object of size bytes
+        assumes size<=qh->qhmem.LASTsize and void **freelistp is a temp
+*/
+
+#if defined qh_NOmem
+#define qh_memalloc_(qh, insize, freelistp, object, type) {\
+  (void)freelistp; /* Avoid warnings */ \
+  object= (type *)qh_memalloc(qh, insize); }
+#elif defined qh_TRACEshort
+#define qh_memalloc_(qh, insize, freelistp, object, type) {\
+  (void)freelistp; /* Avoid warnings */ \
+  object= (type *)qh_memalloc(qh, insize); }
+#else /* !qh_NOmem */
+
+#define qh_memalloc_(qh, insize, freelistp, object, type) {\
+  freelistp= qh->qhmem.freelists + qh->qhmem.indextable[insize];\
+  if ((object= (type *)*freelistp)) {\
+    qh->qhmem.totshort += qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
+    qh->qhmem.totfree -= qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
+    qh->qhmem.cntquick++;  \
+    *freelistp= *((void **)*freelistp);\
+  }else object= (type *)qh_memalloc(qh, insize);}
+#endif
+
+/*----------------------------------
+
+  qh_memfree_(qh, object, insize, freelistp)
+    free up an object
+
+  notes:
+    object may be NULL
+    assumes size<=qh->qhmem.LASTsize and void **freelistp is a temp
+*/
+#if defined qh_NOmem
+#define qh_memfree_(qh, object, insize, freelistp) {\
+  (void)freelistp; /* Avoid warnings */ \
+  qh_memfree(qh, object, insize); }
+#elif defined qh_TRACEshort
+#define qh_memfree_(qh, object, insize, freelistp) {\
+  (void)freelistp; /* Avoid warnings */ \
+  qh_memfree(qh, object, insize); }
+#else /* !qh_NOmem */
+
+#define qh_memfree_(qh, object, insize, freelistp) {\
+  if (object) { \
+    qh->qhmem.freeshort++;\
+    freelistp= qh->qhmem.freelists + qh->qhmem.indextable[insize];\
+    qh->qhmem.totshort -= qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
+    qh->qhmem.totfree += qh->qhmem.sizetable[qh->qhmem.indextable[insize]]; \
+    *((void **)object)= *freelistp;\
+    *freelistp= object;}}
+#endif
+
+/*=============== prototypes in alphabetical order ============*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *qh_memalloc(qhT *qh, int insize);
+void qh_memcheck(qhT *qh);
+void qh_memfree(qhT *qh, void *object, int insize);
+void qh_memfreeshort(qhT *qh, int *curlong, int *totlong);
+void qh_meminit(qhT *qh, FILE *ferr);
+void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes,
+                        int bufsize, int bufinit);
+void qh_memsetup(qhT *qh);
+void qh_memsize(qhT *qh, int size);
+void qh_memstatistics(qhT *qh, FILE *fp);
+void qh_memtotal(qhT *qh, int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* qhDEFmem */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/merge_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/merge_r.c
new file mode 100644
index 00000000000..f820cf80ea8
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/merge_r.c
@@ -0,0 +1,5589 @@
+/*
  ---------------------------------
+
+   merge_r.c
+   merges non-convex facets
+
+   see qh-merge_r.htm and merge_r.h
+
+   other modules call qh_premerge() and qh_postmerge()
+
+   the user may call qh_postmerge() to perform additional merges.
+
+   To remove deleted facets and vertices (qhull() in libqhull_r.c):
+     qh_partitionvisible(qh, !qh_ALL, &numoutside);  // visible_list, newfacet_list
+     qh_deletevisible();         // qh.visible_list
+     qh_resetlists(qh, False, qh_RESETvisible);       // qh.visible_list newvertex_list newfacet_list
+
+   assumes qh.CENTERtype= centrum
+
+   merges occur in qh_mergefacet and in qh_mergecycle
+   vertex->neighbors not set until the first merge occurs
+
+   Copyright (c) 1993-2020 C.B. Barber.
+   $Id: //main/2019/qhull/src/libqhull_r/merge_r.c#15 $$Change: 3664 $
+   $DateTime: 2024/07/22 23:55:01 $$Author: bbarber $
+*/
+
+#include "qhull_ra.h"
+
+#ifndef qh_NOmerge
+
+/* MRGnone, etc. */
+const char *mergetypes[]= {
+  "none",
+  "coplanar",
+  "anglecoplanar",
+  "concave",
+  "concavecoplanar",
+  "twisted",
+  "flip",
+  "dupridge",
+  "subridge",
+  "vertices",
+  "degen",
+  "redundant",
+  "mirror",
+  "coplanarhorizon",
+};
+
+/*===== functions(alphabetical after premerge and postmerge) ======*/
+
+/*---------------------------------
+
+  qh_premerge(qh, apexpointid, maxcentrum )
+    pre-merge nonconvex facets in qh.newfacet_list for apexpointid
+    maxcentrum defines coplanar and concave (qh_test_appendmerge)
+
+  returns:
+    deleted facets added to qh.visible_list with facet->visible set
+
+  notes:
+    only called by qh_addpoint
+    uses globals, qh.MERGEexact, qh.PREmerge
+
+  design:
+    mark dupridges in qh.newfacet_list
+    merge facet cycles in qh.newfacet_list
+    merge dupridges and concave facets in qh.newfacet_list
+    check merged facet cycles for degenerate and redundant facets
+    merge degenerate and redundant facets
+    collect coplanar and concave facets
+    merge concave, coplanar, degenerate, and redundant facets
+*/
+void qh_premerge(qhT *qh, int apexpointid, realT maxcentrum, realT maxangle /* qh.newfacet_list */) {
+  boolT othermerge= False;
+
+  if (qh->ZEROcentrum && qh_checkzero(qh, !qh_ALL))
+    return;
+  trace2((qh, qh->ferr, 2008, "qh_premerge: premerge centrum %2.2g angle %4.4g for apex p%d newfacet_list f%d\n",
+            maxcentrum, maxangle, apexpointid, getid_(qh->newfacet_list)));
+  if (qh->IStracing >= 4 && qh->num_facets < 100)
+    qh_printlists(qh);
+  qh->centrum_radius= maxcentrum;
+  qh->cos_max= maxangle;
+  if (qh->hull_dim >=3) {
+    qh_mark_dupridges(qh, qh->newfacet_list, qh_ALL); /* facet_mergeset */
+    qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);
+    qh_forcedmerges(qh, &othermerge /* qh.facet_mergeset */);
+  }else /* qh.hull_dim == 2 */
+    qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);
+  qh_flippedmerges(qh, qh->newfacet_list, &othermerge);
+  if (!qh->MERGEexact || zzval_(Ztotmerge)) {
+    zinc_(Zpremergetot);
+    qh->POSTmerging= False;
+    qh_getmergeset_initial(qh, qh->newfacet_list);
+    qh_all_merges(qh, othermerge, False);
+  }
+} /* premerge */
+
+/*---------------------------------
+
+  qh_postmerge(qh, reason, maxcentrum, maxangle, vneighbors )
+    post-merge nonconvex facets as defined by maxcentrum and maxangle
+    'reason' is for reporting progress
+    if vneighbors ('Qv'),
+      calls qh_test_vneighbors at end of qh_all_merge from qh_postmerge
+
+  returns:
+    if first call (qh.visible_list != qh.facet_list),
+      builds qh.facet_newlist, qh.newvertex_list
+    deleted facets added to qh.visible_list with facet->visible
+    qh.visible_list == qh.facet_list
+
+  notes:
+    called by qh_qhull after qh_buildhull
+    called if a merge may be needed due to
+      qh.MERGEexact ('Qx'), qh_DIMreduceBuild, POSTmerge (e.g., 'Cn'), or TESTvneighbors ('Qv')
+    if firstmerge,
+      calls qh_reducevertices before qh_getmergeset
+
+  design:
+    if first call
+      set qh.visible_list and qh.newfacet_list to qh.facet_list
+      add all facets to qh.newfacet_list
+      mark non-simplicial facets, facet->newmerge
+      set qh.newvertext_list to qh.vertex_list
+      add all vertices to qh.newvertex_list
+      if a pre-merge occurred
+        set vertex->delridge {will retest the ridge}
+        if qh.MERGEexact
+          call qh_reducevertices()
+      if no pre-merging
+        merge flipped facets
+    determine non-convex facets
+    merge all non-convex facets
+*/
+void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
+                      boolT vneighbors) {
+  facetT *newfacet;
+  boolT othermerges= False;
+  vertexT *vertex;
+
+  if (qh->REPORTfreq || qh->IStracing) {
+    qh_buildtracing(qh, NULL, NULL);
+    qh_printsummary(qh, qh->ferr);
+    if (qh->PRINTstatistics)
+      qh_printallstatistics(qh, qh->ferr, "reason");
+    qh_fprintf(qh, qh->ferr, 8062, "\n%s with 'C%.2g' and 'A%.2g'\n",
+        reason, maxcentrum, maxangle);
+  }
+  trace2((qh, qh->ferr, 2009, "qh_postmerge: postmerge.  test vneighbors? %d\n",
+            vneighbors));
+  qh->centrum_radius= maxcentrum;
+  qh->cos_max= maxangle;
+  qh->POSTmerging= True;
+  if (qh->visible_list != qh->facet_list) {  /* first call due to qh_buildhull, multiple calls if qh.POSTmerge */
+    qh->NEWfacets= True;
+    qh->visible_list= qh->newfacet_list= qh->facet_list;
+    FORALLnew_facets {              /* all facets are new facets for qh_postmerge */
+      newfacet->newfacet= True;
+       if (!newfacet->simplicial)
+        newfacet->newmerge= True;   /* test f.vertices for 'delridge'.  'newmerge' was cleared at end of qh_all_merges */
+     zinc_(Zpostfacets);
+    }
+    qh->newvertex_list= qh->vertex_list;
+    FORALLvertices
+      vertex->newfacet= True;
+    if (qh->VERTEXneighbors) {  /* a merge has occurred */
+      if (qh->MERGEexact && qh->hull_dim <= qh_DIMreduceBuild)
+        qh_reducevertices(qh);  /* qh_all_merges did not call qh_reducevertices for v.delridge */
+    }
+    if (!qh->PREmerge && !qh->MERGEexact)
+      qh_flippedmerges(qh, qh->newfacet_list, &othermerges);
+  }
+  qh_getmergeset_initial(qh, qh->newfacet_list);
+  qh_all_merges(qh, False, vneighbors); /* calls qh_reducevertices before exiting */
+  FORALLnew_facets
+    newfacet->newmerge= False;   /* Was True if no vertex in f.vertices was 'delridge' */
+} /* post_merge */
+
+/*---------------------------------
+
+  qh_all_merges(qh, othermerge, vneighbors )
+    merge all non-convex facets
+
+    set othermerge if already merged facets (calls qh_reducevertices)
+    if vneighbors ('Qv' at qh.POSTmerge)
+      tests vertex neighbors for convexity at end (qh_test_vneighbors)
+    qh.facet_mergeset lists the non-convex ridges in qh_newfacet_list
+    qh.degen_mergeset is defined
+    if qh.MERGEexact && !qh.POSTmerging,
+      does not merge coplanar facets
+
+  returns:
+    deleted facets added to qh.visible_list with facet->visible
+    deleted vertices added qh.delvertex_list with vertex->delvertex
+
+  notes:
+    unless !qh.MERGEindependent,
+      merges facets in independent sets
+    uses qh.newfacet_list as implicit argument since merges call qh_removefacet()
+    [apr'19] restored qh_setdellast in place of qh_next_facetmerge.  Much faster for post-merge
+
+  design:
+    while merges occur
+      for each merge in qh.facet_mergeset
+        unless one of the facets was already merged in this pass
+          merge the facets
+        test merged facets for additional merges
+        add merges to qh.facet_mergeset
+        if qh.POSTmerging
+          periodically call qh_reducevertices to reduce extra vertices and redundant vertices
+      after each pass, if qh.VERTEXneighbors
+        if qh.POSTmerging or was a merge with qh.hull_dim<=5
+          call qh_reducevertices
+          update qh.facet_mergeset if degenredundant merges
+      if 'Qv' and qh.POSTmerging
+        test vertex neighbors for convexity
+*/
+void qh_all_merges(qhT *qh, boolT othermerge, boolT vneighbors) {
+  facetT *facet1, *facet2, *newfacet;
+  mergeT *merge;
+  boolT wasmerge= False, isreduce;
+  void **freelistp;  /* used if !qh_NOmem by qh_memfree_() */
+  vertexT *vertex;
+  realT angle, distance;
+  mergeType mergetype;
+  int numcoplanar=0, numconcave=0, numconcavecoplanar= 0, numdegenredun= 0, numnewmerges= 0, numtwisted= 0;
+
+  trace2((qh, qh->ferr, 2010, "qh_all_merges: starting to merge %d facet and %d degenerate merges for new facets f%d, othermerge? %d\n",
+            qh_setsize(qh, qh->facet_mergeset), qh_setsize(qh, qh->degen_mergeset), getid_(qh->newfacet_list), othermerge));
+
+  while (True) {
+    wasmerge= False;
+    while (qh_setsize(qh, qh->facet_mergeset) > 0 || qh_setsize(qh, qh->degen_mergeset) > 0) {
+      if (qh_setsize(qh, qh->degen_mergeset) > 0) {
+        numdegenredun += qh_merge_degenredundant(qh);
+        wasmerge= True;
+      }
+      while ((merge= (mergeT *)qh_setdellast(qh->facet_mergeset))) {
+        facet1= merge->facet1;
+        facet2= merge->facet2;
+        vertex= merge->vertex1;  /* not used for qh.facet_mergeset*/
+        mergetype= merge->mergetype;
+        angle= merge->angle;
+        distance= merge->distance;
+        qh_memfree_(qh, merge, (int)sizeof(mergeT), freelistp);   /* 'merge' is invalid */
+        if (facet1->visible || facet2->visible) {
+          trace3((qh, qh->ferr, 3045, "qh_all_merges: drop merge of f%d (del? %d) into f%d (del? %d) mergetype %d, dist %4.4g, angle %4.4g.  One or both facets is deleted\n",
+            facet1->id, facet1->visible, facet2->id, facet2->visible, mergetype, distance, angle));
+          continue;
+        }else if (mergetype == MRGcoplanar || mergetype == MRGanglecoplanar) {
+          if (qh->MERGEindependent) {
+            if ((!facet1->tested && facet1->newfacet)
+            || (!facet2->tested && facet2->newfacet)) {
+              trace3((qh, qh->ferr, 3064, "qh_all_merges: drop merge of f%d (tested? %d) into f%d (tested? %d) mergetype %d, dist %2.2g, angle %4.4g.  Merge independent sets of coplanar merges\n",
+                facet1->id, facet1->visible, facet2->id, facet2->visible, mergetype, distance, angle));
+              continue;
+            }
+          }
+        }
+        trace3((qh, qh->ferr, 3047, "qh_all_merges: merge f%d and f%d type %d dist %2.2g angle %4.4g\n",
+          facet1->id, facet2->id, mergetype, distance, angle));
+        if (mergetype == MRGtwisted)
+          qh_merge_twisted(qh, facet1, facet2);
+        else
+          qh_merge_nonconvex(qh, facet1, facet2, mergetype);
+        numnewmerges++;
+        numdegenredun += qh_merge_degenredundant(qh);
+        wasmerge= True;
+        if (mergetype == MRGconcave)
+          numconcave++;
+        else if (mergetype == MRGconcavecoplanar)
+          numconcavecoplanar++;
+        else if (mergetype == MRGtwisted)
+          numtwisted++;
+        else if (mergetype == MRGcoplanar || mergetype == MRGanglecoplanar)
+          numcoplanar++;
+        else {
+          qh_fprintf(qh, qh->ferr, 6394, "qhull internal error (qh_all_merges): expecting concave, coplanar, or twisted merge.  Got merge f%d f%d v%d mergetype %d\n",
+            getid_(facet1), getid_(facet2), getid_(vertex), mergetype);
+          qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
+        }
+      } /* while qh_setdellast */
+      if (qh->POSTmerging && qh->hull_dim <= qh_DIMreduceBuild
+      && numnewmerges > qh_MAXnewmerges) {
+        numnewmerges= 0;
+        wasmerge= othermerge= False;
+        qh_reducevertices(qh);  /* otherwise large post merges too slow */
+      }
+      qh_getmergeset(qh, qh->newfacet_list); /* qh.facet_mergeset */
+    } /* while facet_mergeset or degen_mergeset */
+    if (qh->VERTEXneighbors) {  /* at least one merge */
+      isreduce= False;
+      if (qh->POSTmerging && qh->hull_dim >= 4) {
+        isreduce= True;
+      }else if (qh->POSTmerging || !qh->MERGEexact) {
+        if ((wasmerge || othermerge) && qh->hull_dim > 2 && qh->hull_dim <= qh_DIMreduceBuild)
+          isreduce= True;
+      }
+      if (isreduce) {
+        wasmerge= othermerge= False;
+        if (qh_reducevertices(qh)) {
+          qh_getmergeset(qh, qh->newfacet_list); /* facet_mergeset */
+          continue;
+        }
+      }
+    }
+    if (vneighbors && qh_test_vneighbors(qh /* qh.newfacet_list */))
+      continue;
+    break;
+  } /* while (True) */
+  if (wasmerge || othermerge) {
+    trace3((qh, qh->ferr, 3033, "qh_all_merges: skip qh_reducevertices due to post-merging, no qh.VERTEXneighbors (%d), or hull_dim %d ==2 or >%d\n", qh->VERTEXneighbors, qh->hull_dim, qh_DIMreduceBuild))
+    FORALLnew_facets {
+      newfacet->newmerge= False;
+    }
+  }
+  if (qh->CHECKfrequently && !qh->MERGEexact) {
+    qh->old_randomdist= qh->RANDOMdist;
+    qh->RANDOMdist= False;
+    qh_checkconvex(qh, qh->newfacet_list, qh_ALGORITHMfault);
+    /* qh_checkconnect(qh); [this is slow and it changes the facet order] */
+    qh->RANDOMdist= qh->old_randomdist;
+  }
+  trace1((qh, qh->ferr, 1009, "qh_all_merges: merged %d coplanar %d concave %d concavecoplanar %d twisted facets and %d degen or redundant facets.\n",
+    numcoplanar, numconcave, numconcavecoplanar, numtwisted, numdegenredun));
+  if (qh->IStracing >= 4 && qh->num_facets < 500)
+    qh_printlists(qh);
+} /* all_merges */
+
+/*---------------------------------
+
+  qh_all_vertexmerges(qh, apexpointid, facet, &retryfacet )
+    merge vertices in qh.vertex_mergeset and subsequent merges
+
+  returns:
+    returns retryfacet for facet (if defined)
+    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
+    mergesets are empty
+    if merges, resets facet lists
+
+  notes:
+    called from qh_qhull, qh_addpoint, and qh_buildcone_mergepinched
+    vertex merges occur after facet merges and qh_resetlists
+
+  design:
+    while merges in vertex_mergeset (MRGvertices)
+      merge a pair of pinched vertices
+      update vertex neighbors
+      merge non-convex and degenerate facets and check for ridges with duplicate vertices
+      partition outside points of deleted, "visible" facets
+*/
+void qh_all_vertexmerges(qhT *qh, int apexpointid, facetT *facet, facetT **retryfacet) {
+  int numpoints; /* ignore count of partitioned points.  Used by qh_addpoint for Zpbalance */
+
+  if (retryfacet)
+    *retryfacet= facet;
+  while (qh_setsize(qh, qh->vertex_mergeset) > 0) {
+    trace1((qh, qh->ferr, 1057, "qh_all_vertexmerges: starting to merge %d vertex merges for apex p%d facet f%d\n",
+            qh_setsize(qh, qh->vertex_mergeset), apexpointid, getid_(facet)));
+    if (qh->IStracing >= 4  && qh->num_facets < 1000)
+      qh_printlists(qh);
+    qh_merge_pinchedvertices(qh, apexpointid /* qh.vertex_mergeset, visible_list, newvertex_list, newfacet_list */);
+    qh_update_vertexneighbors(qh); /* update neighbors of qh.newvertex_list from qh_newvertices for deleted facets on qh.visible_list */
+                           /* test ridges and merge non-convex facets */
+    qh_getmergeset(qh, qh->newfacet_list);
+    qh_all_merges(qh, True, False); /* calls qh_reducevertices */
+    if (qh->CHECKfrequently)
+      qh_checkpolygon(qh, qh->facet_list);
+    qh_partitionvisible(qh, !qh_ALL, &numpoints /* qh.visible_list qh.del_vertices*/);
+    if (retryfacet)
+      *retryfacet= qh_getreplacement(qh, *retryfacet);
+    qh_deletevisible(qh /* qh.visible_list  qh.del_vertices*/);
+    qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
+    if (qh->IStracing >= 4  && qh->num_facets < 1000) {
+      qh_printlists(qh);
+      qh_checkpolygon(qh, qh->facet_list);
+    }
+  }
+} /* all_vertexmerges */
+
+/*---------------------------------
+
+  qh_appendmergeset(qh, facet, vertex, neighbor, mergetype, dist, angle )
+    appends an entry to qh.facet_mergeset or qh.degen_mergeset
+    if 'dist' is unknown, set it to 0.0
+        if 'angle' is unknown, set it to 1.0 (coplanar)
+
+  returns:
+    merge appended to facet_mergeset or degen_mergeset
+      sets ->degenerate or ->redundant if degen_mergeset
+
+  notes:
+    caller collects statistics and/or caller of qh_mergefacet
+    see: qh_test_appendmerge()
+
+  design:
+    allocate merge entry
+    if regular merge
+      append to qh.facet_mergeset
+    else if degenerate merge and qh.facet_mergeset is all degenerate
+      append to qh.degen_mergeset
+    else if degenerate merge
+      prepend to qh.degen_mergeset (merged last)
+    else if redundant merge
+      append to qh.degen_mergeset
+*/
+void qh_appendmergeset(qhT *qh, facetT *facet, facetT *neighbor, mergeType mergetype, coordT dist, realT angle) {
+  mergeT *merge, *lastmerge;
+  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
+  const char *mergename;
+
+  if ((facet->redundant && mergetype != MRGmirror) || neighbor->redundant) {
+    trace3((qh, qh->ferr, 3051, "qh_appendmergeset: f%d is already redundant (%d) or f%d is already redundant (%d).  Ignore merge f%d and f%d type %d\n",
+      facet->id, facet->redundant, neighbor->id, neighbor->redundant, facet->id, neighbor->id, mergetype));
+    return;
+  }
+  if (facet->degenerate && mergetype == MRGdegen) {
+    trace3((qh, qh->ferr, 3077, "qh_appendmergeset: f%d is already degenerate.  Ignore merge f%d type %d (MRGdegen)\n",
+      facet->id, facet->id, mergetype));
+    return;
+  }
+  if (!qh->facet_mergeset || !qh->degen_mergeset) {
+    qh_fprintf(qh, qh->ferr, 6403, "qhull internal error (qh_appendmergeset): expecting temp set defined for qh.facet_mergeset (%p) and qh.degen_mergeset (%p).  Got NULL\n",
+      (void *) qh->facet_mergeset, (void *) qh->degen_mergeset);
+    /* otherwise qh_setappend creates a new set that is not freed by qh_freebuild() */
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  if (neighbor->flipped && !facet->flipped) {
+    if (mergetype != MRGdupridge) {
+      qh_fprintf(qh, qh->ferr, 6355, "qhull internal error (qh_appendmergeset): except for MRGdupridge, cannot merge a non-flipped facet f%d into flipped f%d, mergetype %d, dist %4.4g\n",
+        facet->id, neighbor->id, mergetype, dist);
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }else {
+      trace2((qh, qh->ferr, 2106, "qh_appendmergeset: dupridge will merge a non-flipped facet f%d into flipped f%d, dist %4.4g\n",
+        facet->id, neighbor->id, dist));
+    }
+  }
+  qh_memalloc_(qh, (int)sizeof(mergeT), freelistp, merge, mergeT);
+  merge->angle= angle;
+  merge->distance= dist;
+  merge->facet1= facet;
+  merge->facet2= neighbor;
+  merge->vertex1= NULL;
+  merge->vertex2= NULL;
+  merge->ridge1= NULL;
+  merge->ridge2= NULL;
+  merge->mergetype= mergetype;
+  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
+    mergename= mergetypes[mergetype];
+  else
+    mergename= mergetypes[MRGnone];
+  if (mergetype < MRGdegen)
+    qh_setappend(qh, &(qh->facet_mergeset), merge);
+  else if (mergetype == MRGdegen) {
+    facet->degenerate= True;
+    if (!(lastmerge= (mergeT *)qh_setlast(qh->degen_mergeset))
+    || lastmerge->mergetype == MRGdegen)
+      qh_setappend(qh, &(qh->degen_mergeset), merge);
+    else
+      qh_setaddnth(qh, &(qh->degen_mergeset), 0, merge);    /* merged last */
+  }else if (mergetype == MRGredundant) {
+    facet->redundant= True;
+    qh_setappend(qh, &(qh->degen_mergeset), merge);
+  }else /* mergetype == MRGmirror */ {
+    if (facet->redundant || neighbor->redundant) {
+      qh_fprintf(qh, qh->ferr, 6092, "qhull internal error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet (i.e., 'redundant')\n",
+           facet->id, neighbor->id);
+      qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
+    }
+    if (!qh_setequal(facet->vertices, neighbor->vertices)) {
+      qh_fprintf(qh, qh->ferr, 6093, "qhull internal error (qh_appendmergeset): mirrored facets f%d and f%d do not have the same vertices\n",
+           facet->id, neighbor->id);
+      qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
+    }
+    facet->redundant= True;
+    neighbor->redundant= True;
+    qh_setappend(qh, &(qh->degen_mergeset), merge);
+  }
+  if (merge->mergetype >= MRGdegen) {
+    trace3((qh, qh->ferr, 3044, "qh_appendmergeset: append merge f%d and f%d type %d (%s) to qh.degen_mergeset (size %d)\n",
+      merge->facet1->id, merge->facet2->id, merge->mergetype, mergename, qh_setsize(qh, qh->degen_mergeset)));
+  }else {
+    trace3((qh, qh->ferr, 3027, "qh_appendmergeset: append merge f%d and f%d type %d (%s) dist %2.2g angle %4.4g to qh.facet_mergeset (size %d)\n",
+      merge->facet1->id, merge->facet2->id, merge->mergetype, mergename, merge->distance, merge->angle, qh_setsize(qh, qh->facet_mergeset)));
+  }
+} /* appendmergeset */
+
+
+/*---------------------------------
+
+  qh_appendvertexmerge(qh, vertex, vertex2, mergetype, distance, ridge1, ridge2 )
+    appends a vertex merge to qh.vertex_mergeset
+    MRGsubridge includes two ridges (from MRGdupridge)
+    MRGvertices includes two ridges
+
+  notes:
+    called by qh_getpinchedmerges for MRGsubridge
+    called by qh_maybe_duplicateridge and qh_maybe_duplicateridges for MRGvertices
+    only way to add a vertex merge to qh.vertex_mergeset
+    checked by qh_next_vertexmerge
+*/
+void qh_appendvertexmerge(qhT *qh, vertexT *vertex, vertexT *destination, mergeType mergetype, realT distance, ridgeT *ridge1, ridgeT *ridge2) {
+  mergeT *merge;
+  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
+  const char *mergename;
+
+  if (!qh->vertex_mergeset) {
+    qh_fprintf(qh, qh->ferr, 6387, "qhull internal error (qh_appendvertexmerge): expecting temp set defined for qh.vertex_mergeset.  Got NULL\n");
+    /* otherwise qh_setappend creates a new set that is not freed by qh_freebuild() */
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh_memalloc_(qh, (int)sizeof(mergeT), freelistp, merge, mergeT);
+  merge->angle= qh_ANGLEnone;
+  merge->distance= distance;
+  merge->facet1= NULL;
+  merge->facet2= NULL;
+  merge->vertex1= vertex;
+  merge->vertex2= destination;
+  merge->ridge1= ridge1;
+  merge->ridge2= ridge2;
+  merge->mergetype= mergetype;
+  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
+    mergename= mergetypes[mergetype];
+  else
+    mergename= mergetypes[MRGnone];
+  if (mergetype == MRGvertices) {
+    if (!ridge1 || !ridge2 || ridge1 == ridge2) {
+      qh_fprintf(qh, qh->ferr, 6106, "qhull internal error (qh_appendvertexmerge): expecting two distinct ridges for MRGvertices.  Got r%d r%d\n",
+        getid_(ridge1), getid_(ridge2));
+      qh_errexit(qh, qh_ERRqhull, NULL, ridge1);
+    }
+  }
+  qh_setappend(qh, &(qh->vertex_mergeset), merge);
+  trace3((qh, qh->ferr, 3034, "qh_appendvertexmerge: append merge v%d into v%d r%d r%d dist %2.2g type %d (%s)\n",
+    vertex->id, destination->id, getid_(ridge1), getid_(ridge2), distance, merge->mergetype, mergename));
+} /* appendvertexmerge */
+
+
+/*---------------------------------
+
+  qh_basevertices(qh, samecycle )
+    return temporary set of base vertices for samecycle
+    samecycle is first facet in the cycle
+    assumes apex is SETfirst_( samecycle->vertices )
+
+  returns:
+    vertices(settemp)
+    all ->seen are cleared
+
+  notes:
+    uses qh_vertex_visit;
+
+  design:
+    for each facet in samecycle
+      for each unseen vertex in facet->vertices
+        append to result
+*/
+setT *qh_basevertices(qhT *qh, facetT *samecycle) {
+  facetT *same;
+  vertexT *apex, *vertex, **vertexp;
+  setT *vertices= qh_settemp(qh, qh->TEMPsize);
+
+  apex= SETfirstt_(samecycle->vertices, vertexT);
+  apex->visitid= ++qh->vertex_visit;
+  FORALLsame_cycle_(samecycle) {
+    if (same->mergeridge)
+      continue;
+    FOREACHvertex_(same->vertices) {
+      if (vertex->visitid != qh->vertex_visit) {
+        qh_setappend(qh, &vertices, vertex);
+        vertex->visitid= qh->vertex_visit;
+        vertex->seen= False;
+      }
+    }
+  }
+  trace4((qh, qh->ferr, 4019, "qh_basevertices: found %d vertices\n",
+         qh_setsize(qh, vertices)));
+  return vertices;
+} /* basevertices */
+
+/*---------------------------------
+
+  qh_check_dupridge(qh, facet1, dist1, facet2, dist2 )
+    Check dupridge between facet1 and facet2 for wide merge
+    dist1 is the maximum distance of facet1's vertices to facet2
+    dist2 is the maximum distance of facet2's vertices to facet1
+
+  returns
+    Level 1 log of the dupridge with the minimum distance between vertices
+    Throws error if the merge will increase the maximum facet width by qh_WIDEduplicate (100x)
+
+  notes:
+    only called from qh_forcedmerges
+*/
+void qh_check_dupridge(qhT *qh, facetT *facet1, realT dist1, facetT *facet2, realT dist2) {
+  vertexT *vertex, **vertexp, *vertexA, **vertexAp;
+  realT dist, innerplane, mergedist, outerplane, prevdist, ratio, vertexratio;
+  realT minvertex= REALmax;
+
+  mergedist= fmin_(dist1, dist2);
+  qh_outerinner(qh, NULL, &outerplane, &innerplane);  /* ratio from qh_printsummary */
+  FOREACHvertex_(facet1->vertices) {     /* The dupridge is between facet1 and facet2, so either facet can be tested */
+    FOREACHvertexA_(facet1->vertices) {
+      if (vertex > vertexA){   /* Test each pair once */
+        dist= qh_pointdist(vertex->point, vertexA->point, qh->hull_dim);
+        minimize_(minvertex, dist);
+        /* Not quite correct.  A facet may have a dupridge and another pair of nearly adjacent vertices. */
+      }
+    }
+  }
+  prevdist= fmax_(outerplane, innerplane);
+  maximize_(prevdist, qh->ONEmerge + qh->DISTround);
+  maximize_(prevdist, qh->MINoutside + qh->DISTround);
+  ratio= mergedist/prevdist;
+  vertexratio= minvertex/prevdist;
+  trace0((qh, qh->ferr, 16, "qh_check_dupridge: dupridge between f%d and f%d (vertex dist %2.2g), dist %2.2g, reverse dist %2.2g, ratio %2.2g while processing p%d\n",
+        facet1->id, facet2->id, minvertex, dist1, dist2, ratio, qh->furthest_id));
+  if (ratio > qh_WIDEduplicate) {
+    qh_fprintf(qh, qh->ferr, 6271, "qhull topology error (qh_check_dupridge): wide merge (%.1fx wider) due to dupridge between f%d and f%d (vertex dist %2.2g), merge dist %2.2g, while processing p%d\n- Allow error with option 'Q12'\n",
+      ratio, facet1->id, facet2->id, minvertex, mergedist, qh->furthest_id);
+    if (vertexratio < qh_WIDEpinched)
+      qh_fprintf(qh, qh->ferr, 8145, "- Experimental option merge-pinched-vertices ('Q14') may avoid this error.  It merges nearly adjacent vertices.\n");
+    if (qh->DELAUNAY)
+      qh_fprintf(qh, qh->ferr, 8145, "- A bounding box for the input sites may alleviate this error.\n");
+    if (!qh->ALLOWwide)
+      qh_errexit2(qh, qh_ERRwide, facet1, facet2);
+  }
+} /* check_dupridge */
+
+/*---------------------------------
+
+  qh_checkconnect(qh)
+    check that new facets are connected
+    new facets are on qh.newfacet_list
+
+  notes:
+    this is slow and it changes the order of the facets
+    uses qh.visit_id
+
+  design:
+    move first new facet to end of qh.facet_list
+    for all newly appended facets
+      append unvisited neighbors to end of qh.facet_list
+    for all new facets
+      report error if unvisited
+*/
+void qh_checkconnect(qhT *qh /* qh.newfacet_list */) {
+  facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;
+
+  facet= qh->newfacet_list;
+  qh_removefacet(qh, facet);
+  qh_appendfacet(qh, facet);
+  facet->visitid= ++qh->visit_id;
+  FORALLfacet_(facet) {
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh->visit_id) {
+        qh_removefacet(qh, neighbor);
+        qh_appendfacet(qh, neighbor);
+        neighbor->visitid= qh->visit_id;
+      }
+    }
+  }
+  FORALLnew_facets {
+    if (newfacet->visitid == qh->visit_id)
+      break;
+    qh_fprintf(qh, qh->ferr, 6094, "qhull internal error (qh_checkconnect): f%d is not attached to the new facets\n",
+         newfacet->id);
+    errfacet= newfacet;
+  }
+  if (errfacet)
+    qh_errexit(qh, qh_ERRqhull, errfacet, NULL);
+} /* checkconnect */
+
+/*---------------------------------
+
+  qh_checkdelfacet(qh, facet, mergeset )
+    check that mergeset does not reference facet
+
+*/
+void qh_checkdelfacet(qhT *qh, facetT *facet, setT *mergeset) {
+  mergeT *merge, **mergep;
+
+  FOREACHmerge_(mergeset) {
+    if (merge->facet1 == facet || merge->facet2 == facet) {
+      qh_fprintf(qh, qh->ferr, 6390, "qhull internal error (qh_checkdelfacet): cannot delete f%d.  It is referenced by merge f%d f%d mergetype %d\n",
+        facet->id, merge->facet1->id, getid_(merge->facet2), merge->mergetype);
+      qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
+    }
+  }
+} /* checkdelfacet */
+
+/*---------------------------------
+
+  qh_checkdelridge(qh)
+    check that qh_delridge_merge is not needed for deleted ridges
+
+    notes:
+      called from qh_mergecycle, qh_makenewfacets, qh_attachnewfacets
+      errors if qh.vertex_mergeset is non-empty
+      errors if any visible or new facet has a ridge with r.nonconvex set
+      assumes that vertex.delfacet is not needed
+*/
+void qh_checkdelridge(qhT *qh /* qh.visible_facets, vertex_mergeset */) {
+  facetT *newfacet, *visible;
+  ridgeT *ridge, **ridgep;
+
+  if (!SETempty_(qh->vertex_mergeset)) {
+    qh_fprintf(qh, qh->ferr, 6382, "qhull internal error (qh_checkdelridge): expecting empty qh.vertex_mergeset in order to avoid calling qh_delridge_merge.  Got %d merges\n", qh_setsize(qh, qh->vertex_mergeset));
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+
+  FORALLnew_facets {
+    FOREACHridge_(newfacet->ridges) {
+      if (ridge->nonconvex) {
+        qh_fprintf(qh, qh->ferr, 6313, "qhull internal error (qh_checkdelridge): unexpected 'nonconvex' flag for ridge r%d in newfacet f%d.  Otherwise need to call qh_delridge_merge\n",
+           ridge->id, newfacet->id);
+        qh_errexit(qh, qh_ERRqhull, newfacet, ridge);
+      }
+    }
+  }
+
+  FORALLvisible_facets {
+    FOREACHridge_(visible->ridges) {
+      if (ridge->nonconvex) {
+        qh_fprintf(qh, qh->ferr, 6385, "qhull internal error (qh_checkdelridge): unexpected 'nonconvex' flag for ridge r%d in visible facet f%d.  Otherwise need to call qh_delridge_merge\n",
+          ridge->id, visible->id);
+        qh_errexit(qh, qh_ERRqhull, visible, ridge);
+      }
+    }
+  }
+} /* checkdelridge */
+
+
+/*---------------------------------
+
+  qh_checkzero(qh, testall )
+    check that facets are clearly convex for qh.DISTround with qh.MERGEexact
+
+    if testall,
+      test all facets for qh.MERGEexact post-merging
+    else
+      test qh.newfacet_list
+
+    if qh.MERGEexact,
+      allows coplanar ridges
+      skips convexity test while qh.ZEROall_ok
+
+  returns:
+    True if all facets !flipped, !dupridge, normal
+         if all horizon facets are simplicial
+         if all vertices are clearly below neighbor
+         if all opposite vertices of horizon are below
+    clears qh.ZEROall_ok if any problems or coplanar facets
+
+  notes:
+    called by qh_premerge (qh.CHECKzero, 'C-0') and qh_qhull ('Qx')
+    uses qh.vertex_visit
+    horizon facets may define multiple new facets
+
+  design:
+    for all facets in qh.newfacet_list or qh.facet_list
+      check for flagged faults (flipped, etc.)
+    for all facets in qh.newfacet_list or qh.facet_list
+      for each neighbor of facet
+        skip horizon facets for qh.newfacet_list
+        test the opposite vertex
+      if qh.newfacet_list
+        test the other vertices in the facet's horizon facet
+*/
+boolT qh_checkzero(qhT *qh, boolT testall) {
+  facetT *facet, *neighbor;
+  facetT *horizon, *facetlist;
+  int neighbor_i, neighbor_n;
+  vertexT *vertex, **vertexp;
+  realT dist;
+
+  if (testall)
+    facetlist= qh->facet_list;
+  else {
+    facetlist= qh->newfacet_list;
+    FORALLfacet_(facetlist) {
+      horizon= SETfirstt_(facet->neighbors, facetT);
+      if (!horizon->simplicial)
+        goto LABELproblem;
+      if (facet->flipped || facet->dupridge || !facet->normal)
+        goto LABELproblem;
+    }
+    if (qh->MERGEexact && qh->ZEROall_ok) {
+      trace2((qh, qh->ferr, 2011, "qh_checkzero: skip convexity check until first pre-merge\n"));
+      return True;
+    }
+  }
+  FORALLfacet_(facetlist) {
+    qh->vertex_visit++;
+    horizon= NULL;
+    FOREACHneighbor_i_(qh, facet) {
+      if (!neighbor_i && !testall) {
+        horizon= neighbor;
+        continue; /* horizon facet tested in qh_findhorizon */
+      }
+      vertex= SETelemt_(facet->vertices, neighbor_i, vertexT);
+      vertex->visitid= qh->vertex_visit;
+      zzinc_(Zdistzero);
+      qh_distplane(qh, vertex->point, neighbor, &dist);
+      if (dist >= -2 * qh->DISTround) {  /* need 2x for qh_distround and 'Rn' for qh_checkconvex, same as qh.premerge_centrum */
+        qh->ZEROall_ok= False;
+        if (!qh->MERGEexact || testall || dist > qh->DISTround)
+          goto LABELnonconvex;
+      }
+    }
+    if (!testall && horizon) {
+      FOREACHvertex_(horizon->vertices) {
+        if (vertex->visitid != qh->vertex_visit) {
+          zzinc_(Zdistzero);
+          qh_distplane(qh, vertex->point, facet, &dist);
+          if (dist >= -2 * qh->DISTround) {
+            qh->ZEROall_ok= False;
+            if (!qh->MERGEexact || dist > qh->DISTround)
+              goto LABELnonconvexhorizon;
+          }
+          break;
+        }
+      }
+    }
+  }
+  trace2((qh, qh->ferr, 2012, "qh_checkzero: testall %d, facets are %s\n", testall,
+        (qh->MERGEexact && !testall) ?
+           "not concave, flipped, or dupridge" : "clearly convex"));
+  return True;
+
+ LABELproblem:
+  qh->ZEROall_ok= False;
+  trace2((qh, qh->ferr, 2013, "qh_checkzero: qh_premerge is needed.  New facet f%d or its horizon f%d is non-simplicial, flipped, dupridge, or mergehorizon\n",
+       facet->id, horizon->id));
+  return False;
+
+ LABELnonconvex:
+  trace2((qh, qh->ferr, 2014, "qh_checkzero: facet f%d and f%d are not clearly convex.  v%d dist %.2g\n",
+         facet->id, neighbor->id, vertex->id, dist));
+  return False;
+
+ LABELnonconvexhorizon:
+  trace2((qh, qh->ferr, 2060, "qh_checkzero: facet f%d and horizon f%d are not clearly convex.  v%d dist %.2g\n",
+      facet->id, horizon->id, vertex->id, dist));
+  return False;
+} /* checkzero */
+
+/*---------------------------------
+
+  qh_compare_anglemerge( mergeA, mergeB )
+    used by qsort() to order qh.facet_mergeset by mergetype and angle (qh.ANGLEmerge, 'Q1')
+    lower numbered mergetypes done first (MRGcoplanar before MRGconcave)
+
+  notes:
+    qh_all_merges processes qh.facet_mergeset by qh_setdellast
+    [mar'19] evaluated various options with eg/q_benchmark and merging of pinched vertices (Q14)
+*/
+int qh_compare_anglemerge(const void *p1, const void *p2) {
+  const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);
+
+  if (a->mergetype != b->mergetype)
+    return (a->mergetype < b->mergetype ? 1 : -1); /* select MRGcoplanar (1) before MRGconcave (3) */
+  else
+    return (a->angle > b->angle ? 1 : -1);         /* select coplanar merge (1.0) before sharp merge (-0.5) */
+} /* compare_anglemerge */
+
+/*---------------------------------
+
+  qh_compare_facetmerge( mergeA, mergeB )
+    used by qsort() to order merges by mergetype, first merge, first
+    lower numbered mergetypes done first (MRGcoplanar before MRGconcave)
+    if same merge type, flat merges are first
+
+  notes:
+    qh_all_merges processes qh.facet_mergeset by qh_setdellast
+    [mar'19] evaluated various options with eg/q_benchmark and merging of pinched vertices (Q14)
+*/
+int qh_compare_facetmerge(const void *p1, const void *p2) {
+  const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);
+
+  if (a->mergetype != b->mergetype)
+    return (a->mergetype < b->mergetype ? 1 : -1); /* select MRGcoplanar (1) before MRGconcave (3) */
+  else if (a->mergetype == MRGanglecoplanar)
+    return (a->angle > b->angle ? 1 : -1);         /* if MRGanglecoplanar, select coplanar merge (1.0) before sharp merge (-0.5) */
+  else
+    return (a->distance < b->distance ? 1 : -1);   /* select flat (0.0) merge before wide (1e-10) merge */
+} /* compare_facetmerge */
+
+/*---------------------------------
+
+  qh_comparevisit( vertexA, vertexB )
+    used by qsort() to order vertices by their visitid
+
+  notes:
+    only called by qh_find_newvertex
+*/
+int qh_comparevisit(const void *p1, const void *p2) {
+  const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);
+
+  if (a->visitid > b->visitid)
+    return 1;
+  return -1;
+} /* comparevisit */
+
+/*---------------------------------
+
+  qh_copynonconvex(qh, atridge )
+    set non-convex flag on other ridges (if any) between same neighbors
+
+  notes:
+    may be faster if use smaller ridge set
+
+  design:
+    for each ridge of atridge's top facet
+      if ridge shares the same neighbor
+        set nonconvex flag
+*/
+void qh_copynonconvex(qhT *qh, ridgeT *atridge) {
+  facetT *facet, *otherfacet;
+  ridgeT *ridge, **ridgep;
+
+  facet= atridge->top;
+  otherfacet= atridge->bottom;
+  atridge->nonconvex= False;
+  FOREACHridge_(facet->ridges) {
+    if (otherfacet == ridge->top || otherfacet == ridge->bottom) {
+      if (ridge != atridge) {
+        ridge->nonconvex= True;
+        trace4((qh, qh->ferr, 4020, "qh_copynonconvex: moved nonconvex flag from r%d to r%d between f%d and f%d\n",
+                atridge->id, ridge->id, facet->id, otherfacet->id));
+        break;
+      }
+    }
+  }
+} /* copynonconvex */
+
+/*---------------------------------
+
+  qh_degen_redundant_facet(qh, facet )
+    check for a degenerate (too few neighbors) or redundant (subset of vertices) facet
+
+  notes:
+    called at end of qh_mergefacet, qh_renamevertex, and qh_reducevertices
+    bumps vertex_visit
+    called if a facet was redundant but no longer is (qh_merge_degenredundant)
+    qh_appendmergeset() only appends first reference to facet (i.e., redundant)
+    see: qh_test_redundant_neighbors, qh_maydropneighbor
+
+  design:
+    test for redundant neighbor
+    test for degenerate facet
+*/
+void qh_degen_redundant_facet(qhT *qh, facetT *facet) {
+  vertexT *vertex, **vertexp;
+  facetT *neighbor, **neighborp;
+
+  trace3((qh, qh->ferr, 3028, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",
+          facet->id));
+  if (facet->flipped) {
+    trace2((qh, qh->ferr, 3074, "qh_degen_redundant_facet: f%d is flipped, will merge later\n", facet->id));
+    return;
+  }
+  FOREACHneighbor_(facet) {
+    if (neighbor->flipped) /* disallow merge of non-flipped into flipped, neighbor will be merged later */
+      continue;
+    if (neighbor->visible) {
+      qh_fprintf(qh, qh->ferr, 6357, "qhull internal error (qh_degen_redundant_facet): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
+        facet->id, neighbor->id);
+      qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
+    }
+    qh->vertex_visit++;
+    FOREACHvertex_(neighbor->vertices)
+      vertex->visitid= qh->vertex_visit;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh->vertex_visit)
+        break;
+    }
+    if (!vertex) {
+      trace2((qh, qh->ferr, 2015, "qh_degen_redundant_facet: f%d is contained in f%d.  merge\n", facet->id, neighbor->id));
+      qh_appendmergeset(qh, facet, neighbor, MRGredundant, 0.0, 1.0);
+      return;
+    }
+  }
+  if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {
+    qh_appendmergeset(qh, facet, facet, MRGdegen, 0.0, 1.0);
+    trace2((qh, qh->ferr, 2016, "qh_degen_redundant_facet: f%d is degenerate.\n", facet->id));
+  }
+} /* degen_redundant_facet */
+
+
+/*---------------------------------
+
+  qh_delridge_merge(qh, ridge )
+    delete ridge due to a merge
+
+  notes:
+    only called by merge_r.c (qh_mergeridges, qh_renameridgevertex)
+    ridges also freed in qh_freeqhull and qh_mergecycle_ridges
+
+  design:
+    if needed, moves ridge.nonconvex to another ridge
+    sets vertex.delridge for qh_reducevertices
+    deletes ridge from qh.vertex_mergeset
+    deletes ridge from its neighboring facets
+    frees up its memory
+*/
+void qh_delridge_merge(qhT *qh, ridgeT *ridge) {
+  vertexT *vertex, **vertexp;
+  mergeT *merge;
+  int merge_i, merge_n;
+
+  trace3((qh, qh->ferr, 3036, "qh_delridge_merge: delete ridge r%d between f%d and f%d\n",
+    ridge->id, ridge->top->id, ridge->bottom->id));
+  if (ridge->nonconvex)
+    qh_copynonconvex(qh, ridge);
+  FOREACHvertex_(ridge->vertices)
+    vertex->delridge= True;
+  FOREACHmerge_i_(qh, qh->vertex_mergeset) {
+    if (merge->ridge1 == ridge || merge->ridge2 == ridge) {
+      trace3((qh, qh->ferr, 3029, "qh_delridge_merge: drop merge of v%d into v%d (dist %2.2g r%d r%d) due to deleted, duplicated ridge r%d\n",
+        merge->vertex1->id, merge->vertex2->id, merge->distance, merge->ridge1->id, merge->ridge2->id, ridge->id));
+      if (merge->ridge1 == ridge)
+        merge->ridge2->mergevertex= False;
+      else
+        merge->ridge1->mergevertex= False;
+      qh_setdelnth(qh, qh->vertex_mergeset, merge_i);
+      merge_i--; merge_n--; /* next merge after deleted */
+    }
+  }
+  qh_setdel(ridge->top->ridges, ridge);
+  qh_setdel(ridge->bottom->ridges, ridge);
+  qh_delridge(qh, ridge);
+} /* delridge_merge */
+
+
+/*---------------------------------
+
+  qh_drop_mergevertex(qh, merge )
+
+  clear mergevertex flags for ridges of a vertex merge
+*/
+void qh_drop_mergevertex(qhT *qh, mergeT *merge)
+{
+  if (merge->mergetype == MRGvertices) {
+    merge->ridge1->mergevertex= False;
+    merge->ridge1->mergevertex2= True;
+    merge->ridge2->mergevertex= False;
+    merge->ridge2->mergevertex2= True;
+    trace3((qh, qh->ferr, 3032, "qh_drop_mergevertex: unset mergevertex for r%d and r%d due to dropped vertex merge v%d to v%d.  Sets mergevertex2\n",
+      merge->ridge1->id, merge->ridge2->id, merge->vertex1->id, merge->vertex2->id));
+  }
+} /* drop_mergevertex */
+
+/*---------------------------------
+
+  qh_find_newvertex(qh, oldvertex, vertices, ridges )
+    locate new vertex for renaming old vertex
+    vertices is a set of possible new vertices
+      vertices sorted by number of deleted ridges
+
+  returns:
+    newvertex or NULL
+      each ridge includes both newvertex and oldvertex
+    vertices without oldvertex sorted by number of deleted ridges
+    qh.vertex_visit updated
+    sets v.seen
+
+  notes:
+    called by qh_redundant_vertex due to vertex->delridge and qh_rename_sharedvertex
+    sets vertex->visitid to 0..setsize() for vertices
+    new vertex is in one of the ridges
+    renaming will not cause a duplicate ridge
+    renaming will minimize the number of deleted ridges
+    newvertex may not be adjacent in the dual (though unlikely)
+
+  design:
+    for each vertex in vertices
+      set vertex->visitid to number of ridges
+    remove unvisited vertices
+    set qh.vertex_visit above all possible values
+    sort vertices by number of ridges (minimize ridges that need renaming
+    add each ridge to qh.hash_table
+    for each vertex in vertices
+      find the first vertex that would not cause a duplicate ridge after a rename
+*/
+vertexT *qh_find_newvertex(qhT *qh, vertexT *oldvertex, setT *vertices, setT *ridges) {
+  vertexT *vertex, **vertexp;
+  setT *newridges;
+  ridgeT *ridge, **ridgep;
+  int size, hashsize;
+  int hash;
+  unsigned int maxvisit;
+
+#ifndef qh_NOtrace
+  if (qh->IStracing >= 4) {
+    qh_fprintf(qh, qh->ferr, 8063, "qh_find_newvertex: find new vertex for v%d from ",
+             oldvertex->id);
+    FOREACHvertex_(vertices)
+      qh_fprintf(qh, qh->ferr, 8064, "v%d ", vertex->id);
+    FOREACHridge_(ridges)
+      qh_fprintf(qh, qh->ferr, 8065, "r%d ", ridge->id);
+    qh_fprintf(qh, qh->ferr, 8066, "\n");
+  }
+#endif
+  FOREACHridge_(ridges) {
+    FOREACHvertex_(ridge->vertices)
+      vertex->seen= False;
+  }
+  FOREACHvertex_(vertices) {
+    vertex->visitid= 0;  /* v.visitid will be number of ridges */
+    vertex->seen= True;
+  }
+  FOREACHridge_(ridges) {
+    FOREACHvertex_(ridge->vertices) {
+      if (vertex->seen)
+        vertex->visitid++;
+    }
+  }
+  FOREACHvertex_(vertices) {
+    if (!vertex->visitid) {
+      qh_setdelnth(qh, vertices, SETindex_(vertices,vertex));
+      vertexp--; /* repeat since deleted this vertex */
+    }
+  }
+  maxvisit= (unsigned int)qh_setsize(qh, ridges);
+  maximize_(qh->vertex_visit, maxvisit);
+  if (!qh_setsize(qh, vertices)) {
+    trace4((qh, qh->ferr, 4023, "qh_find_newvertex: vertices not in ridges for v%d\n",
+            oldvertex->id));
+    return NULL;
+  }
+  qsort(SETaddr_(vertices, vertexT), (size_t)qh_setsize(qh, vertices),
+                sizeof(vertexT *), qh_comparevisit);
+  /* can now use qh->vertex_visit */
+  if (qh->PRINTstatistics) {
+    size= qh_setsize(qh, vertices);
+    zinc_(Zintersect);
+    zadd_(Zintersecttot, size);
+    zmax_(Zintersectmax, size);
+  }
+  hashsize= qh_newhashtable(qh, qh_setsize(qh, ridges));
+  FOREACHridge_(ridges)
+    qh_hashridge(qh, qh->hash_table, hashsize, ridge, oldvertex);
+  FOREACHvertex_(vertices) {
+    newridges= qh_vertexridges(qh, vertex, !qh_ALL);
+    FOREACHridge_(newridges) {
+      if (qh_hashridge_find(qh, qh->hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {
+        zinc_(Zvertexridge);
+        break;
+      }
+    }
+    qh_settempfree(qh, &newridges);
+    if (!ridge)
+      break;  /* found a rename */
+  }
+  if (vertex) {
+    /* counted in qh_renamevertex */
+    trace2((qh, qh->ferr, 2020, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",
+      vertex->id, oldvertex->id, qh_setsize(qh, vertices), qh_setsize(qh, ridges)));
+  }else {
+    zinc_(Zfindfail);
+    trace0((qh, qh->ferr, 14, "qh_find_newvertex: no vertex for renaming v%d (all duplicated ridges) during p%d\n",
+      oldvertex->id, qh->furthest_id));
+  }
+  qh_setfree(qh, &qh->hash_table);
+  return vertex;
+} /* find_newvertex */
+
+/*---------------------------------
+
+  qh_findbest_pinchedvertex(qh, merge, apex, nearestp, distp )
+    Determine the best pinched vertex to rename as its nearest neighboring vertex
+    Renaming will remove a duplicate MRGdupridge in newfacet_list
+
+  returns:
+    pinched vertex (either apex or subridge), nearest vertex (subridge or neighbor vertex), and the distance between them
+
+  notes:
+    only called by qh_getpinchedmerges
+    assumes qh.VERTEXneighbors
+    see qh_findbest_ridgevertex
+
+  design:
+    if the facets have the same vertices
+      return the nearest vertex pair
+    else
+      the subridge is the intersection of the two new facets minus the apex
+      the subridge consists of qh.hull_dim-2 horizon vertices
+      the subridge is also a matched ridge for the new facets (its duplicate)
+      determine the nearest vertex to the apex
+      determine the nearest pair of subridge vertices
+      for each vertex in the subridge
+        determine the nearest neighbor vertex (not in the subridge)
+*/
+vertexT *qh_findbest_pinchedvertex(qhT *qh, mergeT *merge, vertexT *apex, vertexT **nearestp, coordT *distp /* qh.newfacet_list */) {
+  vertexT *vertex, **vertexp, *vertexA, **vertexAp;
+  vertexT *bestvertex= NULL, *bestpinched= NULL;
+  setT *subridge, *maybepinched;
+  coordT dist, bestdist= REALmax;
+  coordT pincheddist= (qh->ONEmerge+qh->DISTround)*qh_RATIOpinchedsubridge;
+
+  if (!merge->facet1->simplicial || !merge->facet2->simplicial) {
+    qh_fprintf(qh, qh->ferr, 6351, "qhull internal error (qh_findbest_pinchedvertex): expecting merge of adjacent, simplicial new facets.  f%d or f%d is not simplicial\n",
+      merge->facet1->id, merge->facet2->id);
+    qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
+  }
+  subridge= qh_vertexintersect_new(qh, merge->facet1->vertices, merge->facet2->vertices); /* new setT.  No error_exit() */
+  if (qh_setsize(qh, subridge) == qh->hull_dim) { /* duplicate vertices */
+    bestdist= qh_vertex_bestdist2(qh, subridge, &bestvertex, &bestpinched);
+    if(bestvertex == apex) {
+      bestvertex= bestpinched;
+      bestpinched= apex;
+    }
+  }else {
+    qh_setdel(subridge, apex);
+    if (qh_setsize(qh, subridge) != qh->hull_dim - 2) {
+      qh_fprintf(qh, qh->ferr, 6409, "qhull internal error (qh_findbest_pinchedvertex): expecting subridge of qh.hull_dim-2 vertices for the intersection of new facets f%d and f%d minus their apex.  Got %d vertices\n",
+          merge->facet1->id, merge->facet2->id, qh_setsize(qh, subridge));
+      qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
+    }
+    FOREACHvertex_(subridge) {
+      dist= qh_pointdist(vertex->point, apex->point, qh->hull_dim);
+      if (dist < bestdist) {
+        bestpinched= apex;
+        bestvertex= vertex;
+        bestdist= dist;
+      }
+    }
+    if (bestdist > pincheddist) {
+      FOREACHvertex_(subridge) {
+        FOREACHvertexA_(subridge) {
+          if (vertexA->id > vertex->id) { /* once per vertex pair, do not compare addresses */
+            dist= qh_pointdist(vertexA->point, vertex->point, qh->hull_dim);
+            if (dist < bestdist) {
+              bestpinched= vertexA;
+              bestvertex= vertex;
+              bestdist= dist;
+            }
+          }
+        }
+      }
+    }
+    if (bestdist > pincheddist) {
+      FOREACHvertexA_(subridge) {
+        maybepinched= qh_neighbor_vertices(qh, vertexA, subridge); /* subridge and apex tested above */
+        FOREACHvertex_(maybepinched) {
+          dist= qh_pointdist(vertex->point, vertexA->point, qh->hull_dim);
+          if (dist < bestdist) {
+            bestvertex= vertex;
+            bestpinched= vertexA;
+            bestdist= dist;
+          }
+        }
+        qh_settempfree(qh, &maybepinched);
+      }
+    }
+  }
+  *distp= bestdist;
+  qh_setfree(qh, &subridge); /* qh_err_exit not called since allocated */
+  if (!bestvertex) {  /* should never happen if qh.hull_dim > 2 */
+    qh_fprintf(qh, qh->ferr, 6274, "qhull internal error (qh_findbest_pinchedvertex): did not find best vertex for subridge of dupridge between f%d and f%d, while processing p%d\n", merge->facet1->id, merge->facet2->id, qh->furthest_id);
+    qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
+  }
+  *nearestp= bestvertex;
+  trace2((qh, qh->ferr, 2061, "qh_findbest_pinchedvertex: best pinched p%d(v%d) and vertex p%d(v%d) are closest (%2.2g) for duplicate subridge between f%d and f%d\n",
+      qh_pointid(qh, bestpinched->point), bestpinched->id, qh_pointid(qh, bestvertex->point), bestvertex->id, bestdist, merge->facet1->id, merge->facet2->id));
+  return bestpinched;
+} /* findbest_pinchedvertex */
+
+/*---------------------------------
+
+  qh_findbest_ridgevertex(qh, ridge, pinchedp, distp )
+    Determine the best vertex/pinched-vertex to merge for ridges with the same vertices
+
+  returns:
+    vertex, pinched vertex, and the distance between them
+
+  notes:
+    assumes qh.hull_dim>=3
+    see qh_findbest_pinchedvertex
+
+*/
+vertexT *qh_findbest_ridgevertex(qhT *qh, ridgeT *ridge, vertexT **pinchedp, coordT *distp) {
+  vertexT *bestvertex;
+
+  *distp= qh_vertex_bestdist2(qh, ridge->vertices, &bestvertex, pinchedp);
+  trace4((qh, qh->ferr, 4069, "qh_findbest_ridgevertex: best pinched p%d(v%d) and vertex p%d(v%d) are closest (%2.2g) for duplicated ridge r%d (same vertices) between f%d and f%d\n",
+      qh_pointid(qh, (*pinchedp)->point), (*pinchedp)->id, qh_pointid(qh, bestvertex->point), bestvertex->id, *distp, ridge->id, ridge->top->id, ridge->bottom->id));
+  return bestvertex;
+} /* findbest_ridgevertex */
+
+/*---------------------------------
+
+  qh_findbest_test(qh, testcentrum, facet, neighbor, &bestfacet, &dist, &mindist, &maxdist )
+    test neighbor of facet for qh_findbestneighbor()
+    if testcentrum,
+      tests centrum (assumes it is defined)
+    else
+      tests vertices
+    initially *bestfacet==NULL and *dist==REALmax
+
+  returns:
+    if a better facet (i.e., vertices/centrum of facet closer to neighbor)
+      updates bestfacet, dist, mindist, and maxdist
+
+  notes:
+    called by qh_findbestneighbor
+    ignores pairs of flipped facets, unless that's all there is
+*/
+void qh_findbest_test(qhT *qh, boolT testcentrum, facetT *facet, facetT *neighbor,
+      facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {
+  realT dist, mindist, maxdist;
+
+  if (facet->flipped && neighbor->flipped && *bestfacet && !(*bestfacet)->flipped)
+    return; /* do not merge flipped into flipped facets */
+  if (testcentrum) {
+    zzinc_(Zbestdist);
+    qh_distplane(qh, facet->center, neighbor, &dist);
+    dist *= qh->hull_dim; /* estimate furthest vertex */
+    if (dist < 0) {
+      maxdist= 0;
+      mindist= dist;
+      dist= -dist;
+    }else {
+      mindist= 0;
+      maxdist= dist;
+    }
+  }else
+    dist= qh_getdistance(qh, facet, neighbor, &mindist, &maxdist);
+  if (dist < *distp) {
+    *bestfacet= neighbor;
+    *mindistp= mindist;
+    *maxdistp= maxdist;
+    *distp= dist;
+  }
+} /* findbest_test */
+
+/*---------------------------------
+
+  qh_findbestneighbor(qh, facet, dist, mindist, maxdist )
+    finds best neighbor (least dist) of a facet for merging
+
+  returns:
+    returns min and max distances and their max absolute value
+
+  notes:
+    error if qh_ASvoronoi
+    avoids merging old into new
+    assumes ridge->nonconvex only set on one ridge between a pair of facets
+    could use an early out predicate but not worth it
+
+  design:
+    if a large facet
+      will test centrum
+    else
+      will test vertices
+    if a large facet
+      test nonconvex neighbors for best merge
+    else
+      test all neighbors for the best merge
+    if testing centrum
+      get distance information
+*/
+facetT *qh_findbestneighbor(qhT *qh, facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {
+  facetT *neighbor, **neighborp, *bestfacet= NULL;
+  ridgeT *ridge, **ridgep;
+  boolT nonconvex= True, testcentrum= False;
+  int size= qh_setsize(qh, facet->vertices);
+
+  if(qh->CENTERtype==qh_ASvoronoi){
+    qh_fprintf(qh, qh->ferr, 6272, "qhull internal error: cannot call qh_findbestneighor for f%d while qh.CENTERtype is qh_ASvoronoi\n", facet->id);
+    qh_errexit(qh, qh_ERRqhull, facet, NULL);
+  }
+  *distp= REALmax;
+  if (size > qh_BESTcentrum2 * qh->hull_dim + qh_BESTcentrum) {
+    testcentrum= True;
+    zinc_(Zbestcentrum);
+    if (!facet->center)
+       facet->center= qh_getcentrum(qh, facet);
+  }
+  if (size > qh->hull_dim + qh_BESTnonconvex) {
+    FOREACHridge_(facet->ridges) {
+      if (ridge->nonconvex) {
+        neighbor= otherfacet_(ridge, facet);
+        qh_findbest_test(qh, testcentrum, facet, neighbor,
+                          &bestfacet, distp, mindistp, maxdistp);
+      }
+    }
+  }
+  if (!bestfacet) {
+    nonconvex= False;
+    FOREACHneighbor_(facet)
+      qh_findbest_test(qh, testcentrum, facet, neighbor,
+                        &bestfacet, distp, mindistp, maxdistp);
+  }
+  if (!bestfacet) {
+    qh_fprintf(qh, qh->ferr, 6095, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);
+    qh_errexit(qh, qh_ERRqhull, facet, NULL);
+  }
+  if (testcentrum)
+    qh_getdistance(qh, facet, bestfacet, mindistp, maxdistp);
+  trace3((qh, qh->ferr, 3002, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",
+     bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));
+  return(bestfacet);
+} /* findbestneighbor */
+
+
+/*---------------------------------
+
+  qh_flippedmerges(qh, facetlist, wasmerge )
+    merge flipped facets into best neighbor
+    assumes qh.facet_mergeset at top of temporary stack
+
+  returns:
+    no flipped facets on facetlist
+    sets wasmerge if merge occurred
+    degen/redundant merges passed through
+
+  notes:
+    othermerges not needed since qh.facet_mergeset is empty before & after
+      keep it in case of change
+
+  design:
+    append flipped facets to qh.facetmergeset
+    for each flipped merge
+      find best neighbor
+      merge facet into neighbor
+      merge degenerate and redundant facets
+    remove flipped merges from qh.facet_mergeset
+*/
+void qh_flippedmerges(qhT *qh, facetT *facetlist, boolT *wasmerge) {
+  facetT *facet, *neighbor, *facet1;
+  realT dist, mindist, maxdist;
+  mergeT *merge, **mergep;
+  setT *othermerges;
+  int nummerge= 0, numdegen= 0;
+
+  trace4((qh, qh->ferr, 4024, "qh_flippedmerges: begin\n"));
+  FORALLfacet_(facetlist) {
+    if (facet->flipped && !facet->visible)
+      qh_appendmergeset(qh, facet, facet, MRGflip, 0.0, 1.0);
+  }
+  othermerges= qh_settemppop(qh);
+  if(othermerges != qh->facet_mergeset) {
+    qh_fprintf(qh, qh->ferr, 6392, "qhull internal error (qh_flippedmerges): facet_mergeset (%d merges) not at top of tempstack (%d merges)\n",
+        qh_setsize(qh, qh->facet_mergeset), qh_setsize(qh, othermerges));
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);
+  qh_settemppush(qh, othermerges);
+  FOREACHmerge_(othermerges) {
+    facet1= merge->facet1;
+    if (merge->mergetype != MRGflip || facet1->visible)
+      continue;
+    if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
+      qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
+    neighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
+    trace0((qh, qh->ferr, 15, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",
+      facet1->id, neighbor->id, dist, qh->furthest_id));
+    qh_mergefacet(qh, facet1, neighbor, merge->mergetype, &mindist, &maxdist, !qh_MERGEapex);
+    nummerge++;
+    if (qh->PRINTstatistics) {
+      zinc_(Zflipped);
+      wadd_(Wflippedtot, dist);
+      wmax_(Wflippedmax, dist);
+    }
+  }
+  FOREACHmerge_(othermerges) {
+    if (merge->facet1->visible || merge->facet2->visible)
+      qh_memfree(qh, merge, (int)sizeof(mergeT)); /* invalidates merge and othermerges */
+    else
+      qh_setappend(qh, &qh->facet_mergeset, merge);
+  }
+  qh_settempfree(qh, &othermerges);
+  numdegen += qh_merge_degenredundant(qh); /* somewhat better here than after each flipped merge -- qtest.sh 10 '500 C1,2e-13 D4' 'd Qbb' */
+  if (nummerge)
+    *wasmerge= True;
+  trace1((qh, qh->ferr, 1010, "qh_flippedmerges: merged %d flipped and %d degenredundant facets into a good neighbor\n",
+    nummerge, numdegen));
+} /* flippedmerges */
+
+
+/*---------------------------------
+
+  qh_forcedmerges(qh, wasmerge )
+    merge dupridges
+    calls qh_check_dupridge to report an error on wide merges
+    assumes qh_settemppop is qh.facet_mergeset
+
+  returns:
+    removes all dupridges on facet_mergeset
+    wasmerge set if merge
+    qh.facet_mergeset may include non-forced merges(none for now)
+    qh.degen_mergeset includes degen/redun merges
+
+  notes:
+    called by qh_premerge
+    dupridges occur when the horizon is pinched,
+        i.e. a subridge occurs in more than two horizon ridges.
+     could rename vertices that pinch the horizon
+    assumes qh_merge_degenredundant() has not be called
+    othermerges isn't needed since facet_mergeset is empty afterwards
+      keep it in case of change
+
+  design:
+    for each dupridge
+      find current facets by chasing f.replace links
+      check for wide merge due to dupridge
+      determine best direction for facet
+      merge one facet into the other
+      remove dupridges from qh.facet_mergeset
+*/
+void qh_forcedmerges(qhT *qh, boolT *wasmerge) {
+  facetT *facet1, *facet2, *merging, *merged, *newfacet;
+  mergeT *merge, **mergep;
+  realT dist, mindist, maxdist, dist2, mindist2, maxdist2;
+  setT *othermerges;
+  int nummerge=0, numflip=0, numdegen= 0;
+  boolT wasdupridge= False;
+
+  if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
+    qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
+  trace3((qh, qh->ferr, 3054, "qh_forcedmerges: merge dupridges\n"));
+  othermerges= qh_settemppop(qh); /* was facet_mergeset */
+  if (qh->facet_mergeset != othermerges ) {
+      qh_fprintf(qh, qh->ferr, 6279, "qhull internal error (qh_forcedmerges): qh_settemppop (size %d) is not qh->facet_mergeset (size %d)\n",
+          qh_setsize(qh, othermerges), qh_setsize(qh, qh->facet_mergeset));
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);
+  qh_settemppush(qh, othermerges);
+  FOREACHmerge_(othermerges) {
+    if (merge->mergetype != MRGdupridge)
+        continue;
+    wasdupridge= True;
+    if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
+        qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
+    facet1= qh_getreplacement(qh, merge->facet1);  /* must exist, no qh_merge_degenredunant */
+    facet2= qh_getreplacement(qh, merge->facet2);  /* previously merged facet, if any */
+    if (facet1 == facet2)
+      continue;
+    if (!qh_setin(facet2->neighbors, facet1)) {
+      qh_fprintf(qh, qh->ferr, 6096, "qhull internal error (qh_forcedmerges): f%d and f%d had a dupridge but as f%d and f%d they are no longer neighbors\n",
+               merge->facet1->id, merge->facet2->id, facet1->id, facet2->id);
+      qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
+    }
+    dist= qh_getdistance(qh, facet1, facet2, &mindist, &maxdist);
+    dist2= qh_getdistance(qh, facet2, facet1, &mindist2, &maxdist2);
+    qh_check_dupridge(qh, facet1, dist, facet2, dist2);
+    if (dist < dist2) {
+      if (facet2->flipped && !facet1->flipped && dist2 < qh_WIDEdupridge*(qh->ONEmerge+qh->DISTround)) { /* prefer merge of flipped facet */
+        merging= facet2;
+        merged= facet1;
+        dist= dist2;
+        mindist= mindist2;
+        maxdist= maxdist2;
+      }else {
+        merging= facet1;
+        merged= facet2;
+      }
+    }else {
+      if (facet1->flipped && !facet2->flipped && dist < qh_WIDEdupridge*(qh->ONEmerge+qh->DISTround)) { /* prefer merge of flipped facet */
+        merging= facet1;
+        merged= facet2;
+      }else {
+        merging= facet2;
+        merged= facet1;
+        dist= dist2;
+        mindist= mindist2;
+        maxdist= maxdist2;
+      }
+    }
+    qh_mergefacet(qh, merging, merged, merge->mergetype, &mindist, &maxdist, !qh_MERGEapex);
+    numdegen += qh_merge_degenredundant(qh); /* better here than at end -- qtest.sh 10 '500 C1,2e-13 D4' 'd Qbb' */
+    if (facet1->flipped) {
+      zinc_(Zmergeflipdup);
+      numflip++;
+    }else
+      nummerge++;
+    if (qh->PRINTstatistics) {
+      zinc_(Zduplicate);
+      wadd_(Wduplicatetot, dist);
+      wmax_(Wduplicatemax, dist);
+    }
+  }
+  FOREACHmerge_(othermerges) {
+    if (merge->mergetype == MRGdupridge)
+      qh_memfree(qh, merge, (int)sizeof(mergeT)); /* invalidates merge and othermerges */
+    else
+      qh_setappend(qh, &qh->facet_mergeset, merge);
+  }
+  qh_settempfree(qh, &othermerges);
+  if (wasdupridge) {
+    FORALLnew_facets {
+      if (newfacet->dupridge) {
+        newfacet->dupridge= False;
+        newfacet->mergeridge= False;
+        newfacet->mergeridge2= False;
+        if (qh_setsize(qh, newfacet->neighbors) < qh->hull_dim) { /* not tested for MRGdupridge */
+          qh_appendmergeset(qh, newfacet, newfacet, MRGdegen, 0.0, 1.0);
+          trace2((qh, qh->ferr, 2107, "qh_forcedmerges: dupridge f%d is degenerate with fewer than %d neighbors\n",
+                      newfacet->id, qh->hull_dim));
+        }
+      }
+    }
+    numdegen += qh_merge_degenredundant(qh);
+  }
+  if (nummerge || numflip) {
+    *wasmerge= True;
+    trace1((qh, qh->ferr, 1011, "qh_forcedmerges: merged %d facets, %d flipped facets, and %d degenredundant facets across dupridges\n",
+                  nummerge, numflip, numdegen));
+  }
+} /* forcedmerges */
+
+
+/*---------------------------------
+
+  qh_freemergesets(qh )
+    free the merge sets
+
+  notes:
+    matches qh_initmergesets
+*/
+void qh_freemergesets(qhT *qh) {
+
+  if (!qh->facet_mergeset || !qh->degen_mergeset || !qh->vertex_mergeset) {
+    qh_fprintf(qh, qh->ferr, 6388, "qhull internal error (qh_freemergesets): expecting mergesets.  Got a NULL mergeset, qh.facet_mergeset (%p), qh.degen_mergeset (%p), qh.vertex_mergeset (%p)\n",
+      (void *) qh->facet_mergeset, (void *) qh->degen_mergeset, (void *) qh->vertex_mergeset);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  if (!SETempty_(qh->facet_mergeset) || !SETempty_(qh->degen_mergeset) || !SETempty_(qh->vertex_mergeset)) {
+    qh_fprintf(qh, qh->ferr, 6389, "qhull internal error (qh_freemergesets): expecting empty mergesets.  Got qh.facet_mergeset (%d merges), qh.degen_mergeset (%d merges), qh.vertex_mergeset (%d merges)\n",
+      qh_setsize(qh, qh->facet_mergeset), qh_setsize(qh, qh->degen_mergeset), qh_setsize(qh, qh->vertex_mergeset));
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh_settempfree(qh, &qh->facet_mergeset);
+  qh_settempfree(qh, &qh->vertex_mergeset);
+  qh_settempfree(qh, &qh->degen_mergeset);
+} /* freemergesets */
+
+/*---------------------------------
+
+  qh_getmergeset(qh, facetlist )
+    determines nonconvex facets on facetlist
+    tests !tested ridges and nonconvex ridges of !tested facets
+
+  returns:
+    returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged
+    all ridges tested
+
+  notes:
+    facetlist is qh.facet_newlist, use qh_getmergeset_initial for all facets
+    assumes no nonconvex ridges with both facets tested
+    uses facet->tested/ridge->tested to prevent duplicate tests
+    can not limit tests to modified ridges since the centrum changed
+    uses qh.visit_id
+
+  design:
+    for each facet on facetlist
+      for each ridge of facet
+        if untested ridge
+          test ridge for convexity
+          if non-convex
+            append ridge to qh.facet_mergeset
+    sort qh.facet_mergeset by mergetype and angle or distance
+*/
+void qh_getmergeset(qhT *qh, facetT *facetlist) {
+  facetT *facet, *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int nummerges;
+  boolT simplicial;
+
+  nummerges= qh_setsize(qh, qh->facet_mergeset);
+  trace4((qh, qh->ferr, 4026, "qh_getmergeset: started.\n"));
+  qh->visit_id++;
+  FORALLfacet_(facetlist) {
+    if (facet->tested)
+      continue;
+    facet->visitid= qh->visit_id;
+    FOREACHneighbor_(facet)
+      neighbor->seen= False;
+    /* facet must be non-simplicial due to merge to qh.facet_newlist */
+    FOREACHridge_(facet->ridges) {
+      if (ridge->tested && !ridge->nonconvex)
+        continue;
+      /* if r.tested & r.nonconvex, need to retest and append merge */
+      neighbor= otherfacet_(ridge, facet);
+      if (neighbor->seen) { /* another ridge for this facet-neighbor pair was already tested in this loop */
+        ridge->tested= True;
+        ridge->nonconvex= False;   /* only one ridge is marked nonconvex per facet-neighbor pair */
+      }else if (neighbor->visitid != qh->visit_id) {
+        neighbor->seen= True;
+        ridge->nonconvex= False;
+        simplicial= False;
+        if (ridge->simplicialbot && ridge->simplicialtop)
+          simplicial= True;
+        if (qh_test_appendmerge(qh, facet, neighbor, simplicial))
+          ridge->nonconvex= True;
+        ridge->tested= True;
+      }
+    }
+    facet->tested= True;
+  }
+  nummerges= qh_setsize(qh, qh->facet_mergeset);
+  if (qh->ANGLEmerge)
+    qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_anglemerge);
+  else
+    qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_facetmerge);
+  nummerges += qh_setsize(qh, qh->degen_mergeset);
+  if (qh->POSTmerging) {
+    zadd_(Zmergesettot2, nummerges);
+  }else {
+    zadd_(Zmergesettot, nummerges);
+    zmax_(Zmergesetmax, nummerges);
+  }
+  trace2((qh, qh->ferr, 2021, "qh_getmergeset: %d merges found\n", nummerges));
+} /* getmergeset */
+
+
+/*---------------------------------
+
+  qh_getmergeset_initial(qh, facetlist )
+    determine initial qh.facet_mergeset for facets
+    tests all facet/neighbor pairs on facetlist
+
+  returns:
+    sorted qh.facet_mergeset with nonconvex ridges
+    sets facet->tested, ridge->tested, and ridge->nonconvex
+
+  notes:
+    uses visit_id, assumes ridge->nonconvex is False
+    see qh_getmergeset
+
+  design:
+    for each facet on facetlist
+      for each untested neighbor of facet
+        test facet and neighbor for convexity
+        if non-convex
+          append merge to qh.facet_mergeset
+          mark one of the ridges as nonconvex
+    sort qh.facet_mergeset by mergetype and angle or distance
+*/
+void qh_getmergeset_initial(qhT *qh, facetT *facetlist) {
+  facetT *facet, *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int nummerges;
+  boolT simplicial;
+
+  qh->visit_id++;
+  FORALLfacet_(facetlist) {
+    facet->visitid= qh->visit_id;
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh->visit_id) {
+        simplicial= False; /* ignores r.simplicialtop/simplicialbot.  Need to test horizon facets */
+        if (facet->simplicial && neighbor->simplicial)
+          simplicial= True;
+        if (qh_test_appendmerge(qh, facet, neighbor, simplicial)) {
+          FOREACHridge_(neighbor->ridges) {
+            if (facet == otherfacet_(ridge, neighbor)) {
+              ridge->nonconvex= True;
+              break;    /* only one ridge is marked nonconvex */
+            }
+          }
+        }
+      }
+    }
+    facet->tested= True;
+    FOREACHridge_(facet->ridges)
+      ridge->tested= True;
+  }
+  nummerges= qh_setsize(qh, qh->facet_mergeset);
+  if (qh->ANGLEmerge)
+    qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_anglemerge);
+  else
+    qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_facetmerge);
+  nummerges += qh_setsize(qh, qh->degen_mergeset);
+  if (qh->POSTmerging) {
+    zadd_(Zmergeinittot2, nummerges);
+  }else {
+    zadd_(Zmergeinittot, nummerges);
+    zmax_(Zmergeinitmax, nummerges);
+  }
+  trace2((qh, qh->ferr, 2022, "qh_getmergeset_initial: %d merges found\n", nummerges));
+} /* getmergeset_initial */
+
+/*---------------------------------
+
+  qh_getpinchedmerges(qh, apex, maxdist, iscoplanar )
+    get pinched merges for dupridges in qh.facet_mergeset
+    qh.NEWtentative==True
+      qh.newfacet_list with apex
+      qh.horizon_list is attached to qh.visible_list instead of qh.newfacet_list
+      maxdist for vertex-facet of a dupridge
+    qh.facet_mergeset is empty
+    qh.vertex_mergeset is a temporary set
+
+  returns:
+    False if nearest vertex would increase facet width by more than maxdist or qh_WIDEpinched
+    True and iscoplanar, if the pinched vertex is the apex (i.e., make the apex a coplanar point)
+    True and !iscoplanar, if should merge a pinched vertex of a dupridge
+      qh.vertex_mergeset contains one or more MRGsubridge with a pinched vertex and a nearby, neighboring vertex
+    qh.facet_mergeset is empty
+
+  notes:
+    called by qh_buildcone_mergepinched
+    hull_dim >= 3
+    a pinched vertex is in a dupridge and the horizon
+    selects the pinched vertex that is closest to its neighbor
+
+  design:
+    for each dupridge
+        determine the best pinched vertex to be merged into a neighboring vertex
+        if merging the pinched vertex would produce a wide merge (qh_WIDEpinched)
+           ignore pinched vertex with a warning, and use qh_merge_degenredundant instead
+        else
+           append the pinched vertex to vertex_mergeset for merging
+*/
+boolT qh_getpinchedmerges(qhT *qh, vertexT *apex, coordT maxdupdist, boolT *iscoplanar /* qh.newfacet_list, qh.vertex_mergeset */) {
+  mergeT *merge, **mergep, *bestmerge= NULL;
+  vertexT *nearest, *pinched, *bestvertex= NULL, *bestpinched= NULL;
+  boolT result;
+  coordT dist, prevdist, bestdist= REALmax/(qh_RATIOcoplanarapex+1.0); /* allow *3.0 */
+  realT ratio;
+
+  trace2((qh, qh->ferr, 2062, "qh_getpinchedmerges: try to merge pinched vertices for dupridges in new facets with apex p%d(v%d) max dupdist %2.2g\n",
+      qh_pointid(qh, apex->point), apex->id, maxdupdist));
+  *iscoplanar= False;
+  prevdist= fmax_(qh->ONEmerge + qh->DISTround, qh->MINoutside + qh->DISTround);
+  maximize_(prevdist, qh->max_outside);
+  maximize_(prevdist, -qh->min_vertex);
+  qh_mark_dupridges(qh, qh->newfacet_list, !qh_ALL); /* qh.facet_mergeset, creates ridges */
+  /* qh_mark_dupridges is called a second time in qh_premerge */
+  FOREACHmerge_(qh->facet_mergeset) {  /* read-only */
+    if (merge->mergetype != MRGdupridge) {
+      qh_fprintf(qh, qh->ferr, 6393, "qhull internal error (qh_getpinchedmerges): expecting MRGdupridge from qh_mark_dupridges.  Got merge f%d f%d type %d\n",
+        getid_(merge->facet1), getid_(merge->facet2), merge->mergetype);
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }
+    /* dist is distance between vertices */
+    pinched= qh_findbest_pinchedvertex(qh, merge, apex, &nearest, &dist /* qh.newfacet_list */);
+    if (pinched == apex && dist < qh_RATIOcoplanarapex*bestdist) { /* prefer coplanar apex since it always works */
+      bestdist= dist/qh_RATIOcoplanarapex;
+      bestmerge= merge;
+      bestpinched= pinched;
+      bestvertex= nearest;
+    }else if (dist < bestdist) {
+      bestdist= dist;
+      bestmerge= merge;
+      bestpinched= pinched;
+      bestvertex= nearest;
+    }
+  }
+  result= False;
+  if (bestmerge && bestdist < maxdupdist) {
+    ratio= bestdist / prevdist;
+    if (ratio > qh_WIDEpinched) {
+      if (bestmerge->facet1->mergehorizon || bestmerge->facet2->mergehorizon) { /* e.g., rbox 175 C3,2e-13 t1539182828 | qhull d */
+        trace1((qh, qh->ferr, 1051, "qh_getpinchedmerges: dupridge (MRGdupridge) of coplanar horizon would produce a wide merge (%.0fx) due to pinched vertices v%d and v%d (dist %2.2g) for f%d and f%d.  qh_mergecycle_all will merge one or both facets\n",
+          ratio, bestpinched->id, bestvertex->id, bestdist, bestmerge->facet1->id, bestmerge->facet2->id));
+      }else {
+        qh_fprintf(qh, qh->ferr, 7081, "qhull precision warning (qh_getpinchedmerges): pinched vertices v%d and v%d (dist %2.2g, %.0fx) would produce a wide merge for f%d and f%d.  Will merge dupridge instead\n",
+          bestpinched->id, bestvertex->id, bestdist, ratio, bestmerge->facet1->id, bestmerge->facet2->id);
+      }
+    }else {
+      if (bestpinched == apex) {
+        trace2((qh, qh->ferr, 2063, "qh_getpinchedmerges: will make the apex a coplanar point.  apex p%d(v%d) is the nearest vertex to v%d on dupridge.  Dist %2.2g\n",
+          qh_pointid(qh, apex->point), apex->id, bestvertex->id, bestdist*qh_RATIOcoplanarapex));
+        qh->coplanar_apex= apex->point;
+        *iscoplanar= True;
+        result= True;
+      }else if (qh_setin(bestmerge->facet1->vertices, bestpinched) != qh_setin(bestmerge->facet2->vertices, bestpinched)) { /* pinched in one facet but not the other facet */
+        trace2((qh, qh->ferr, 2064, "qh_getpinchedmerges: will merge new facets to resolve dupridge between f%d and f%d with pinched v%d and v%d\n",
+          bestmerge->facet1->id, bestmerge->facet2->id, bestpinched->id, bestvertex->id));
+        qh_appendvertexmerge(qh, bestpinched, bestvertex, MRGsubridge, bestdist, NULL, NULL);
+        result= True;
+      }else {
+        trace2((qh, qh->ferr, 2065, "qh_getpinchedmerges: will merge pinched v%d into v%d to resolve dupridge between f%d and f%d\n",
+          bestpinched->id, bestvertex->id, bestmerge->facet1->id, bestmerge->facet2->id));
+        qh_appendvertexmerge(qh, bestpinched, bestvertex, MRGsubridge, bestdist, NULL, NULL);
+        result= True;
+      }
+    }
+  }
+  /* delete MRGdupridge, qh_mark_dupridges is called a second time in qh_premerge */
+  while ((merge= (mergeT *)qh_setdellast(qh->facet_mergeset)))
+    qh_memfree(qh, merge, (int)sizeof(mergeT));
+  return result;
+}/* getpinchedmerges */
+
+/*---------------------------------
+
+  qh_hasmerge( mergeset, mergetype, facetA, facetB )
+    True if mergeset has mergetype for facetA and facetB
+*/
+boolT   qh_hasmerge(setT *mergeset, mergeType type, facetT *facetA, facetT *facetB) {
+  mergeT *merge, **mergep;
+
+  FOREACHmerge_(mergeset) {
+    if (merge->mergetype == type) {
+      if (merge->facet1 == facetA && merge->facet2 == facetB)
+        return True;
+      if (merge->facet1 == facetB && merge->facet2 == facetA)
+        return True;
+    }
+  }
+  return False;
+}/* hasmerge */
+
+/*---------------------------------
+
+  qh_hashridge(qh, hashtable, hashsize, ridge, oldvertex )
+    add ridge to hashtable without oldvertex
+
+  notes:
+    assumes hashtable is large enough
+
+  design:
+    determine hash value for ridge without oldvertex
+    find next empty slot for ridge
+*/
+void qh_hashridge(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {
+  int hash;
+  ridgeT *ridgeA;
+
+  hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, oldvertex);
+  while (True) {
+    if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
+      SETelem_(hashtable, hash)= ridge;
+      break;
+    }else if (ridgeA == ridge)
+      break;
+    if (++hash == hashsize)
+      hash= 0;
+  }
+} /* hashridge */
+
+
+/*---------------------------------
+
+  qh_hashridge_find(qh, hashtable, hashsize, ridge, vertex, oldvertex, hashslot )
+    returns matching ridge without oldvertex in hashtable
+      for ridge without vertex
+    if oldvertex is NULL
+      matches with any one skip
+
+  returns:
+    matching ridge or NULL
+    if no match,
+      if ridge already in   table
+        hashslot= -1
+      else
+        hashslot= next NULL index
+
+  notes:
+    assumes hashtable is large enough
+    can't match ridge to itself
+
+  design:
+    get hash value for ridge without vertex
+    for each hashslot
+      return match if ridge matches ridgeA without oldvertex
+*/
+ridgeT *qh_hashridge_find(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge,
+              vertexT *vertex, vertexT *oldvertex, int *hashslot) {
+  int hash;
+  ridgeT *ridgeA;
+
+  *hashslot= 0;
+  zinc_(Zhashridge);
+  hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, vertex);
+  while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
+    if (ridgeA == ridge)
+      *hashslot= -1;
+    else {
+      zinc_(Zhashridgetest);
+      if (qh_setequal_except(ridge->vertices, vertex, ridgeA->vertices, oldvertex))
+        return ridgeA;
+    }
+    if (++hash == hashsize)
+      hash= 0;
+  }
+  if (!*hashslot)
+    *hashslot= hash;
+  return NULL;
+} /* hashridge_find */
+
+
+/*---------------------------------
+
+  qh_initmergesets(qh )
+    initialize the merge sets
+    if 'all', include qh.degen_mergeset
+
+  notes:
+    matches qh_freemergesets
+*/
+void qh_initmergesets(qhT *qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */) {
+
+  if (qh->facet_mergeset || qh->degen_mergeset || qh->vertex_mergeset) {
+    qh_fprintf(qh, qh->ferr, 6386, "qhull internal error (qh_initmergesets): expecting NULL mergesets.  Got qh.facet_mergeset (%p), qh.degen_mergeset (%p), qh.vertex_mergeset (%p)\n",
+      (void *) qh->facet_mergeset, (void *) qh->degen_mergeset, (void *) qh->vertex_mergeset);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);
+  qh->vertex_mergeset= qh_settemp(qh, qh->TEMPsize);
+  qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize); /* last temporary set for qh_forcedmerges */
+} /* initmergesets */
+
+/*---------------------------------
+
+  qh_makeridges(qh, facet )
+    creates explicit ridges between simplicial facets
+
+  returns:
+    facet with ridges and without qh_MERGEridge
+    ->simplicial is False
+    if facet was tested, new ridges are tested
+
+  notes:
+    allows qh_MERGEridge flag
+    uses existing ridges
+    duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)
+
+  see:
+    qh_mergecycle_ridges()
+    qh_rename_adjacentvertex for qh_merge_pinchedvertices
+
+  design:
+    look for qh_MERGEridge neighbors
+    mark neighbors that already have ridges
+    for each unprocessed neighbor of facet
+      create a ridge for neighbor and facet
+    if any qh_MERGEridge neighbors
+      delete qh_MERGEridge flags (previously processed by qh_mark_dupridges)
+*/
+void qh_makeridges(qhT *qh, facetT *facet) {
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int neighbor_i, neighbor_n;
+  boolT toporient, mergeridge= False;
+
+  if (!facet->simplicial)
+    return;
+  trace4((qh, qh->ferr, 4027, "qh_makeridges: make ridges for f%d\n", facet->id));
+  facet->simplicial= False;
+  FOREACHneighbor_(facet) {
+    if (neighbor == qh_MERGEridge)
+      mergeridge= True;
+    else
+      neighbor->seen= False;
+  }
+  FOREACHridge_(facet->ridges)
+    otherfacet_(ridge, facet)->seen= True;
+  FOREACHneighbor_i_(qh, facet) {
+    if (neighbor == qh_MERGEridge)
+      continue;  /* fixed by qh_mark_dupridges */
+    else if (!neighbor->seen) {  /* no current ridges */
+      ridge= qh_newridge(qh);
+      ridge->vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,
+                                                          neighbor_i, 0);
+      toporient= (boolT)(facet->toporient ^ (neighbor_i & 0x1));
+      if (toporient) {
+        ridge->top= facet;
+        ridge->bottom= neighbor;
+        ridge->simplicialtop= True;
+        ridge->simplicialbot= neighbor->simplicial;
+      }else {
+        ridge->top= neighbor;
+        ridge->bottom= facet;
+        ridge->simplicialtop= neighbor->simplicial;
+        ridge->simplicialbot= True;
+      }
+      if (facet->tested && !mergeridge)
+        ridge->tested= True;
+#if 0 /* this also works */
+      flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1);
+      if (facet->toporient ^ (skip1 & 0x1) ^ flip) {
+        ridge->top= neighbor;
+        ridge->bottom= facet;
+        ridge->simplicialtop= True;
+        ridge->simplicialbot= neighbor->simplicial;
+      }else {
+        ridge->top= facet;
+        ridge->bottom= neighbor;
+        ridge->simplicialtop= neighbor->simplicial;
+        ridge->simplicialbot= True;
+      }
+#endif
+      qh_setappend(qh, &(facet->ridges), ridge);
+      trace5((qh, qh->ferr, 5005, "makeridges: appended r%d to ridges for f%d.  Next is ridges for neighbor f%d\n",
+            ridge->id, facet->id, neighbor->id));
+      qh_setappend(qh, &(neighbor->ridges), ridge);
+      if (qh->ridge_id == qh->traceridge_id)
+        qh->traceridge= ridge;
+    }
+  }
+  if (mergeridge) {
+    while (qh_setdel(facet->neighbors, qh_MERGEridge))
+      ; /* delete each one */
+  }
+} /* makeridges */
+
+
+/*---------------------------------
+
+  qh_mark_dupridges(qh, facetlist, allmerges )
+    add duplicated ridges to qh.facet_mergeset
+    facet-dupridge is true if it contains a subridge shared by more than one new facet
+    for each such facet, one has a neighbor marked qh_MERGEridge
+    allmerges is true if merging dupridges
+    allmerges is false if merging pinched vertices followed by retry addpoint
+      qh_mark_dupridges will be called again if pinched vertices not found
+
+  returns:
+    dupridges on qh.facet_mergeset (MRGdupridge)
+    f.mergeridge and f.mergeridge2 set for facet
+    f.mergeridge set for neighbor
+    if allmerges is true
+      make ridges for facets with dupridges as marked by qh_MERGEridge and both sides facet->dupridge
+      removes qh_MERGEridge from neighbor sets
+
+  notes:
+    called by qh_premerge and qh_getpinchedmerges
+    dupridges are due to duplicate subridges
+        i.e. a subridge occurs in more than two horizon ridges.
+        i.e., a ridge has more than two neighboring facets
+    dupridges occur in at least two cases
+    1) a pinched horizon with nearly adjacent vertices -> merge the vertices (qh_getpinchedmerges)
+    2) more than one newfacet for a horizon face -> merge coplanar facets (qh_premerge)
+    qh_matchdupridge previously identified the furthest apart pair of facets to retain
+       they must have a matching subridge and the same orientation
+    only way to set facet->mergeridge and mergeridge2
+    uses qh.visit_id
+
+  design:
+    for all facets on facetlist
+      if facet contains a dupridge
+        for each neighbor of facet
+          if neighbor marked qh_MERGEridge (one side of the merge)
+            set facet->mergeridge
+          else
+            if neighbor contains a dupridge
+            and the back link is qh_MERGEridge
+              append dupridge to qh.facet_mergeset
+   exit if !allmerges for repeating qh_mark_dupridges later
+   for each dupridge
+     make ridge sets in preparation for merging
+     remove qh_MERGEridge from neighbor set
+   for each dupridge
+     restore the missing neighbor from the neighbor set that was qh_MERGEridge
+     add the missing ridge for this neighbor
+*/
+void qh_mark_dupridges(qhT *qh, facetT *facetlist, boolT allmerges) {
+  facetT *facet, *neighbor, **neighborp;
+  int nummerge=0;
+  mergeT *merge, **mergep;
+
+  trace4((qh, qh->ferr, 4028, "qh_mark_dupridges: identify dupridges in facetlist f%d, allmerges? %d\n",
+    facetlist->id, allmerges));
+  FORALLfacet_(facetlist) {  /* not necessary for first call */
+    facet->mergeridge2= False;
+    facet->mergeridge= False;
+  }
+  FORALLfacet_(facetlist) {
+    if (facet->dupridge) {
+      FOREACHneighbor_(facet) {
+        if (neighbor == qh_MERGEridge) {
+          facet->mergeridge= True;
+          continue;
+        }
+        if (neighbor->dupridge) {
+          if (!qh_setin(neighbor->neighbors, facet)) { /* i.e., it is qh_MERGEridge, neighbors are distinct */
+            qh_appendmergeset(qh, facet, neighbor, MRGdupridge, 0.0, 1.0);
+            facet->mergeridge2= True;
+            facet->mergeridge= True;
+            nummerge++;
+          }else if (qh_setequal(facet->vertices, neighbor->vertices)) { /* neighbors are the same except for horizon and qh_MERGEridge, see QH7085 */
+            trace3((qh, qh->ferr, 3043, "qh_mark_dupridges): dupridge due to duplicate vertices for subridges f%d and f%d\n",
+                 facet->id, neighbor->id));
+            qh_appendmergeset(qh, facet, neighbor, MRGdupridge, 0.0, 1.0);
+            facet->mergeridge2= True;
+            facet->mergeridge= True;
+            nummerge++;
+            break; /* same for all neighbors */
+          }
+        }
+      }
+    }
+  }
+  if (!nummerge)
+    return;
+  if (!allmerges) {
+    trace1((qh, qh->ferr, 1012, "qh_mark_dupridges: found %d duplicated ridges (MRGdupridge) for qh_getpinchedmerges\n", nummerge));
+    return;
+  }
+  trace1((qh, qh->ferr, 1048, "qh_mark_dupridges: found %d duplicated ridges (MRGdupridge) for qh_premerge.  Prepare facets for merging\n", nummerge));
+  /* make ridges in preparation for merging */
+  FORALLfacet_(facetlist) {
+    if (facet->mergeridge && !facet->mergeridge2)
+      qh_makeridges(qh, facet);
+  }
+  trace3((qh, qh->ferr, 3075, "qh_mark_dupridges: restore missing neighbors and ridges due to qh_MERGEridge\n"));
+  FOREACHmerge_(qh->facet_mergeset) {   /* restore the missing neighbors */
+    if (merge->mergetype == MRGdupridge) { /* only between simplicial facets */
+      if (merge->facet2->mergeridge2 && qh_setin(merge->facet2->neighbors, merge->facet1)) {
+        /* Due to duplicate or multiple subridges, e.g., ../eg/qtest.sh t712682 '200 s W1e-13  C1,1e-13 D5' 'd'
+            merge->facet1:    - neighboring facets: f27779 f59186 f59186 f59186 MERGEridge f59186
+            merge->facet2:    - neighboring facets: f27779 f59100 f59100 f59100 f59100 f59100
+           or, ../eg/qtest.sh 100 '500 s W1e-13 C1,1e-13 D4' 'd'
+           both facets will be degenerate after merge, consider for special case handling
+        */
+        qh_fprintf(qh, qh->ferr, 6361, "qhull topological error (qh_mark_dupridges): multiple dupridges for f%d and f%d, including reverse\n",
+          merge->facet1->id, merge->facet2->id);
+        qh_errexit2(qh, qh_ERRtopology, merge->facet1, merge->facet2);
+      }else
+        qh_setappend(qh, &merge->facet2->neighbors, merge->facet1);
+      qh_makeridges(qh, merge->facet1);   /* and the missing ridges */
+    }
+  }
+} /* mark_dupridges */
+
+/*---------------------------------
+
+  qh_maybe_duplicateridge(qh, ridge )
+    add MRGvertices if neighboring facet has another ridge with the same vertices
+
+  returns:
+    adds rename requests to qh.vertex_mergeset
+
+  notes:
+    called by qh_renamevertex
+    nop if 2-D
+    expensive test
+    Duplicate ridges may lead to new facets with same vertex set (QH7084), will try merging vertices
+    same as qh_maybe_duplicateridges
+
+  design:
+    for the two neighbors
+      if non-simplicial
+        for each ridge with the same first and last vertices (max id and min id)
+          if the remaining vertices are the same
+            get the closest pair of vertices
+            add to vertex_mergeset for merging
+*/
+void qh_maybe_duplicateridge(qhT *qh, ridgeT *ridgeA) {
+  ridgeT *ridge, **ridgep;
+  vertexT *vertex, *pinched;
+  facetT *neighbor;
+  coordT dist;
+  int i, k, last= qh->hull_dim-2;
+
+  if (qh->hull_dim < 3 )
+    return;
+
+  for (neighbor= ridgeA->top, i=0; i<2; neighbor= ridgeA->bottom, i++) {
+    if (!neighbor->simplicial && neighbor->nummerge > 0) { /* skip degenerate neighbors with both new and old vertices that will be merged */
+      FOREACHridge_(neighbor->ridges) {
+        if (ridge != ridgeA && SETfirst_(ridge->vertices) == SETfirst_(ridgeA->vertices)) {
+          if (SETelem_(ridge->vertices, last) == SETelem_(ridgeA->vertices, last)) {
+            for (k=1; kvertices, k) != SETelem_(ridgeA->vertices, k))
+                break;
+            }
+            if (k == last) {
+              vertex= qh_findbest_ridgevertex(qh, ridge, &pinched, &dist);
+              trace2((qh, qh->ferr, 2069, "qh_maybe_duplicateridge: will merge v%d into v%d (dist %2.2g) due to duplicate ridges r%d/r%d with the same vertices.  mergevertex set\n",
+                pinched->id, vertex->id, dist, ridgeA->id, ridge->id));
+              qh_appendvertexmerge(qh, pinched, vertex, MRGvertices, dist, ridgeA, ridge);
+              ridge->mergevertex= True; /* disables check for duplicate vertices in qh_checkfacet */
+              ridgeA->mergevertex= True;
+            }
+          }
+        }
+      }
+    }
+  }
+} /* maybe_duplicateridge */
+
+/*---------------------------------
+
+  qh_maybe_duplicateridges(qh, facet )
+    if Q17, add MRGvertices if facet has ridges with the same vertices
+
+  returns:
+    adds rename requests to qh.vertex_mergeset
+
+  notes:
+    called at end of qh_mergefacet and qh_mergecycle_all
+    only enabled if qh.CHECKduplicates ('Q17') and 3-D or more
+    expensive test, not worth it
+    same as qh_maybe_duplicateridge
+
+  design:
+    for all ridge pairs in facet
+        if the same first and last vertices (max id and min id)
+          if the remaining vertices are the same
+            get the closest pair of vertices
+            add to vertex_mergeset for merging
+*/
+void qh_maybe_duplicateridges(qhT *qh, facetT *facet) {
+  facetT *otherfacet;
+  ridgeT *ridge, *ridge2;
+  vertexT *vertex, *pinched;
+  coordT dist;
+  int ridge_i, ridge_n, i, k, last_v= qh->hull_dim-2;
+
+  if (qh->hull_dim < 3 || !qh->CHECKduplicates)
+    return;
+
+  FOREACHridge_i_(qh, facet->ridges) {
+    otherfacet= otherfacet_(ridge, facet);
+    if (otherfacet->degenerate || otherfacet->redundant || otherfacet->dupridge || otherfacet->flipped) /* will merge */
+      continue;
+    for (i=ridge_i+1; i < ridge_n; i++) {
+      ridge2= SETelemt_(facet->ridges, i, ridgeT);
+      otherfacet= otherfacet_(ridge2, facet);
+      if (otherfacet->degenerate || otherfacet->redundant || otherfacet->dupridge || otherfacet->flipped) /* will merge */
+        continue;
+      /* optimize qh_setequal(ridge->vertices, ridge2->vertices) */
+      if (SETelem_(ridge->vertices, last_v) == SETelem_(ridge2->vertices, last_v)) { /* SETfirst is likely to be the same */
+        if (SETfirst_(ridge->vertices) == SETfirst_(ridge2->vertices)) {
+          for (k=1; kvertices, k) != SETelem_(ridge2->vertices, k))
+              break;
+          }
+          if (k == last_v) {
+            vertex= qh_findbest_ridgevertex(qh, ridge, &pinched, &dist);
+            if (ridge->top == ridge2->bottom && ridge->bottom == ridge2->top) {
+              /* proof that ridges may have opposite orientation */
+              trace2((qh, qh->ferr, 2088, "qh_maybe_duplicateridges: will merge v%d into v%d (dist %2.2g) due to opposite oriented ridges r%d/r%d for f%d and f%d\n",
+                pinched->id, vertex->id, dist, ridge->id, ridge2->id, ridge->top->id, ridge->bottom->id));
+            }else {
+              trace2((qh, qh->ferr, 2083, "qh_maybe_duplicateridges: will merge v%d into v%d (dist %2.2g) due to duplicate ridges with the same vertices r%d/r%d in merged facet f%d\n",
+                pinched->id, vertex->id, dist, ridge->id, ridge2->id, facet->id));
+            }
+            qh_appendvertexmerge(qh, pinched, vertex, MRGvertices, dist, ridge, ridge2);
+            ridge->mergevertex= True; /* disables check for duplicate vertices in qh_checkfacet */
+            ridge2->mergevertex= True;
+          }
+        }
+      }
+    }
+  }
+} /* maybe_duplicateridges */
+
+/*---------------------------------
+
+  qh_maydropneighbor(qh, facet )
+    drop neighbor relationship if ridge was deleted between a non-simplicial facet and its neighbors
+
+  returns:
+    for deleted ridges
+      ridges made for simplicial neighbors
+      neighbor sets updated
+      appends degenerate facets to qh.facet_mergeset
+
+  notes:
+    called by qh_renamevertex
+    assumes neighbors do not include qh_MERGEridge (qh_makeridges)
+    won't cause redundant facets since vertex inclusion is the same
+    may drop vertex and neighbor if no ridge
+    uses qh.visit_id
+
+  design:
+    visit all neighbors with ridges
+    for each unvisited neighbor of facet
+      delete neighbor and facet from the non-simplicial neighbor sets
+      if neighbor becomes degenerate
+        append neighbor to qh.degen_mergeset
+    if facet is degenerate
+      append facet to qh.degen_mergeset
+*/
+void qh_maydropneighbor(qhT *qh, facetT *facet) {
+  ridgeT *ridge, **ridgep;
+  facetT *neighbor, **neighborp;
+
+  qh->visit_id++;
+  trace4((qh, qh->ferr, 4029, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",
+          facet->id));
+  if (facet->simplicial) {
+    qh_fprintf(qh, qh->ferr, 6278, "qhull internal error (qh_maydropneighbor): not valid for simplicial f%d while adding furthest p%d\n",
+      facet->id, qh->furthest_id);
+    qh_errexit(qh, qh_ERRqhull, facet, NULL);
+  }
+  FOREACHridge_(facet->ridges) {
+    ridge->top->visitid= qh->visit_id;
+    ridge->bottom->visitid= qh->visit_id;
+  }
+  FOREACHneighbor_(facet) {
+    if (neighbor->visible) {
+      qh_fprintf(qh, qh->ferr, 6358, "qhull internal error (qh_maydropneighbor): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
+            facet->id, neighbor->id);
+      qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
+    }
+    if (neighbor->visitid != qh->visit_id) {
+      trace2((qh, qh->ferr, 2104, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors while adding furthest p%d\n",
+            facet->id, neighbor->id, qh->furthest_id));
+      if (neighbor->simplicial) {
+        qh_fprintf(qh, qh->ferr, 6280, "qhull internal error (qh_maydropneighbor): not valid for simplicial neighbor f%d of f%d while adding furthest p%d\n",
+            neighbor->id, facet->id, qh->furthest_id);
+        qh_errexit2(qh, qh_ERRqhull, neighbor, facet);
+      }
+      zinc_(Zdropneighbor);
+      qh_setdel(neighbor->neighbors, facet);
+      if (qh_setsize(qh, neighbor->neighbors) < qh->hull_dim) {
+        zinc_(Zdropdegen);
+        qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, 0.0, qh_ANGLEnone);
+        trace2((qh, qh->ferr, 2023, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));
+      }
+      qh_setdel(facet->neighbors, neighbor);
+      neighborp--;  /* repeat, deleted a neighbor */
+    }
+  }
+  if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {
+    zinc_(Zdropdegen);
+    qh_appendmergeset(qh, facet, facet, MRGdegen, 0.0, qh_ANGLEnone);
+    trace2((qh, qh->ferr, 2024, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
+  }
+} /* maydropneighbor */
+
+
+/*---------------------------------
+
+  qh_merge_degenredundant(qh)
+    merge all degenerate and redundant facets
+    qh.degen_mergeset contains merges from  qh_test_degen_neighbors, qh_test_redundant_neighbors, and qh_degen_redundant_facet
+
+  returns:
+    number of merges performed
+    resets facet->degenerate/redundant
+    if deleted (visible) facet has no neighbors
+      sets ->f.replace to NULL
+
+  notes:
+    redundant merges happen before degenerate ones
+    merging and renaming vertices can result in degen/redundant facets
+    check for coplanar and convex neighbors afterwards
+
+  design:
+    for each merge on qh.degen_mergeset
+      if redundant merge
+        if non-redundant facet merged into redundant facet
+          recheck facet for redundancy
+        else
+          merge redundant facet into other facet
+*/
+int qh_merge_degenredundant(qhT *qh) {
+  int size;
+  mergeT *merge;
+  facetT *bestneighbor, *facet1, *facet2, *facet3;
+  realT dist, mindist, maxdist;
+  vertexT *vertex, **vertexp;
+  int nummerges= 0;
+  mergeType mergetype;
+  setT *mergedfacets;
+
+  trace2((qh, qh->ferr, 2095, "qh_merge_degenredundant: merge %d degenerate, redundant, and mirror facets\n",
+    qh_setsize(qh, qh->degen_mergeset)));
+  mergedfacets= qh_settemp(qh, qh->TEMPsize);
+  while ((merge= (mergeT *)qh_setdellast(qh->degen_mergeset))) {
+    facet1= merge->facet1;
+    facet2= merge->facet2;
+    mergetype= merge->mergetype;
+    qh_memfree(qh, merge, (int)sizeof(mergeT)); /* 'merge' is invalidated */
+    if (facet1->visible)
+      continue;
+    facet1->degenerate= False;
+    facet1->redundant= False;
+    if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
+      qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
+    if (mergetype == MRGredundant) {
+      zinc_(Zredundant);
+      facet3= qh_getreplacement(qh, facet2); /* the same facet if !facet2.visible */
+      if (!facet3) {
+          qh_fprintf(qh, qh->ferr, 6097, "qhull internal error (qh_merge_degenredunant): f%d is redundant but visible f%d has no replacement\n",
+               facet1->id, getid_(facet2));
+          qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
+      }
+      qh_setunique(qh, &mergedfacets, facet3);
+      if (facet1 == facet3) {
+        continue;
+      }
+      trace2((qh, qh->ferr, 2025, "qh_merge_degenredundant: merge redundant f%d into f%d (arg f%d)\n",
+            facet1->id, facet3->id, facet2->id));
+      qh_mergefacet(qh, facet1, facet3, mergetype, NULL, NULL, !qh_MERGEapex);
+      /* merge distance is already accounted for */
+      nummerges++;
+    }else {  /* mergetype == MRGdegen or MRGmirror, other merges may have fixed */
+      if (!(size= qh_setsize(qh, facet1->neighbors))) {
+        zinc_(Zdelfacetdup);
+        trace2((qh, qh->ferr, 2026, "qh_merge_degenredundant: facet f%d has no neighbors.  Deleted\n", facet1->id));
+        qh_willdelete(qh, facet1, NULL);
+        FOREACHvertex_(facet1->vertices) {
+          qh_setdel(vertex->neighbors, facet1);
+          if (!SETfirst_(vertex->neighbors)) {
+            zinc_(Zdegenvertex);
+            trace2((qh, qh->ferr, 2027, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",
+                 vertex->id, facet1->id));
+            vertex->deleted= True;
+            qh_setappend(qh, &qh->del_vertices, vertex);
+          }
+        }
+        nummerges++;
+      }else if (size < qh->hull_dim) {
+        bestneighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
+        trace2((qh, qh->ferr, 2028, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",
+              facet1->id, size, bestneighbor->id, dist));
+        qh_mergefacet(qh, facet1, bestneighbor, mergetype, &mindist, &maxdist, !qh_MERGEapex);
+        nummerges++;
+        if (qh->PRINTstatistics) {
+          zinc_(Zdegen);
+          wadd_(Wdegentot, dist);
+          wmax_(Wdegenmax, dist);
+        }
+      } /* else, another merge fixed the degeneracy and redundancy tested */
+    }
+  }
+  qh_settempfree(qh, &mergedfacets);
+  return nummerges;
+} /* merge_degenredundant */
+
+/*---------------------------------
+
+  qh_merge_nonconvex(qh, facet1, facet2, mergetype )
+    remove non-convex ridge between facet1 into facet2
+    mergetype gives why the facet's are non-convex
+
+  returns:
+    merges one of the facets into the best neighbor
+
+  notes:
+    mergetype is MRGcoplanar..MRGconvex
+
+  design:
+    if one of the facets is a new facet
+      prefer merging new facet into old facet
+    find best neighbors for both facets
+    merge the nearest facet into its best neighbor
+    update the statistics
+*/
+void qh_merge_nonconvex(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype) {
+  facetT *bestfacet, *bestneighbor, *neighbor, *merging, *merged;
+  realT dist, dist2, mindist, mindist2, maxdist, maxdist2;
+
+  if (mergetype < MRGcoplanar || mergetype > MRGconcavecoplanar) {
+    qh_fprintf(qh, qh->ferr, 6398, "qhull internal error (qh_merge_nonconvex): expecting mergetype MRGcoplanar..MRGconcavecoplanar.  Got merge f%d and f%d type %d\n",
+      facet1->id, facet2->id, mergetype);
+    qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
+  }
+  if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
+    qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
+  trace3((qh, qh->ferr, 3003, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",
+      zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));
+  /* concave or coplanar */
+  if (!facet1->newfacet) {
+    bestfacet= facet2;   /* avoid merging old facet if new is ok */
+    facet2= facet1;
+    facet1= bestfacet;
+  }else
+    bestfacet= facet1;
+  bestneighbor= qh_findbestneighbor(qh, bestfacet, &dist, &mindist, &maxdist);
+  neighbor= qh_findbestneighbor(qh, facet2, &dist2, &mindist2, &maxdist2);
+  if (dist < dist2) {
+    merging= bestfacet;
+    merged= bestneighbor;
+  }else if (qh->AVOIDold && !facet2->newfacet
+  && ((mindist >= -qh->MAXcoplanar && maxdist <= qh->max_outside)
+       || dist * 1.5 < dist2)) {
+    zinc_(Zavoidold);
+    wadd_(Wavoidoldtot, dist);
+    wmax_(Wavoidoldmax, dist);
+    trace2((qh, qh->ferr, 2029, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g.  Use f%d dist %2.2g instead\n",
+           facet2->id, dist2, facet1->id, dist2));
+    merging= bestfacet;
+    merged= bestneighbor;
+  }else {
+    merging= facet2;
+    merged= neighbor;
+    dist= dist2;
+    mindist= mindist2;
+    maxdist= maxdist2;
+  }
+  qh_mergefacet(qh, merging, merged, mergetype, &mindist, &maxdist, !qh_MERGEapex);
+  /* caller merges qh_degenredundant */
+  if (qh->PRINTstatistics) {
+    if (mergetype == MRGanglecoplanar) {
+      zinc_(Zacoplanar);
+      wadd_(Wacoplanartot, dist);
+      wmax_(Wacoplanarmax, dist);
+    }else if (mergetype == MRGconcave) {
+      zinc_(Zconcave);
+      wadd_(Wconcavetot, dist);
+      wmax_(Wconcavemax, dist);
+    }else if (mergetype == MRGconcavecoplanar) {
+      zinc_(Zconcavecoplanar);
+      wadd_(Wconcavecoplanartot, dist);
+      wmax_(Wconcavecoplanarmax, dist);
+    }else { /* MRGcoplanar */
+      zinc_(Zcoplanar);
+      wadd_(Wcoplanartot, dist);
+      wmax_(Wcoplanarmax, dist);
+    }
+  }
+} /* merge_nonconvex */
+
+/*---------------------------------
+
+  qh_merge_pinchedvertices(qh, apex )
+    merge pinched vertices in qh.vertex_mergeset to avoid qh_forcedmerges of dupridges
+
+  notes:
+    only called by qh_all_vertexmerges
+    hull_dim >= 3
+
+  design:
+    make vertex neighbors if necessary
+    for each pinched vertex
+      determine the ridges for the pinched vertex (make ridges as needed)
+      merge the pinched vertex into the horizon vertex
+      merge the degenerate and redundant facets that result
+    check and resolve new dupridges
+*/
+void qh_merge_pinchedvertices(qhT *qh, int apexpointid /* qh.newfacet_list */) {
+  mergeT *merge, *mergeA, **mergeAp;
+  vertexT *vertex, *vertex2;
+  realT dist;
+  boolT firstmerge= True;
+
+  qh_vertexneighbors(qh);
+  if (qh->visible_list || qh->newfacet_list || qh->newvertex_list) {
+    qh_fprintf(qh, qh->ferr, 6402, "qhull internal error (qh_merge_pinchedvertices): qh.visible_list (f%d), newfacet_list (f%d), or newvertex_list (v%d) not empty\n",
+      getid_(qh->visible_list), getid_(qh->newfacet_list), getid_(qh->newvertex_list));
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh->visible_list= qh->newfacet_list= qh->facet_tail;
+  qh->newvertex_list= qh->vertex_tail;
+  qh->isRenameVertex= True; /* disable duplicate ridge vertices check in qh_checkfacet */
+  while ((merge= qh_next_vertexmerge(qh /* qh.vertex_mergeset */))) { /* only one at a time from qh_getpinchedmerges */
+    if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
+      qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
+    if (merge->mergetype == MRGsubridge) {
+      zzinc_(Zpinchedvertex);
+      trace1((qh, qh->ferr, 1050, "qh_merge_pinchedvertices: merge one of %d pinched vertices before adding apex p%d.  Try to resolve duplicate ridges in newfacets\n",
+        qh_setsize(qh, qh->vertex_mergeset)+1, apexpointid));
+      qh_remove_mergetype(qh, qh->vertex_mergeset, MRGsubridge);
+    }else {
+      zzinc_(Zpinchduplicate);
+      if (firstmerge)
+        trace1((qh, qh->ferr, 1056, "qh_merge_pinchedvertices: merge %d pinched vertices from dupridges in merged facets, apex p%d\n",
+           qh_setsize(qh, qh->vertex_mergeset)+1, apexpointid));
+      firstmerge= False;
+    }
+    vertex= merge->vertex1;
+    vertex2= merge->vertex2;
+    dist= merge->distance;
+    qh_memfree(qh, merge, (int)sizeof(mergeT)); /* merge is invalidated */
+    qh_rename_adjacentvertex(qh, vertex, vertex2, dist);
+#ifndef qh_NOtrace
+    if (qh->IStracing >= 2) {
+      FOREACHmergeA_(qh->degen_mergeset) {
+        if (mergeA->mergetype== MRGdegen) {
+          qh_fprintf(qh, qh->ferr, 2072, "qh_merge_pinchedvertices: merge degenerate f%d into an adjacent facet\n", mergeA->facet1->id);
+        }else {
+          qh_fprintf(qh, qh->ferr, 2084, "qh_merge_pinchedvertices: merge f%d into f%d mergeType %d\n", mergeA->facet1->id, mergeA->facet2->id, mergeA->mergetype);
+        }
+      }
+    }
+#endif
+    qh_merge_degenredundant(qh); /* simplicial facets with both old and new vertices */
+  }
+  qh->isRenameVertex= False;
+}/* merge_pinchedvertices */
+
+/*---------------------------------
+
+  qh_merge_twisted(qh, facet1, facet2 )
+    remove twisted ridge between facet1 into facet2 or report error
+
+  returns:
+    merges one of the facets into the best neighbor
+
+  notes:
+    a twisted ridge has opposite vertices that are convex and concave
+
+  design:
+    find best neighbors for both facets
+    error if wide merge
+    merge the nearest facet into its best neighbor
+    update statistics
+*/
+void qh_merge_twisted(qhT *qh, facetT *facet1, facetT *facet2) {
+  facetT *neighbor2, *neighbor, *merging, *merged;
+  vertexT *bestvertex, *bestpinched;
+  realT dist, dist2, mindist, mindist2, maxdist, maxdist2, mintwisted, bestdist;
+
+  if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
+    qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
+  trace3((qh, qh->ferr, 3050, "qh_merge_twisted: merge #%d for twisted f%d and f%d\n",
+      zzval_(Ztotmerge) + 1, facet1->id, facet2->id));
+  /* twisted */
+  neighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
+  neighbor2= qh_findbestneighbor(qh, facet2, &dist2, &mindist2, &maxdist2);
+  mintwisted= qh_RATIOtwisted * qh->ONEmerge;
+  maximize_(mintwisted, facet1->maxoutside);
+  maximize_(mintwisted, facet2->maxoutside);
+  if (dist > mintwisted && dist2 > mintwisted) {
+    bestdist= qh_vertex_bestdist2(qh, facet1->vertices, &bestvertex, &bestpinched);
+    if (bestdist > mintwisted) {
+      qh_fprintf(qh, qh->ferr, 6417, "qhull precision error (qh_merge_twisted): twisted facet f%d does not contain pinched vertices.  Too wide to merge into neighbor.  mindist %2.2g maxdist %2.2g vertexdist %2.2g maxpinched %2.2g neighbor f%d mindist %2.2g maxdist %2.2g\n",
+        facet1->id, mindist, maxdist, bestdist, mintwisted, facet2->id, mindist2, maxdist2);
+    }else {
+      qh_fprintf(qh, qh->ferr, 6418, "qhull precision error (qh_merge_twisted): twisted facet f%d with pinched vertices.  Could merge vertices, but too wide to merge into neighbor.   mindist %2.2g maxdist %2.2g vertexdist %2.2g neighbor f%d mindist %2.2g maxdist %2.2g\n",
+        facet1->id, mindist, maxdist, bestdist, facet2->id, mindist2, maxdist2);
+    }
+    qh_errexit2(qh, qh_ERRwide, facet1, facet2);
+  }
+  if (dist < dist2) {
+    merging= facet1;
+    merged= neighbor;
+  }else {
+    /* ignores qh.AVOIDold ('Q4') */
+    merging= facet2;
+    merged= neighbor2;
+    dist= dist2;
+    mindist= mindist2;
+    maxdist= maxdist2;
+  }
+  qh_mergefacet(qh, merging, merged, MRGtwisted, &mindist, &maxdist, !qh_MERGEapex);
+  /* caller merges qh_degenredundant */
+  zinc_(Ztwisted);
+  wadd_(Wtwistedtot, dist);
+  wmax_(Wtwistedmax, dist);
+} /* merge_twisted */
+
+/*---------------------------------
+
+  qh_mergecycle(qh, samecycle, newfacet )
+    merge a cycle of facets starting at samecycle into a newfacet
+    newfacet is a horizon facet with ->normal
+    samecycle facets are simplicial from an apex
+
+  returns:
+    initializes vertex neighbors on first merge
+    samecycle deleted (placed on qh.visible_list)
+    newfacet at end of qh.facet_list
+    deleted vertices on qh.del_vertices
+
+  notes:
+    only called by qh_mergecycle_all for multiple, same cycle facets
+    see qh_mergefacet
+
+  design:
+    make vertex neighbors if necessary
+    make ridges for newfacet
+    merge neighbor sets of samecycle into newfacet
+    merge ridges of samecycle into newfacet
+    merge vertex neighbors of samecycle into newfacet
+    make apex of samecycle the apex of newfacet
+    if newfacet wasn't a new facet
+      add its vertices to qh.newvertex_list
+    delete samecycle facets a make newfacet a newfacet
+*/
+void qh_mergecycle(qhT *qh, facetT *samecycle, facetT *newfacet) {
+  int traceonce= False, tracerestore= 0;
+  vertexT *apex;
+#ifndef qh_NOtrace
+  facetT *same;
+#endif
+
+  zzinc_(Ztotmerge);
+  if (qh->REPORTfreq2 && qh->POSTmerging) {
+    if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)
+      qh_tracemerging(qh);
+  }
+#ifndef qh_NOtrace
+  if (qh->TRACEmerge == zzval_(Ztotmerge))
+    qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
+  trace2((qh, qh->ferr, 2030, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n",
+        zzval_(Ztotmerge), samecycle->id, newfacet->id));
+  if (newfacet == qh->tracefacet) {
+    tracerestore= qh->IStracing;
+    qh->IStracing= 4;
+    qh_fprintf(qh, qh->ferr, 8068, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",
+               zzval_(Ztotmerge), samecycle->id, newfacet->id,  qh->furthest_id);
+    traceonce= True;
+  }
+  if (qh->IStracing >=4) {
+    qh_fprintf(qh, qh->ferr, 8069, "  same cycle:");
+    FORALLsame_cycle_(samecycle)
+      qh_fprintf(qh, qh->ferr, 8070, " f%d", same->id);
+    qh_fprintf(qh, qh->ferr, 8071, "\n");
+  }
+  if (qh->IStracing >=4)
+    qh_errprint(qh, "MERGING CYCLE", samecycle, newfacet, NULL, NULL);
+#endif /* !qh_NOtrace */
+  if (newfacet->tricoplanar) {
+    if (!qh->TRInormals) {
+      qh_fprintf(qh, qh->ferr, 6224, "qhull internal error (qh_mergecycle): does not work for tricoplanar facets.  Use option 'Q11'\n");
+      qh_errexit(qh, qh_ERRqhull, newfacet, NULL);
+    }
+    newfacet->tricoplanar= False;
+    newfacet->keepcentrum= False;
+  }
+  if (qh->CHECKfrequently)
+    qh_checkdelridge(qh);
+  if (!qh->VERTEXneighbors)
+    qh_vertexneighbors(qh);
+  apex= SETfirstt_(samecycle->vertices, vertexT);
+  qh_makeridges(qh, newfacet);
+  qh_mergecycle_neighbors(qh, samecycle, newfacet);
+  qh_mergecycle_ridges(qh, samecycle, newfacet);
+  qh_mergecycle_vneighbors(qh, samecycle, newfacet);
+  if (SETfirstt_(newfacet->vertices, vertexT) != apex)
+    qh_setaddnth(qh, &newfacet->vertices, 0, apex);  /* apex has last id */
+  if (!newfacet->newfacet)
+    qh_newvertices(qh, newfacet->vertices);
+  qh_mergecycle_facets(qh, samecycle, newfacet);
+  qh_tracemerge(qh, samecycle, newfacet, MRGcoplanarhorizon);
+  /* check for degen_redundant_neighbors after qh_forcedmerges() */
+  if (traceonce) {
+    qh_fprintf(qh, qh->ferr, 8072, "qh_mergecycle: end of trace facet\n");
+    qh->IStracing= tracerestore;
+  }
+} /* mergecycle */
+
+/*---------------------------------
+
+  qh_mergecycle_all(qh, facetlist, wasmerge )
+    merge all samecycles of coplanar facets into horizon
+    don't merge facets with ->mergeridge (these already have ->normal)
+    all facets are simplicial from apex
+    all facet->cycledone == False
+
+  returns:
+    all newfacets merged into coplanar horizon facets
+    deleted vertices on  qh.del_vertices
+    sets wasmerge if any merge
+
+  notes:
+    called by qh_premerge
+    calls qh_mergecycle for multiple, same cycle facets
+
+  design:
+    for each facet on facetlist
+      skip facets with dupridges and normals
+      check that facet is in a samecycle (->mergehorizon)
+      if facet only member of samecycle
+        sets vertex->delridge for all vertices except apex
+        merge facet into horizon
+      else
+        mark all facets in samecycle
+        remove facets with dupridges from samecycle
+        merge samecycle into horizon (deletes facets from facetlist)
+*/
+void qh_mergecycle_all(qhT *qh, facetT *facetlist, boolT *wasmerge) {
+  facetT *facet, *same, *prev, *horizon, *newfacet;
+  facetT *samecycle= NULL, *nextfacet, *nextsame;
+  vertexT *apex, *vertex, **vertexp;
+  int cycles=0, total=0, facets, nummerge, numdegen= 0;
+
+  trace2((qh, qh->ferr, 2031, "qh_mergecycle_all: merge new facets into coplanar horizon facets.  Bulk merge a cycle of facets with the same horizon facet\n"));
+  for (facet=facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {
+    if (facet->normal)
+      continue;
+    if (!facet->mergehorizon) {
+      qh_fprintf(qh, qh->ferr, 6225, "qhull internal error (qh_mergecycle_all): f%d without normal\n", facet->id);
+      qh_errexit(qh, qh_ERRqhull, facet, NULL);
+    }
+    horizon= SETfirstt_(facet->neighbors, facetT);
+    if (facet->f.samecycle == facet) {
+      if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
+        qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
+      zinc_(Zonehorizon);
+      /* merge distance done in qh_findhorizon */
+      apex= SETfirstt_(facet->vertices, vertexT);
+      FOREACHvertex_(facet->vertices) {
+        if (vertex != apex)
+          vertex->delridge= True;
+      }
+      horizon->f.newcycle= NULL;
+      qh_mergefacet(qh, facet, horizon, MRGcoplanarhorizon, NULL, NULL, qh_MERGEapex);
+    }else {
+      samecycle= facet;
+      facets= 0;
+      prev= facet;
+      for (same= facet->f.samecycle; same;  /* FORALLsame_cycle_(facet) */
+           same= (same == facet ? NULL :nextsame)) { /* ends at facet */
+        nextsame= same->f.samecycle;
+        if (same->cycledone || same->visible)
+          qh_infiniteloop(qh, same);
+        same->cycledone= True;
+        if (same->normal) {
+          prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */
+          same->f.samecycle= NULL;
+        }else {
+          prev= same;
+          facets++;
+        }
+      }
+      while (nextfacet && nextfacet->cycledone)  /* will delete samecycle */
+        nextfacet= nextfacet->next;
+      horizon->f.newcycle= NULL;
+      qh_mergecycle(qh, samecycle, horizon);
+      nummerge= horizon->nummerge + facets;
+      if (nummerge > qh_MAXnummerge)
+        horizon->nummerge= qh_MAXnummerge;
+      else
+        horizon->nummerge= (short unsigned int)nummerge; /* limited to 9 bits by qh_MAXnummerge, -Wconversion */
+      zzinc_(Zcyclehorizon);
+      total += facets;
+      zzadd_(Zcyclefacettot, facets);
+      zmax_(Zcyclefacetmax, facets);
+    }
+    cycles++;
+  }
+  if (cycles) {
+    FORALLnew_facets {
+      /* qh_maybe_duplicateridges postponed since qh_mergecycle_ridges deletes ridges without calling qh_delridge_merge */
+      if (newfacet->coplanarhorizon) {
+        qh_test_redundant_neighbors(qh, newfacet);
+        qh_maybe_duplicateridges(qh, newfacet);
+        newfacet->coplanarhorizon= False;
+      }
+    }
+    numdegen += qh_merge_degenredundant(qh);
+    *wasmerge= True;
+    trace1((qh, qh->ferr, 1013, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons and %d degenredundant facets\n",
+      cycles, numdegen));
+  }
+} /* mergecycle_all */
+
+/*---------------------------------
+
+  qh_mergecycle_facets(qh, samecycle, newfacet )
+    finish merge of samecycle into newfacet
+
+  returns:
+    samecycle prepended to visible_list for later deletion and partitioning
+      each facet->f.replace == newfacet
+
+    newfacet moved to end of qh.facet_list
+      makes newfacet a newfacet (get's facet1->id if it was old)
+      sets newfacet->newmerge
+      clears newfacet->center (unless merging into a large facet)
+      clears newfacet->tested and ridge->tested for facet1
+
+    adds neighboring facets to facet_mergeset if redundant or degenerate
+
+  design:
+    make newfacet a new facet and set its flags
+    move samecycle facets to qh.visible_list for later deletion
+    unless newfacet is large
+      remove its centrum
+*/
+void qh_mergecycle_facets(qhT *qh, facetT *samecycle, facetT *newfacet) {
+  facetT *same, *next;
+
+  trace4((qh, qh->ferr, 4030, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));
+  qh_removefacet(qh, newfacet);  /* append as a newfacet to end of qh->facet_list */
+  qh_appendfacet(qh, newfacet);
+  newfacet->newfacet= True;
+  newfacet->simplicial= False;
+  newfacet->newmerge= True;
+
+  for (same= samecycle->f.samecycle; same; same= (same == samecycle ?  NULL : next)) {
+    next= same->f.samecycle;  /* reused by willdelete */
+    qh_willdelete(qh, same, newfacet);
+  }
+  if (newfacet->center
+      && qh_setsize(qh, newfacet->vertices) <= qh->hull_dim + qh_MAXnewcentrum) {
+    qh_memfree(qh, newfacet->center, qh->normal_size);
+    newfacet->center= NULL;
+  }
+  trace3((qh, qh->ferr, 3004, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n",
+             samecycle->id, newfacet->id));
+} /* mergecycle_facets */
+
+/*---------------------------------
+
+  qh_mergecycle_neighbors(qh, samecycle, newfacet )
+    add neighbors for samecycle facets to newfacet
+
+  returns:
+    newfacet with updated neighbors and vice-versa
+    newfacet has ridges
+    all neighbors of newfacet marked with qh.visit_id
+    samecycle facets marked with qh.visit_id-1
+    ridges updated for simplicial neighbors of samecycle with a ridge
+
+  notes:
+    assumes newfacet not in samecycle
+    usually, samecycle facets are new, simplicial facets without internal ridges
+      not so if horizon facet is coplanar to two different samecycles
+
+  see:
+    qh_mergeneighbors()
+
+  design:
+    check samecycle
+    delete neighbors from newfacet that are also in samecycle
+    for each neighbor of a facet in samecycle
+      if neighbor is simplicial
+        if first visit
+          move the neighbor relation to newfacet
+          update facet links for its ridges
+        else
+          make ridges for neighbor
+          remove samecycle reference
+      else
+        update neighbor sets
+*/
+void qh_mergecycle_neighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {
+  facetT *same, *neighbor, **neighborp;
+  int delneighbors= 0, newneighbors= 0;
+  unsigned int samevisitid;
+  ridgeT *ridge, **ridgep;
+
+  samevisitid= ++qh->visit_id;
+  FORALLsame_cycle_(samecycle) {
+    if (same->visitid == samevisitid || same->visible)
+      qh_infiniteloop(qh, samecycle);
+    same->visitid= samevisitid;
+  }
+  newfacet->visitid= ++qh->visit_id;
+  trace4((qh, qh->ferr, 4031, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));
+  FOREACHneighbor_(newfacet) {
+    if (neighbor->visitid == samevisitid) {
+      SETref_(neighbor)= NULL;  /* samecycle neighbors deleted */
+      delneighbors++;
+    }else
+      neighbor->visitid= qh->visit_id;
+  }
+  qh_setcompact(qh, newfacet->neighbors);
+
+  trace4((qh, qh->ferr, 4032, "qh_mergecycle_neighbors: update neighbors\n"));
+  FORALLsame_cycle_(samecycle) {
+    FOREACHneighbor_(same) {
+      if (neighbor->visitid == samevisitid)
+        continue;
+      if (neighbor->simplicial) {
+        if (neighbor->visitid != qh->visit_id) {
+          qh_setappend(qh, &newfacet->neighbors, neighbor);
+          qh_setreplace(qh, neighbor->neighbors, same, newfacet);
+          newneighbors++;
+          neighbor->visitid= qh->visit_id;
+          FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */
+            if (ridge->top == same) {
+              ridge->top= newfacet;
+              break;
+            }else if (ridge->bottom == same) {
+              ridge->bottom= newfacet;
+              break;
+            }
+          }
+        }else {
+          qh_makeridges(qh, neighbor);
+          qh_setdel(neighbor->neighbors, same);
+          /* same can't be horizon facet for neighbor */
+        }
+      }else { /* non-simplicial neighbor */
+        qh_setdel(neighbor->neighbors, same);
+        if (neighbor->visitid != qh->visit_id) {
+          qh_setappend(qh, &neighbor->neighbors, newfacet);
+          qh_setappend(qh, &newfacet->neighbors, neighbor);
+          neighbor->visitid= qh->visit_id;
+          newneighbors++;
+        }
+      }
+    }
+  }
+  trace2((qh, qh->ferr, 2032, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n",
+             delneighbors, newneighbors));
+} /* mergecycle_neighbors */
+
+/*---------------------------------
+
+  qh_mergecycle_ridges(qh, samecycle, newfacet )
+    add ridges/neighbors for facets in samecycle to newfacet
+    all new/old neighbors of newfacet marked with qh.visit_id
+    facets in samecycle marked with qh.visit_id-1
+    newfacet marked with qh.visit_id
+
+  returns:
+    newfacet has merged ridges
+
+  notes:
+    ridge already updated for simplicial neighbors of samecycle with a ridge
+    qh_checkdelridge called by qh_mergecycle
+
+  see:
+    qh_mergeridges()
+    qh_makeridges()
+
+  design:
+    remove ridges between newfacet and samecycle
+    for each facet in samecycle
+      for each ridge in facet
+        update facet pointers in ridge
+        skip ridges processed in qh_mergecycle_neighors
+        free ridges between newfacet and samecycle
+        free ridges between facets of samecycle (on 2nd visit)
+        append remaining ridges to newfacet
+      if simplicial facet
+        for each neighbor of facet
+          if simplicial facet
+          and not samecycle facet or newfacet
+            make ridge between neighbor and newfacet
+*/
+void qh_mergecycle_ridges(qhT *qh, facetT *samecycle, facetT *newfacet) {
+  facetT *same, *neighbor= NULL;
+  int numold=0, numnew=0;
+  int neighbor_i, neighbor_n;
+  unsigned int samevisitid;
+  ridgeT *ridge, **ridgep;
+  boolT toporient;
+  void **freelistp; /* used if !qh_NOmem by qh_memfree_() */
+
+  trace4((qh, qh->ferr, 4033, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));
+  samevisitid= qh->visit_id -1;
+  FOREACHridge_(newfacet->ridges) {
+    neighbor= otherfacet_(ridge, newfacet);
+    if (neighbor->visitid == samevisitid)
+      SETref_(ridge)= NULL; /* ridge free'd below */
+  }
+  qh_setcompact(qh, newfacet->ridges);
+
+  trace4((qh, qh->ferr, 4034, "qh_mergecycle_ridges: add ridges to newfacet\n"));
+  FORALLsame_cycle_(samecycle) {
+    FOREACHridge_(same->ridges) {
+      if (ridge->top == same) {
+        ridge->top= newfacet;
+        neighbor= ridge->bottom;
+      }else if (ridge->bottom == same) {
+        ridge->bottom= newfacet;
+        neighbor= ridge->top;
+      }else if (ridge->top == newfacet || ridge->bottom == newfacet) {
+        qh_setappend(qh, &newfacet->ridges, ridge);
+        numold++;  /* already set by qh_mergecycle_neighbors */
+        continue;
+      }else {
+        qh_fprintf(qh, qh->ferr, 6098, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);
+        qh_errexit(qh, qh_ERRqhull, NULL, ridge);
+      }
+      if (neighbor == newfacet) {
+        if (qh->traceridge == ridge)
+          qh->traceridge= NULL;
+        qh_setfree(qh, &(ridge->vertices));
+        qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
+        numold++;
+      }else if (neighbor->visitid == samevisitid) {
+        qh_setdel(neighbor->ridges, ridge);
+        if (qh->traceridge == ridge)
+          qh->traceridge= NULL;
+        qh_setfree(qh, &(ridge->vertices));
+        qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
+        numold++;
+      }else {
+        qh_setappend(qh, &newfacet->ridges, ridge);
+        numold++;
+      }
+    }
+    if (same->ridges)
+      qh_settruncate(qh, same->ridges, 0);
+    if (!same->simplicial)
+      continue;
+    FOREACHneighbor_i_(qh, same) {       /* note: !newfact->simplicial */
+      if (neighbor->visitid != samevisitid && neighbor->simplicial) {
+        ridge= qh_newridge(qh);
+        ridge->vertices= qh_setnew_delnthsorted(qh, same->vertices, qh->hull_dim,
+                                                          neighbor_i, 0);
+        toporient= (boolT)(same->toporient ^ (neighbor_i & 0x1));
+        if (toporient) {
+          ridge->top= newfacet;
+          ridge->bottom= neighbor;
+          ridge->simplicialbot= True;
+        }else {
+          ridge->top= neighbor;
+          ridge->bottom= newfacet;
+          ridge->simplicialtop= True;
+        }
+        qh_setappend(qh, &(newfacet->ridges), ridge);
+        qh_setappend(qh, &(neighbor->ridges), ridge);
+        if (qh->ridge_id == qh->traceridge_id)
+          qh->traceridge= ridge;
+        numnew++;
+      }
+    }
+  }
+
+  trace2((qh, qh->ferr, 2033, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n",
+             numold, numnew));
+} /* mergecycle_ridges */
+
+/*---------------------------------
+
+  qh_mergecycle_vneighbors(qh, samecycle, newfacet )
+    create vertex neighbors for newfacet from vertices of facets in samecycle
+    samecycle marked with visitid == qh.visit_id - 1
+
+  returns:
+    newfacet vertices with updated neighbors
+    marks newfacet with qh.visit_id-1
+    deletes vertices that are merged away
+    sets delridge on all vertices (faster here than in mergecycle_ridges)
+
+  see:
+    qh_mergevertex_neighbors()
+
+  design:
+    for each vertex of samecycle facet
+      set vertex->delridge
+      delete samecycle facets from vertex neighbors
+      append newfacet to vertex neighbors
+      if vertex only in newfacet
+        delete it from newfacet
+        add it to qh.del_vertices for later deletion
+*/
+void qh_mergecycle_vneighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {
+  facetT *neighbor, **neighborp;
+  unsigned int mergeid;
+  vertexT *vertex, **vertexp, *apex;
+  setT *vertices;
+
+  trace4((qh, qh->ferr, 4035, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));
+  mergeid= qh->visit_id - 1;
+  newfacet->visitid= mergeid;
+  vertices= qh_basevertices(qh, samecycle); /* temp */
+  apex= SETfirstt_(samecycle->vertices, vertexT);
+  qh_setappend(qh, &vertices, apex);
+  FOREACHvertex_(vertices) {
+    vertex->delridge= True;
+    FOREACHneighbor_(vertex) {
+      if (neighbor->visitid == mergeid)
+        SETref_(neighbor)= NULL;
+    }
+    qh_setcompact(qh, vertex->neighbors);
+    qh_setappend(qh, &vertex->neighbors, newfacet);
+    if (!SETsecond_(vertex->neighbors)) {
+      zinc_(Zcyclevertex);
+      trace2((qh, qh->ferr, 2034, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",
+        vertex->id, samecycle->id, newfacet->id));
+      qh_setdelsorted(newfacet->vertices, vertex);
+      vertex->deleted= True;
+      qh_setappend(qh, &qh->del_vertices, vertex);
+    }
+  }
+  qh_settempfree(qh, &vertices);
+  trace3((qh, qh->ferr, 3005, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n",
+             samecycle->id, newfacet->id));
+} /* mergecycle_vneighbors */
+
+/*---------------------------------
+
+  qh_mergefacet(qh, facet1, facet2, mergetype, mindist, maxdist, mergeapex )
+    merges facet1 into facet2
+    mergeapex==qh_MERGEapex if merging new facet into coplanar horizon (optimizes qh_mergesimplex)
+
+  returns:
+    qh.max_outside and qh.min_vertex updated
+    initializes vertex neighbors on first merge
+
+  note:
+    mergetype only used for logging and error reporting
+
+  returns:
+    facet2 contains facet1's vertices, neighbors, and ridges
+      facet2 moved to end of qh.facet_list
+      makes facet2 a newfacet
+      sets facet2->newmerge set
+      clears facet2->center (unless merging into a large facet)
+      clears facet2->tested and ridge->tested for facet1
+
+    facet1 prepended to visible_list for later deletion and partitioning
+      facet1->f.replace == facet2
+
+    adds neighboring facets to facet_mergeset if redundant or degenerate
+
+  notes:
+    when done, tests facet1 and facet2 for degenerate or redundant neighbors and dupridges
+    mindist/maxdist may be NULL (only if both NULL)
+    traces merge if fmax_(maxdist,-mindist) > TRACEdist
+
+  see:
+    qh_mergecycle()
+
+  design:
+    trace merge and check for degenerate simplex
+    make ridges for both facets
+    update qh.max_outside, qh.max_vertex, qh.min_vertex
+    update facet2->maxoutside and keepcentrum
+    update facet2->nummerge
+    update tested flags for facet2
+    if facet1 is simplicial
+      merge facet1 into facet2
+    else
+      merge facet1's neighbors into facet2
+      merge facet1's ridges into facet2
+      merge facet1's vertices into facet2
+      merge facet1's vertex neighbors into facet2
+      add facet2's vertices to qh.new_vertexlist
+    move facet2 to end of qh.newfacet_list
+    unless MRGcoplanarhorizon
+      test facet2 for redundant neighbors
+      test facet1 for degenerate neighbors
+      test for redundant facet2
+      maybe test for duplicate ridges ('Q17')
+    move facet1 to qh.visible_list for later deletion
+*/
+void qh_mergefacet(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype, realT *mindist, realT *maxdist, boolT mergeapex) {
+  boolT traceonce= False;
+  vertexT *vertex, **vertexp;
+  realT mintwisted, vertexdist;
+  realT onemerge;
+  int tracerestore=0, nummerge;
+  const char *mergename;
+
+  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
+    mergename= mergetypes[mergetype];
+  else
+    mergename= mergetypes[MRGnone];
+  if (facet1->tricoplanar || facet2->tricoplanar) {
+    if (!qh->TRInormals) {
+      qh_fprintf(qh, qh->ferr, 6226, "qhull internal error (qh_mergefacet): merge f%d into f%d for mergetype %d (%s) does not work for tricoplanar facets.  Use option 'Q11'\n",
+        facet1->id, facet2->id, mergetype, mergename);
+      qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
+    }
+    if (facet2->tricoplanar) {
+      facet2->tricoplanar= False;
+      facet2->keepcentrum= False;
+    }
+  }
+  zzinc_(Ztotmerge);
+  if (qh->REPORTfreq2 && qh->POSTmerging) {
+    if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)
+      qh_tracemerging(qh);
+  }
+#ifndef qh_NOtrace
+  if (qh->build_cnt >= qh->RERUN) {
+    if (mindist && (-*mindist > qh->TRACEdist || *maxdist > qh->TRACEdist)) {
+      tracerestore= 0;
+      qh->IStracing= qh->TRACElevel;
+      traceonce= True;
+      qh_fprintf(qh, qh->ferr, 8075, "qh_mergefacet: ========= trace wide merge #%d(%2.2g) for f%d into f%d for mergetype %d (%s), last point was p%d\n",
+          zzval_(Ztotmerge), fmax_(-*mindist, *maxdist), facet1->id, facet2->id, mergetype, mergename, qh->furthest_id);
+    }else if (facet1 == qh->tracefacet || facet2 == qh->tracefacet) {
+      tracerestore= qh->IStracing;
+      qh->IStracing= 4;
+      traceonce= True;
+      qh_fprintf(qh, qh->ferr, 8076, "qh_mergefacet: ========= trace merge #%d for f%d into f%d for mergetype %d (%s), furthest is p%d\n",
+                 zzval_(Ztotmerge), facet1->id, facet2->id, mergetype, mergename, qh->furthest_id);
+    }
+  }
+  if (qh->IStracing >= 2) {
+    realT mergemin= -2;
+    realT mergemax= -2;
+
+    if (mindist) {
+      mergemin= *mindist;
+      mergemax= *maxdist;
+    }
+    qh_fprintf(qh, qh->ferr, 2081, "qh_mergefacet: #%d merge f%d into f%d for merge for mergetype %d (%s), mindist= %2.2g, maxdist= %2.2g, max_outside %2.2g\n",
+    zzval_(Ztotmerge), facet1->id, facet2->id, mergetype, mergename, mergemin, mergemax, qh->max_outside);
+  }
+#endif /* !qh_NOtrace */
+  if(!qh->ALLOWwide && mindist) {
+    mintwisted= qh_WIDEmaxoutside * qh->ONEmerge;  /* same as qh_merge_twisted and qh_check_maxout (poly2) */
+    maximize_(mintwisted, facet1->maxoutside);
+    maximize_(mintwisted, facet2->maxoutside);
+    if (*maxdist > mintwisted || -*mindist > mintwisted) {
+      vertexdist= qh_vertex_bestdist(qh, facet1->vertices);
+      onemerge= qh->ONEmerge + qh->DISTround;
+      if (vertexdist > mintwisted) {
+        qh_fprintf(qh, qh->ferr, 6347, "qhull precision error (qh_mergefacet): wide merge for facet f%d into f%d for mergetype %d (%s).  maxdist %2.2g (%.1fx) mindist %2.2g (%.1fx) vertexdist %2.2g  Allow with 'Q12' (allow-wide)\n",
+          facet1->id, facet2->id, mergetype, mergename, *maxdist, *maxdist/onemerge, *mindist, -*mindist/onemerge, vertexdist);
+      }else {
+        qh_fprintf(qh, qh->ferr, 6348, "qhull precision error (qh_mergefacet): wide merge for pinched facet f%d into f%d for mergetype %d (%s).  maxdist %2.2g (%.fx) mindist %2.2g (%.1fx) vertexdist %2.2g  Allow with 'Q12' (allow-wide)\n",
+          facet1->id, facet2->id, mergetype, mergename, *maxdist, *maxdist/onemerge, *mindist, -*mindist/onemerge, vertexdist);
+      }
+      qh_errexit2(qh, qh_ERRwide, facet1, facet2);
+    }
+  }
+  if (facet1 == facet2 || facet1->visible || facet2->visible) {
+    qh_fprintf(qh, qh->ferr, 6099, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet, mergetype %d (%s)\n",
+             facet1->id, facet2->id, mergetype, mergename);
+    qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
+  }
+  if (qh->num_facets - qh->num_visible <= qh->hull_dim + 1) {
+    qh_fprintf(qh, qh->ferr, 6227, "qhull topology error: Only %d facets remain.  The input is too degenerate or the convexity constraints are too strong.\n",
+          qh->hull_dim+1);
+    if (qh->hull_dim >= 5 && !qh->MERGEexact)
+      qh_fprintf(qh, qh->ferr, 8079, "    Option 'Qx' may avoid this problem.\n");
+    qh_errexit(qh, qh_ERRtopology, NULL, NULL);
+  }
+  if (!qh->VERTEXneighbors)
+    qh_vertexneighbors(qh);
+  qh_makeridges(qh, facet1);
+  qh_makeridges(qh, facet2);
+  if (qh->IStracing >=4)
+    qh_errprint(qh, "MERGING", facet1, facet2, NULL, NULL);
+  if (mindist) {
+    maximize_(qh->max_outside, *maxdist);
+    maximize_(qh->max_vertex, *maxdist);
+#if qh_MAXoutside
+    maximize_(facet2->maxoutside, *maxdist);
+#endif
+    minimize_(qh->min_vertex, *mindist);
+    if (!facet2->keepcentrum
+    && (*maxdist > qh->WIDEfacet || *mindist < -qh->WIDEfacet)) {
+      facet2->keepcentrum= True;
+      zinc_(Zwidefacet);
+    }
+  }
+  nummerge= facet1->nummerge + facet2->nummerge + 1;
+  if (nummerge >= qh_MAXnummerge)
+    facet2->nummerge= qh_MAXnummerge;
+  else
+    facet2->nummerge= (short unsigned int)nummerge; /* limited to 9 bits by qh_MAXnummerge, -Wconversion */
+  facet2->newmerge= True;
+  facet2->dupridge= False;
+  qh_updatetested(qh, facet1, facet2);
+  if (qh->hull_dim > 2 && qh_setsize(qh, facet1->vertices) == qh->hull_dim)
+    qh_mergesimplex(qh, facet1, facet2, mergeapex);
+  else {
+    qh->vertex_visit++;
+    FOREACHvertex_(facet2->vertices)
+      vertex->visitid= qh->vertex_visit;
+    if (qh->hull_dim == 2)
+      qh_mergefacet2d(qh, facet1, facet2);
+    else {
+      qh_mergeneighbors(qh, facet1, facet2);
+      qh_mergevertices(qh, facet1->vertices, &facet2->vertices);
+    }
+    qh_mergeridges(qh, facet1, facet2);
+    qh_mergevertex_neighbors(qh, facet1, facet2);
+    if (!facet2->newfacet)
+      qh_newvertices(qh, facet2->vertices);
+  }
+  if (facet2->coplanarhorizon) {
+    zinc_(Zmergeintocoplanar);
+  }else if (!facet2->newfacet) {
+    zinc_(Zmergeintohorizon);
+  }else if (!facet1->newfacet && facet2->newfacet) {
+    zinc_(Zmergehorizon);
+  }else {
+    zinc_(Zmergenew);
+  }
+  qh_removefacet(qh, facet2);  /* append as a newfacet to end of qh->facet_list */
+  qh_appendfacet(qh, facet2);
+  facet2->newfacet= True;
+  facet2->tested= False;
+  qh_tracemerge(qh, facet1, facet2, mergetype);
+  if (traceonce) {
+    qh_fprintf(qh, qh->ferr, 8080, "qh_mergefacet: end of wide tracing\n");
+    qh->IStracing= tracerestore;
+  }
+  if (mergetype != MRGcoplanarhorizon) {
+    trace3((qh, qh->ferr, 3076, "qh_mergefacet: check f%d and f%d for redundant and degenerate neighbors\n",
+        facet1->id, facet2->id));
+    qh_test_redundant_neighbors(qh, facet2);
+    qh_test_degen_neighbors(qh, facet1);  /* after qh_test_redundant_neighbors since MRGdegen more difficult than MRGredundant
+                                             and before qh_willdelete which clears facet1.neighbors */
+    qh_degen_redundant_facet(qh, facet2); /* may occur in qh_merge_pinchedvertices, e.g., rbox 175 C3,2e-13 D4 t1545228104 | qhull d */
+    qh_maybe_duplicateridges(qh, facet2);
+  }
+  qh_willdelete(qh, facet1, facet2);
+} /* mergefacet */
+
+
+/*---------------------------------
+
+  qh_mergefacet2d(qh, facet1, facet2 )
+    in 2d, merges neighbors and vertices of facet1 into facet2
+
+  returns:
+    build ridges for neighbors if necessary
+    facet2 looks like a simplicial facet except for centrum, ridges
+      neighbors are opposite the corresponding vertex
+      maintains orientation of facet2
+
+  notes:
+    qh_mergefacet() retains non-simplicial structures
+      they are not needed in 2d, but later routines may use them
+    preserves qh.vertex_visit for qh_mergevertex_neighbors()
+
+  design:
+    get vertices and neighbors
+    determine new vertices and neighbors
+    set new vertices and neighbors and adjust orientation
+    make ridges for new neighbor if needed
+*/
+void qh_mergefacet2d(qhT *qh, facetT *facet1, facetT *facet2) {
+  vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;
+  facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;
+
+  vertex1A= SETfirstt_(facet1->vertices, vertexT);
+  vertex1B= SETsecondt_(facet1->vertices, vertexT);
+  vertex2A= SETfirstt_(facet2->vertices, vertexT);
+  vertex2B= SETsecondt_(facet2->vertices, vertexT);
+  neighbor1A= SETfirstt_(facet1->neighbors, facetT);
+  neighbor1B= SETsecondt_(facet1->neighbors, facetT);
+  neighbor2A= SETfirstt_(facet2->neighbors, facetT);
+  neighbor2B= SETsecondt_(facet2->neighbors, facetT);
+  if (vertex1A == vertex2A) {
+    vertexA= vertex1B;
+    vertexB= vertex2B;
+    neighborA= neighbor2A;
+    neighborB= neighbor1A;
+  }else if (vertex1A == vertex2B) {
+    vertexA= vertex1B;
+    vertexB= vertex2A;
+    neighborA= neighbor2B;
+    neighborB= neighbor1A;
+  }else if (vertex1B == vertex2A) {
+    vertexA= vertex1A;
+    vertexB= vertex2B;
+    neighborA= neighbor2A;
+    neighborB= neighbor1B;
+  }else { /* 1B == 2B */
+    vertexA= vertex1A;
+    vertexB= vertex2A;
+    neighborA= neighbor2B;
+    neighborB= neighbor1B;
+  }
+  /* vertexB always from facet2, neighborB always from facet1 */
+  if (vertexA->id > vertexB->id) {
+    SETfirst_(facet2->vertices)= vertexA;
+    SETsecond_(facet2->vertices)= vertexB;
+    if (vertexB == vertex2A)
+      facet2->toporient= !facet2->toporient;
+    SETfirst_(facet2->neighbors)= neighborA;
+    SETsecond_(facet2->neighbors)= neighborB;
+  }else {
+    SETfirst_(facet2->vertices)= vertexB;
+    SETsecond_(facet2->vertices)= vertexA;
+    if (vertexB == vertex2B)
+      facet2->toporient= !facet2->toporient;
+    SETfirst_(facet2->neighbors)= neighborB;
+    SETsecond_(facet2->neighbors)= neighborA;
+  }
+  /* qh_makeridges not needed since neighborB is not degenerate */
+  qh_setreplace(qh, neighborB->neighbors, facet1, facet2);
+  trace4((qh, qh->ferr, 4036, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",
+       vertexA->id, neighborB->id, facet1->id, facet2->id));
+} /* mergefacet2d */
+
+
+/*---------------------------------
+
+  qh_mergeneighbors(qh, facet1, facet2 )
+    merges the neighbors of facet1 into facet2
+
+  notes:
+    only called by qh_mergefacet
+    qh.hull_dim >= 3
+    see qh_mergecycle_neighbors
+
+  design:
+    for each neighbor of facet1
+      if neighbor is also a neighbor of facet2
+        if neighbor is simplicial
+          make ridges for later deletion as a degenerate facet
+        update its neighbor set
+      else
+        move the neighbor relation to facet2
+    remove the neighbor relation for facet1 and facet2
+*/
+void qh_mergeneighbors(qhT *qh, facetT *facet1, facetT *facet2) {
+  facetT *neighbor, **neighborp;
+
+  trace4((qh, qh->ferr, 4037, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",
+          facet1->id, facet2->id));
+  qh->visit_id++;
+  FOREACHneighbor_(facet2) {
+    neighbor->visitid= qh->visit_id;
+  }
+  FOREACHneighbor_(facet1) {
+    if (neighbor->visitid == qh->visit_id) {
+      if (neighbor->simplicial)    /* is degen, needs ridges */
+        qh_makeridges(qh, neighbor);
+      if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/
+        qh_setdel(neighbor->neighbors, facet1);
+      else {
+        qh_setdel(neighbor->neighbors, facet2);
+        qh_setreplace(qh, neighbor->neighbors, facet1, facet2);
+      }
+    }else if (neighbor != facet2) {
+      qh_setappend(qh, &(facet2->neighbors), neighbor);
+      qh_setreplace(qh, neighbor->neighbors, facet1, facet2);
+    }
+  }
+  qh_setdel(facet1->neighbors, facet2);  /* here for makeridges */
+  qh_setdel(facet2->neighbors, facet1);
+} /* mergeneighbors */
+
+
+/*---------------------------------
+
+  qh_mergeridges(qh, facet1, facet2 )
+    merges the ridge set of facet1 into facet2
+
+  returns:
+    may delete all ridges for a vertex
+    sets vertex->delridge on deleted ridges
+
+  see:
+    qh_mergecycle_ridges()
+
+  design:
+    delete ridges between facet1 and facet2
+      mark (delridge) vertices on these ridges for later testing
+    for each remaining ridge
+      rename facet1 to facet2
+*/
+void qh_mergeridges(qhT *qh, facetT *facet1, facetT *facet2) {
+  ridgeT *ridge, **ridgep;
+
+  trace4((qh, qh->ferr, 4038, "qh_mergeridges: merge ridges of f%d into f%d\n",
+          facet1->id, facet2->id));
+  FOREACHridge_(facet2->ridges) {
+    if ((ridge->top == facet1) || (ridge->bottom == facet1)) {
+      /* ridge.nonconvex is irrelevant due to merge */
+      qh_delridge_merge(qh, ridge);  /* expensive in high-d, could rebuild */
+      ridgep--; /* deleted this ridge, repeat with next ridge*/
+    }
+  }
+  FOREACHridge_(facet1->ridges) {
+    if (ridge->top == facet1) {
+      ridge->top= facet2;
+      ridge->simplicialtop= False;
+    }else { /* ridge.bottom is facet1 */
+      ridge->bottom= facet2;
+      ridge->simplicialbot= False;
+    }
+    qh_setappend(qh, &(facet2->ridges), ridge);
+  }
+} /* mergeridges */
+
+
+/*---------------------------------
+
+  qh_mergesimplex(qh, facet1, facet2, mergeapex )
+    merge simplicial facet1 into facet2
+    mergeapex==qh_MERGEapex if merging samecycle into horizon facet
+      vertex id is latest (most recently created)
+    facet1 may be contained in facet2
+    ridges exist for both facets
+
+  returns:
+    facet2 with updated vertices, ridges, neighbors
+    updated neighbors for facet1's vertices
+    facet1 not deleted
+    sets vertex->delridge on deleted ridges
+
+  notes:
+    special case code since this is the most common merge
+    called from qh_mergefacet()
+
+  design:
+    if qh_MERGEapex
+      add vertices of facet2 to qh.new_vertexlist if necessary
+      add apex to facet2
+    else
+      for each ridge between facet1 and facet2
+        set vertex->delridge
+      determine the apex for facet1 (i.e., vertex to be merged)
+      unless apex already in facet2
+        insert apex into vertices for facet2
+      add vertices of facet2 to qh.new_vertexlist if necessary
+      add apex to qh.new_vertexlist if necessary
+      for each vertex of facet1
+        if apex
+          rename facet1 to facet2 in its vertex neighbors
+        else
+          delete facet1 from vertex neighbors
+          if only in facet2
+            add vertex to qh.del_vertices for later deletion
+      for each ridge of facet1
+        delete ridges between facet1 and facet2
+        append other ridges to facet2 after renaming facet to facet2
+*/
+void qh_mergesimplex(qhT *qh, facetT *facet1, facetT *facet2, boolT mergeapex) {
+  vertexT *vertex, **vertexp, *opposite;
+  ridgeT *ridge, **ridgep;
+  boolT isnew= False;
+  facetT *neighbor, **neighborp, *otherfacet;
+
+  if (mergeapex) {
+    opposite= SETfirstt_(facet1->vertices, vertexT); /* apex is opposite facet2.  It has the last vertex id */
+    trace4((qh, qh->ferr, 4086, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",
+      opposite->id, facet1->id, facet2->id));
+    if (!facet2->newfacet)
+      qh_newvertices(qh, facet2->vertices);  /* apex, the first vertex, is already new */
+    if (SETfirstt_(facet2->vertices, vertexT) != opposite) {
+      qh_setaddnth(qh, &facet2->vertices, 0, opposite);
+      isnew= True;
+    }
+  }else {
+    zinc_(Zmergesimplex);
+    FOREACHvertex_(facet1->vertices)
+      vertex->seen= False;
+    FOREACHridge_(facet1->ridges) {
+      if (otherfacet_(ridge, facet1) == facet2) {
+        FOREACHvertex_(ridge->vertices) {
+          vertex->seen= True;
+          vertex->delridge= True;
+        }
+        break;
+      }
+    }
+    FOREACHvertex_(facet1->vertices) {
+      if (!vertex->seen)
+        break;  /* must occur */
+    }
+    opposite= vertex;
+    trace4((qh, qh->ferr, 4039, "qh_mergesimplex: merge opposite v%d of f%d into facet f%d\n",
+          opposite->id, facet1->id, facet2->id));
+    isnew= qh_addfacetvertex(qh, facet2, opposite);
+    if (!facet2->newfacet)
+      qh_newvertices(qh, facet2->vertices);
+    else if (!opposite->newfacet) {
+      qh_removevertex(qh, opposite);
+      qh_appendvertex(qh, opposite);
+    }
+  }
+  trace4((qh, qh->ferr, 4040, "qh_mergesimplex: update vertex neighbors of f%d\n",
+          facet1->id));
+  FOREACHvertex_(facet1->vertices) {
+    if (vertex == opposite && isnew)
+      qh_setreplace(qh, vertex->neighbors, facet1, facet2);
+    else {
+      qh_setdel(vertex->neighbors, facet1);
+      if (!SETsecond_(vertex->neighbors))
+        qh_mergevertex_del(qh, vertex, facet1, facet2);
+    }
+  }
+  trace4((qh, qh->ferr, 4041, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",
+          facet1->id, facet2->id));
+  qh->visit_id++;
+  FOREACHneighbor_(facet2)
+    neighbor->visitid= qh->visit_id;
+  FOREACHridge_(facet1->ridges) {
+    otherfacet= otherfacet_(ridge, facet1);
+    if (otherfacet == facet2) {
+      /* ridge.nonconvex is irrelevant due to merge */
+      qh_delridge_merge(qh, ridge);  /* expensive in high-d, could rebuild */
+      ridgep--; /* deleted this ridge, repeat with next ridge*/
+      qh_setdel(facet2->neighbors, facet1); /* a simplicial facet may have duplicate neighbors, need to delete each one */
+    }else if (otherfacet->dupridge && !qh_setin(otherfacet->neighbors, facet1)) {
+      qh_fprintf(qh, qh->ferr, 6356, "qhull topology error (qh_mergesimplex): f%d is a dupridge of f%d, cannot merge f%d into f%d\n",
+        facet1->id, otherfacet->id, facet1->id, facet2->id);
+      qh_errexit2(qh, qh_ERRqhull, facet1, otherfacet);
+    }else {
+      trace4((qh, qh->ferr, 4059, "qh_mergesimplex: move r%d with f%d to f%d, new neighbor? %d, maybe horizon? %d\n",
+        ridge->id, otherfacet->id, facet2->id, (otherfacet->visitid != qh->visit_id), (SETfirstt_(otherfacet->neighbors, facetT) == facet1)));
+      qh_setappend(qh, &facet2->ridges, ridge);
+      if (otherfacet->visitid != qh->visit_id) {
+        qh_setappend(qh, &facet2->neighbors, otherfacet);
+        qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);
+        otherfacet->visitid= qh->visit_id;
+      }else {
+        if (otherfacet->simplicial)    /* is degen, needs ridges */
+          qh_makeridges(qh, otherfacet);
+        if (SETfirstt_(otherfacet->neighbors, facetT) == facet1) {
+          /* keep new, otherfacet->neighbors->horizon */
+          qh_setdel(otherfacet->neighbors, facet2);
+          qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);
+        }else {
+          /* facet2 is already a neighbor of otherfacet, by f.visitid */
+          qh_setdel(otherfacet->neighbors, facet1);
+        }
+      }
+      if (ridge->top == facet1) { /* wait until after qh_makeridges */
+        ridge->top= facet2;
+        ridge->simplicialtop= False;
+      }else {
+        ridge->bottom= facet2;
+        ridge->simplicialbot= False;
+      }
+    }
+  }
+  trace3((qh, qh->ferr, 3006, "qh_mergesimplex: merged simplex f%d v%d into facet f%d\n",
+          facet1->id, opposite->id, facet2->id));
+} /* mergesimplex */
+
+/*---------------------------------
+
+  qh_mergevertex_del(qh, vertex, facet1, facet2 )
+    delete a vertex because of merging facet1 into facet2
+
+  returns:
+    deletes vertex from facet2
+    adds vertex to qh.del_vertices for later deletion
+*/
+void qh_mergevertex_del(qhT *qh, vertexT *vertex, facetT *facet1, facetT *facet2) {
+
+  zinc_(Zmergevertex);
+  trace2((qh, qh->ferr, 2035, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",
+          vertex->id, facet1->id, facet2->id));
+  qh_setdelsorted(facet2->vertices, vertex);
+  vertex->deleted= True;
+  qh_setappend(qh, &qh->del_vertices, vertex);
+} /* mergevertex_del */
+
+/*---------------------------------
+
+  qh_mergevertex_neighbors(qh, facet1, facet2 )
+    merge the vertex neighbors of facet1 to facet2
+
+  returns:
+    if vertex is current qh.vertex_visit
+      deletes facet1 from vertex->neighbors
+    else
+      renames facet1 to facet2 in vertex->neighbors
+    deletes vertices if only one neighbor
+
+  notes:
+    assumes vertex neighbor sets are good
+*/
+void qh_mergevertex_neighbors(qhT *qh, facetT *facet1, facetT *facet2) {
+  vertexT *vertex, **vertexp;
+
+  trace4((qh, qh->ferr, 4042, "qh_mergevertex_neighbors: merge vertex neighborset for f%d into f%d\n",
+          facet1->id, facet2->id));
+  if (qh->tracevertex) {
+    qh_fprintf(qh, qh->ferr, 8081, "qh_mergevertex_neighbors: of f%d into f%d at furthest p%d f0= %p\n",
+             facet1->id, facet2->id, qh->furthest_id, (void *) qh->tracevertex->neighbors->e[0].p);
+    qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);
+  }
+  FOREACHvertex_(facet1->vertices) {
+    if (vertex->visitid != qh->vertex_visit)
+      qh_setreplace(qh, vertex->neighbors, facet1, facet2);
+    else {
+      qh_setdel(vertex->neighbors, facet1);
+      if (!SETsecond_(vertex->neighbors))
+        qh_mergevertex_del(qh, vertex, facet1, facet2);
+    }
+  }
+  if (qh->tracevertex)
+    qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);
+} /* mergevertex_neighbors */
+
+
+/*---------------------------------
+
+  qh_mergevertices(qh, vertices1, vertices2 )
+    merges the vertex set of facet1 into facet2
+
+  returns:
+    replaces vertices2 with merged set
+    preserves vertex_visit for qh_mergevertex_neighbors
+    updates qh.newvertex_list
+
+  design:
+    create a merged set of both vertices (in inverse id order)
+*/
+void qh_mergevertices(qhT *qh, setT *vertices1, setT **vertices2) {
+  int newsize= qh_setsize(qh, vertices1)+qh_setsize(qh, *vertices2) - qh->hull_dim + 1;
+  setT *mergedvertices;
+  vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);
+
+  mergedvertices= qh_settemp(qh, newsize);
+  FOREACHvertex_(vertices1) {
+    if (!*vertex2 || vertex->id > (*vertex2)->id)
+      qh_setappend(qh, &mergedvertices, vertex);
+    else {
+      while (*vertex2 && (*vertex2)->id > vertex->id)
+        qh_setappend(qh, &mergedvertices, *vertex2++);
+      if (!*vertex2 || (*vertex2)->id < vertex->id)
+        qh_setappend(qh, &mergedvertices, vertex);
+      else
+        qh_setappend(qh, &mergedvertices, *vertex2++);
+    }
+  }
+  while (*vertex2)
+    qh_setappend(qh, &mergedvertices, *vertex2++);
+  if (newsize < qh_setsize(qh, mergedvertices)) {
+    qh_fprintf(qh, qh->ferr, 6100, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh_setfree(qh, vertices2);
+  *vertices2= mergedvertices;
+  qh_settemppop(qh);
+} /* mergevertices */
+
+
+/*---------------------------------
+
+  qh_neighbor_intersections(qh, vertex )
+    return intersection of all vertices in vertex->neighbors except for vertex
+
+  returns:
+    returns temporary set of vertices
+    does not include vertex
+    NULL if a neighbor is simplicial
+    NULL if empty set
+
+  notes:
+    only called by qh_redundant_vertex for qh_reducevertices
+      so f.vertices does not contain extraneous vertices that are not in f.ridges
+    used for renaming vertices
+
+  design:
+    initialize the intersection set with vertices of the first two neighbors
+    delete vertex from the intersection
+    for each remaining neighbor
+      intersect its vertex set with the intersection set
+      return NULL if empty
+    return the intersection set
+*/
+setT *qh_neighbor_intersections(qhT *qh, vertexT *vertex) {
+  facetT *neighbor, **neighborp, *neighborA, *neighborB;
+  setT *intersect;
+  int neighbor_i, neighbor_n;
+
+  FOREACHneighbor_(vertex) {
+    if (neighbor->simplicial)
+      return NULL;
+  }
+  neighborA= SETfirstt_(vertex->neighbors, facetT);
+  neighborB= SETsecondt_(vertex->neighbors, facetT);
+  zinc_(Zintersectnum);
+  if (!neighborA)
+    return NULL;
+  if (!neighborB)
+    intersect= qh_setcopy(qh, neighborA->vertices, 0);
+  else
+    intersect= qh_vertexintersect_new(qh, neighborA->vertices, neighborB->vertices);
+  qh_settemppush(qh, intersect);
+  qh_setdelsorted(intersect, vertex);
+  FOREACHneighbor_i_(qh, vertex) {
+    if (neighbor_i >= 2) {
+      zinc_(Zintersectnum);
+      qh_vertexintersect(qh, &intersect, neighbor->vertices);
+      if (!SETfirst_(intersect)) {
+        zinc_(Zintersectfail);
+        qh_settempfree(qh, &intersect);
+        return NULL;
+      }
+    }
+  }
+  trace3((qh, qh->ferr, 3007, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n",
+          qh_setsize(qh, intersect), vertex->id));
+  return intersect;
+} /* neighbor_intersections */
+
+/*---------------------------------
+
+  qh_neighbor_vertices(qh, vertex )
+    return neighboring vertices for a vertex (not in subridge)
+    assumes vertices have full vertex->neighbors
+
+  returns:
+    temporary set of vertices
+
+  notes:
+    updates qh.visit_id and qh.vertex_visit
+    similar to qh_vertexridges
+
+*/
+setT *qh_neighbor_vertices(qhT *qh, vertexT *vertexA, setT *subridge) {
+  facetT *neighbor, **neighborp;
+  vertexT *vertex, **vertexp;
+  setT *vertices= qh_settemp(qh, qh->TEMPsize);
+
+  qh->visit_id++;
+  FOREACHneighbor_(vertexA)
+    neighbor->visitid= qh->visit_id;
+  qh->vertex_visit++;
+  vertexA->visitid= qh->vertex_visit;
+  FOREACHvertex_(subridge) {
+    vertex->visitid= qh->vertex_visit;
+  }
+  FOREACHneighbor_(vertexA) {
+    if (*neighborp)   /* no new ridges in last neighbor */
+      qh_neighbor_vertices_facet(qh, vertexA, neighbor, &vertices);
+  }
+  trace3((qh, qh->ferr, 3035, "qh_neighbor_vertices: %d non-subridge, vertex neighbors for v%d\n",
+    qh_setsize(qh, vertices), vertexA->id));
+  return vertices;
+} /* neighbor_vertices */
+
+/*---------------------------------
+
+  qh_neighbor_vertices_facet(qh, vertex, facet, vertices )
+    add neighboring vertices on ridges for vertex in facet
+    neighbor->visitid==qh.visit_id if it hasn't been visited
+    v.visitid==qh.vertex_visit if it is already in vertices
+
+  returns:
+    vertices updated
+    sets facet->visitid to qh.visit_id-1
+
+  notes:
+    only called by qh_neighbor_vertices
+    similar to qh_vertexridges_facet
+
+  design:
+    for each ridge of facet
+      if ridge of visited neighbor (i.e., unprocessed)
+        if vertex in ridge
+          append unprocessed vertices of ridge
+    mark facet processed
+*/
+void qh_neighbor_vertices_facet(qhT *qh, vertexT *vertexA, facetT *facet, setT **vertices) {
+  ridgeT *ridge, **ridgep;
+  facetT *neighbor;
+  vertexT *second, *last, *vertex, **vertexp;
+  int last_i= qh->hull_dim-2, count= 0;
+  boolT isridge;
+
+  if (facet->simplicial) {
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh->vertex_visit) {
+        vertex->visitid= qh->vertex_visit;
+        qh_setappend(qh, vertices, vertex);
+        count++;
+      }
+    }
+  }else {
+    FOREACHridge_(facet->ridges) {
+      neighbor= otherfacet_(ridge, facet);
+      if (neighbor->visitid == qh->visit_id) {
+        isridge= False;
+        if (SETfirst_(ridge->vertices) == vertexA) {
+          isridge= True;
+        }else if (last_i > 2) {
+          second= SETsecondt_(ridge->vertices, vertexT);
+          last= SETelemt_(ridge->vertices, last_i, vertexT);
+          if (second->id >= vertexA->id && last->id <= vertexA->id) { /* vertices inverse sorted by id */
+            if (second == vertexA || last == vertexA)
+              isridge= True;
+            else if (qh_setin(ridge->vertices, vertexA))
+              isridge= True;
+          }
+        }else if (SETelem_(ridge->vertices, last_i) == vertexA) {
+          isridge= True;
+        }else if (last_i > 1 && SETsecond_(ridge->vertices) == vertexA) {
+          isridge= True;
+        }
+        if (isridge) {
+          FOREACHvertex_(ridge->vertices) {
+            if (vertex->visitid != qh->vertex_visit) {
+              vertex->visitid= qh->vertex_visit;
+              qh_setappend(qh, vertices, vertex);
+              count++;
+            }
+          }
+        }
+      }
+    }
+  }
+  facet->visitid= qh->visit_id-1;
+  if (count) {
+    trace4((qh, qh->ferr, 4079, "qh_neighbor_vertices_facet: found %d vertex neighbors for v%d in f%d (simplicial? %d)\n",
+      count, vertexA->id, facet->id, facet->simplicial));
+  }
+} /* neighbor_vertices_facet */
+
+
+/*---------------------------------
+
+  qh_newvertices(qh, vertices )
+    add vertices to end of qh.vertex_list (marks as new vertices)
+
+  returns:
+    vertices on qh.newvertex_list
+    vertex->newfacet set
+*/
+void qh_newvertices(qhT *qh, setT *vertices) {
+  vertexT *vertex, **vertexp;
+
+  FOREACHvertex_(vertices) {
+    if (!vertex->newfacet) {
+      qh_removevertex(qh, vertex);
+      qh_appendvertex(qh, vertex);
+    }
+  }
+} /* newvertices */
+
+/*---------------------------------
+
+  qh_next_vertexmerge(qh )
+    return next vertex merge from qh.vertex_mergeset
+
+  returns:
+    vertex merge either MRGvertices or MRGsubridge
+    drops merges of deleted vertices
+
+  notes:
+    called from qh_merge_pinchedvertices
+*/
+mergeT *qh_next_vertexmerge(qhT *qh /* qh.vertex_mergeset */) {
+  mergeT *merge;
+  int merge_i, merge_n, best_i= -1;
+  realT bestdist= REALmax;
+
+  FOREACHmerge_i_(qh, qh->vertex_mergeset) {
+    if (!merge->vertex1 || !merge->vertex2) {
+      qh_fprintf(qh, qh->ferr, 6299, "qhull internal error (qh_next_vertexmerge): expecting two vertices for vertex merge.  Got v%d v%d and optional f%d\n",
+        getid_(merge->vertex1), getid_(merge->vertex2), getid_(merge->facet1));
+      qh_errexit(qh, qh_ERRqhull, merge->facet1, NULL);
+    }
+    if (merge->vertex1->deleted || merge->vertex2->deleted) {
+      trace3((qh, qh->ferr, 3030, "qh_next_vertexmerge: drop merge of v%d (del? %d) into v%d (del? %d) due to deleted vertex of r%d and r%d\n",
+        merge->vertex1->id, merge->vertex1->deleted, merge->vertex2->id, merge->vertex2->deleted, getid_(merge->ridge1), getid_(merge->ridge2)));
+      qh_drop_mergevertex(qh, merge);
+      qh_setdelnth(qh, qh->vertex_mergeset, merge_i);
+      merge_i--; merge_n--;
+      qh_memfree(qh, merge, (int)sizeof(mergeT));
+    }else if (merge->distance < bestdist) {
+      bestdist= merge->distance;
+      best_i= merge_i;
+    }
+  }
+  merge= NULL;
+  if (best_i >= 0) {
+    merge= SETelemt_(qh->vertex_mergeset, best_i, mergeT);
+    if (bestdist/qh->ONEmerge > qh_WIDEpinched) {
+      if (merge->mergetype==MRGvertices) {
+        if (merge->ridge1->top == merge->ridge2->bottom && merge->ridge1->bottom == merge->ridge2->top)
+          qh_fprintf(qh, qh->ferr, 6391, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r%d and r%d in f%d and f%d.  Nearest v%d and v%d dist %2.2g (%.1fx)\n",
+            merge->ridge1->id, merge->ridge2->id, merge->ridge1->top->id, merge->ridge1->bottom->id, merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh->ONEmerge);
+        else
+          qh_fprintf(qh, qh->ferr, 6381, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r%d and r%d.  Nearest v%d and v%d dist %2.2g (%.1fx)\n",
+            merge->ridge1->id, merge->ridge2->id, merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh->ONEmerge);
+      }else {
+        qh_fprintf(qh, qh->ferr, 6208, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve dupridge.  Nearest v%d and v%d dist %2.2g (%.1fx)\n",
+          merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh->ONEmerge);
+      }
+      /* it may be possible to find a different vertex, after other vertex merges have occurred */
+      qh_errexit(qh, qh_ERRtopology, NULL, merge->ridge1);
+    }
+    qh_setdelnth(qh, qh->vertex_mergeset, best_i);
+  }
+  return merge;
+} /* next_vertexmerge */
+
+/*---------------------------------
+
+  qh_opposite_horizonfacet(qh, merge, opposite )
+    return horizon facet for one of the merge facets, and its opposite vertex across the ridge
+    assumes either facet1 or facet2 of merge is 'mergehorizon'
+    assumes both facets are simplicial facets on qh.new_facetlist
+
+  returns:
+    horizon facet and opposite vertex
+
+  notes:
+    called by qh_getpinchedmerges
+*/
+facetT *qh_opposite_horizonfacet(qhT *qh, mergeT *merge, vertexT **opposite) {
+  facetT *facet, *horizon, *otherfacet;
+  int neighbor_i;
+
+  if (!merge->facet1->simplicial || !merge->facet2->simplicial || (!merge->facet1->mergehorizon && !merge->facet2->mergehorizon)) {
+    qh_fprintf(qh, qh->ferr, 6273, "qhull internal error (qh_opposite_horizonfacet): expecting merge of simplicial facets, at least one of which is mergehorizon.  Either simplicial or mergehorizon is wrong\n");
+    qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
+  }
+  if (merge->facet1->mergehorizon) {
+    facet= merge->facet1;
+    otherfacet= merge->facet2;
+  }else {
+    facet= merge->facet2;
+    otherfacet= merge->facet1;
+  }
+  horizon= SETfirstt_(facet->neighbors, facetT);
+  neighbor_i= qh_setindex(otherfacet->neighbors, facet);
+  if (neighbor_i==-1)
+    neighbor_i= qh_setindex(otherfacet->neighbors, qh_MERGEridge);
+  if (neighbor_i==-1) {
+    qh_fprintf(qh, qh->ferr, 6238, "qhull internal error (qh_opposite_horizonfacet): merge facet f%d not connected to mergehorizon f%d\n",
+      otherfacet->id, facet->id);
+    qh_errexit2(qh, qh_ERRqhull, otherfacet, facet);
+  }
+  *opposite= SETelemt_(otherfacet->vertices, neighbor_i, vertexT);
+  return horizon;
+} /* opposite_horizonfacet */
+
+
+/*---------------------------------
+
+  qh_reducevertices(qh)
+    reduce extra vertices, shared vertices, and redundant vertices
+    facet->newmerge is set if merged since last call
+    vertex->delridge is set if vertex was on a deleted ridge
+    if !qh.MERGEvertices, only removes extra vertices
+
+  returns:
+    True if also merged degen_redundant facets
+    vertices are renamed if possible
+    clears facet->newmerge and vertex->delridge
+
+  notes:
+    called by qh_all_merges and qh_postmerge
+    ignored if 2-d
+
+  design:
+    merge any degenerate or redundant facets
+    repeat until no more degenerate or redundant facets
+      for each newly merged facet
+        remove extra vertices
+      if qh.MERGEvertices
+        for each newly merged facet
+          for each vertex
+            if vertex was on a deleted ridge
+              rename vertex if it is shared
+        for each new, undeleted vertex
+          remove delridge flag
+          if vertex is redundant
+            merge degenerate or redundant facets
+*/
+boolT qh_reducevertices(qhT *qh) {
+  int numshare=0, numrename= 0;
+  boolT degenredun= False;
+  facetT *newfacet;
+  vertexT *vertex, **vertexp;
+
+  if (qh->hull_dim == 2)
+    return False;
+  trace2((qh, qh->ferr, 2101, "qh_reducevertices: reduce extra vertices, shared vertices, and redundant vertices\n"));
+  if (qh_merge_degenredundant(qh))
+    degenredun= True;
+LABELrestart:
+  FORALLnew_facets {
+    if (newfacet->newmerge) {
+      if (!qh->MERGEvertices)
+        newfacet->newmerge= False;
+      if (qh_remove_extravertices(qh, newfacet)) {
+        qh_degen_redundant_facet(qh, newfacet);
+        if (qh_merge_degenredundant(qh)) {
+          degenredun= True;
+          goto LABELrestart;
+        }
+      }
+    }
+  }
+  if (!qh->MERGEvertices)
+    return False;
+  FORALLnew_facets {
+    if (newfacet->newmerge) {
+      newfacet->newmerge= False;
+      FOREACHvertex_(newfacet->vertices) {
+        if (vertex->delridge) {
+          if (qh_rename_sharedvertex(qh, vertex, newfacet)) {
+            numshare++;
+            if (qh_merge_degenredundant(qh)) {
+              degenredun= True;
+              goto LABELrestart;
+            }
+            vertexp--; /* repeat since deleted vertex */
+          }
+        }
+      }
+    }
+  }
+  FORALLvertex_(qh->newvertex_list) {
+    if (vertex->delridge && !vertex->deleted) {
+      vertex->delridge= False;
+      if (qh->hull_dim >= 4 && qh_redundant_vertex(qh, vertex)) {
+        numrename++;
+        if (qh_merge_degenredundant(qh)) {
+          degenredun= True;
+          goto LABELrestart;
+        }
+      }
+    }
+  }
+  trace1((qh, qh->ferr, 1014, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",
+          numshare, numrename, degenredun));
+  return degenredun;
+} /* reducevertices */
+
+/*---------------------------------
+
+  qh_redundant_vertex(qh, vertex )
+    rename a redundant vertex if qh_find_newvertex succeeds
+    assumes vertices have full vertex->neighbors
+
+  returns:
+    if find a replacement vertex
+      returns new vertex
+      qh_renamevertex sets vertex->deleted for redundant vertex
+
+  notes:
+    only called by qh_reducevertices for vertex->delridge and hull_dim >= 4
+    may add degenerate facets to qh.facet_mergeset
+    doesn't change vertex->neighbors or create redundant facets
+
+  design:
+    intersect vertices of all facet neighbors of vertex
+    determine ridges for these vertices
+    if find a new vertex for vertex among these ridges and vertices
+      rename vertex to the new vertex
+*/
+vertexT *qh_redundant_vertex(qhT *qh, vertexT *vertex) {
+  vertexT *newvertex= NULL;
+  setT *vertices, *ridges;
+
+  trace3((qh, qh->ferr, 3008, "qh_redundant_vertex: check if v%d from a deleted ridge can be renamed\n", vertex->id));
+  if ((vertices= qh_neighbor_intersections(qh, vertex))) {
+    ridges= qh_vertexridges(qh, vertex, !qh_ALL);
+    if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges))) {
+      zinc_(Zrenameall);
+      qh_renamevertex(qh, vertex, newvertex, ridges, NULL, NULL); /* ridges invalidated */
+    }
+    qh_settempfree(qh, &ridges);
+    qh_settempfree(qh, &vertices);
+  }
+  return newvertex;
+} /* redundant_vertex */
+
+/*---------------------------------
+
+  qh_remove_extravertices(qh, facet )
+    remove extra vertices from non-simplicial facets
+
+  returns:
+    returns True if it finds them
+      deletes facet from vertex neighbors
+      facet may be redundant (test with qh_degen_redundant)
+
+  notes:
+    called by qh_renamevertex and qh_reducevertices
+    a merge (qh_reducevertices) or qh_renamevertex may drop all ridges for a vertex in a facet
+
+  design:
+    for each vertex in facet
+      if vertex not in a ridge (i.e., no longer used)
+        delete vertex from facet
+        delete facet from vertex's neighbors
+        unless vertex in another facet
+          add vertex to qh.del_vertices for later deletion
+*/
+boolT qh_remove_extravertices(qhT *qh, facetT *facet) {
+  ridgeT *ridge, **ridgep;
+  vertexT *vertex, **vertexp;
+  boolT foundrem= False;
+
+  if (facet->simplicial) {
+    return False;
+  }
+  trace4((qh, qh->ferr, 4043, "qh_remove_extravertices: test non-simplicial f%d for extra vertices\n",
+          facet->id));
+  FOREACHvertex_(facet->vertices)
+    vertex->seen= False;
+  FOREACHridge_(facet->ridges) {
+    FOREACHvertex_(ridge->vertices)
+      vertex->seen= True;
+  }
+  FOREACHvertex_(facet->vertices) {
+    if (!vertex->seen) {
+      foundrem= True;
+      zinc_(Zremvertex);
+      qh_setdelsorted(facet->vertices, vertex);
+      qh_setdel(vertex->neighbors, facet);
+      if (!qh_setsize(qh, vertex->neighbors)) {
+        vertex->deleted= True;
+        qh_setappend(qh, &qh->del_vertices, vertex);
+        zinc_(Zremvertexdel);
+        trace2((qh, qh->ferr, 2036, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
+      }else
+        trace3((qh, qh->ferr, 3009, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));
+      vertexp--; /*repeat*/
+    }
+  }
+  return foundrem;
+} /* remove_extravertices */
+
+/*---------------------------------
+
+  qh_remove_mergetype(qh, mergeset, mergetype )
+    Remove mergetype merges from mergeset
+
+  notes:
+    Does not preserve order
+*/
+void qh_remove_mergetype(qhT *qh, setT *mergeset, mergeType type) {
+  mergeT *merge;
+  int merge_i, merge_n;
+
+  FOREACHmerge_i_(qh, mergeset) {
+    if (merge->mergetype == type) {
+        trace3((qh, qh->ferr, 3037, "qh_remove_mergetype: remove merge f%d f%d v%d v%d r%d r%d dist %2.2g type %d",
+            getid_(merge->facet1), getid_(merge->facet2), getid_(merge->vertex1), getid_(merge->vertex2), getid_(merge->ridge1), getid_(merge->ridge2), merge->distance, type));
+        qh_setdelnth(qh, mergeset, merge_i);
+        merge_i--; merge_n--;  /* repeat with next merge */
+    }
+  }
+} /* remove_mergetype */
+
+/*---------------------------------
+
+  qh_rename_adjacentvertex(qh, oldvertex, newvertex )
+    renames oldvertex as newvertex.  Must be adjacent (i.e., in the same subridge)
+    no-op if either vertex is deleted
+
+  notes:
+    called from qh_merge_pinchedvertices
+
+  design:
+    for all neighbors of oldvertex
+      if simplicial, rename oldvertex to newvertex and drop if degenerate
+      if needed, add oldvertex neighbor to newvertex
+    determine ridges for oldvertex
+    rename oldvertex as newvertex in ridges (qh_renamevertex)
+*/
+void qh_rename_adjacentvertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, realT dist) {
+  setT *ridges;
+  facetT *neighbor, **neighborp, *maxfacet= NULL;
+  ridgeT *ridge, **ridgep;
+  boolT istrace= False;
+  int oldsize= qh_setsize(qh, oldvertex->neighbors);
+  int newsize= qh_setsize(qh, newvertex->neighbors);
+  coordT maxdist2= -REALmax, dist2;
+
+  if (qh->IStracing >= 4 || oldvertex->id == qh->tracevertex_id || newvertex->id == qh->tracevertex_id) {
+    istrace= True;
+  }
+  zzinc_(Ztotmerge);
+  if (istrace) {
+    qh_fprintf(qh, qh->ferr, 2071, "qh_rename_adjacentvertex: merge #%d rename v%d (%d neighbors) to v%d (%d neighbors) dist %2.2g\n",
+      zzval_(Ztotmerge), oldvertex->id, oldsize, newvertex->id, newsize, dist);
+  }
+  if (oldvertex->deleted || newvertex->deleted) {
+    if (istrace || qh->IStracing >= 2) {
+      qh_fprintf(qh, qh->ferr, 2072, "qh_rename_adjacentvertex: ignore rename.  Either v%d (%d) or v%d (%d) is deleted\n",
+        oldvertex->id, oldvertex->deleted, newvertex->id, newvertex->deleted);
+    }
+    return;
+  }
+  if (oldsize == 0 || newsize == 0) {
+    qh_fprintf(qh, qh->ferr, 2072, "qhull internal error (qh_rename_adjacentvertex): expecting neighbor facets for v%d and v%d.  Got %d and %d neighbors resp.\n",
+      oldvertex->id, newvertex->id, oldsize, newsize);
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  FOREACHneighbor_(oldvertex) {
+    if (neighbor->simplicial) {
+      if (qh_setin(neighbor->vertices, newvertex)) {
+        if (istrace || qh->IStracing >= 2) {
+          qh_fprintf(qh, qh->ferr, 2070, "qh_rename_adjacentvertex: simplicial f%d contains old v%d and new v%d.  Will be marked degenerate by qh_renamevertex\n",
+            neighbor->id, oldvertex->id, newvertex->id);
+        }
+        qh_makeridges(qh, neighbor); /* no longer simplicial, nummerge==0, skipped by qh_maybe_duplicateridge */
+      }else {
+        qh_replacefacetvertex(qh, neighbor, oldvertex, newvertex);
+        qh_setunique(qh, &newvertex->neighbors, neighbor);
+        qh_newvertices(qh, neighbor->vertices);  /* for qh_update_vertexneighbors of vertex neighbors */
+      }
+    }
+  }
+  ridges= qh_vertexridges(qh, oldvertex, qh_ALL);
+  if (istrace) {
+    FOREACHridge_(ridges) {
+      qh_printridge(qh, qh->ferr, ridge);
+    }
+  }
+  FOREACHneighbor_(oldvertex) {
+    if (!neighbor->simplicial){
+      qh_addfacetvertex(qh, neighbor, newvertex);
+      qh_setunique(qh, &newvertex->neighbors, neighbor);
+      qh_newvertices(qh, neighbor->vertices);  /* for qh_update_vertexneighbors of vertex neighbors */
+      if (qh->newfacet_list == qh->facet_tail) {
+        qh_removefacet(qh, neighbor);  /* add a neighbor to newfacet_list so that qh_partitionvisible has a newfacet */
+        qh_appendfacet(qh, neighbor);
+        neighbor->newfacet= True;
+      }
+    }
+  }
+  qh_renamevertex(qh, oldvertex, newvertex, ridges, NULL, NULL);  /* ridges invalidated */
+  if (oldvertex->deleted && !oldvertex->partitioned) {
+    FOREACHneighbor_(newvertex) {
+      if (!neighbor->visible) {
+        qh_distplane(qh, oldvertex->point, neighbor, &dist2);
+        if (dist2>maxdist2) {
+          maxdist2= dist2;
+          maxfacet= neighbor;
+        }
+      }
+    }
+    trace2((qh, qh->ferr, 2096, "qh_rename_adjacentvertex: partition old p%d(v%d) as a coplanar point for furthest f%d dist %2.2g.  Maybe repartition later (QH0031)\n",
+      qh_pointid(qh, oldvertex->point), oldvertex->id, maxfacet->id, maxdist2))
+    qh_partitioncoplanar(qh, oldvertex->point, maxfacet, NULL, !qh_ALL);  /* faster with maxdist2, otherwise duplicates distance tests from maxdist2/dist2 */
+    oldvertex->partitioned= True;
+  }
+  qh_settempfree(qh, &ridges);
+} /* rename_adjacentvertex */
+
+/*---------------------------------
+
+  qh_rename_sharedvertex(qh, vertex, facet )
+    detect and rename if shared vertex in facet
+    vertices have full ->neighbors
+
+  returns:
+    newvertex or NULL
+    the vertex may still exist in other facets (i.e., a neighbor was pinched)
+    does not change facet->neighbors
+    updates vertex->neighbors
+
+  notes:
+    only called by qh_reducevertices after qh_remove_extravertices
+       so f.vertices does not contain extraneous vertices
+    a shared vertex for a facet is only in ridges to one neighbor
+    this may undo a pinched facet
+
+    it does not catch pinches involving multiple facets.  These appear
+      to be difficult to detect, since an exhaustive search is too expensive.
+
+  design:
+    if vertex only has two neighbors
+      determine the ridges that contain the vertex
+      determine the vertices shared by both neighbors
+      if can find a new vertex in this set
+        rename the vertex to the new vertex
+*/
+vertexT *qh_rename_sharedvertex(qhT *qh, vertexT *vertex, facetT *facet) {
+  facetT *neighbor, **neighborp, *neighborA= NULL;
+  setT *vertices, *ridges;
+  vertexT *newvertex= NULL;
+
+  if (qh_setsize(qh, vertex->neighbors) == 2) {
+    neighborA= SETfirstt_(vertex->neighbors, facetT);
+    if (neighborA == facet)
+      neighborA= SETsecondt_(vertex->neighbors, facetT);
+  }else if (qh->hull_dim == 3)
+    return NULL;
+  else {
+    qh->visit_id++;
+    FOREACHneighbor_(facet)
+      neighbor->visitid= qh->visit_id;
+    FOREACHneighbor_(vertex) {
+      if (neighbor->visitid == qh->visit_id) {
+        if (neighborA)
+          return NULL;
+        neighborA= neighbor;
+      }
+    }
+  }
+  if (!neighborA) {
+    qh_fprintf(qh, qh->ferr, 6101, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",
+        vertex->id, facet->id);
+    qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, vertex);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  if (neighborA) { /* avoid warning */
+    /* the vertex is shared by facet and neighborA */
+    ridges= qh_settemp(qh, qh->TEMPsize);
+    neighborA->visitid= ++qh->visit_id;
+    qh_vertexridges_facet(qh, vertex, facet, &ridges);
+    trace2((qh, qh->ferr, 2037, "qh_rename_sharedvertex: p%d(v%d) is shared by f%d(%d ridges) and f%d\n",
+      qh_pointid(qh, vertex->point), vertex->id, facet->id, qh_setsize(qh, ridges), neighborA->id));
+    zinc_(Zintersectnum);
+    vertices= qh_vertexintersect_new(qh, facet->vertices, neighborA->vertices);
+    qh_setdel(vertices, vertex);
+    qh_settemppush(qh, vertices);
+    if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges)))
+      qh_renamevertex(qh, vertex, newvertex, ridges, facet, neighborA);  /* ridges invalidated */
+    qh_settempfree(qh, &vertices);
+    qh_settempfree(qh, &ridges);
+  }
+  return newvertex;
+} /* rename_sharedvertex */
+
+/*---------------------------------
+
+  qh_renameridgevertex(qh, ridge, oldvertex, newvertex )
+    renames oldvertex as newvertex in ridge
+
+  returns:
+    True if renames oldvertex
+    False if deleted the ridge
+
+  notes:
+    called by qh_renamevertex
+    caller sets newvertex->delridge for deleted ridges (qh_reducevertices)
+
+  design:
+    delete oldvertex from ridge
+    if newvertex already in ridge
+      copy ridge->noconvex to another ridge if possible
+      delete the ridge
+    else
+      insert newvertex into the ridge
+      adjust the ridge's orientation
+*/
+boolT qh_renameridgevertex(qhT *qh, ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {
+  int nth= 0, oldnth;
+  facetT *temp;
+  vertexT *vertex, **vertexp;
+
+  oldnth= qh_setindex(ridge->vertices, oldvertex);
+  if (oldnth < 0) {
+    qh_fprintf(qh, qh->ferr, 6424, "qhull internal error (qh_renameridgevertex): oldvertex v%d not found in r%d.  Cannot rename to v%d\n",
+        oldvertex->id, ridge->id, newvertex->id);
+    qh_errexit(qh, qh_ERRqhull, NULL, ridge);
+  }
+  qh_setdelnthsorted(qh, ridge->vertices, oldnth);
+  FOREACHvertex_(ridge->vertices) {
+    if (vertex == newvertex) {
+      zinc_(Zdelridge);
+      if (ridge->nonconvex) /* only one ridge has nonconvex set */
+        qh_copynonconvex(qh, ridge);
+      trace2((qh, qh->ferr, 2038, "qh_renameridgevertex: ridge r%d deleted.  It contained both v%d and v%d\n",
+        ridge->id, oldvertex->id, newvertex->id));
+      qh_delridge_merge(qh, ridge); /* ridge.vertices deleted */
+      return False;
+    }
+    if (vertex->id < newvertex->id)
+      break;
+    nth++;
+  }
+  qh_setaddnth(qh, &ridge->vertices, nth, newvertex);
+  ridge->simplicialtop= False;
+  ridge->simplicialbot= False;
+  if (abs(oldnth - nth)%2) {
+    trace3((qh, qh->ferr, 3010, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n",
+            ridge->id));
+    temp= ridge->top;
+    ridge->top= ridge->bottom;
+    ridge->bottom= temp;
+  }
+  return True;
+} /* renameridgevertex */
+
+
+/*---------------------------------
+
+  qh_renamevertex(qh, oldvertex, newvertex, ridges, oldfacet, neighborA )
+    renames oldvertex as newvertex in ridges of non-simplicial neighbors
+    set oldfacet/neighborA if oldvertex is shared between two facets (qh_rename_sharedvertex)
+    otherwise qh_redundant_vertex or qh_rename_adjacentvertex
+
+  returns:
+    if oldfacet and multiple neighbors, oldvertex may still exist afterwards
+    otherwise sets oldvertex->deleted for later deletion
+    one or more ridges maybe deleted
+    ridges is invalidated
+    merges may be added to degen_mergeset via qh_maydropneighbor or qh_degen_redundant_facet
+
+  notes:
+    qh_rename_sharedvertex can not change neighbors of newvertex (since it's a subset)
+    qh_redundant_vertex due to vertex->delridge for qh_reducevertices
+    qh_rename_adjacentvertex for complete renames
+
+  design:
+    for each ridge in ridges
+      rename oldvertex to newvertex and delete degenerate ridges
+    if oldfacet not defined
+      for each non-simplicial neighbor of oldvertex
+        delete oldvertex from neighbor's vertices
+        remove extra vertices from neighbor
+      add oldvertex to qh.del_vertices
+    else if oldvertex only between oldfacet and neighborA
+      delete oldvertex from oldfacet and neighborA
+      add oldvertex to qh.del_vertices
+    else oldvertex is in oldfacet and neighborA and other facets (i.e., pinched)
+      delete oldvertex from oldfacet
+      delete oldfacet from old vertex's neighbors
+      remove extra vertices (e.g., oldvertex) from neighborA
+*/
+void qh_renamevertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int topsize, bottomsize;
+  boolT istrace= False;
+
+#ifndef qh_NOtrace
+  if (qh->IStracing >= 2 || oldvertex->id == qh->tracevertex_id ||
+        newvertex->id == qh->tracevertex_id) {
+    istrace= True;
+    qh_fprintf(qh, qh->ferr, 2086, "qh_renamevertex: rename v%d to v%d in %d ridges with old f%d and neighbor f%d\n",
+      oldvertex->id, newvertex->id, qh_setsize(qh, ridges), getid_(oldfacet), getid_(neighborA));
+  }
+#endif
+  FOREACHridge_(ridges) {
+    if (qh_renameridgevertex(qh, ridge, oldvertex, newvertex)) { /* ridge is deleted if False, invalidating ridges */
+      topsize= qh_setsize(qh, ridge->top->vertices);
+      bottomsize= qh_setsize(qh, ridge->bottom->vertices);
+      if (topsize < qh->hull_dim || (topsize == qh->hull_dim && !ridge->top->simplicial && qh_setin(ridge->top->vertices, newvertex))) {
+        trace4((qh, qh->ferr, 4070, "qh_renamevertex: ignore duplicate check for r%d.  top f%d (size %d) will be degenerate after rename v%d to v%d\n",
+          ridge->id, ridge->top->id, topsize, oldvertex->id, newvertex->id));
+      }else if (bottomsize < qh->hull_dim || (bottomsize == qh->hull_dim && !ridge->bottom->simplicial && qh_setin(ridge->bottom->vertices, newvertex))) {
+        trace4((qh, qh->ferr, 4071, "qh_renamevertex: ignore duplicate check for r%d.  bottom f%d (size %d) will be degenerate after rename v%d to v%d\n",
+          ridge->id, ridge->bottom->id, bottomsize, oldvertex->id, newvertex->id));
+      }else
+        qh_maybe_duplicateridge(qh, ridge);
+    }
+  }
+  if (!oldfacet) {
+    /* stat Zrenameall or Zpinchduplicate */
+    if (istrace)
+      qh_fprintf(qh, qh->ferr, 2087, "qh_renamevertex: renaming v%d to v%d in several facets for qh_redundant_vertex or MRGsubridge\n",
+               oldvertex->id, newvertex->id);
+    FOREACHneighbor_(oldvertex) {
+      if (neighbor->simplicial) {
+        qh_degen_redundant_facet(qh, neighbor); /* e.g., rbox 175 C3,2e-13 D4 t1545235541 | qhull d */
+      }else {
+        if (istrace)
+          qh_fprintf(qh, qh->ferr, 4080, "qh_renamevertex: rename vertices in non-simplicial neighbor f%d of v%d\n", neighbor->id, oldvertex->id);
+        qh_maydropneighbor(qh, neighbor);
+        qh_setdelsorted(neighbor->vertices, oldvertex); /* if degenerate, qh_degen_redundant_facet will add to mergeset */
+        if (qh_remove_extravertices(qh, neighbor))
+          neighborp--; /* neighbor deleted from oldvertex neighborset */
+        qh_degen_redundant_facet(qh, neighbor); /* either direction may be redundant, faster if combine? */
+        qh_test_redundant_neighbors(qh, neighbor);
+        qh_test_degen_neighbors(qh, neighbor);
+      }
+    }
+    if (!oldvertex->deleted) {
+      oldvertex->deleted= True;
+      qh_setappend(qh, &qh->del_vertices, oldvertex);
+    }
+  }else if (qh_setsize(qh, oldvertex->neighbors) == 2) {
+    zinc_(Zrenameshare);
+    if (istrace)
+      qh_fprintf(qh, qh->ferr, 3039, "qh_renamevertex: renaming v%d to v%d in oldfacet f%d for qh_rename_sharedvertex\n",
+               oldvertex->id, newvertex->id, oldfacet->id);
+    FOREACHneighbor_(oldvertex) {
+      qh_setdelsorted(neighbor->vertices, oldvertex);
+      qh_degen_redundant_facet(qh, neighbor);
+    }
+    oldvertex->deleted= True;
+    qh_setappend(qh, &qh->del_vertices, oldvertex);
+  }else {
+    zinc_(Zrenamepinch);
+    if (istrace || qh->IStracing >= 1)
+      qh_fprintf(qh, qh->ferr, 3040, "qh_renamevertex: renaming pinched v%d to v%d between f%d and f%d\n",
+               oldvertex->id, newvertex->id, oldfacet->id, neighborA->id);
+    qh_setdelsorted(oldfacet->vertices, oldvertex);
+    qh_setdel(oldvertex->neighbors, oldfacet);
+    if (qh_remove_extravertices(qh, neighborA))
+      qh_degen_redundant_facet(qh, neighborA);
+  }
+  if (oldfacet)
+    qh_degen_redundant_facet(qh, oldfacet);
+} /* renamevertex */
+
+/*---------------------------------
+
+  qh_test_appendmerge(qh, facet, neighbor, simplicial )
+    test convexity and append to qh.facet_mergeset if non-convex
+    if pre-merging,
+      no-op if qh.SKIPconvex, or qh.MERGEexact and coplanar
+    if simplicial, assumes centrum test is valid (e.g., adjacent, simplicial new facets)
+
+  returns:
+    true if appends facet/neighbor to qh.facet_mergeset
+    sets facet->center as needed
+    does not change facet->seen
+
+  notes:
+    called from qh_getmergeset_initial, qh_getmergeset, and qh_test_vneighbors
+    must be at least as strong as qh_checkconvex (poly2_r.c)
+    assumes !f.flipped
+
+  design:
+    exit if qh.SKIPconvex ('Q0') and !qh.POSTmerging
+    if qh.cos_max ('An') is defined and merging coplanars
+      if the angle between facet normals is too shallow
+        append an angle-coplanar merge to qh.mergeset
+        return True
+    test convexity of facet and neighbor
+*/
+boolT qh_test_appendmerge(qhT *qh, facetT *facet, facetT *neighbor, boolT simplicial) {
+  realT angle= -REALmax;
+  boolT okangle= False;
+
+  if (qh->SKIPconvex && !qh->POSTmerging)
+    return False;
+  if (qh->cos_max < REALmax/2 && (!qh->MERGEexact || qh->POSTmerging)) {
+    angle= qh_getangle(qh, facet->normal, neighbor->normal);
+    okangle= True;
+    zinc_(Zangletests);
+    if (angle > qh->cos_max) {
+      zinc_(Zcoplanarangle);
+      qh_appendmergeset(qh, facet, neighbor, MRGanglecoplanar, 0.0, angle);
+      trace2((qh, qh->ferr, 2039, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",
+         angle, facet->id, neighbor->id));
+      return True;
+    }
+  }
+  if (simplicial || qh->hull_dim <= 3)
+    return qh_test_centrum_merge(qh, facet, neighbor, angle, okangle);
+  else
+    return qh_test_nonsimplicial_merge(qh, facet, neighbor, angle, okangle);
+} /* test_appendmerge */
+
+/*---------------------------------
+
+  qh_test_centrum_merge(qh, facet, neighbor, angle, okangle )
+    test centrum convexity and append non-convex facets to qh.facet_mergeset
+    'angle' is angle between facets if okangle is true, otherwise use 0.0
+
+  returns:
+    true if append facet/neighbor to qh.facet_mergeset
+    sets facet->center as needed
+    does not change facet->seen
+
+  notes:
+    called from test_appendmerge if adjacent simplicial facets or 2-d/3-d
+    at least as strict as qh_checkconvex, including qh.DISTround ('En' and 'Rn')
+
+  design:
+    make facet's centrum if needed
+    if facet's centrum is above the neighbor (qh.centrum_radius)
+      set isconcave
+
+    if facet's centrum is not below the neighbor (-qh.centrum_radius)
+      set iscoplanar
+    make neighbor's centrum if needed
+    if neighbor's centrum is above the facet
+      set isconcave
+    else if neighbor's centrum is not below the facet
+      set iscoplanar
+    if isconcave or iscoplanar and merging coplanars
+      get angle if needed (qh.ANGLEmerge 'An')
+      append concave-coplanar, concave ,or coplanar merge to qh.mergeset
+*/
+boolT qh_test_centrum_merge(qhT *qh, facetT *facet, facetT *neighbor, realT angle, boolT okangle) {
+  coordT dist, dist2, mergedist;
+  boolT isconcave= False, iscoplanar= False;
+
+  if (!facet->center)
+    facet->center= qh_getcentrum(qh, facet);
+  zzinc_(Zcentrumtests);
+  qh_distplane(qh, facet->center, neighbor, &dist);
+  if (dist > qh->centrum_radius)
+    isconcave= True;
+  else if (dist >= -qh->centrum_radius)
+    iscoplanar= True;
+  if (!neighbor->center)
+    neighbor->center= qh_getcentrum(qh, neighbor);
+  zzinc_(Zcentrumtests);
+  qh_distplane(qh, neighbor->center, facet, &dist2);
+  if (dist2 > qh->centrum_radius)
+    isconcave= True;
+  else if (!iscoplanar && dist2 >= -qh->centrum_radius)
+    iscoplanar= True;
+  if (!isconcave && (!iscoplanar || (qh->MERGEexact && !qh->POSTmerging)))
+    return False;
+  if (!okangle && qh->ANGLEmerge) {
+    angle= qh_getangle(qh, facet->normal, neighbor->normal);
+    zinc_(Zangletests);
+  }
+  if (isconcave && iscoplanar) {
+    zinc_(Zconcavecoplanarridge);
+    if (dist > dist2)
+      qh_appendmergeset(qh, facet, neighbor, MRGconcavecoplanar, dist, angle);
+    else
+      qh_appendmergeset(qh, neighbor, facet, MRGconcavecoplanar, dist2, angle);
+    trace0((qh, qh->ferr, 36, "qh_test_centrum_merge: concave f%d to coplanar f%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
+           facet->id, neighbor->id, dist, dist2, angle, qh->furthest_id));
+  }else if (isconcave) {
+    mergedist= fmax_(dist, dist2);
+    zinc_(Zconcaveridge);
+    qh_appendmergeset(qh, facet, neighbor, MRGconcave, mergedist, angle);
+    trace0((qh, qh->ferr, 37, "qh_test_centrum_merge: concave f%d to f%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
+      facet->id, neighbor->id, dist, dist2, angle, qh->furthest_id));
+  }else /* iscoplanar */ {
+    mergedist= fmin_(fabs_(dist), fabs_(dist2));
+    zinc_(Zcoplanarcentrum);
+    qh_appendmergeset(qh, facet, neighbor, MRGcoplanar, mergedist, angle);
+    trace2((qh, qh->ferr, 2097, "qh_test_centrum_merge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n",
+              facet->id, neighbor->id, dist, dist2, angle));
+  }
+  return True;
+} /* test_centrum_merge */
+
+/*---------------------------------
+
+  qh_test_degen_neighbors(qh, facet )
+    append degenerate neighbors to qh.degen_mergeset
+
+  notes:
+  called at end of qh_mergefacet() and qh_renamevertex()
+  call after test_redundant_facet() since MRGredundant is less expensive then MRGdegen
+    a degenerate facet has fewer than hull_dim neighbors
+    see: qh_merge_degenredundant()
+
+*/
+void qh_test_degen_neighbors(qhT *qh, facetT *facet) {
+  facetT *neighbor, **neighborp;
+  int size;
+
+  trace4((qh, qh->ferr, 4073, "qh_test_degen_neighbors: test for degenerate neighbors of f%d\n", facet->id));
+  FOREACHneighbor_(facet) {
+    if (neighbor->visible) {
+      qh_fprintf(qh, qh->ferr, 6359, "qhull internal error (qh_test_degen_neighbors): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
+        facet->id, neighbor->id);
+      qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
+    }
+    if (neighbor->degenerate || neighbor->redundant || neighbor->dupridge) /* will merge or delete */
+      continue;
+    /* merge flipped-degenerate facet before flipped facets */
+    if ((size= qh_setsize(qh, neighbor->neighbors)) < qh->hull_dim) {
+      qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, 0.0, 1.0);
+      trace2((qh, qh->ferr, 2019, "qh_test_degen_neighbors: f%d is degenerate with %d neighbors.  Neighbor of f%d.\n", neighbor->id, size, facet->id));
+    }
+  }
+} /* test_degen_neighbors */
+
+
+/*---------------------------------
+
+  qh_test_nonsimplicial_merge(qh, facet, neighbor, angle, okangle )
+    test centrum and vertex convexity and append non-convex or redundant facets to qh.facet_mergeset
+    'angle' is angle between facets if okangle is true, otherwise use 0.0
+    skips coplanar merges if pre-merging with qh.MERGEexact ('Qx')
+
+  returns:
+    true if appends facet/neighbor to qh.facet_mergeset
+    sets facet->center as needed
+    does not change facet->seen
+
+  notes:
+    only called from test_appendmerge if a non-simplicial facet and at least 4-d
+    at least as strict as qh_checkconvex, including qh.DISTround ('En' and 'Rn')
+      centrums must be < -qh.centrum_radius
+    tests vertices as well as centrums since a facet may be twisted relative to its neighbor
+
+  design:
+    set precision constants for maxoutside, clearlyconcave, minvertex, and coplanarcentrum
+      use maxoutside for coplanarcentrum if premerging with 'Qx' and qh_MAXcoplanarcentrum merges
+      otherwise use qh.centrum_radious for coplanarcentrum
+    make facet and neighbor centrums if needed
+    isconcave if a centrum is above neighbor (coplanarcentrum)
+    iscoplanar if a centrum is not below neighbor (-qh.centrum_radius)
+    maybeconvex if a centrum is clearly below neighbor (-clearyconvex)
+    return False if both centrums clearly below neighbor (-clearyconvex)
+    return MRGconcave if isconcave
+
+    facets are neither clearly convex nor clearly concave
+    test vertices as well as centrums
+    if maybeconvex
+      determine mindist and maxdist for vertices of the other facet
+      maybe MRGredundant
+    otherwise
+      determine mindist and maxdist for vertices of either facet
+      maybe MRGredundant
+      maybeconvex if a vertex is clearly below neighbor (-clearconvex)
+
+    vertices are concave if dist > clearlyconcave
+    vertices are twisted if dist > maxoutside (isconcave and maybeconvex)
+    return False if not concave and pre-merge of 'Qx' (qh.MERGEexact)
+    vertices are coplanar if dist in -minvertex..maxoutside
+    if !isconcave, vertices are coplanar if dist >= -qh.MAXcoplanar (n*qh.premerge_centrum)
+
+    return False if neither concave nor coplanar
+    return MRGtwisted if isconcave and maybeconvex
+    return MRGconcavecoplanar if isconcave and isconvex
+    return MRGconcave if isconcave
+    return MRGcoplanar if iscoplanar
+*/
+boolT qh_test_nonsimplicial_merge(qhT *qh, facetT *facet, facetT *neighbor, realT angle, boolT okangle) {
+  coordT dist, mindist, maxdist, mindist2, maxdist2, dist2, maxoutside, clearlyconcave, minvertex, clearlyconvex, mergedist, coplanarcentrum;
+  boolT isconcave= False, iscoplanar= False, maybeconvex= False, isredundant= False;
+  vertexT *maxvertex= NULL, *maxvertex2= NULL;
+
+  maxoutside= fmax_(neighbor->maxoutside, qh->ONEmerge + qh->DISTround);
+  maxoutside= fmax_(maxoutside, facet->maxoutside);
+  clearlyconcave= qh_RATIOconcavehorizon * maxoutside;
+  minvertex= fmax_(-qh->min_vertex, qh->MAXcoplanar); /* non-negative, not available per facet, not used for iscoplanar */
+  clearlyconvex= qh_RATIOconvexmerge * minvertex; /* must be convex for MRGtwisted */
+  if (qh->MERGEexact && !qh->POSTmerging && (facet->nummerge > qh_MAXcoplanarcentrum || neighbor->nummerge > qh_MAXcoplanarcentrum))
+    coplanarcentrum= maxoutside;
+  else
+    coplanarcentrum= qh->centrum_radius;
+
+  if (!facet->center)
+    facet->center= qh_getcentrum(qh, facet);
+  zzinc_(Zcentrumtests);
+  qh_distplane(qh, facet->center, neighbor, &dist);
+  if (dist > coplanarcentrum)
+    isconcave= True;
+  else if (dist >= -qh->centrum_radius)
+    iscoplanar= True;
+  else if (dist < -clearlyconvex)
+    maybeconvex= True;
+  if (!neighbor->center)
+    neighbor->center= qh_getcentrum(qh, neighbor);
+  zzinc_(Zcentrumtests);
+  qh_distplane(qh, neighbor->center, facet, &dist2);
+  if (dist2 > coplanarcentrum)
+    isconcave= True;
+  else if (dist2 >= -qh->centrum_radius)
+    iscoplanar= True;
+  else if (dist2 < -clearlyconvex) {
+    if (maybeconvex)
+      return False; /* both centrums clearly convex */
+    maybeconvex= True;
+  }
+  if (isconcave) {
+    if (!okangle && qh->ANGLEmerge) {
+      angle= qh_getangle(qh, facet->normal, neighbor->normal);
+      zinc_(Zangletests);
+    }
+    mergedist= fmax_(dist, dist2);
+    zinc_(Zconcaveridge);
+    qh_appendmergeset(qh, facet, neighbor, MRGconcave, mergedist, angle);
+    trace0((qh, qh->ferr, 18, "qh_test_nonsimplicial_merge: concave centrum for f%d or f%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
+      facet->id, neighbor->id, dist, dist2, angle, qh->furthest_id));
+    return True;
+  }
+  /* neither clearly convex nor clearly concave, test vertices as well as centrums */
+  if (maybeconvex) {
+    if (dist < -clearlyconvex) {
+      maxdist= dist;  /* facet centrum clearly convex, no need to test its vertex distance */
+      mindist= dist;
+      maxvertex2= qh_furthestvertex(qh, neighbor, facet, &maxdist2, &mindist2);
+      if (!maxvertex2) {
+        qh_appendmergeset(qh, neighbor, facet, MRGredundant, maxdist2, qh_ANGLEnone);
+        isredundant= True;
+      }
+    }else { /* dist2 < -clearlyconvex */
+      maxdist2= dist2;   /* neighbor centrum clearly convex, no need to test its vertex distance */
+      mindist2= dist2;
+      maxvertex= qh_furthestvertex(qh, facet, neighbor, &maxdist, &mindist);
+      if (!maxvertex) {
+        qh_appendmergeset(qh, facet, neighbor, MRGredundant, maxdist, qh_ANGLEnone);
+        isredundant= True;
+      }
+    }
+  }else {
+    maxvertex= qh_furthestvertex(qh, facet, neighbor, &maxdist, &mindist);
+    if (maxvertex) {
+      maxvertex2= qh_furthestvertex(qh, neighbor, facet, &maxdist2, &mindist2);
+      if (!maxvertex2) {
+        qh_appendmergeset(qh, neighbor, facet, MRGredundant, maxdist2, qh_ANGLEnone);
+        isredundant= True;
+      }else if (mindist < -clearlyconvex || mindist2 < -clearlyconvex)
+        maybeconvex= True;
+    }else { /* !maxvertex */
+      qh_appendmergeset(qh, facet, neighbor, MRGredundant, maxdist, qh_ANGLEnone);
+      isredundant= True;
+    }
+  }
+  if (isredundant) {
+    zinc_(Zredundantmerge);
+    return True;
+  }
+
+  if (maxdist > clearlyconcave || maxdist2 > clearlyconcave)
+    isconcave= True;
+  else if (maybeconvex) {
+    if (maxdist > maxoutside || maxdist2 > maxoutside)
+      isconcave= True;  /* MRGtwisted */
+  }
+  if (!isconcave && qh->MERGEexact && !qh->POSTmerging)
+    return False;
+  if (isconcave && !iscoplanar) {
+    if (maxdist < maxoutside && (-qh->MAXcoplanar || (maxdist2 < maxoutside && mindist2 >= -qh->MAXcoplanar)))
+      iscoplanar= True; /* MRGconcavecoplanar */
+  }else if (!iscoplanar) {
+    if (mindist >= -qh->MAXcoplanar || mindist2 >= -qh->MAXcoplanar)
+      iscoplanar= True;  /* MRGcoplanar */
+  }
+  if (!isconcave && !iscoplanar)
+    return False;
+  if (!okangle && qh->ANGLEmerge) {
+    angle= qh_getangle(qh, facet->normal, neighbor->normal);
+    zinc_(Zangletests);
+  }
+  if (isconcave && maybeconvex) {
+    zinc_(Ztwistedridge);
+    if (maxdist > maxdist2)
+      qh_appendmergeset(qh, facet, neighbor, MRGtwisted, maxdist, angle);
+    else
+      qh_appendmergeset(qh, neighbor, facet, MRGtwisted, maxdist2, angle);
+    trace0((qh, qh->ferr, 27, "qh_test_nonsimplicial_merge: twisted concave f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
+           facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
+  }else if (isconcave && iscoplanar) {
+    zinc_(Zconcavecoplanarridge);
+    if (maxdist > maxdist2)
+      qh_appendmergeset(qh, facet, neighbor, MRGconcavecoplanar, maxdist, angle);
+    else
+      qh_appendmergeset(qh, neighbor, facet, MRGconcavecoplanar, maxdist2, angle);
+    trace0((qh, qh->ferr, 28, "qh_test_nonsimplicial_merge: concave coplanar f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
+      facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
+  }else if (isconcave) {
+    mergedist= fmax_(maxdist, maxdist2);
+    zinc_(Zconcaveridge);
+    qh_appendmergeset(qh, facet, neighbor, MRGconcave, mergedist, angle);
+    trace0((qh, qh->ferr, 29, "qh_test_nonsimplicial_merge: concave f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
+      facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
+  }else /* iscoplanar */ {
+    mergedist= fmax_(fmax_(maxdist, maxdist2), fmax_(-mindist, -mindist2));
+    zinc_(Zcoplanarcentrum);
+    qh_appendmergeset(qh, facet, neighbor, MRGcoplanar, mergedist, angle);
+    trace2((qh, qh->ferr, 2099, "qh_test_nonsimplicial_merge: coplanar f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
+      facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
+  }
+  return True;
+} /* test_nonsimplicial_merge */
+
+/*---------------------------------
+
+  qh_test_redundant_neighbors(qh, facet )
+    append degenerate facet or its redundant neighbors to qh.degen_mergeset
+
+  returns:
+    bumps vertex_visit
+
+  notes:
+    called at end of qh_mergefacet(), qh_mergecycle_all(), and qh_renamevertex
+    call before qh_test_degen_neighbors (MRGdegen are more likely to cause problems)
+    a redundant neighbor's vertices is a subset of the facet's vertices
+    with pinched and flipped facets, a redundant neighbor may have a wildly different normal
+
+    see qh_merge_degenredundant() and qh_-_facet()
+
+  design:
+    if facet is degenerate
+       appends facet to degen_mergeset
+    else
+       appends redundant neighbors of facet to degen_mergeset
+*/
+void qh_test_redundant_neighbors(qhT *qh, facetT *facet) {
+  vertexT *vertex, **vertexp;
+  facetT *neighbor, **neighborp;
+  int size;
+
+  trace4((qh, qh->ferr, 4022, "qh_test_redundant_neighbors: test neighbors of f%d vertex_visit %d\n",
+          facet->id, qh->vertex_visit+1));
+  if ((size= qh_setsize(qh, facet->neighbors)) < qh->hull_dim) {
+    qh_appendmergeset(qh, facet, facet, MRGdegen, 0.0, 1.0);
+    trace2((qh, qh->ferr, 2017, "qh_test_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));
+  }else {
+    qh->vertex_visit++;
+    FOREACHvertex_(facet->vertices)
+      vertex->visitid= qh->vertex_visit;
+    FOREACHneighbor_(facet) {
+      if (neighbor->visible) {
+        qh_fprintf(qh, qh->ferr, 6360, "qhull internal error (qh_test_redundant_neighbors): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
+          facet->id, neighbor->id);
+        qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
+      }
+      if (neighbor->degenerate || neighbor->redundant || neighbor->dupridge) /* will merge or delete */
+        continue;
+      if (facet->flipped && !neighbor->flipped) /* do not merge non-flipped into flipped */
+        continue;
+      /* merge redundant-flipped facet first */
+      /* uses early out instead of checking vertex count */
+      FOREACHvertex_(neighbor->vertices) {
+        if (vertex->visitid != qh->vertex_visit)
+          break;
+      }
+      if (!vertex) {
+        qh_appendmergeset(qh, neighbor, facet, MRGredundant, 0.0, 1.0);
+        trace2((qh, qh->ferr, 2018, "qh_test_redundant_neighbors: f%d is contained in f%d.  merge\n", neighbor->id, facet->id));
+      }
+    }
+  }
+} /* test_redundant_neighbors */
+
+/*---------------------------------
+
+  qh_test_vneighbors(qh)
+    test vertex neighbors for convexity
+    tests all facets on qh.newfacet_list
+
+  returns:
+    true if non-convex vneighbors appended to qh.facet_mergeset
+    initializes vertex neighbors if needed
+
+  notes:
+    called by qh_all_merges from qh_postmerge if qh.TESTvneighbors ('Qv')
+    assumes all facet neighbors have been tested
+    this can be expensive
+    this does not guarantee that a centrum is below all facets
+      but it is unlikely
+    uses qh.visit_id
+
+  design:
+    build vertex neighbors if necessary
+    for all new facets
+      for all vertices
+        for each unvisited facet neighbor of the vertex
+          test new facet and neighbor for convexity
+*/
+boolT qh_test_vneighbors(qhT *qh /* qh.newfacet_list */) {
+  facetT *newfacet, *neighbor, **neighborp;
+  vertexT *vertex, **vertexp;
+  int nummerges= 0;
+
+  trace1((qh, qh->ferr, 1015, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));
+  if (!qh->VERTEXneighbors)
+    qh_vertexneighbors(qh);
+  FORALLnew_facets
+    newfacet->seen= False;
+  FORALLnew_facets {
+    newfacet->seen= True;
+    newfacet->visitid= qh->visit_id++;
+    FOREACHneighbor_(newfacet)
+      newfacet->visitid= qh->visit_id;
+    FOREACHvertex_(newfacet->vertices) {
+      FOREACHneighbor_(vertex) {
+        if (neighbor->seen || neighbor->visitid == qh->visit_id)
+          continue;
+        if (qh_test_appendmerge(qh, newfacet, neighbor, False)) /* ignores optimization for simplicial ridges */
+          nummerges++;
+      }
+    }
+  }
+  zadd_(Ztestvneighbor, nummerges);
+  trace1((qh, qh->ferr, 1016, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",
+           nummerges));
+  return (nummerges > 0);
+} /* test_vneighbors */
+
+/*---------------------------------
+
+  qh_tracemerge(qh, facet1, facet2 )
+    print trace message after merge
+*/
+void qh_tracemerge(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype) {
+  boolT waserror= False;
+  const char *mergename;
+
+#ifndef qh_NOtrace
+  if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
+    mergename= mergetypes[mergetype];
+  else
+    mergename= mergetypes[MRGnone];
+  if (qh->IStracing >= 4)
+    qh_errprint(qh, "MERGED", facet2, NULL, NULL, NULL);
+  if (facet2 == qh->tracefacet || (qh->tracevertex && qh->tracevertex->newfacet)) {
+    qh_fprintf(qh, qh->ferr, 8085, "qh_tracemerge: trace facet and vertex after merge of f%d into f%d type %d (%s), furthest p%d\n",
+      facet1->id, facet2->id, mergetype, mergename, qh->furthest_id);
+    if (facet2 != qh->tracefacet)
+      qh_errprint(qh, "TRACE", qh->tracefacet,
+        (qh->tracevertex && qh->tracevertex->neighbors) ?
+           SETfirstt_(qh->tracevertex->neighbors, facetT) : NULL,
+        NULL, qh->tracevertex);
+  }
+  if (qh->tracevertex) {
+    if (qh->tracevertex->deleted)
+      qh_fprintf(qh, qh->ferr, 8086, "qh_tracemerge: trace vertex deleted at furthest p%d\n",
+            qh->furthest_id);
+    else
+      qh_checkvertex(qh, qh->tracevertex, qh_ALL, &waserror);
+  }
+  if (qh->tracefacet && qh->tracefacet->normal && !qh->tracefacet->visible)
+    qh_checkfacet(qh, qh->tracefacet, True /* newmerge */, &waserror);
+#endif /* !qh_NOtrace */
+  if (qh->CHECKfrequently || qh->IStracing >= 4) { /* can't check polygon here */
+    if (qh->IStracing >= 4 && qh->num_facets < 500) {
+      qh_printlists(qh);
+    }
+    qh_checkfacet(qh, facet2, True /* newmerge */, &waserror);
+  }
+  if (waserror)
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL); /* erroneous facet logged by qh_checkfacet */
+} /* tracemerge */
+
+/*---------------------------------
+
+  qh_tracemerging(qh)
+    print trace message during POSTmerging
+
+  returns:
+    updates qh.mergereport
+
+  notes:
+    called from qh_mergecycle() and qh_mergefacet()
+
+  see:
+    qh_buildtracing()
+*/
+void qh_tracemerging(qhT *qh) {
+  realT cpu;
+  int total;
+  time_t timedata;
+  struct tm *tp;
+
+  qh->mergereport= zzval_(Ztotmerge);
+  time(&timedata);
+  tp= localtime(&timedata);
+  cpu= qh_CPUclock;
+  cpu /= qh_SECticks;
+  total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+  qh_fprintf(qh, qh->ferr, 8087, "\n\
+At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets with max_outside %2.2g, min_vertex %2.2g.\n\
+  The hull contains %d facets and %d vertices.\n",
+      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, total, qh->max_outside, qh->min_vertex,
+      qh->num_facets - qh->num_visible,
+      qh->num_vertices-qh_setsize(qh, qh->del_vertices));
+} /* tracemerging */
+
+/*---------------------------------
+
+  qh_updatetested(qh, facet1, facet2 )
+    clear facet2->tested and facet1->ridge->tested for merge
+
+  returns:
+    deletes facet2->center unless it's already large
+      if so, clears facet2->ridge->tested
+
+  notes:
+    only called by qh_mergefacet
+
+  design:
+    clear facet2->tested
+    clear ridge->tested for facet1's ridges
+    if facet2 has a centrum
+      if facet2 is large
+        set facet2->keepcentrum
+      else if facet2 has 3 vertices due to many merges, or not large and post merging
+        clear facet2->keepcentrum
+      unless facet2->keepcentrum
+        clear facet2->center to recompute centrum later
+        clear ridge->tested for facet2's ridges
+*/
+void qh_updatetested(qhT *qh, facetT *facet1, facetT *facet2) {
+  ridgeT *ridge, **ridgep;
+  int size;
+
+  facet2->tested= False;
+  FOREACHridge_(facet1->ridges)
+    ridge->tested= False;
+  if (!facet2->center)
+    return;
+  size= qh_setsize(qh, facet2->vertices);
+  if (!facet2->keepcentrum) {
+    if (size > qh->hull_dim + qh_MAXnewcentrum) {
+      facet2->keepcentrum= True;
+      zinc_(Zwidevertices);
+    }
+  }else if (size <= qh->hull_dim + qh_MAXnewcentrum) {
+    /* center and keepcentrum was set */
+    if (size == qh->hull_dim || qh->POSTmerging)
+      facet2->keepcentrum= False; /* if many merges need to recompute centrum */
+  }
+  if (!facet2->keepcentrum) {
+    qh_memfree(qh, facet2->center, qh->normal_size);
+    facet2->center= NULL;
+    FOREACHridge_(facet2->ridges)
+      ridge->tested= False;
+  }
+} /* updatetested */
+
+/*---------------------------------
+
+  qh_vertexridges(qh, vertex, allneighbors )
+    return temporary set of ridges adjacent to a vertex
+    vertex->neighbors defined (qh_vertexneighbors)
+
+  notes:
+    uses qh.visit_id
+    does not include implicit ridges for simplicial facets
+    skips last neighbor, unless allneighbors.  For new facets, the last neighbor shares ridges with adjacent neighbors
+    if the last neighbor is not simplicial, it will have ridges for its simplicial neighbors
+    Use allneighbors when a new cone is attached to an existing convex hull
+    similar to qh_neighbor_vertices
+
+  design:
+    for each neighbor of vertex
+      add ridges that include the vertex to ridges
+*/
+setT *qh_vertexridges(qhT *qh, vertexT *vertex, boolT allneighbors) {
+  facetT *neighbor, **neighborp;
+  setT *ridges= qh_settemp(qh, qh->TEMPsize);
+  int size;
+
+  qh->visit_id += 2;  /* visit_id for vertex neighbors, visit_id-1 for facets of visited ridges */
+  FOREACHneighbor_(vertex)
+    neighbor->visitid= qh->visit_id;
+  FOREACHneighbor_(vertex) {
+    if (*neighborp || allneighbors)   /* no new ridges in last neighbor */
+      qh_vertexridges_facet(qh, vertex, neighbor, &ridges);
+  }
+  if (qh->PRINTstatistics || qh->IStracing) {
+    size= qh_setsize(qh, ridges);
+    zinc_(Zvertexridge);
+    zadd_(Zvertexridgetot, size);
+    zmax_(Zvertexridgemax, size);
+    trace3((qh, qh->ferr, 3011, "qh_vertexridges: found %d ridges for v%d\n",
+             size, vertex->id));
+  }
+  return ridges;
+} /* vertexridges */
+
+/*---------------------------------
+
+  qh_vertexridges_facet(qh, vertex, facet, ridges )
+    add adjacent ridges for vertex in facet
+    neighbor->visitid==qh.visit_id if it hasn't been visited
+
+  returns:
+    ridges updated
+    sets facet->visitid to qh.visit_id-1
+
+  design:
+    for each ridge of facet
+      if ridge of visited neighbor (i.e., unprocessed)
+        if vertex in ridge
+          append ridge
+    mark facet processed
+*/
+void qh_vertexridges_facet(qhT *qh, vertexT *vertex, facetT *facet, setT **ridges) {
+  ridgeT *ridge, **ridgep;
+  facetT *neighbor;
+  int last_i= qh->hull_dim-2;
+  vertexT *second, *last;
+
+  FOREACHridge_(facet->ridges) {
+    neighbor= otherfacet_(ridge, facet);
+    if (neighbor->visitid == qh->visit_id) {
+      if (SETfirst_(ridge->vertices) == vertex) {
+        qh_setappend(qh, ridges, ridge);
+      }else if (last_i > 2) {
+        second= SETsecondt_(ridge->vertices, vertexT);
+        last= SETelemt_(ridge->vertices, last_i, vertexT);
+        if (second->id >= vertex->id && last->id <= vertex->id) { /* vertices inverse sorted by id */
+          if (second == vertex || last == vertex)
+            qh_setappend(qh, ridges, ridge);
+          else if (qh_setin(ridge->vertices, vertex))
+            qh_setappend(qh, ridges, ridge);
+        }
+      }else if (SETelem_(ridge->vertices, last_i) == vertex
+          || (last_i > 1 && SETsecond_(ridge->vertices) == vertex)) {
+        qh_setappend(qh, ridges, ridge);
+      }
+    }
+  }
+  facet->visitid= qh->visit_id-1;
+} /* vertexridges_facet */
+
+/*---------------------------------
+
+  qh_willdelete(qh, facet, replace )
+    moves facet to visible list for qh_deletevisible
+    sets facet->f.replace to replace (may be NULL)
+    clears f.ridges and f.neighbors -- no longer valid
+
+  returns:
+    bumps qh.num_visible
+*/
+void qh_willdelete(qhT *qh, facetT *facet, facetT *replace) {
+
+  trace4((qh, qh->ferr, 4081, "qh_willdelete: move f%d to visible list, set its replacement as f%d, and clear f.neighbors and f.ridges\n", facet->id, getid_(replace)));
+  if (!qh->visible_list && qh->newfacet_list) {
+    qh_fprintf(qh, qh->ferr, 6378, "qhull internal error (qh_willdelete): expecting qh.visible_list at before qh.newfacet_list f%d.   Got NULL\n",
+        qh->newfacet_list->id);
+    qh_errexit2(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh_removefacet(qh, facet);
+  qh_prependfacet(qh, facet, &qh->visible_list);
+  qh->num_visible++;
+  facet->visible= True;
+  facet->f.replace= replace;
+  if (facet->ridges)
+    SETfirst_(facet->ridges)= NULL;
+  if (facet->neighbors)
+    SETfirst_(facet->neighbors)= NULL;
+} /* willdelete */
+
+#else /* qh_NOmerge */
+
+void qh_all_vertexmerges(qhT *qh, int apexpointid, facetT *facet, facetT **retryfacet) {
+  QHULL_UNUSED(qh)
+  QHULL_UNUSED(apexpointid)
+  QHULL_UNUSED(facet)
+  QHULL_UNUSED(retryfacet)
+}
+void qh_premerge(qhT *qh, int apexpointid, realT maxcentrum, realT maxangle) {
+  QHULL_UNUSED(qh)
+  QHULL_UNUSED(apexpointid)
+  QHULL_UNUSED(maxcentrum)
+  QHULL_UNUSED(maxangle)
+}
+void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
+                      boolT vneighbors) {
+  QHULL_UNUSED(qh)
+  QHULL_UNUSED(reason)
+  QHULL_UNUSED(maxcentrum)
+  QHULL_UNUSED(maxangle)
+  QHULL_UNUSED(vneighbors)
+}
+void qh_checkdelfacet(qhT *qh, facetT *facet, setT *mergeset) {
+  QHULL_UNUSED(qh)
+  QHULL_UNUSED(facet)
+  QHULL_UNUSED(mergeset)
+}
+void qh_checkdelridge(qhT *qh /* qh.visible_facets, vertex_mergeset */) {
+  QHULL_UNUSED(qh)
+}
+boolT qh_checkzero(qhT *qh, boolT testall) {
+  QHULL_UNUSED(qh)
+  QHULL_UNUSED(testall)
+
+  return True;
+}
+void qh_freemergesets(qhT *qh) {
+  QHULL_UNUSED(qh)
+}
+void qh_initmergesets(qhT *qh) {
+  QHULL_UNUSED(qh)
+}
+void qh_merge_pinchedvertices(qhT *qh, int apexpointid /* qh.newfacet_list */) {
+  QHULL_UNUSED(qh)
+  QHULL_UNUSED(apexpointid)
+}
+#endif /* qh_NOmerge */
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/merge_r.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/merge_r.h
new file mode 100644
index 00000000000..a0d4091ec87
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/merge_r.h
@@ -0,0 +1,238 @@
+/*
  ---------------------------------
+
+   merge_r.h
+   header file for merge_r.c
+
+   see qh-merge_r.htm and merge_r.c
+
+   Copyright (c) 1993-2020 C.B. Barber.
+   $Id: //main/2019/qhull/src/libqhull_r/merge_r.h#2 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+*/
+
+#ifndef qhDEFmerge
+#define qhDEFmerge 1
+
+#include "libqhull_r.h"
+
+
+/*============ -constants- ==============*/
+
+/*----------------------------------
+
+  qh_ANGLEnone
+    indicates missing angle for mergeT->angle
+*/
+#define qh_ANGLEnone 2.0
+
+/*----------------------------------
+
+  MRG... (mergeType)
+    indicates the type of a merge (mergeT->type)
+    MRGcoplanar...MRGtwisted set by qh_test_centrum_merge, qh_test_nonsimplicial_merge
+*/
+typedef enum {  /* must match mergetypes[] */
+  MRGnone= 0,
+                  /* MRGcoplanar..MRGtwisted go into qh.facet_mergeset for qh_all_merges 
+                     qh_compare_facetmerge selects lower mergetypes for merging first */
+  MRGcoplanar,          /* (1) centrum coplanar if centrum ('Cn') or vertex not clearly above or below neighbor */
+  MRGanglecoplanar,     /* (2) angle coplanar if angle ('An') is coplanar */
+  MRGconcave,           /* (3) concave ridge */
+  MRGconcavecoplanar,   /* (4) concave and coplanar ridge, one side concave, other side coplanar */
+  MRGtwisted,           /* (5) twisted ridge, both concave and convex, facet1 is wider */
+                  /* MRGflip go into qh.facet_mergeset for qh_flipped_merges */
+  MRGflip,              /* (6) flipped facet if qh.interior_point is above facet, w/ facet1 == facet2 */
+                  /* MRGdupridge go into qh.facet_mergeset for qh_forcedmerges */
+  MRGdupridge,          /* (7) dupridge if more than two neighbors.  Set by qh_mark_dupridges for qh_MERGEridge */
+                  /* MRGsubridge and MRGvertices go into vertex_mergeset */
+  MRGsubridge,          /* (8) merge pinched vertex to remove the subridge of a MRGdupridge */
+  MRGvertices,          /* (9) merge pinched vertex to remove a facet's ridges with the same vertices */
+                  /* MRGdegen, MRGredundant, and MRGmirror go into qh.degen_mergeset */
+  MRGdegen,             /* (10) degenerate facet (!enough neighbors) facet1 == facet2 */
+  MRGredundant,         /* (11) redundant facet (vertex subset) */
+                        /* merge_degenredundant assumes degen < redundant */
+  MRGmirror,            /* (12) mirror facets: same vertices due to null facets in qh_triangulate 
+                           f.redundant for both facets*/
+                  /* MRGcoplanarhorizon for qh_mergecycle_all only */
+  MRGcoplanarhorizon,   /* (13) new facet coplanar with the horizon (qh_mergecycle_all) */
+  ENDmrg
+} mergeType;
+
+/*----------------------------------
+
+  qh_MERGEapex
+    flag for qh_mergefacet() to indicate an apex merge
+*/
+#define qh_MERGEapex     True
+
+/*============ -structures- ====================*/
+
+/*----------------------------------
+
+  mergeT
+    structure used to merge facets
+*/
+
+typedef struct mergeT mergeT;
+struct mergeT {         /* initialize in qh_appendmergeset */
+  realT   angle;        /* cosine of angle between normals of facet1 and facet2, 
+                           null value and right angle is 0.0, coplanar is 1.0, narrow is -1.0 */
+  realT   distance;     /* absolute value of distance between vertices, centrum and facet, or vertex and facet */
+  facetT *facet1;       /* will merge facet1 into facet2 */
+  facetT *facet2;
+  vertexT *vertex1;     /* will merge vertext1 into vertex2 for MRGsubridge or MRGvertices */
+  vertexT *vertex2;
+  ridgeT  *ridge1;      /* the duplicate ridges resolved by MRGvertices */
+  ridgeT  *ridge2;      /* merge is deleted if either ridge is deleted (qh_delridge) */
+  mergeType mergetype;
+};
+
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+
+  FOREACHmerge_( merges ) {...}
+    assign 'merge' to each merge in merges
+
+  notes:
+    uses 'mergeT *merge, **mergep;'
+    if qh_mergefacet(),
+      restart or use qh_setdellast() since qh.facet_mergeset may change
+    see FOREACHsetelement_
+*/
+#define FOREACHmerge_(merges) FOREACHsetelement_(mergeT, merges, merge)
+
+/*----------------------------------
+
+  FOREACHmergeA_( vertices ) { ... }
+    assign 'mergeA' to each merge in merges
+
+  notes:
+    uses 'mergeT *mergeA, *mergeAp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHmergeA_(merges) FOREACHsetelement_(mergeT, merges, mergeA)
+
+/*----------------------------------
+
+  FOREACHmerge_i_(qh, vertices ) { ... }
+    assign 'merge' and 'merge_i' for each merge in mergeset
+
+  declare:
+    mergeT *merge;
+    int     merge_n, merge_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHmerge_i_(qh, mergeset) FOREACHsetelement_i_(qh, mergeT, mergeset, merge)
+
+/*============ prototypes in alphabetical order after pre/postmerge =======*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void    qh_premerge(qhT *qh, int apexpointid, realT maxcentrum, realT maxangle);
+void    qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
+             boolT vneighbors);
+void    qh_all_merges(qhT *qh, boolT othermerge, boolT vneighbors);
+void    qh_all_vertexmerges(qhT *qh, int apexpointid, facetT *facet, facetT **retryfacet);
+void    qh_appendmergeset(qhT *qh, facetT *facet, facetT *neighbor, mergeType mergetype, coordT dist, realT angle);
+void    qh_appendvertexmerge(qhT *qh, vertexT *vertex, vertexT *destination, mergeType mergetype, realT distance, ridgeT *ridge1, ridgeT *ridge2);
+setT   *qh_basevertices(qhT *qh, facetT *samecycle);
+void    qh_check_dupridge(qhT *qh, facetT *facet1, realT dist1, facetT *facet2, realT dist2);
+void    qh_checkconnect(qhT *qh /* qh.new_facets */);
+void    qh_checkdelfacet(qhT *qh, facetT *facet, setT *mergeset);
+void    qh_checkdelridge(qhT *qh /* qh.visible_facets, vertex_mergeset */);
+boolT   qh_checkzero(qhT *qh, boolT testall);
+int     qh_compare_anglemerge(const void *p1, const void *p2);
+int     qh_compare_facetmerge(const void *p1, const void *p2);
+int     qh_comparevisit(const void *p1, const void *p2);
+void    qh_copynonconvex(qhT *qh, ridgeT *atridge);
+void    qh_degen_redundant_facet(qhT *qh, facetT *facet);
+void    qh_drop_mergevertex(qhT *qh, mergeT *merge);
+void    qh_delridge_merge(qhT *qh, ridgeT *ridge);
+vertexT *qh_find_newvertex(qhT *qh, vertexT *oldvertex, setT *vertices, setT *ridges);
+vertexT *qh_findbest_pinchedvertex(qhT *qh, mergeT *merge, vertexT *apex, vertexT **pinchedp, realT *distp /* qh.newfacet_list */);
+vertexT *qh_findbest_ridgevertex(qhT *qh, ridgeT *ridge, vertexT **pinchedp, coordT *distp);
+void    qh_findbest_test(qhT *qh, boolT testcentrum, facetT *facet, facetT *neighbor,
+           facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp);
+facetT *qh_findbestneighbor(qhT *qh, facetT *facet, realT *distp, realT *mindistp, realT *maxdistp);
+void    qh_flippedmerges(qhT *qh, facetT *facetlist, boolT *wasmerge);
+void    qh_forcedmerges(qhT *qh, boolT *wasmerge);
+void    qh_freemergesets(qhT *qh);
+void    qh_getmergeset(qhT *qh, facetT *facetlist);
+void    qh_getmergeset_initial(qhT *qh, facetT *facetlist);
+boolT   qh_getpinchedmerges(qhT *qh, vertexT *apex, coordT maxdupdist, boolT *iscoplanar /* qh.newfacet_list, vertex_mergeset */);
+boolT   qh_hasmerge(setT *mergeset, mergeType type, facetT *facetA, facetT *facetB);
+void    qh_hashridge(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex);
+ridgeT *qh_hashridge_find(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge,
+              vertexT *vertex, vertexT *oldvertex, int *hashslot);
+void    qh_initmergesets(qhT *qh);
+void    qh_makeridges(qhT *qh, facetT *facet);
+void    qh_mark_dupridges(qhT *qh, facetT *facetlist, boolT allmerges);
+void    qh_maybe_duplicateridge(qhT *qh, ridgeT *ridge);
+void    qh_maybe_duplicateridges(qhT *qh, facetT *facet);
+void    qh_maydropneighbor(qhT *qh, facetT *facet);
+int     qh_merge_degenredundant(qhT *qh);
+void    qh_merge_nonconvex(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype);
+void    qh_merge_pinchedvertices(qhT *qh, int apexpointid /* qh.newfacet_list */);
+void    qh_merge_twisted(qhT *qh, facetT *facet1, facetT *facet2);
+void    qh_mergecycle(qhT *qh, facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_all(qhT *qh, facetT *facetlist, boolT *wasmerge);
+void    qh_mergecycle_facets(qhT *qh, facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_neighbors(qhT *qh, facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_ridges(qhT *qh, facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_vneighbors(qhT *qh, facetT *samecycle, facetT *newfacet);
+void    qh_mergefacet(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype, realT *mindist, realT *maxdist, boolT mergeapex);
+void    qh_mergefacet2d(qhT *qh, facetT *facet1, facetT *facet2);
+void    qh_mergeneighbors(qhT *qh, facetT *facet1, facetT *facet2);
+void    qh_mergeridges(qhT *qh, facetT *facet1, facetT *facet2);
+void    qh_mergesimplex(qhT *qh, facetT *facet1, facetT *facet2, boolT mergeapex);
+void    qh_mergevertex_del(qhT *qh, vertexT *vertex, facetT *facet1, facetT *facet2);
+void    qh_mergevertex_neighbors(qhT *qh, facetT *facet1, facetT *facet2);
+void    qh_mergevertices(qhT *qh, setT *vertices1, setT **vertices);
+setT   *qh_neighbor_intersections(qhT *qh, vertexT *vertex);
+setT   *qh_neighbor_vertices(qhT *qh, vertexT *vertex, setT *subridge);
+void    qh_neighbor_vertices_facet(qhT *qh, vertexT *vertexA, facetT *facet, setT **vertices);
+void    qh_newvertices(qhT *qh, setT *vertices);
+mergeT *qh_next_vertexmerge(qhT *qh);
+facetT *qh_opposite_horizonfacet(qhT *qh, mergeT *merge, vertexT **vertex);
+boolT   qh_reducevertices(qhT *qh);
+vertexT *qh_redundant_vertex(qhT *qh, vertexT *vertex);
+boolT   qh_remove_extravertices(qhT *qh, facetT *facet);
+void    qh_remove_mergetype(qhT *qh, setT *mergeset, mergeType type);
+void    qh_rename_adjacentvertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, realT dist);
+vertexT *qh_rename_sharedvertex(qhT *qh, vertexT *vertex, facetT *facet);
+boolT   qh_renameridgevertex(qhT *qh, ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex);
+void    qh_renamevertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, setT *ridges,
+                        facetT *oldfacet, facetT *neighborA);
+boolT   qh_test_appendmerge(qhT *qh, facetT *facet, facetT *neighbor, boolT simplicial);
+void    qh_test_degen_neighbors(qhT *qh, facetT *facet);
+boolT   qh_test_centrum_merge(qhT *qh, facetT *facet, facetT *neighbor, realT angle, boolT okangle);
+boolT   qh_test_nonsimplicial_merge(qhT *qh, facetT *facet, facetT *neighbor, realT angle, boolT okangle);
+void    qh_test_redundant_neighbors(qhT *qh, facetT *facet);
+boolT   qh_test_vneighbors(qhT *qh /* qh.newfacet_list */);
+void    qh_tracemerge(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype);
+void    qh_tracemerging(qhT *qh);
+void    qh_undo_newfacets(qhT *qh);
+void    qh_updatetested(qhT *qh, facetT *facet1, facetT *facet2);
+setT   *qh_vertexridges(qhT *qh, vertexT *vertex, boolT allneighbors);
+void    qh_vertexridges_facet(qhT *qh, vertexT *vertex, facetT *facet, setT **ridges);
+void    qh_willdelete(qhT *qh, facetT *facet, facetT *replace);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* qhDEFmerge */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/poly2_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/poly2_r.c
new file mode 100644
index 00000000000..aed77e001f7
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/poly2_r.c
@@ -0,0 +1,3959 @@
+/*
  ---------------------------------
+
+   poly2_r.c
+   implements polygons and simplicies
+
+   see qh-poly_r.htm, poly_r.h and libqhull_r.h
+
+   frequently used code is in poly_r.c
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/poly2_r.c#22 $$Change: 3978 $
+   $DateTime: 2025/08/24 21:38:45 $$Author: bbarber $
+*/
+
+#include "qhull_ra.h"
+
+/*======== functions in alphabetical order ==========*/
+
+/*---------------------------------
+
+  qh_addfacetvertex(qh, facet, newvertex )
+    add newvertex to facet.vertices if not already there
+    vertices are inverse sorted by vertex->id
+
+  returns:
+    True if new vertex for facet
+
+  notes:
+    see qh_replacefacetvertex
+*/
+boolT qh_addfacetvertex(qhT *qh, facetT *facet, vertexT *newvertex) {
+  vertexT *vertex;
+  int vertex_i= 0, vertex_n;
+  boolT isnew= True;
+
+  FOREACHvertex_i_(qh, facet->vertices) {
+    if (vertex->id < newvertex->id) {
+      break;
+    }else if (vertex->id == newvertex->id) {
+      isnew= False;
+      break;
+    }
+  }
+  if (isnew)
+    qh_setaddnth(qh, &facet->vertices, vertex_i, newvertex);
+  return isnew;
+} /* addfacetvertex */
+
+/*---------------------------------
+
+  qh_addhash( newelem, hashtable, hashsize, hash )
+    add newelem to linear hash table at hash if not already there
+*/
+void qh_addhash(void *newelem, setT *hashtable, int hashsize, int hash) {
+  int scan;
+  void *elem;
+
+  for (scan= (int)hash; (elem= SETelem_(hashtable, scan));
+       scan= (++scan >= hashsize ? 0 : scan)) {
+    if (elem == newelem)
+      break;
+  }
+  /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */
+  if (!elem)
+    SETelem_(hashtable, scan)= newelem;
+} /* addhash */
+
+/*---------------------------------
+
+  qh_check_bestdist(qh)
+    check that all points are within max_outside of the nearest facet
+    if qh.ONLYgood,
+      ignores !good facets
+
+  see:
+    qh_check_maxout(), qh_outerinner()
+
+  notes:
+    only called from qh_check_points()
+      seldom used since qh.MERGING is almost always set
+    if notverified>0 at end of routine
+      some points were well inside the hull.  If the hull contains
+      a lens-shaped component, these points were not verified.  Use
+      options 'Qi Tv' to verify all points.  (Exhaustive check also verifies)
+
+  design:
+    determine facet for each point (if any)
+    for each point
+      start with the assigned facet or with the first facet
+      find the best facet for the point and check all coplanar facets
+      error if point is outside of facet
+*/
+void qh_check_bestdist(qhT *qh) {
+  boolT waserror= False, unassigned;
+  facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;
+  facetT *facetlist;
+  realT dist, maxoutside, maxdist= -REALmax;
+  pointT *point;
+  int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;
+  setT *facets;
+
+  trace1((qh, qh->ferr, 1020, "qh_check_bestdist: check points below nearest facet.  Facet_list f%d\n",
+      qh->facet_list->id));
+  maxoutside= qh_maxouter(qh);
+  maxoutside += qh->DISTround;
+  /* one more qh.DISTround for check computation */
+  trace1((qh, qh->ferr, 1021, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));
+  facets= qh_pointfacet(qh /* qh.facet_list */);
+  if (!qh_QUICKhelp && qh->PRINTprecision)
+    qh_fprintf(qh, qh->ferr, 8091, "\n\
+qhull output completed.  Verifying that %d points are\n\
+below %2.2g of the nearest %sfacet.\n",
+             qh_setsize(qh, facets), maxoutside, (qh->ONLYgood ?  "good " : ""));
+  FOREACHfacet_i_(qh, facets) {  /* for each point with facet assignment */
+    if (facet)
+      unassigned= False;
+    else {
+      unassigned= True;
+      facet= qh->facet_list;
+    }
+    point= qh_point(qh, facet_i);
+    if (point == qh->GOODpointp)
+      continue;
+    qh_distplane(qh, point, facet, &dist);
+    numpart++;
+    bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);
+    /* occurs after statistics reported */
+    maximize_(maxdist, dist);
+    if (dist > maxoutside) {
+      if (qh->ONLYgood && !bestfacet->good
+      && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))
+      && dist > maxoutside))
+        notgood++;
+      else {
+        waserror= True;
+        qh_fprintf(qh, qh->ferr, 6109, "qhull precision error (qh_check_bestdist): point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",
+                facet_i, bestfacet->id, dist, maxoutside);
+        if (errfacet1 != bestfacet) {
+          errfacet2= errfacet1;
+          errfacet1= bestfacet;
+        }
+      }
+    }else if (unassigned && dist < -qh->MAXcoplanar)
+      notverified++;
+  }
+  qh_settempfree(qh, &facets);
+  if (notverified && !qh->DELAUNAY && !qh_QUICKhelp && qh->PRINTprecision)
+    qh_fprintf(qh, qh->ferr, 8092, "\n%d points were well inside the hull.  If the hull contains\n\
+a lens-shaped component, these points were not verified.  Use\n\
+options 'Qci Tv' to verify all points.\n", notverified);
+  if (maxdist > qh->outside_err) {
+    qh_fprintf(qh, qh->ferr, 6110, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull.  The maximum value is qh.outside_err (%6.2g)\n",
+              maxdist, qh->outside_err);
+    qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
+  }else if (waserror && qh->outside_err > REALmax/2)
+    qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
+  /* else if waserror, the error was logged to qh.ferr but does not effect the output */
+  trace0((qh, qh->ferr, 20, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));
+} /* check_bestdist */
+
+#ifndef qh_NOmerge
+/*---------------------------------
+
+  qh_check_maxout(qh)
+    updates qh.max_outside by checking all points against bestfacet
+    if qh.ONLYgood, ignores !good facets
+
+  returns:
+    updates facet->maxoutside via qh_findbesthorizon()
+    sets qh.maxoutdone
+    if printing qh.min_vertex (qh_outerinner),
+      it is updated to the current vertices
+    removes inside/coplanar points from coplanarset as needed
+
+  notes:
+    defines coplanar as qh.min_vertex instead of qh.MAXcoplanar
+    may not need to check near-inside points because of qh.MAXcoplanar
+      and qh.KEEPnearinside (before it was -qh.DISTround)
+
+  see also:
+    qh_check_bestdist()
+
+  design:
+    if qh.min_vertex is needed
+      for all neighbors of all vertices
+        test distance from vertex to neighbor
+    determine facet for each point (if any)
+    for each point with an assigned facet
+      find the best facet for the point and check all coplanar facets
+        (updates outer planes)
+    remove near-inside points from coplanar sets
+*/
+void qh_check_maxout(qhT *qh) {
+  facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist, *maxbestfacet= NULL, *minfacet, *maxfacet, *maxpointfacet;
+  realT dist, maxoutside, mindist, nearest;
+  realT maxoutside_base, minvertex_base;
+  pointT *point, *maxpoint= NULL;
+  int numpart= 0, facet_i, facet_n, notgood= 0;
+  setT *facets, *vertices;
+  vertexT *vertex, *minvertex;
+
+  trace1((qh, qh->ferr, 1022, "qh_check_maxout: check and update qh.min_vertex %2.2g and qh.max_outside %2.2g\n", qh->min_vertex, qh->max_outside));
+  minvertex_base= fmin_(qh->min_vertex, -(qh->ONEmerge+qh->DISTround));
+  maxoutside= mindist= 0.0;
+  minvertex= qh->vertex_list;
+  maxfacet= minfacet= maxpointfacet= qh->facet_list;
+  if (qh->VERTEXneighbors
+  && (qh->PRINTsummary || qh->KEEPinside || qh->KEEPcoplanar
+        || qh->TRACElevel || qh->PRINTstatistics || qh->VERIFYoutput || qh->CHECKfrequently
+        || qh->PRINTout[0] == qh_PRINTsummary || qh->PRINTout[0] == qh_PRINTnone)) {
+    trace1((qh, qh->ferr, 1023, "qh_check_maxout: determine actual minvertex\n"));
+    vertices= qh_pointvertex(qh /* qh.facet_list */);
+    FORALLvertices {
+      FOREACHneighbor_(vertex) {
+        zinc_(Zdistvertex);  /* distance also computed by main loop below */
+        qh_distplane(qh, vertex->point, neighbor, &dist);
+        if (dist < mindist) {
+          if (qh->min_vertex/minvertex_base > qh_WIDEmaxoutside && (qh->PRINTprecision || !qh->ALLOWwide)) {
+            nearest= qh_vertex_bestdist(qh, neighbor->vertices);
+            /* should be caught in qh_mergefacet */
+            qh_fprintf(qh, qh->ferr, 7083, "Qhull precision warning: in post-processing (qh_check_maxout) p%d(v%d) is %2.2g below f%d nearest vertices %2.2g\n",
+              qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id, nearest);
+          }
+          mindist= dist;
+          minvertex= vertex;
+          minfacet= neighbor;
+        }
+#ifndef qh_NOtrace
+        if (-dist > qh->TRACEdist || dist > qh->TRACEdist
+        || neighbor == qh->tracefacet || vertex == qh->tracevertex) {
+          nearest= qh_vertex_bestdist(qh, neighbor->vertices);
+          qh_fprintf(qh, qh->ferr, 8093, "qh_check_maxout: p%d(v%d) is %.2g from f%d nearest vertices %2.2g\n",
+                    qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id, nearest);
+        }
+#endif
+      }
+    }
+    if (qh->MERGING) {
+      wmin_(Wminvertex, qh->min_vertex);
+    }
+    qh->min_vertex= mindist;
+    qh_settempfree(qh, &vertices);
+  }
+  trace1((qh, qh->ferr, 1055, "qh_check_maxout: determine actual maxoutside\n"));
+  maxoutside_base= fmax_(qh->max_outside, qh->ONEmerge+qh->DISTround);
+  /* maxoutside_base is same as qh.MAXoutside without qh.MINoutside (qh_detmaxoutside) */
+  facets= qh_pointfacet(qh /* qh.facet_list */);
+  FOREACHfacet_i_(qh, facets) {     /* for each point with facet assignment */
+    if (facet) {
+      point= qh_point(qh, facet_i);
+      if (point == qh->GOODpointp)
+        continue;
+      zzinc_(Ztotcheck);
+      qh_distplane(qh, point, facet, &dist);
+      numpart++;
+      bestfacet= qh_findbesthorizon(qh, qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);
+      if (bestfacet && dist >= maxoutside) {
+        if (qh->ONLYgood && !bestfacet->good
+        && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))
+        && dist > maxoutside)) {
+          notgood++;
+        }else if (dist/maxoutside_base > qh_WIDEmaxoutside && (qh->PRINTprecision || !qh->ALLOWwide)) {
+          nearest= qh_vertex_bestdist(qh, bestfacet->vertices);
+          if (nearest < fmax_(qh->ONEmerge, qh->max_outside) * qh_RATIOcoplanaroutside * 2) {
+            qh_fprintf(qh, qh->ferr, 7087, "Qhull precision warning: in post-processing (qh_check_maxout) p%d for f%d is %2.2g above twisted facet f%d nearest vertices %2.2g\n",
+              qh_pointid(qh, point), facet->id, dist, bestfacet->id, nearest);
+          }else {
+            qh_fprintf(qh, qh->ferr, 7088, "Qhull precision warning: in post-processing (qh_check_maxout) p%d for f%d is %2.2g above hidden facet f%d nearest vertices %2.2g\n",
+              qh_pointid(qh, point), facet->id, dist, bestfacet->id, nearest);
+          }
+          maxbestfacet= bestfacet;
+        }
+        maxoutside= dist;
+        maxfacet= bestfacet;
+        maxpoint= point;
+        maxpointfacet= facet;
+      }
+      if (dist > qh->TRACEdist || (bestfacet && bestfacet == qh->tracefacet))
+        qh_fprintf(qh, qh->ferr, 8094, "qh_check_maxout: p%d is %.2g above f%d\n",
+              qh_pointid(qh, point), dist, (bestfacet ? bestfacet->id : UINT_MAX));
+    }
+  }
+  zzadd_(Zcheckpart, numpart);
+  qh_settempfree(qh, &facets);
+  wval_(Wmaxout)= maxoutside - qh->max_outside;
+  wmax_(Wmaxoutside, qh->max_outside);
+  if (!qh->APPROXhull && maxoutside > qh->DISTround) { /* initial value for f.maxoutside */
+    FORALLfacets {
+      if (maxoutside < facet->maxoutside) {
+        if (!qh->KEEPcoplanar) {
+          maxoutside= facet->maxoutside;
+        }else if (maxoutside + qh->DISTround < facet->maxoutside) { /* maxoutside is computed distance, e.g., rbox 100 s D3 t1547136913 | qhull R1e-3 Tcv Qc */
+          qh_fprintf(qh, qh->ferr, 7082, "Qhull precision warning (qh_check_maxout): f%d.maxoutside (%4.4g) is greater than computed qh.max_outside (%2.2g) + qh.DISTround (%2.2g).  It should be less than or equal\n",
+            facet->id, facet->maxoutside, maxoutside, qh->DISTround);
+        }
+      }
+    }
+  }
+  qh->max_outside= maxoutside;
+  qh_nearcoplanar(qh /* qh.facet_list */);
+  qh->maxoutdone= True;
+  trace1((qh, qh->ferr, 1024, "qh_check_maxout:  p%d(v%d) is qh.min_vertex %2.2g below facet f%d.  Point p%d for f%d is qh.max_outside %2.2g above f%d.  %d points are outside of not-good facets\n",
+    qh_pointid(qh, minvertex->point), minvertex->id, qh->min_vertex, minfacet->id, qh_pointid(qh, maxpoint), maxpointfacet->id, qh->max_outside, maxfacet->id, notgood));
+  if(!qh->ALLOWwide) {
+    if (maxoutside/maxoutside_base > qh_WIDEmaxoutside) {
+      qh_fprintf(qh, qh->ferr, 6297, "Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist %2.2g (%.1fx).  See warning QH0032/QH0033.  Allow with 'Q12' (allow-wide) and 'Pp'\n",
+        maxoutside, maxoutside/maxoutside_base);
+      qh_errexit(qh, qh_ERRwide, maxbestfacet, NULL);
+    }else if (!qh->APPROXhull && maxoutside_base > (qh->ONEmerge * qh_WIDEmaxoutside2)) {
+      if (maxoutside > (qh->ONEmerge * qh_WIDEmaxoutside2)) {  /* wide facets may have been deleted */
+        qh_fprintf(qh, qh->ferr, 6298, "Qhull precision error (qh_check_maxout): a facet merge, vertex merge, vertex, or coplanar point produced a wide facet %2.2g (%.1fx). Trace with option 'TWn' to identify the merge.   Allow with 'Q12' (allow-wide)\n",
+          maxoutside_base, maxoutside_base/(qh->ONEmerge + qh->DISTround));
+        qh_errexit(qh, qh_ERRwide, maxbestfacet, NULL);
+      }
+    }else if (qh->min_vertex/minvertex_base > qh_WIDEmaxoutside) {
+      qh_fprintf(qh, qh->ferr, 6354, "Qhull precision error (qh_check_maxout): large increase in qh.min_vertex during post-processing dist %2.2g (%.1fx).  See warning QH7083.  Allow with 'Q12' (allow-wide) and 'Pp'\n",
+        qh->min_vertex, qh->min_vertex/minvertex_base);
+      qh_errexit(qh, qh_ERRwide, minfacet, NULL);
+    }else if (minvertex_base < -(qh->ONEmerge * qh_WIDEmaxoutside2)) {
+      if (qh->min_vertex < -(qh->ONEmerge * qh_WIDEmaxoutside2)) {  /* wide facets may have been deleted */
+        qh_fprintf(qh, qh->ferr, 6380, "Qhull precision error (qh_check_maxout): a facet or vertex merge produced a wide facet: v%d below f%d distance %2.2g (%.1fx). Trace with option 'TWn' to identify the merge.  Allow with 'Q12' (allow-wide)\n",
+          minvertex->id, minfacet->id, mindist, -qh->min_vertex/(qh->ONEmerge + qh->DISTround));
+        qh_errexit(qh, qh_ERRwide, minfacet, NULL);
+      }
+    }
+  }
+} /* check_maxout */
+#else /* qh_NOmerge */
+void qh_check_maxout(qhT *qh) {
+  QHULL_UNUSED(qh)
+}
+#endif
+
+/*---------------------------------
+
+  qh_check_output(qh)
+    performs the checks at the end of qhull algorithm
+    Maybe called after Voronoi output.  If so, it recomputes centrums since they are Voronoi centers instead.
+*/
+void qh_check_output(qhT *qh) {
+  int i;
+
+  if (qh->STOPcone)
+    return;
+  if (qh->VERIFYoutput || qh->IStracing || qh->CHECKfrequently) {
+    qh_checkpolygon(qh, qh->facet_list);
+    qh_checkflipped_all(qh, qh->facet_list);
+    qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
+  }else if (!qh->MERGING && qh_newstats(qh, qh->qhstat.precision, &i)) {
+    qh_checkflipped_all(qh, qh->facet_list);
+    qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
+  }
+} /* check_output */
+
+
+
+/*---------------------------------
+
+  qh_check_point(qh, point, facet, maxoutside, maxdist, errfacet1, errfacet2, errcount )
+    check that point is less than maxoutside from facet
+
+  notes:
+    only called from qh_checkpoints
+    reports up to qh_MAXcheckpoint-1 errors per facet
+*/
+void qh_check_point(qhT *qh, pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2, int *errcount) {
+  realT dist, nearest;
+
+  /* occurs after statistics reported */
+  qh_distplane(qh, point, facet, &dist);
+  maximize_(*maxdist, dist);
+  if (dist > *maxoutside) {
+    (*errcount)++;
+    if (*errfacet1 != facet) {
+      *errfacet2= *errfacet1;
+      *errfacet1= facet;
+    }
+    if (*errcount < qh_MAXcheckpoint) {
+      nearest= qh_vertex_bestdist(qh, facet->vertices);
+      qh_fprintf(qh, qh->ferr, 6111, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g nearest vertices %2.2g\n",
+                qh_pointid(qh, point), facet->id, dist, *maxoutside, nearest);
+    }
+  }
+} /* qh_check_point */
+
+
+/*---------------------------------
+
+  qh_check_points(qh)
+    checks that all points are inside all facets
+
+  notes:
+    if many points and qh_check_maxout not called (i.e., !qh.MERGING),
+       calls qh_findbesthorizon via qh_check_bestdist (seldom done).
+    ignores flipped facets
+    maxoutside includes 2 qh.DISTrounds
+      one qh.DISTround for the computed distances in qh_check_points
+    qh_printafacet and qh_printsummary needs only one qh.DISTround
+    the computation for qh.VERIFYdirect does not account for qh.other_points
+
+  design:
+    if many points
+      use qh_check_bestdist()
+    else
+      for all facets
+        for all points
+          check that point is inside facet
+*/
+void qh_check_points(qhT *qh) {
+  facetT *facet, *errfacet1= NULL, *errfacet2= NULL;
+  realT total, maxoutside, maxdist= -REALmax;
+  pointT *point, **pointp, *pointtemp;
+  int errcount;
+  boolT testouter;
+
+  maxoutside= qh_maxouter(qh);
+  maxoutside += qh->DISTround;
+  /* one more qh.DISTround for check computation */
+  trace1((qh, qh->ferr, 1025, "qh_check_points: check all points below %2.2g of all facet planes\n",
+          maxoutside));
+  if (qh->num_good)   /* miss counts other_points and !good facets */
+     total= (realT)qh->num_good * (realT)qh->num_points;
+  else
+     total= (realT)qh->num_facets * (realT)qh->num_points;
+  if (total >= qh_VERIFYdirect && !qh->maxoutdone) {
+    if (!qh_QUICKhelp && qh->SKIPcheckmax && qh->MERGING)
+      qh_fprintf(qh, qh->ferr, 7075, "qhull input warning: merging without checking outer planes('Q5' or 'Po').  Verify may report that a point is outside of a facet.\n");
+    qh_check_bestdist(qh);
+  }else {
+    if (qh_MAXoutside && qh->maxoutdone)
+      testouter= True;
+    else
+      testouter= False;
+    if (!qh_QUICKhelp) {
+      if (qh->MERGEexact)
+        qh_fprintf(qh, qh->ferr, 7076, "qhull input warning: exact merge ('Qx').  Verify may report that a point is outside of a facet.  See qh-optq.htm#Qx\n");
+      else if (qh->SKIPcheckmax || qh->NOnearinside)
+        qh_fprintf(qh, qh->ferr, 7077, "qhull input warning: no outer plane check ('Q5') or no processing of near-inside points ('Q8').  Verify may report that a point is outside of a facet.\n");
+    }
+    if (qh->PRINTprecision) {
+      if (testouter)
+        qh_fprintf(qh, qh->ferr, 8098, "\n\
+Output completed.  Verifying that all points are below outer planes of\n\
+all %sfacets.  Will make %2.0f distance computations.\n",
+              (qh->ONLYgood ?  "good " : ""), total);
+      else
+        qh_fprintf(qh, qh->ferr, 8099, "\n\
+Output completed.  Verifying that all points are below %2.2g of\n\
+all %sfacets.  Will make %2.0f distance computations.\n",
+              maxoutside, (qh->ONLYgood ?  "good " : ""), total);
+    }
+    FORALLfacets {
+      if (!facet->good && qh->ONLYgood)
+        continue;
+      if (facet->flipped)
+        continue;
+      if (!facet->normal) {
+        qh_fprintf(qh, qh->ferr, 7061, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);
+        if (!errfacet1)
+          errfacet1= facet;
+        continue;
+      }
+      if (testouter) {
+#if qh_MAXoutside
+        maxoutside= facet->maxoutside + 2 * qh->DISTround;
+        /* one DISTround to actual point and another to computed point */
+#endif
+      }
+      errcount= 0;
+      FORALLpoints {
+        if (point != qh->GOODpointp)
+          qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2, &errcount);
+      }
+      FOREACHpoint_(qh->other_points) {
+        if (point != qh->GOODpointp)
+          qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2, &errcount);
+      }
+      if (errcount >= qh_MAXcheckpoint) {
+        qh_fprintf(qh, qh->ferr, 6422, "qhull precision error (qh_check_points): %d additional points outside facet f%d, maxdist= %6.8g\n",
+             errcount-qh_MAXcheckpoint+1, facet->id, maxdist);
+      }
+    }
+    if (maxdist > qh->outside_err) {
+      qh_fprintf(qh, qh->ferr, 6112, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull.  The maximum value(qh.outside_err) is %6.2g\n",
+                maxdist, qh->outside_err );
+      qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );
+    }else if (errfacet1 && qh->outside_err > REALmax/2)
+        qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );
+    /* else if errfacet1, the error was logged to qh.ferr but does not effect the output */
+    trace0((qh, qh->ferr, 21, "qh_check_points: max distance outside %2.2g\n", maxdist));
+  }
+} /* check_points */
+
+
+/*---------------------------------
+
+  qh_checkconvex(qh, facetlist, fault )
+    check that each ridge in facetlist is convex
+    fault = qh_DATAfault if reporting errors from qh_initialhull with qh.ZEROcentrum
+          = qh_ALGORITHMfault otherwise
+
+  returns:
+    counts Zconcaveridges and Zcoplanarridges
+    errors if !qh.FORCEoutput ('Fo') and concaveridge or if merging a coplanar ridge
+    overwrites Voronoi centers if set by qh_setvoronoi_all/qh_ASvoronoi
+
+  notes:
+    called by qh_initial_hull, qh_check_output, qh_all_merges ('Tc'), qh_build_withrestart ('QJ')
+    does not test f.tricoplanar facets (qh_triangulate)
+    must be no stronger than qh_test_appendmerge
+    if not merging,
+      tests vertices for neighboring simplicial facets < -qh.DISTround
+    else if ZEROcentrum and simplicial facet,
+      tests vertices for neighboring simplicial facets < 0.0
+      tests centrums of neighboring nonsimplicial facets < 0.0
+    else if ZEROcentrum
+      tests centrums of neighboring facets < 0.0
+    else
+      tests centrums of neighboring facets < -qh.DISTround ('En' 'Rn')
+    Does not test against -qh.centrum_radius since repeated computations may have different round-off errors (e.g., 'Rn')
+
+  design:
+    for all facets
+      report flipped facets
+      if ZEROcentrum and simplicial neighbors
+        test vertices against neighbor
+      else
+        test centrum against neighbor
+*/
+void qh_checkconvex(qhT *qh, facetT *facetlist, int fault) {
+  facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;
+  vertexT *vertex;
+  realT dist;
+  pointT *centrum;
+  boolT waserror= False, centrum_warning= False, tempcentrum= False, first_nonsimplicial= False, tested_simplicial, allsimplicial;
+  int neighbor_i, neighbor_n;
+
+  if (qh->ZEROcentrum) {
+    trace1((qh, qh->ferr, 1064, "qh_checkconvex: check that facets are not-flipped and for qh.ZEROcentrum that simplicial vertices are below their neighbor (dist<0.0)\n"));
+    first_nonsimplicial= True;
+  }else if (!qh->MERGING) {
+    trace1((qh, qh->ferr, 1026, "qh_checkconvex: check that facets are not-flipped and that simplicial vertices are convex by qh.DISTround ('En', 'Rn')\n"));
+    first_nonsimplicial= True;
+  }else
+    trace1((qh, qh->ferr, 1062, "qh_checkconvex: check that facets are not-flipped and that their centrums are convex by qh.DISTround ('En', 'Rn') \n"));
+  if (!qh->RERUN) {
+    zzval_(Zconcaveridges)= 0;
+    zzval_(Zcoplanarridges)= 0;
+  }
+  FORALLfacet_(facetlist) {
+    if (facet->flipped) {
+      qh_joggle_restart(qh, "flipped facet"); /* also tested by qh_checkflipped */
+      qh_fprintf(qh, qh->ferr, 6113, "qhull precision error: f%d is flipped (interior point is outside)\n",
+               facet->id);
+      errfacet1= facet;
+      waserror= True;
+      continue;
+    }
+    if (facet->tricoplanar)
+      continue;
+    if (qh->MERGING && (!qh->ZEROcentrum || !facet->simplicial)) {
+      allsimplicial= False;
+      tested_simplicial= False;
+    }else {
+      allsimplicial= True;
+      tested_simplicial= True;
+      FOREACHneighbor_i_(qh, facet) {
+        if (neighbor->tricoplanar)
+          continue;
+        if (!neighbor->simplicial) {
+          allsimplicial= False;
+          continue;
+        }
+        vertex= SETelemt_(facet->vertices, neighbor_i, vertexT);
+        qh_distplane(qh, vertex->point, neighbor, &dist);
+        if (dist >= -qh->DISTround) {
+          if (fault == qh_DATAfault) {
+            qh_joggle_restart(qh, "non-convex initial simplex");
+            if (dist > qh->DISTround)
+              qh_fprintf(qh, qh->ferr, 6114, "qhull precision error: initial simplex is not convex, since p%d(v%d) is %6.4g above opposite f%d\n",
+                  qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);
+            else
+              qh_fprintf(qh, qh->ferr, 6379, "qhull precision error: initial simplex is not convex, since p%d(v%d) is within roundoff of opposite facet f%d (dist %6.4g)\n",
+                  qh_pointid(qh, vertex->point), vertex->id, neighbor->id, dist);
+            qh_errexit(qh, qh_ERRsingular, neighbor, NULL);
+          }
+          if (dist > qh->DISTround) {
+            zzinc_(Zconcaveridges);
+            qh_joggle_restart(qh, "concave ridge");
+            qh_fprintf(qh, qh->ferr, 6115, "qhull precision error: f%d is concave to f%d, since p%d(v%d) is %6.4g above f%d\n",
+              facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);
+            errfacet1= facet;
+            errfacet2= neighbor;
+            waserror= True;
+          }else if (qh->ZEROcentrum) {
+            if (dist > 0.0) {     /* qh_checkzero checked convex (dist < (- 2*qh->DISTround)), computation may differ e.g. 'Rn' */
+              zzinc_(Zcoplanarridges);
+              qh_joggle_restart(qh, "coplanar ridge");
+              qh_fprintf(qh, qh->ferr, 6116, "qhull precision error: f%d is clearly not convex to f%d, since p%d(v%d) is %6.4g above or coplanar with f%d with qh.ZEROcentrum\n",
+                facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);
+              errfacet1= facet;
+              errfacet2= neighbor;
+              waserror= True;
+            }
+          }else {
+            zzinc_(Zcoplanarridges);
+            qh_joggle_restart(qh, "coplanar ridge");
+            trace0((qh, qh->ferr, 22, "qhull precision error: f%d is coplanar to f%d, since p%d(v%d) is within %6.4g of f%d, during p%d\n",
+              facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id, qh->furthest_id));
+          }
+        }
+      }
+    }
+    if (!allsimplicial) {
+      if (first_nonsimplicial) {
+        trace1((qh, qh->ferr, 1063, "qh_checkconvex: starting with f%d, also check that centrums of non-simplicial ridges are below their neighbors (dist<0.0)\n",
+             facet->id));
+        first_nonsimplicial= False;
+      }
+      if (qh->CENTERtype == qh_AScentrum) {
+        if (!facet->center)
+          facet->center= qh_getcentrum(qh, facet);
+        centrum= facet->center;
+      }else {
+        if (!centrum_warning && !facet->simplicial) {  /* recomputed centrum correct for simplicial facets */
+           centrum_warning= True;
+           qh_fprintf(qh, qh->ferr, 7062, "qhull warning: recomputing centrums for convexity test.  This may lead to false, precision errors.\n");
+        }
+        centrum= qh_getcentrum(qh, facet);
+        tempcentrum= True;
+      }
+      FOREACHneighbor_(facet) {
+        if (neighbor->simplicial && tested_simplicial) /* tested above since f.simplicial */
+          continue;
+        if (neighbor->tricoplanar)
+          continue;
+        zzinc_(Zdistconvex);
+        qh_distplane(qh, centrum, neighbor, &dist);
+        if (dist > qh->DISTround) {
+          zzinc_(Zconcaveridges);
+          qh_joggle_restart(qh, "concave ridge");
+          qh_fprintf(qh, qh->ferr, 6117, "qhull precision error: f%d is concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
+            facet->id, neighbor->id, facet->id, dist, neighbor->id);
+          errfacet1= facet;
+          errfacet2= neighbor;
+          waserror= True;
+        }else if (dist >= 0.0) {   /* if arithmetic always rounds the same,
+                                     can test against centrum radius instead */
+          zzinc_(Zcoplanarridges);
+          qh_joggle_restart(qh, "coplanar ridge");
+          qh_fprintf(qh, qh->ferr, 6118, "qhull precision error: f%d is coplanar or concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
+            facet->id, neighbor->id, facet->id, dist, neighbor->id);
+          errfacet1= facet;
+          errfacet2= neighbor;
+          waserror= True;
+        }
+      }
+      if (tempcentrum)
+        qh_memfree(qh, centrum, qh->normal_size);
+    }
+  }
+  if (waserror && !qh->FORCEoutput)
+    qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
+} /* checkconvex */
+
+
+/*---------------------------------
+
+  qh_checkfacet(qh, facet, newmerge, waserror )
+    checks for consistency errors in facet
+    newmerge set if from merge_r.c
+
+  returns:
+    sets waserror if any error occurs
+
+  checks:
+    vertex ids are inverse sorted
+    unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)
+    if non-simplicial, at least as many ridges as neighbors
+    neighbors are not duplicated
+    ridges are not duplicated
+    in 3-d, ridges=verticies
+    (qh.hull_dim-1) ridge vertices
+    neighbors are reciprocated
+    ridge neighbors are facet neighbors and a ridge for every neighbor
+    simplicial neighbors match facetintersect
+    vertex intersection matches vertices of common ridges
+    vertex neighbors and facet vertices agree
+    all ridges have distinct vertex sets
+
+  notes:
+    called by qh_tracemerge and qh_checkpolygon
+    uses neighbor->seen
+
+  design:
+    check sets
+    check vertices
+    check sizes of neighbors and vertices
+    check for qh_MERGEridge and qh_DUPLICATEridge flags
+    check neighbor set
+    check ridge set
+    check ridges, neighbors, and vertices
+*/
+void qh_checkfacet(qhT *qh, facetT *facet, boolT newmerge, boolT *waserrorp) {
+  facetT *neighbor, **neighborp, *errother=NULL;
+  ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2;
+  vertexT *vertex, **vertexp;
+  unsigned int previousid= INT_MAX;
+  int numneighbors, numvertices, numridges=0, numRvertices=0;
+  boolT waserror= False;
+  int skipA, skipB, ridge_i, ridge_n, i, last_v= qh->hull_dim-2;
+  setT *intersection;
+
+  trace4((qh, qh->ferr, 4088, "qh_checkfacet: check f%d newmerge? %d\n", facet->id, newmerge));
+  if (facet->id >= qh->facet_id) {
+    qh_fprintf(qh, qh->ferr, 6414, "qhull internal error (qh_checkfacet): unknown facet id f%d >= qh.facet_id (%d)\n", facet->id, qh->facet_id);
+    waserror= True;
+  }
+  if (facet->visitid > qh->visit_id) {
+    qh_fprintf(qh, qh->ferr, 6415, "qhull internal error (qh_checkfacet): expecting f%d.visitid <= qh.visit_id (%d).  Got visitid %d\n", facet->id, qh->visit_id, facet->visitid);
+    waserror= True;
+  }
+  if (facet->visible && !qh->NEWtentative) {
+    qh_fprintf(qh, qh->ferr, 6119, "qhull internal error (qh_checkfacet): facet f%d is on qh.visible_list\n",
+      facet->id);
+    qh_errexit(qh, qh_ERRqhull, facet, NULL);
+  }
+  if (facet->redundant && !facet->visible && qh_setsize(qh, qh->degen_mergeset)==0) {
+    qh_fprintf(qh, qh->ferr, 6399, "qhull internal error (qh_checkfacet): redundant facet f%d not on qh.visible_list\n",
+      facet->id);
+    waserror= True;
+  }
+  if (facet->degenerate && !facet->visible && qh_setsize(qh, qh->degen_mergeset)==0) {
+    qh_fprintf(qh, qh->ferr, 6400, "qhull internal error (qh_checkfacet): degenerate facet f%d is not on qh.visible_list and qh.degen_mergeset is empty\n",
+      facet->id);
+    waserror= True;
+  }
+  if (!facet->normal) {
+    qh_fprintf(qh, qh->ferr, 6120, "qhull internal error (qh_checkfacet): facet f%d does not have a normal\n",
+      facet->id);
+    waserror= True;
+  }
+  if (!facet->newfacet) {
+    if (facet->dupridge) {
+      qh_fprintf(qh, qh->ferr, 6349, "qhull internal error (qh_checkfacet): f%d is 'dupridge' but it is not a newfacet on qh.newfacet_list f%d\n",
+        facet->id, getid_(qh->newfacet_list));
+      waserror= True;
+    }
+    if (facet->newmerge) {
+      qh_fprintf(qh, qh->ferr, 6383, "qhull internal error (qh_checkfacet): f%d is 'newmerge' but it is not a newfacet on qh.newfacet_list f%d.  Missing call to qh_reducevertices\n",
+        facet->id, getid_(qh->newfacet_list));
+      waserror= True;
+    }
+  }
+  qh_setcheck(qh, facet->vertices, "vertices for f", facet->id);
+  qh_setcheck(qh, facet->ridges, "ridges for f", facet->id);
+  qh_setcheck(qh, facet->outsideset, "outsideset for f", facet->id);
+  qh_setcheck(qh, facet->coplanarset, "coplanarset for f", facet->id);
+  qh_setcheck(qh, facet->neighbors, "neighbors for f", facet->id);
+  FOREACHvertex_(facet->vertices) {
+    if (vertex->deleted) {
+      qh_fprintf(qh, qh->ferr, 6121, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);
+      qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
+      waserror= True;
+    }
+    if (vertex->id >= previousid) {
+      qh_fprintf(qh, qh->ferr, 6122, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);
+      waserror= True;
+      break;
+    }
+    previousid= vertex->id;
+  }
+  numneighbors= qh_setsize(qh, facet->neighbors);
+  numvertices= qh_setsize(qh, facet->vertices);
+  numridges= qh_setsize(qh, facet->ridges);
+  if (facet->simplicial) {
+    if (numvertices+numneighbors != 2*qh->hull_dim
+    && !facet->degenerate && !facet->redundant) {
+      qh_fprintf(qh, qh->ferr, 6123, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh->hull_dim\n",
+                facet->id, numvertices, numneighbors);
+      qh_setprint(qh, qh->ferr, "", facet->neighbors);
+      waserror= True;
+    }
+  }else { /* non-simplicial */
+    if (!newmerge
+    &&(numvertices < qh->hull_dim || numneighbors < qh->hull_dim)
+    && !facet->degenerate && !facet->redundant) {
+      qh_fprintf(qh, qh->ferr, 6124, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh->hull_dim\n",
+         facet->id, numvertices, numneighbors);
+       waserror= True;
+    }
+    /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */
+    if (numridges < numneighbors
+    ||(qh->hull_dim == 3 && numvertices > numridges && !qh->NEWfacets)
+    ||(qh->hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {
+      if (!facet->degenerate && !facet->redundant) {
+        qh_fprintf(qh, qh->ferr, 6125, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or(3-d) > #vertices %d or(2-d) not all 2\n",
+            facet->id, numridges, numneighbors, numvertices);
+        waserror= True;
+      }
+    }
+  }
+  FOREACHneighbor_(facet) {
+    if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {
+      qh_fprintf(qh, qh->ferr, 6126, "qhull internal error (qh_checkfacet): facet f%d still has a MERGEridge or DUPLICATEridge neighbor\n", facet->id);
+      qh_errexit(qh, qh_ERRqhull, facet, NULL);
+    }
+    if (neighbor->visible) {
+      qh_fprintf(qh, qh->ferr, 6401, "qhull internal error (qh_checkfacet): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
+        facet->id, neighbor->id);
+      errother= neighbor;
+      waserror= True;
+    }
+    neighbor->seen= True;
+  }
+  FOREACHneighbor_(facet) {
+    if (!qh_setin(neighbor->neighbors, facet)) {
+      qh_fprintf(qh, qh->ferr, 6127, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",
+              facet->id, neighbor->id, neighbor->id, facet->id);
+      errother= neighbor;
+      waserror= True;
+    }
+    if (!neighbor->seen) {
+      qh_fprintf(qh, qh->ferr, 6128, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",
+              facet->id, neighbor->id);
+      errother= neighbor;
+      waserror= True;
+    }
+    neighbor->seen= False;
+  }
+  FOREACHridge_(facet->ridges) {
+    qh_setcheck(qh, ridge->vertices, "vertices for r", ridge->id);
+    ridge->seen= False;
+  }
+  FOREACHridge_(facet->ridges) {
+    if (ridge->seen) {
+      qh_fprintf(qh, qh->ferr, 6129, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",
+              facet->id, ridge->id);
+      errridge= ridge;
+      waserror= True;
+    }
+    ridge->seen= True;
+    numRvertices= qh_setsize(qh, ridge->vertices);
+    if (numRvertices != qh->hull_dim - 1) {
+      qh_fprintf(qh, qh->ferr, 6130, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n",
+                ridge->top->id, ridge->bottom->id, numRvertices);
+      errridge= ridge;
+      waserror= True;
+    }
+    neighbor= otherfacet_(ridge, facet);
+    neighbor->seen= True;
+    if (!qh_setin(facet->neighbors, neighbor)) {
+      qh_fprintf(qh, qh->ferr, 6131, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",
+           facet->id, neighbor->id, ridge->id);
+      errridge= ridge;
+      waserror= True;
+    }
+    if (!facet->newfacet && !neighbor->newfacet) {
+      if ((!ridge->tested) | ridge->nonconvex | ridge->mergevertex) {
+        qh_fprintf(qh, qh->ferr, 6384, "qhull internal error (qh_checkfacet): ridge r%d is nonconvex (%d), mergevertex (%d) or not tested (%d) for facet f%d, neighbor f%d\n",
+          ridge->id, ridge->nonconvex, ridge->mergevertex, ridge->tested, facet->id, neighbor->id);
+        errridge= ridge;
+        waserror= True;
+      }
+    }
+  }
+  if (!facet->simplicial) {
+    FOREACHneighbor_(facet) {
+      if (!neighbor->seen) {
+        qh_fprintf(qh, qh->ferr, 6132, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",
+              facet->id, neighbor->id);
+        errother= neighbor;
+        waserror= True;
+      }
+      intersection= qh_vertexintersect_new(qh, facet->vertices, neighbor->vertices);
+      qh_settemppush(qh, intersection);
+      FOREACHvertex_(facet->vertices) {
+        vertex->seen= False;
+        vertex->seen2= False;
+      }
+      FOREACHvertex_(intersection)
+        vertex->seen= True;
+      FOREACHridge_(facet->ridges) {
+        if (neighbor != otherfacet_(ridge, facet))
+            continue;
+        FOREACHvertex_(ridge->vertices) {
+          if (!vertex->seen) {
+            qh_fprintf(qh, qh->ferr, 6133, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n",
+                  vertex->id, ridge->id, facet->id, neighbor->id);
+            qh_errexit(qh, qh_ERRqhull, facet, ridge);
+          }
+          vertex->seen2= True;
+        }
+      }
+      if (!newmerge) {
+        FOREACHvertex_(intersection) {
+          if (!vertex->seen2) {
+            if (!qh->MERGING) {
+              qh_fprintf(qh, qh->ferr, 6420, "qhull topology error (qh_checkfacet): vertex v%d in f%d intersect f%d but not in a ridge.  Last point was p%d\n",
+                     vertex->id, facet->id, neighbor->id, qh->furthest_id);
+              if (!qh->FORCEoutput) {
+                qh_errprint(qh, "ERRONEOUS", facet, neighbor, NULL, vertex);
+                qh_errexit(qh, qh_ERRtopology, NULL, NULL);
+              }
+            }else {
+              trace4((qh, qh->ferr, 4025, "qh_checkfacet: vertex v%d in f%d intersect f%d but not in a ridge.  Repaired by qh_remove_extravertices in qh_reducevertices\n",
+                vertex->id, facet->id, neighbor->id));
+            }
+          }
+        }
+      }
+      qh_settempfree(qh, &intersection);
+    }
+  }else { /* simplicial */
+    FOREACHneighbor_(facet) {
+      if (neighbor->simplicial && !facet->degenerate && !neighbor->degenerate) {
+        skipA= SETindex_(facet->neighbors, neighbor);
+        skipB= qh_setindex(neighbor->neighbors, facet);
+        if (skipA<0 || skipB<0 || !qh_setequal_skip(facet->vertices, skipA, neighbor->vertices, skipB)) {
+          qh_fprintf(qh, qh->ferr, 6135, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",
+                   facet->id, skipA, neighbor->id, skipB);
+          errother= neighbor;
+          waserror= True;
+        }
+      }
+    }
+  }
+  if (!newmerge && qh->CHECKduplicates && qh->hull_dim < 5 && (qh->IStracing > 2 || qh->CHECKfrequently)) {
+    FOREACHridge_i_(qh, facet->ridges) {           /* expensive, if was merge and qh_maybe_duplicateridges hasn't been called yet */
+      if (!ridge->mergevertex) {
+        for (i=ridge_i+1; i < ridge_n; i++) {
+          ridge2= SETelemt_(facet->ridges, i, ridgeT);
+          if (SETelem_(ridge->vertices, last_v) == SETelem_(ridge2->vertices, last_v)) { /* SETfirst is likely to be the same */
+            if (SETfirst_(ridge->vertices) == SETfirst_(ridge2->vertices)) {
+              if (qh_setequal(ridge->vertices, ridge2->vertices)) {
+                qh_fprintf(qh, qh->ferr, 6294, "qhull internal error (qh_checkfacet): ridges r%d and r%d (f%d) have the same vertices\n", /* same as duplicate ridge */
+                    ridge->id, ridge2->id, facet->id);
+                errridge= ridge;
+                waserror= True;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  if (waserror) {
+    qh_errprint(qh, "ERRONEOUS", facet, errother, errridge, NULL);
+    *waserrorp= True;
+  }
+} /* checkfacet */
+
+/*---------------------------------
+
+  qh_checkflipped_all(qh, facetlist )
+    checks orientation of facets in list against interior point
+
+  notes:
+    called by qh_checkoutput
+*/
+void qh_checkflipped_all(qhT *qh, facetT *facetlist) {
+  facetT *facet;
+  boolT waserror= False;
+  realT dist;
+
+  if (facetlist == qh->facet_list)
+    zzval_(Zflippedfacets)= 0;
+  FORALLfacet_(facetlist) {
+    if (facet->normal && !qh_checkflipped(qh, facet, &dist, !qh_ALL)) {
+      qh_fprintf(qh, qh->ferr, 6136, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",
+              facet->id, dist);
+      if (!qh->FORCEoutput) {
+        qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, NULL);
+        waserror= True;
+      }
+    }
+  }
+  if (waserror) {
+    qh_fprintf(qh, qh->ferr, 8101, "\n\
+A flipped facet occurs when its distance to the interior point is\n\
+greater than or equal to %2.2g, the maximum roundoff error.\n", -qh->DISTround);
+    qh_errexit(qh, qh_ERRprec, NULL, NULL);
+  }
+} /* checkflipped_all */
+
+/*---------------------------------
+
+  qh_checklists(qh, facetlist )
+    Check and repair facetlist and qh.vertex_list for infinite loops or overwritten facets
+    Checks that qh.newvertex_list is on qh.vertex_list
+    if facetlist is qh.facet_list
+      Checks that qh.visible_list and qh.newfacet_list are on qh.facet_list
+    Updates qh.facetvisit and qh.vertexvisit
+
+  returns:
+    True if no errors found
+    If false, repairs erroneous lists to prevent infinite loops by FORALL macros
+
+  notes:
+    called by qh_buildtracing, qh_checkpolygon, qh_collectstatistics, qh_printfacetlist, qh_printsummary
+    not called by qh_printlists
+
+  design:
+    if facetlist
+      check qh.facet_tail
+      for each facet
+        check for infinite loop or overwritten facet
+        check previous facet
+      if facetlist is qh.facet_list
+        check qh.next_facet, qh.visible_list and qh.newfacet_list
+    if vertexlist
+      check qh.vertex_tail
+      for each vertex
+        check for infinite loop or overwritten vertex
+        check previous vertex
+      check qh.newvertex_list
+*/
+boolT qh_checklists(qhT *qh, facetT *facetlist) {
+  facetT *facet, *errorfacet= NULL, *errorfacet2= NULL, *previousfacet;
+  vertexT *vertex, *vertexlist, *previousvertex, *errorvertex= NULL;
+  boolT waserror= False, newseen= False, nextseen= False, newvertexseen= False, visibleseen= False;
+
+  if (facetlist == qh->newfacet_list || facetlist == qh->visible_list) {
+    vertexlist= qh->vertex_list;
+    previousvertex= NULL;
+    trace2((qh, qh->ferr, 2110, "qh_checklists: check qh.%s_list f%d and qh.vertex_list v%d\n",
+        (facetlist == qh->newfacet_list ? "newfacet" : "visible"), facetlist->id, getid_(vertexlist)));
+  }else {
+    vertexlist= qh->vertex_list;
+    previousvertex= NULL;
+    trace2((qh, qh->ferr, 2111, "qh_checklists: check %slist f%d and qh.vertex_list v%d\n",
+        (facetlist == qh->facet_list ? "qh.facet_" : "facet"), getid_(facetlist), getid_(vertexlist)));
+  }
+  if (facetlist) {
+    if (qh->facet_tail == NULL || qh->facet_tail->id != 0 || qh->facet_tail->next != NULL) {
+      qh_fprintf(qh, qh->ferr, 6397, "qhull internal error (qh_checklists): either qh.facet_tail f%d is NULL, or its id is not 0, or its next is not NULL\n",
+          getid_(qh->facet_tail));
+      qh_errexit(qh, qh_ERRqhull, qh->facet_tail, NULL);
+    }
+    previousfacet= (facetlist == qh->facet_list ? NULL : facetlist->previous);
+    qh->visit_id++;
+    FORALLfacet_(facetlist) {
+      if (facet->visitid >= qh->visit_id || facet->id >= qh->facet_id) {
+        waserror= True;
+        errorfacet= facet;
+        errorfacet2= previousfacet;
+        if (facet->visitid == qh->visit_id)
+          qh_fprintf(qh, qh->ferr, 6039, "qhull internal error (qh_checklists): f%d already in facetlist causing an infinite loop ... f%d > f%d ... > f%d > f%d.  Truncate facetlist at f%d\n",
+            facet->id, facet->id, facet->next->id, getid_(previousfacet), facet->id, getid_(previousfacet));
+        else
+          qh_fprintf(qh, qh->ferr, 6350, "qhull internal error (qh_checklists): unknown or overwritten facet f%d, either id >= qh.facet_id (%d) or f.visitid %u > qh.visit_id %u.  Facetlist terminated at previous facet f%d\n",
+              facet->id, qh->facet_id, facet->visitid, qh->visit_id, getid_(previousfacet));
+        if (previousfacet)
+          previousfacet->next= qh->facet_tail;
+        else
+          facetlist= qh->facet_tail;
+        break;
+      }
+      facet->visitid= qh->visit_id;
+      if (facet->previous != previousfacet) {
+        qh_fprintf(qh, qh->ferr, 6416, "qhull internal error (qh_checklists): expecting f%d.previous == f%d.  Got f%d\n",
+          facet->id, getid_(previousfacet), getid_(facet->previous));
+        waserror= True;
+        errorfacet= facet;
+        errorfacet2= facet->previous;
+      }
+      previousfacet= facet;
+      if (facetlist == qh->facet_list) {
+        if (facet == qh->visible_list) {
+          if(newseen){
+            qh_fprintf(qh, qh->ferr, 6285, "qhull internal error (qh_checklists): qh.visible_list f%d is after qh.newfacet_list f%d.  It should be at, before, or NULL\n",
+              facet->id, getid_(qh->newfacet_list));
+            waserror= True;
+            errorfacet= facet;
+            errorfacet2= qh->newfacet_list;
+          }
+          visibleseen= True;
+        }
+        if (facet == qh->newfacet_list)
+          newseen= True;
+        if (facet == qh->facet_next)
+          nextseen= True;
+      }
+    }
+    if (facetlist == qh->facet_list) {
+      if (!nextseen && qh->facet_next && qh->facet_next->next) {
+        qh_fprintf(qh, qh->ferr, 6369, "qhull internal error (qh_checklists): qh.facet_next f%d for qh_addpoint is not on qh.facet_list f%d\n",
+          qh->facet_next->id, facetlist->id);
+        waserror= True;
+        errorfacet= qh->facet_next;
+        errorfacet2= facetlist;
+      }
+      if (!newseen && qh->newfacet_list && qh->newfacet_list->next) {
+        qh_fprintf(qh, qh->ferr, 6286, "qhull internal error (qh_checklists): qh.newfacet_list f%d is not on qh.facet_list f%d\n",
+          qh->newfacet_list->id, facetlist->id);
+        waserror= True;
+        errorfacet= qh->newfacet_list;
+        errorfacet2= facetlist;
+      }
+      if (!visibleseen && qh->visible_list && qh->visible_list->next) {
+        qh_fprintf(qh, qh->ferr, 6138, "qhull internal error (qh_checklists): qh.visible_list f%d is not on qh.facet_list f%d\n",
+          qh->visible_list->id, facetlist->id);
+        waserror= True;
+        errorfacet= qh->visible_list;
+        errorfacet2= facetlist;
+      }
+    }
+  }
+  if (vertexlist) {
+    if (qh->vertex_tail == NULL || qh->vertex_tail->id != 0 || qh->vertex_tail->next != NULL) {
+      qh_fprintf(qh, qh->ferr, 6366, "qhull internal error (qh_checklists): either qh.vertex_tail v%d is NULL, or its id is not 0, or its next is not NULL\n",
+           getid_(qh->vertex_tail));
+      qh_errprint(qh, "ERRONEOUS", errorfacet, errorfacet2, NULL, qh->vertex_tail);
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+    }
+    qh->vertex_visit++;
+    FORALLvertex_(vertexlist) {
+      if (vertex->visitid >= qh->vertex_visit || vertex->id >= qh->vertex_id) {
+        waserror= True;
+        errorvertex= vertex;
+        if (vertex->visitid == qh->visit_id)
+          qh_fprintf(qh, qh->ferr, 6367, "qhull internal error (qh_checklists): v%d already in vertexlist causing an infinite loop ... v%d > v%d ... > v%d > v%d.  Truncate vertexlist at v%d\n",
+            vertex->id, vertex->id, vertex->next->id, getid_(previousvertex), vertex->id, getid_(previousvertex));
+        else
+          qh_fprintf(qh, qh->ferr, 6368, "qhull internal error (qh_checklists): unknown or overwritten vertex v%d, either id >= qh.vertex_id (%d) or v.visitid %u > qh.visit_id %u.  vertexlist terminated at previous vertex v%d\n",
+            vertex->id, qh->vertex_id, vertex->visitid, qh->visit_id, getid_(previousvertex));
+        if (previousvertex)
+          previousvertex->next= qh->vertex_tail;
+        else
+          vertexlist= qh->vertex_tail;
+        break;
+      }
+      vertex->visitid= qh->vertex_visit;
+      if (vertex->previous != previousvertex) {
+        qh_fprintf(qh, qh->ferr, 6427, "qhull internal error (qh_checklists): expecting v%d.previous == v%d.  Got v%d\n",
+              vertex->id, getid_(previousvertex), getid_(vertex->previous));
+        waserror= True;
+        errorvertex= vertex;
+      }
+      previousvertex= vertex;
+      if(vertex == qh->newvertex_list)
+        newvertexseen= True;
+    }
+    if(!newvertexseen && qh->newvertex_list && qh->newvertex_list->next) {
+      qh_fprintf(qh, qh->ferr, 6287, "qhull internal error (qh_checklists): new vertex list v%d is not on vertex list\n", qh->newvertex_list->id);
+      waserror= True;
+      errorvertex= qh->newvertex_list;
+    }
+  }
+  if (waserror) {
+    qh_errprint(qh, "ERRONEOUS", errorfacet, errorfacet2, NULL, errorvertex);
+    return False;
+  }
+  return True;
+} /* checklists */
+
+/*---------------------------------
+
+  qh_checkpolygon(qh, facetlist )
+    checks the correctness of the structure
+
+  notes:
+    called by qh_addpoint, qh_all_vertexmerge, qh_check_output, qh_initialhull, qh_prepare_output, qh_triangulate
+    call with qh.facet_list or qh.newfacet_list or another list
+    checks num_facets and num_vertices if qh.facet_list
+
+  design:
+    check and repair lists for infinite loop
+    for each facet
+      check f.newfacet and f.visible
+      check facet and outside set if qh.NEWtentative and not f.newfacet, or not f.visible
+    initializes vertexlist for qh.facet_list or qh.newfacet_list
+    for each vertex
+      check vertex
+      check v.newfacet
+    for each facet
+      count f.ridges
+      check and count f.vertices
+    if checking qh.facet_list
+      check facet count
+      if qh.VERTEXneighbors
+        check and count v.neighbors for all vertices
+        check v.neighbors count and report possible causes of mismatch
+        check that facets are in their v.neighbors
+      check vertex count
+*/
+void qh_checkpolygon(qhT *qh, facetT *facetlist) {
+  facetT *facet, *neighbor, **neighborp;
+  facetT *errorfacet= NULL, *errorfacet2= NULL;
+  vertexT *vertex, **vertexp, *vertexlist;
+  int numfacets= 0, numvertices= 0, numridges= 0;
+  int totvneighbors= 0, totfacetvertices= 0;
+  boolT waserror= False, newseen= False, newvertexseen= False, nextseen= False, visibleseen= False;
+  boolT checkfacet;
+
+  trace1((qh, qh->ferr, 1027, "qh_checkpolygon: check all facets from f%d, qh.NEWtentative? %d\n", facetlist->id, qh->NEWtentative));
+  if (!qh_checklists(qh, facetlist)) {
+    waserror= True;
+    qh_fprintf(qh, qh->ferr, 6374, "qhull internal error: qh_checklists failed in qh_checkpolygon\n");
+    if (qh->num_facets < 4000)
+      qh_printlists(qh);
+  }
+  if (facetlist != qh->facet_list || qh->ONLYgood)
+    nextseen= True; /* allow f.outsideset */
+  FORALLfacet_(facetlist) {
+    if (facet == qh->visible_list)
+      visibleseen= True;
+    if (facet == qh->newfacet_list)
+      newseen= True;
+    if (facet->newfacet && !newseen && !visibleseen) {
+        qh_fprintf(qh, qh->ferr, 6289, "qhull internal error (qh_checkpolygon): f%d is 'newfacet' but it is not on qh.newfacet_list f%d or visible_list f%d\n",  facet->id, getid_(qh->newfacet_list), getid_(qh->visible_list));
+        qh_errexit(qh, qh_ERRqhull, facet, NULL);
+    }
+    if (!facet->newfacet && newseen) {
+        qh_fprintf(qh, qh->ferr, 6292, "qhull internal error (qh_checkpolygon): f%d is on qh.newfacet_list f%d but it is not 'newfacet'\n",  facet->id, getid_(qh->newfacet_list));
+        qh_errexit(qh, qh_ERRqhull, facet, NULL);
+    }
+    if (facet->visible != (visibleseen & !newseen)) {
+      if(facet->visible)
+        qh_fprintf(qh, qh->ferr, 6290, "qhull internal error (qh_checkpolygon): f%d is 'visible' but it is not on qh.visible_list f%d\n", facet->id, getid_(qh->visible_list));
+      else
+        qh_fprintf(qh, qh->ferr, 6291, "qhull internal error (qh_checkpolygon): f%d is on qh.visible_list f%d but it is not 'visible'\n", facet->id, qh->newfacet_list->id);
+      qh_errexit(qh, qh_ERRqhull, facet, NULL);
+    }
+    if (qh->NEWtentative) {
+      checkfacet= !facet->newfacet;
+    }else {
+      checkfacet= !facet->visible;
+    }
+    if(checkfacet) {
+      if (!nextseen) {
+        if (facet == qh->facet_next)  /* previous facets do not have outsideset */
+          nextseen= True;
+        else if (qh_setsize(qh, facet->outsideset)) {
+          if (!qh->NARROWhull
+#if !qh_COMPUTEfurthest
+          || facet->furthestdist >= qh->MINoutside
+#endif
+          ) {
+            qh_fprintf(qh, qh->ferr, 6137, "qhull internal error (qh_checkpolygon): f%d has outside points before qh.facet_next f%d\n",
+                     facet->id, getid_(qh->facet_next));
+            qh_errexit2(qh, qh_ERRqhull, facet, qh->facet_next);
+          }
+        }
+      }
+      numfacets++;
+      qh_checkfacet(qh, facet, False, &waserror);
+    }else if (facet->visible && qh->NEWfacets) {
+      if (!SETempty_(facet->neighbors) || !SETempty_(facet->ridges)) {
+        qh_fprintf(qh, qh->ferr, 6376, "qhull internal error (qh_checkpolygon): expecting empty f.neighbors and f.ridges for visible facet f%d.  Got %d neighbors and %d ridges\n",
+          facet->id, qh_setsize(qh, facet->neighbors), qh_setsize(qh, facet->ridges));
+        qh_errexit(qh, qh_ERRqhull, facet, NULL);
+      }
+    }
+  }
+  if (facetlist == qh->facet_list) {
+    vertexlist= qh->vertex_list;
+  }else if (facetlist == qh->newfacet_list) {
+    vertexlist= qh->newvertex_list;
+  }else {
+    vertexlist= NULL;
+  }
+  FORALLvertex_(vertexlist) {
+    qh_checkvertex(qh, vertex, !qh_ALL, &waserror);
+    if(vertex == qh->newvertex_list)
+      newvertexseen= True;
+    vertex->seen= False;
+    vertex->visitid= 0;
+    if(vertex->newfacet && !newvertexseen && !vertex->deleted) {
+      qh_fprintf(qh, qh->ferr, 6288, "qhull internal error (qh_checkpolygon): v%d is 'newfacet' but it is not on new vertex list v%d\n", vertex->id, getid_(qh->newvertex_list));
+      qh_errexit(qh, qh_ERRqhull, qh->visible_list, NULL);
+    }
+  }
+  FORALLfacet_(facetlist) {
+    if (facet->visible)
+      continue;
+    if (facet->simplicial)
+      numridges += qh->hull_dim;
+    else
+      numridges += qh_setsize(qh, facet->ridges);
+    FOREACHvertex_(facet->vertices) {
+      vertex->visitid++;
+      if (!vertex->seen) {
+        vertex->seen= True;
+        numvertices++;
+        if (qh_pointid(qh, vertex->point) == qh_IDunknown) {
+          qh_fprintf(qh, qh->ferr, 6139, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",
+                   (void *) vertex->point, vertex->id, (void *) qh->first_point);
+          waserror= True;
+        }
+      }
+    }
+  }
+  qh->vertex_visit += (unsigned int)numfacets;
+  if (facetlist == qh->facet_list) {
+    if (numfacets != qh->num_facets - qh->num_visible) {
+      qh_fprintf(qh, qh->ferr, 6140, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n",
+              numfacets, qh->num_facets, qh->num_visible);
+      waserror= True;
+    }
+    qh->vertex_visit++;
+    if (qh->VERTEXneighbors) {
+      FORALLvertices {
+        if (!vertex->neighbors) {
+          qh_fprintf(qh, qh->ferr, 6407, "qhull internal error (qh_checkpolygon): missing vertex neighbors for v%d\n", vertex->id);
+          waserror= True;
+        }
+        qh_setcheck(qh, vertex->neighbors, "neighbors for v", vertex->id);
+        if (vertex->deleted)
+          continue;
+        totvneighbors += qh_setsize(qh, vertex->neighbors);
+      }
+      FORALLfacet_(facetlist) {
+        if (!facet->visible)
+          totfacetvertices += qh_setsize(qh, facet->vertices);
+      }
+      if (totvneighbors != totfacetvertices) {
+        qh_fprintf(qh, qh->ferr, 6141, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent (tot_vneighbors %d != tot_facetvertices %d).  Maybe duplicate or missing vertex\n",
+                totvneighbors, totfacetvertices);
+        waserror= True;
+        FORALLvertices {
+          if (vertex->deleted)
+            continue;
+          qh->visit_id++;
+          FOREACHneighbor_(vertex) {
+            if (neighbor->visitid==qh->visit_id) {
+              qh_fprintf(qh, qh->ferr, 6275, "qhull internal error (qh_checkpolygon): facet f%d occurs twice in neighbors of vertex v%d\n",
+                  neighbor->id, vertex->id);
+              errorfacet2= errorfacet;
+              errorfacet= neighbor;
+            }
+            neighbor->visitid= qh->visit_id;
+            if (!qh_setin(neighbor->vertices, vertex)) {
+              qh_fprintf(qh, qh->ferr, 6276, "qhull internal error (qh_checkpolygon): facet f%d is a neighbor of vertex v%d but v%d is not a vertex of f%d\n",
+                  neighbor->id, vertex->id, vertex->id, neighbor->id);
+              errorfacet2= errorfacet;
+              errorfacet= neighbor;
+            }
+          }
+        }
+        FORALLfacet_(facetlist){
+          if (!facet->visible) {
+            /* vertices are inverse sorted and are unlikely to be duplicated */
+            FOREACHvertex_(facet->vertices){
+              if (!qh_setin(vertex->neighbors, facet)) {
+                qh_fprintf(qh, qh->ferr, 6277, "qhull internal error (qh_checkpolygon): v%d is a vertex of facet f%d but f%d is not a neighbor of v%d\n",
+                  vertex->id, facet->id, facet->id, vertex->id);
+                errorfacet2= errorfacet;
+                errorfacet= facet;
+              }
+            }
+          }
+        }
+      }
+    }
+    if (numvertices != qh->num_vertices - qh_setsize(qh, qh->del_vertices)) {
+      qh_fprintf(qh, qh->ferr, 6142, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",
+              numvertices, qh->num_vertices - qh_setsize(qh, qh->del_vertices));
+      waserror= True;
+    }
+    if (qh->hull_dim == 2 && numvertices != numfacets) {
+      qh_fprintf(qh, qh->ferr, 6143, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",
+        numvertices, numfacets);
+      waserror= True;
+    }
+    if (qh->hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
+      qh_fprintf(qh, qh->ferr, 7063, "qhull warning: #vertices %d + #facets %d - #edges %d != 2.  A vertex appears twice in a edge list.  May occur during merging.\n",
+          numvertices, numfacets, numridges/2);
+      /* occurs if lots of merging and a vertex ends up twice in an edge list.  e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv */
+    }
+  }
+  if (waserror)
+    qh_errexit2(qh, qh_ERRqhull, errorfacet, errorfacet2);
+} /* checkpolygon */
+
+
+/*---------------------------------
+
+  qh_checkvertex(qh, vertex, allchecks, &waserror )
+    check vertex for consistency
+    if allchecks, checks vertex->neighbors
+
+  returns:
+    sets waserror if any error occurs
+
+  notes:
+    called by qh_tracemerge and qh_checkpolygon
+    neighbors checked efficiently in qh_checkpolygon
+*/
+void qh_checkvertex(qhT *qh, vertexT *vertex, boolT allchecks, boolT *waserrorp) {
+  boolT waserror= False;
+  facetT *neighbor, **neighborp, *errfacet=NULL;
+
+  if (qh_pointid(qh, vertex->point) == qh_IDunknown) {
+    qh_fprintf(qh, qh->ferr, 6144, "qhull internal error (qh_checkvertex): unknown point id %p\n", (void *) vertex->point);
+    waserror= True;
+  }
+  if (vertex->id >= qh->vertex_id) {
+    qh_fprintf(qh, qh->ferr, 6145, "qhull internal error (qh_checkvertex): unknown vertex id v%d >= qh.vertex_id (%d)\n", vertex->id, qh->vertex_id);
+    waserror= True;
+  }
+  if (vertex->visitid > qh->vertex_visit) {
+    qh_fprintf(qh, qh->ferr, 6413, "qhull internal error (qh_checkvertex): expecting v%d.visitid <= qh.vertex_visit (%d).  Got visitid %d\n", vertex->id, qh->vertex_visit, vertex->visitid);
+    waserror= True;
+  }
+  if (allchecks && !waserror && !vertex->deleted) {
+    if (qh_setsize(qh, vertex->neighbors)) {
+      FOREACHneighbor_(vertex) {
+        if (!qh_setin(neighbor->vertices, vertex)) {
+          qh_fprintf(qh, qh->ferr, 6146, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);
+          errfacet= neighbor;
+          waserror= True;
+        }
+      }
+    }
+  }
+  if (waserror) {
+    qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
+    if (errfacet)
+      qh_errexit(qh, qh_ERRqhull, errfacet, NULL);
+    *waserrorp= True;
+  }
+} /* checkvertex */
+
+/*---------------------------------
+
+  qh_clearcenters(qh, type )
+    clear old data from facet->center
+
+  notes:
+    sets new centertype
+    nop if CENTERtype is the same
+*/
+void qh_clearcenters(qhT *qh, qh_CENTER type) {
+  facetT *facet;
+
+  if (qh->CENTERtype != type) {
+    FORALLfacets {
+      if (facet->tricoplanar && !facet->keepcentrum)
+          facet->center= NULL;  /* center is owned by the ->keepcentrum facet */
+      else if (qh->CENTERtype == qh_ASvoronoi){
+        if (facet->center) {
+          qh_memfree(qh, facet->center, qh->center_size);
+          facet->center= NULL;
+        }
+      }else /* qh.CENTERtype == qh_AScentrum */ {
+        if (facet->center) {
+          qh_memfree(qh, facet->center, qh->normal_size);
+          facet->center= NULL;
+        }
+      }
+    }
+    qh->CENTERtype= type;
+  }
+  trace2((qh, qh->ferr, 2043, "qh_clearcenters: switched to center type %d\n", type));
+} /* clearcenters */
+
+/*---------------------------------
+
+  qh_createsimplex(qh, vertices )
+    creates a simplex from a set of vertices
+
+  returns:
+    initializes qh.facet_list to the simplex
+
+  notes:
+    only called by qh_initialhull
+
+  design:
+    for each vertex
+      create a new facet
+    for each new facet
+      create its neighbor set
+*/
+void qh_createsimplex(qhT *qh, setT *vertices /* qh.facet_list */) {
+  facetT *facet= NULL, *newfacet;
+  boolT toporient= True;
+  int vertex_i, vertex_n, nth;
+  setT *newfacets= qh_settemp(qh, qh->hull_dim+1);
+  vertexT *vertex;
+
+  FOREACHvertex_i_(qh, vertices) {
+    newfacet= qh_newfacet(qh);
+    newfacet->vertices= qh_setnew_delnthsorted(qh, vertices, vertex_n, vertex_i, 0);
+    if (toporient)
+      newfacet->toporient= True;
+    qh_appendfacet(qh, newfacet);
+    newfacet->newfacet= True;
+    qh_appendvertex(qh, vertex);
+    qh_setappend(qh, &newfacets, newfacet);
+    toporient ^= True;
+  }
+  FORALLnew_facets {
+    nth= 0;
+    FORALLfacet_(qh->newfacet_list) {
+      if (facet != newfacet)
+        SETelem_(newfacet->neighbors, nth++)= facet;
+    }
+    qh_settruncate(qh, newfacet->neighbors, qh->hull_dim);
+  }
+  qh_settempfree(qh, &newfacets);
+  trace1((qh, qh->ferr, 1028, "qh_createsimplex: created simplex\n"));
+} /* createsimplex */
+
+/*---------------------------------
+
+  qh_delridge(qh, ridge )
+    delete a ridge's vertices and frees its memory
+
+  notes:
+    assumes r.top->ridges and r.bottom->ridges have been updated
+*/
+void qh_delridge(qhT *qh, ridgeT *ridge) {
+
+  if (ridge == qh->traceridge)
+    qh->traceridge= NULL;
+  qh_setfree(qh, &(ridge->vertices));
+  qh_memfree(qh, ridge, (int)sizeof(ridgeT));
+} /* delridge */
+
+/*---------------------------------
+
+  qh_delvertex(qh, vertex )
+    deletes a vertex and frees its memory
+
+  notes:
+    assumes vertex->adjacencies have been updated if needed
+    unlinks from vertex_list
+*/
+void qh_delvertex(qhT *qh, vertexT *vertex) {
+
+  if (vertex->deleted && !vertex->partitioned && !qh->NOerrexit) {
+    qh_fprintf(qh, qh->ferr, 6395, "qhull internal error (qh_delvertex): vertex v%d was deleted but it was not partitioned as a coplanar point\n",
+      vertex->id);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  if (vertex == qh->tracevertex)
+    qh->tracevertex= NULL;
+  qh_removevertex(qh, vertex);
+  qh_setfree(qh, &vertex->neighbors);
+  qh_memfree(qh, vertex, (int)sizeof(vertexT));
+} /* delvertex */
+
+
+/*---------------------------------
+
+  qh_facet3vertex(qh )
+    return temporary set of 3-d vertices in qh_ORIENTclock order
+
+  design:
+    if simplicial facet
+      build set from facet->vertices with facet->toporient
+    else
+      for each ridge in order
+        build set from ridge's vertices
+*/
+setT *qh_facet3vertex(qhT *qh, facetT *facet) {
+  ridgeT *ridge, *firstridge;
+  vertexT *vertex;
+  int cntvertices, cntprojected=0;
+  setT *vertices;
+
+  cntvertices= qh_setsize(qh, facet->vertices);
+  vertices= qh_settemp(qh, cntvertices);
+  if (facet->simplicial) {
+    if (cntvertices != 3) {
+      qh_fprintf(qh, qh->ferr, 6147, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n",
+                  cntvertices, facet->id);
+      qh_errexit(qh, qh_ERRqhull, facet, NULL);
+    }
+    qh_setappend(qh, &vertices, SETfirst_(facet->vertices));
+    if (facet->toporient ^ qh_ORIENTclock)
+      qh_setappend(qh, &vertices, SETsecond_(facet->vertices));
+    else
+      qh_setaddnth(qh, &vertices, 0, SETsecond_(facet->vertices));
+    qh_setappend(qh, &vertices, SETelem_(facet->vertices, 2));
+  }else {
+    ridge= firstridge= SETfirstt_(facet->ridges, ridgeT);   /* no infinite */
+    while ((ridge= qh_nextridge3d(ridge, facet, &vertex))) {
+      qh_setappend(qh, &vertices, vertex);
+      if (++cntprojected > cntvertices || ridge == firstridge)
+        break;
+    }
+    if (!ridge || cntprojected != cntvertices) {
+      qh_fprintf(qh, qh->ferr, 6148, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up.  got at least %d\n",
+                  facet->id, cntprojected);
+      qh_errexit(qh, qh_ERRqhull, facet, ridge);
+    }
+  }
+  return vertices;
+} /* facet3vertex */
+
+/*---------------------------------
+
+  qh_findbestfacet(qh, point, bestoutside, bestdist, isoutside )
+    find facet that is furthest below a point
+
+    for Delaunay triangulations,
+      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
+      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
+
+  returns:
+    if bestoutside is set (e.g., qh_ALL)
+      returns best facet that is not upperdelaunay
+      if Delaunay and inside, point is outside circumsphere of bestfacet
+    else
+      returns first facet below point
+      if point is inside, returns nearest, !upperdelaunay facet
+    distance to facet
+    isoutside set if outside of facet
+
+  notes:
+    Distance is measured by distance to the facet's hyperplane.  For
+    Delaunay facets, this is not the same as the containing facet.  It may
+    be an adjacent facet or a different tricoplanar facet.  See
+    locate a facet with qh_findbestfacet()
+
+    For tricoplanar facets, this finds one of the tricoplanar facets closest
+    to the point.
+
+    If inside, qh_findbestfacet performs an exhaustive search
+       this may be too conservative.  Sometimes it is clearly required.
+
+    qh_findbestfacet is not used by qhull.
+    uses qh.visit_id and qh.coplanarset
+
+  see:
+    qh_findbest
+*/
+facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside) {
+  facetT *bestfacet= NULL;
+  int numpart, totpart= 0;
+
+  bestfacet= qh_findbest(qh, point, qh->facet_list,
+                            bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,
+                            bestdist, isoutside, &totpart);
+  if (*bestdist < -qh->DISTround) {
+    bestfacet= qh_findfacet_all(qh, point, !qh_NOupper, bestdist, isoutside, &numpart);
+    totpart += numpart;
+    if ((isoutside && *isoutside && bestoutside)
+    || (isoutside && !*isoutside && bestfacet->upperdelaunay)) {
+      bestfacet= qh_findbest(qh, point, bestfacet,
+                            bestoutside, False, bestoutside,
+                            bestdist, isoutside, &totpart);
+      totpart += numpart;
+    }
+  }
+  trace3((qh, qh->ferr, 3014, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",
+          bestfacet->id, *bestdist, (isoutside ? *isoutside : UINT_MAX), totpart));
+  return bestfacet;
+} /* findbestfacet */
+
+/*---------------------------------
+
+  qh_findbestlower(qh, facet, point, bestdist, numpart )
+    returns best non-upper, non-flipped neighbor of facet for point
+    if needed, searches vertex neighbors
+
+  returns:
+    returns bestdist and updates numpart
+
+  notes:
+    called by qh_findbest() for points above an upperdelaunay facet
+    if Delaunay and inside, point is outside of circumsphere of bestfacet
+
+*/
+facetT *qh_findbestlower(qhT *qh, facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart) {
+  facetT *neighbor, **neighborp, *bestfacet= NULL;
+  realT bestdist= -REALmax/2 /* avoid underflow */;
+  realT dist;
+  vertexT *vertex;
+  boolT isoutside= False;  /* not used */
+
+  zinc_(Zbestlower);
+  FOREACHneighbor_(upperfacet) {
+    if (neighbor->upperdelaunay || neighbor->flipped)
+      continue;
+    (*numpart)++;
+    qh_distplane(qh, point, neighbor, &dist);
+    if (dist > bestdist) {
+      bestfacet= neighbor;
+      bestdist= dist;
+    }
+  }
+  if (!bestfacet) {
+    zinc_(Zbestlowerv);
+    /* rarely called, numpart does not count nearvertex computations */
+    vertex= qh_nearvertex(qh, upperfacet, point, &dist);
+    qh_vertexneighbors(qh);
+    FOREACHneighbor_(vertex) {
+      if (neighbor->upperdelaunay || neighbor->flipped)
+        continue;
+      (*numpart)++;
+      qh_distplane(qh, point, neighbor, &dist);
+      if (dist > bestdist) {
+        bestfacet= neighbor;
+        bestdist= dist;
+      }
+    }
+  }
+  if (!bestfacet) {
+    zinc_(Zbestlowerall);  /* invoked once per point in outsideset */
+    zmax_(Zbestloweralln, qh->num_facets);
+    /* [dec'15] Previously reported as QH6228 */
+    trace3((qh, qh->ferr, 3025, "qh_findbestlower: all neighbors of facet %d are flipped or upper Delaunay.  Search all facets\n",
+        upperfacet->id));
+    /* rarely called */
+    bestfacet= qh_findfacet_all(qh, point, qh_NOupper, &bestdist, &isoutside, numpart);
+  }
+  *bestdistp= bestdist;
+  trace3((qh, qh->ferr, 3015, "qh_findbestlower: f%d dist %2.2g for f%d p%d\n",
+          bestfacet->id, bestdist, upperfacet->id, qh_pointid(qh, point)));
+  return bestfacet;
+} /* findbestlower */
+
+/*---------------------------------
+
+  qh_findfacet_all(qh, point, noupper, bestdist, isoutside, numpart )
+    exhaustive search for facet below a point
+    ignore flipped and visible facets, f.normal==NULL, and if noupper, f.upperdelaunay facets
+
+    for Delaunay triangulations,
+      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
+      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
+
+  returns:
+    returns first facet below point
+    if point is inside,
+      returns nearest facet
+    distance to facet
+    isoutside if point is outside of the hull
+    number of distance tests
+
+  notes:
+    called by qh_findbestlower if all neighbors are flipped or upper Delaunay (QH3025)
+    primarily for library users (qh_findbestfacet), rarely used by Qhull
+*/
+facetT *qh_findfacet_all(qhT *qh, pointT *point, boolT noupper, realT *bestdist, boolT *isoutside,
+                          int *numpart) {
+  facetT *bestfacet= NULL, *facet;
+  realT dist;
+  int totpart= 0;
+
+  *bestdist= -REALmax;
+  *isoutside= False;
+  FORALLfacets {
+    if (facet->flipped || !facet->normal || facet->visible)
+      continue;
+    if (noupper && facet->upperdelaunay)
+      continue;
+    totpart++;
+    qh_distplane(qh, point, facet, &dist);
+    if (dist > *bestdist) {
+      *bestdist= dist;
+      bestfacet= facet;
+      if (dist > qh->MINoutside) {
+        *isoutside= True;
+        break;
+      }
+    }
+  }
+  *numpart= totpart;
+  trace3((qh, qh->ferr, 3016, "qh_findfacet_all: p%d, noupper? %d, f%d, dist %2.2g, isoutside %d, totpart %d\n",
+      qh_pointid(qh, point), noupper, getid_(bestfacet), *bestdist, *isoutside, totpart));
+  return bestfacet;
+} /* findfacet_all */
+
+/*---------------------------------
+
+  qh_findgood(qh, facetlist, goodhorizon )
+    identify good facets for qh.PRINTgood and qh_buildcone_onlygood
+    goodhorizon is count of good, horizon facets from qh_find_horizon, otherwise 0 from qh_findgood_all
+    if not qh.MERGING and qh.GOODvertex>0
+      facet includes point as vertex
+      if !match, returns goodhorizon
+    if qh.GOODpoint
+      facet is visible or coplanar (>0) or not visible (<0)
+    if qh.GOODthreshold
+      facet->normal matches threshold
+    if !goodhorizon and !match,
+      selects facet with closest angle to thresholds
+      sets GOODclosest
+
+  returns:
+    number of new, good facets found
+    determines facet->good
+    may update qh.GOODclosest
+
+  notes:
+    called from qh_initbuild, qh_buildcone_onlygood, and qh_findgood_all
+    qh_findgood_all (called from qh_prepare_output) further reduces the good region
+
+  design:
+    count good facets
+    if not merging, clear good facets that fail qh.GOODvertex ('QVn', but not 'QV-n')
+    clear good facets that fail qh.GOODpoint ('QGn' or 'QG-n')
+    clear good facets that fail qh.GOODthreshold
+    if !goodhorizon and !find f.good,
+      sets GOODclosest to facet with closest angle to thresholds
+*/
+int qh_findgood(qhT *qh, facetT *facetlist, int goodhorizon) {
+  facetT *facet, *bestfacet= NULL;
+  realT angle, bestangle= REALmax, dist;
+  int  numgood=0;
+
+  FORALLfacet_(facetlist) {
+    if (facet->good)
+      numgood++;
+  }
+  if (qh->GOODvertex>0 && !qh->MERGING) {
+    FORALLfacet_(facetlist) {
+      if (facet->good && !qh_isvertex(qh->GOODvertexp, facet->vertices)) {
+        facet->good= False;
+        numgood--;
+      }
+    }
+  }
+  if (qh->GOODpoint && numgood) {
+    FORALLfacet_(facetlist) {
+      if (facet->good && facet->normal) {
+        zinc_(Zdistgood);
+        qh_distplane(qh, qh->GOODpointp, facet, &dist);
+        if ((qh->GOODpoint > 0) ^ (dist > 0.0)) {
+          facet->good= False;
+          numgood--;
+        }
+      }
+    }
+  }
+  if (qh->GOODthreshold && (numgood || goodhorizon || qh->GOODclosest)) {
+    FORALLfacet_(facetlist) {
+      if (facet->good && facet->normal) {
+        if (!qh_inthresholds(qh, facet->normal, &angle)) {
+          facet->good= False;
+          numgood--;
+          if (angle < bestangle) {
+            bestangle= angle;
+            bestfacet= facet;
+          }
+        }
+      }
+    }
+    if (numgood == 0 && (goodhorizon == 0 || qh->GOODclosest)) {
+      if (qh->GOODclosest) {
+        if (qh->GOODclosest->visible)
+          qh->GOODclosest= NULL;
+        else {
+          qh_inthresholds(qh, qh->GOODclosest->normal, &angle);
+          if (angle < bestangle)
+            bestfacet= qh->GOODclosest;
+        }
+      }
+      if (bestfacet && bestfacet != qh->GOODclosest) {   /* numgood == 0 */
+        if (qh->GOODclosest)
+          qh->GOODclosest->good= False;
+        qh->GOODclosest= bestfacet;
+        bestfacet->good= True;
+        numgood++;
+        trace2((qh, qh->ferr, 2044, "qh_findgood: f%d is closest(%2.2g) to thresholds\n",
+           bestfacet->id, bestangle));
+        return numgood;
+      }
+    }else if (qh->GOODclosest) { /* numgood > 0 */
+      qh->GOODclosest->good= False;
+      qh->GOODclosest= NULL;
+    }
+  }
+  zadd_(Zgoodfacet, numgood);
+  trace2((qh, qh->ferr, 2045, "qh_findgood: found %d good facets with %d good horizon and qh.GOODclosest f%d\n",
+               numgood, goodhorizon, getid_(qh->GOODclosest)));
+  if (!numgood && qh->GOODvertex>0 && !qh->MERGING)
+    return goodhorizon;
+  return numgood;
+} /* findgood */
+
+/*---------------------------------
+
+  qh_findgood_all(qh, facetlist )
+    apply other constraints for good facets (used by qh.PRINTgood)
+    if qh.GOODvertex
+      facet includes (>0) or doesn't include (<0) point as vertex
+      if last good facet and ONLYgood, prints warning and continues
+    if qh.SPLITthresholds (e.g., qh.DELAUNAY)
+      facet->normal matches threshold, or if none, the closest one
+    calls qh_findgood
+    nop if good not used
+
+  returns:
+    clears facet->good if not good
+    sets qh.num_good
+
+  notes:
+    called by qh_prepare_output and qh_printneighborhood
+    unless qh.ONLYgood, calls qh_findgood first
+
+  design:
+    uses qh_findgood to mark good facets
+    clear f.good for failed qh.GOODvertex
+    clear f.good for failed qh.SPLITthreholds
+       if no more good facets, select best of qh.SPLITthresholds
+*/
+void qh_findgood_all(qhT *qh, facetT *facetlist) {
+  facetT *facet, *bestfacet=NULL;
+  realT angle, bestangle= REALmax;
+  int  numgood=0, startgood;
+
+  if (!qh->GOODvertex && !qh->GOODthreshold && !qh->GOODpoint
+  && !qh->SPLITthresholds)
+    return;
+  if (!qh->ONLYgood)
+    qh_findgood(qh, qh->facet_list, 0);
+  FORALLfacet_(facetlist) {
+    if (facet->good)
+      numgood++;
+  }
+  if (qh->GOODvertex <0 || (qh->GOODvertex > 0 && qh->MERGING)) {
+    FORALLfacet_(facetlist) {
+      if (facet->good && ((qh->GOODvertex > 0) ^ !!qh_isvertex(qh->GOODvertexp, facet->vertices))) { /* convert to bool */
+        if (!--numgood) {
+          if (qh->ONLYgood) {
+            qh_fprintf(qh, qh->ferr, 7064, "qhull warning: good vertex p%d does not match last good facet f%d.  Ignored.\n",
+               qh_pointid(qh, qh->GOODvertexp), facet->id);
+            return;
+          }else if (qh->GOODvertex > 0)
+            qh_fprintf(qh, qh->ferr, 7065, "qhull warning: point p%d is not a vertex('QV%d').\n",
+                qh->GOODvertex-1, qh->GOODvertex-1);
+          else
+            qh_fprintf(qh, qh->ferr, 7066, "qhull warning: point p%d is a vertex for every facet('QV-%d').\n",
+                -qh->GOODvertex - 1, -qh->GOODvertex - 1);
+        }
+        facet->good= False;
+      }
+    }
+  }
+  startgood= numgood;
+  if (qh->SPLITthresholds) {
+    FORALLfacet_(facetlist) {
+      if (facet->good) {
+        if (!qh_inthresholds(qh, facet->normal, &angle)) {
+          facet->good= False;
+          numgood--;
+          if (angle < bestangle) {
+            bestangle= angle;
+            bestfacet= facet;
+          }
+        }
+      }
+    }
+    if (!numgood && bestfacet) {
+      bestfacet->good= True;
+      numgood++;
+      trace0((qh, qh->ferr, 23, "qh_findgood_all: f%d is closest(%2.2g) to split thresholds\n",
+           bestfacet->id, bestangle));
+      return;
+    }
+  }
+  if (numgood == 1 && !qh->PRINTgood && qh->GOODclosest && qh->GOODclosest->good) {
+    trace2((qh, qh->ferr, 2109, "qh_findgood_all: undo selection of qh.GOODclosest f%d since it would fail qh_inthresholds in qh_skipfacet\n",
+      qh->GOODclosest->id));
+    qh->GOODclosest->good= False;
+    numgood= 0;
+  }
+  qh->num_good= numgood;
+  trace0((qh, qh->ferr, 24, "qh_findgood_all: %d good facets remain out of %d facets\n",
+        numgood, startgood));
+} /* findgood_all */
+
+/*---------------------------------
+
+  qh_furthestnext()
+    set qh.facet_next to facet with furthest of all furthest points
+    searches all facets on qh.facet_list
+
+  notes:
+    this may help avoid precision problems
+*/
+void qh_furthestnext(qhT *qh /* qh.facet_list */) {
+  facetT *facet, *bestfacet= NULL;
+  realT dist, bestdist= -REALmax;
+
+  FORALLfacets {
+    if (facet->outsideset) {
+#if qh_COMPUTEfurthest
+      pointT *furthest;
+      furthest= (pointT *)qh_setlast(facet->outsideset);
+      zinc_(Zcomputefurthest);
+      qh_distplane(qh, furthest, facet, &dist);
+#else
+      dist= facet->furthestdist;
+#endif
+      if (dist > bestdist) {
+        bestfacet= facet;
+        bestdist= dist;
+      }
+    }
+  }
+  if (bestfacet) {
+    qh_removefacet(qh, bestfacet);
+    qh_prependfacet(qh, bestfacet, &qh->facet_next);
+    trace1((qh, qh->ferr, 1029, "qh_furthestnext: made f%d next facet(dist %.2g)\n",
+            bestfacet->id, bestdist));
+  }
+} /* furthestnext */
+
+/*---------------------------------
+
+  qh_furthestout(qh, facet )
+    make furthest outside point the last point of outsideset
+
+  returns:
+    updates facet->outsideset
+    clears facet->notfurthest
+    sets facet->furthestdist
+
+  design:
+    determine best point of outsideset
+    make it the last point of outsideset
+*/
+void qh_furthestout(qhT *qh, facetT *facet) {
+  pointT *point, **pointp, *bestpoint= NULL;
+  realT dist, bestdist= -REALmax;
+
+  FOREACHpoint_(facet->outsideset) {
+    qh_distplane(qh, point, facet, &dist);
+    zinc_(Zcomputefurthest);
+    if (dist > bestdist) {
+      bestpoint= point;
+      bestdist= dist;
+    }
+  }
+  if (bestpoint) {
+    qh_setdel(facet->outsideset, point);
+    qh_setappend(qh, &facet->outsideset, point);
+#if !qh_COMPUTEfurthest
+    facet->furthestdist= bestdist;
+#endif
+  }
+  facet->notfurthest= False;
+  trace3((qh, qh->ferr, 3017, "qh_furthestout: p%d is furthest outside point of f%d\n",
+          qh_pointid(qh, point), facet->id));
+} /* furthestout */
+
+
+/*---------------------------------
+
+  qh_infiniteloop(qh, facet )
+    report infinite loop error due to facet
+*/
+void qh_infiniteloop(qhT *qh, facetT *facet) {
+
+  qh_fprintf(qh, qh->ferr, 6149, "qhull internal error (qh_infiniteloop): potential infinite loop detected.  If visible, f.replace. If newfacet, f.samecycle\n");
+  qh_errexit(qh, qh_ERRqhull, facet, NULL);
+} /* qh_infiniteloop */
+
+/*---------------------------------
+
+  qh_initbuild()
+    initialize hull and outside sets with point array
+    qh.FIRSTpoint/qh.NUMpoints is point array
+    if qh.GOODpoint
+      adds qh.GOODpoint to initial hull
+
+  returns:
+    qh_facetlist with initial hull
+    points partitioned into outside sets, coplanar sets, or inside
+    initializes qh.GOODpointp, qh.GOODvertexp,
+
+  design:
+    initialize global variables used during qh_buildhull
+    determine precision constants and points with max/min coordinate values
+      if qh.SCALElast, scale last coordinate(for 'd')
+    initialize qh.newfacet_list, qh.facet_tail
+    initialize qh.vertex_list, qh.newvertex_list, qh.vertex_tail
+    determine initial vertices
+    build initial simplex
+    partition input points into facets of initial simplex
+    set up lists
+    if qh.ONLYgood
+      check consistency
+      add qh.GOODvertex if defined
+*/
+void qh_initbuild(qhT *qh) {
+  setT *maxpoints, *vertices;
+  facetT *facet;
+  int i, numpart;
+  realT dist;
+  boolT isoutside;
+
+  if (qh->PRINTstatistics) {
+    qh_fprintf(qh, qh->ferr, 9350, "qhull %s Statistics: %s | %s\n",
+      qh_version, qh->rbox_command, qh->qhull_command);
+    fflush(NULL);
+  }
+  qh->furthest_id= qh_IDunknown;
+  qh->lastreport= 0;
+  qh->lastfacets= 0;
+  qh->lastmerges= 0;
+  qh->lastplanes= 0;
+  qh->lastdist= 0;
+  qh->facet_id= qh->vertex_id= qh->ridge_id= 0;
+  qh->visit_id= qh->vertex_visit= 0;
+  qh->maxoutdone= False;
+
+  if (qh->GOODpoint > 0)
+    qh->GOODpointp= qh_point(qh, qh->GOODpoint-1);
+  else if (qh->GOODpoint < 0)
+    qh->GOODpointp= qh_point(qh, -qh->GOODpoint-1);
+  if (qh->GOODvertex > 0)
+    qh->GOODvertexp= qh_point(qh, qh->GOODvertex-1);
+  else if (qh->GOODvertex < 0)
+    qh->GOODvertexp= qh_point(qh, -qh->GOODvertex-1);
+  if ((qh->GOODpoint
+       && (qh->GOODpointp < qh->first_point  /* also catches !GOODpointp */
+           || qh->GOODpointp > qh_point(qh, qh->num_points-1)))
+  || (qh->GOODvertex
+       && (qh->GOODvertexp < qh->first_point  /* also catches !GOODvertexp */
+           || qh->GOODvertexp > qh_point(qh, qh->num_points-1)))) {
+    qh_fprintf(qh, qh->ferr, 6150, "qhull input error: either QGn or QVn point is > p%d\n",
+             qh->num_points-1);
+    qh_errexit(qh, qh_ERRinput, NULL, NULL);
+  }
+  maxpoints= qh_maxmin(qh, qh->first_point, qh->num_points, qh->hull_dim);
+  if (qh->SCALElast)
+    qh_scalelast(qh, qh->first_point, qh->num_points, qh->hull_dim, qh->MINlastcoord, qh->MAXlastcoord, qh->MAXabs_coord);
+  qh_detroundoff(qh);
+  if (qh->DELAUNAY && qh->upper_threshold[qh->hull_dim-1] > REALmax/2
+                  && qh->lower_threshold[qh->hull_dim-1] < -REALmax/2) {
+    for (i=qh_PRINTEND; i--; ) {
+      if (qh->PRINTout[i] == qh_PRINTgeom && qh->DROPdim < 0
+          && !qh->GOODthreshold && !qh->SPLITthresholds)
+        break;  /* in this case, don't set upper_threshold */
+    }
+    if (i < 0) {
+      if (qh->UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */
+        qh->lower_threshold[qh->hull_dim-1]= qh->ANGLEround * qh_ZEROdelaunay;
+        qh->GOODthreshold= True;
+      }else {
+        qh->upper_threshold[qh->hull_dim-1]= -qh->ANGLEround * qh_ZEROdelaunay;
+        if (!qh->GOODthreshold)
+          qh->SPLITthresholds= True; /* build upper-convex hull even if Qg */
+          /* qh_initqhull_globals errors if Qg without Pdk/etc. */
+      }
+    }
+  }
+  trace4((qh, qh->ferr, 4091, "qh_initbuild: create sentinels for qh.facet_tail and qh.vertex_tail\n"));
+  qh->facet_list= qh->newfacet_list= qh->facet_tail= qh_newfacet(qh);
+  qh->num_facets= qh->num_vertices= qh->num_visible= 0;
+  qh->vertex_list= qh->newvertex_list= qh->vertex_tail= qh_newvertex(qh, NULL);
+  vertices= qh_initialvertices(qh, qh->hull_dim, maxpoints, qh->first_point, qh->num_points);
+  qh_initialhull(qh, vertices);  /* initial qh->facet_list */
+  qh_partitionall(qh, vertices, qh->first_point, qh->num_points);
+  if (qh->PRINToptions1st || qh->TRACElevel || qh->IStracing) {
+    if (qh->TRACElevel || qh->IStracing)
+      qh_fprintf(qh, qh->ferr, 8103, "\nTrace level T%d, IStracing %d, point TP%d, merge TM%d, dist TW%2.2g, qh.tracefacet_id %d, traceridge_id %d, tracevertex_id %d, last qh.RERUN %d, %s | %s\n",
+         qh->TRACElevel, qh->IStracing, qh->TRACEpoint, qh->TRACEmerge, qh->TRACEdist, qh->tracefacet_id, qh->traceridge_id, qh->tracevertex_id, qh->TRACElastrun, qh->rbox_command, qh->qhull_command);
+    qh_fprintf(qh, qh->ferr, 8104, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);
+  }
+  qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
+  qh->facet_next= qh->facet_list;
+  qh_furthestnext(qh /* qh.facet_list */);
+  if (qh->PREmerge) {
+    qh->cos_max= qh->premerge_cos;
+    qh->centrum_radius= qh->premerge_centrum; /* overwritten by qh_premerge */
+  }
+  if (qh->ONLYgood) {
+    if (qh->GOODvertex > 0 && qh->MERGING) {
+      qh_fprintf(qh, qh->ferr, 6151, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    if (!(qh->GOODthreshold || qh->GOODpoint
+         || (!qh->MERGEexact && !qh->PREmerge && qh->GOODvertexp))) {
+      qh_fprintf(qh, qh->ferr, 6152, "qhull input error: 'Qg' (ONLYgood) needs a good threshold('Pd0D0'), a good point(QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");
+      qh_errexit(qh, qh_ERRinput, NULL, NULL);
+    }
+    if (qh->GOODvertex > 0  && !qh->MERGING  /* matches qh_partitionall */
+    && !qh_isvertex(qh->GOODvertexp, vertices)) {
+      facet= qh_findbestnew(qh, qh->GOODvertexp, qh->facet_list,
+                          &dist, !qh_ALL, &isoutside, &numpart);
+      zadd_(Zdistgood, numpart);
+      if (!isoutside) {
+        qh_fprintf(qh, qh->ferr, 6153, "qhull input error: point for QV%d is inside initial simplex.  It can not be made a vertex.\n",
+               qh_pointid(qh, qh->GOODvertexp));
+        qh_errexit(qh, qh_ERRinput, NULL, NULL);
+      }
+      if (!qh_addpoint(qh, qh->GOODvertexp, facet, False)) {
+        qh_settempfree(qh, &vertices);
+        qh_settempfree(qh, &maxpoints);
+        return;
+      }
+    }
+    qh_findgood(qh, qh->facet_list, 0);
+  }
+  qh_settempfree(qh, &vertices);
+  qh_settempfree(qh, &maxpoints);
+  trace1((qh, qh->ferr, 1030, "qh_initbuild: initial hull created and points partitioned\n"));
+} /* initbuild */
+
+/*---------------------------------
+
+  qh_initialhull(qh, vertices )
+    constructs the initial hull as a DIM3 simplex of vertices
+
+  notes:
+    only called by qh_initbuild
+
+  design:
+    creates a simplex (initializes lists)
+    determines orientation of simplex
+    sets hyperplanes for facets
+    doubles checks orientation (in case of axis-parallel facets with Gaussian elimination)
+    checks for flipped facets and qh.NARROWhull
+    checks the result
+*/
+void qh_initialhull(qhT *qh, setT *vertices) {
+  facetT *facet, *firstfacet, *neighbor, **neighborp;
+  realT angle, minangle= REALmax, dist;
+
+  qh_createsimplex(qh, vertices /* qh.facet_list */);
+  qh_resetlists(qh, False, qh_RESETvisible);
+  qh->facet_next= qh->facet_list;      /* advance facet when processed */
+  qh->interior_point= qh_getcenter(qh, vertices);
+  if (qh->IStracing) {
+    qh_fprintf(qh, qh->ferr, 8105, "qh_initialhull: ");
+    qh_printpoint(qh, qh->ferr, "qh.interior_point", qh->interior_point);
+  }
+  firstfacet= qh->facet_list;
+  qh_setfacetplane(qh, firstfacet);   /* qh_joggle_restart if flipped */
+  if (firstfacet->flipped) {
+    trace1((qh, qh->ferr, 1065, "qh_initialhull: ignore f%d flipped.  Test qh.interior_point (p-2) for clearly flipped\n", firstfacet->id));
+    firstfacet->flipped= False;
+  }
+  zzinc_(Zdistcheck);
+  qh_distplane(qh, qh->interior_point, firstfacet, &dist);
+  if (dist > qh->DISTround) {  /* clearly flipped */
+    trace1((qh, qh->ferr, 1060, "qh_initialhull: initial orientation incorrect, qh.interior_point is %2.2g from f%d.  Reversing orientation of all facets\n",
+          dist, firstfacet->id));
+    FORALLfacets
+      facet->toporient ^= (unsigned char)True;
+    qh_setfacetplane(qh, firstfacet);
+  }
+  FORALLfacets {
+    if (facet != firstfacet)
+      qh_setfacetplane(qh, facet);    /* qh_joggle_restart if flipped */
+  }
+  FORALLfacets {
+    if (facet->flipped) {
+      trace1((qh, qh->ferr, 1066, "qh_initialhull: ignore f%d flipped.  Test qh.interior_point (p-2) for clearly flipped\n", facet->id));
+      facet->flipped= False;
+    }
+    zzinc_(Zdistcheck);
+    qh_distplane(qh, qh->interior_point, facet, &dist);  /* duplicates qh_setfacetplane */
+    if (dist > qh->DISTround) {  /* clearly flipped, due to axis-parallel facet or coplanar firstfacet */
+      trace1((qh, qh->ferr, 1031, "qh_initialhull: initial orientation incorrect, qh.interior_point is %2.2g from f%d.  Either axis-parallel facet or coplanar firstfacet f%d.  Force outside orientation of all facets\n",
+        dist, facet->id, firstfacet->id));
+      FORALLfacets { /* reuse facet, then 'break' */
+        facet->flipped= False;
+        facet->toporient ^= (unsigned char)True;
+        qh_orientoutside(qh, facet);  /* force outside orientation for f.normal */
+      }
+      break;
+    }
+  }
+  FORALLfacets {
+    if (!qh_checkflipped(qh, facet, NULL, qh_ALL)) {
+      if (qh->DELAUNAY && ! qh->ATinfinity) {
+        qh_joggle_restart(qh, "initial Delaunay cocircular or cospherical");
+        if (qh->UPPERdelaunay)
+          qh_fprintf(qh, qh->ferr, 6240, "Qhull precision error: initial Delaunay input sites are cocircular or cospherical.  Option 'Qs' searches all points.  Use option 'QJ' to joggle the input, otherwise cannot compute the upper Delaunay triangulation or upper Voronoi diagram of cocircular/cospherical points.\n");
+        else
+          qh_fprintf(qh, qh->ferr, 6239, "Qhull precision error: initial Delaunay input sites are cocircular or cospherical.  Use option 'Qz' for the Delaunay triangulation or Voronoi diagram of cocircular/cospherical points; it adds a point \"at infinity\".  Alternatively use option 'QJ' to joggle the input.  Use option 'Qs' to search all points for the initial simplex.\n");
+        qh_printvertexlist(qh, qh->ferr, "\ninput sites with last coordinate projected to a paraboloid\n", qh->facet_list, NULL, qh_ALL);
+        qh_errexit(qh, qh_ERRinput, NULL, NULL);
+      }else {
+        qh_joggle_restart(qh, "initial simplex is flat");
+        qh_fprintf(qh, qh->ferr, 6154, "Qhull precision error: Initial simplex is flat (facet %d is coplanar with the interior point)\n",
+                   facet->id);
+        qh_errexit(qh, qh_ERRsingular, NULL, NULL);  /* calls qh_printhelp_singular */
+      }
+    }
+    FOREACHneighbor_(facet) {
+      angle= qh_getangle(qh, facet->normal, neighbor->normal);
+      minimize_( minangle, angle);
+    }
+  }
+  if (minangle < qh_MAXnarrow && !qh->NOnarrow) {
+    realT diff= 1.0 + minangle;
+
+    qh->NARROWhull= True;
+    qh_option(qh, "_narrow-hull", NULL, &diff);
+    if (minangle < qh_WARNnarrow && !qh->RERUN && qh->PRINTprecision)
+      qh_printhelp_narrowhull(qh, qh->ferr, minangle);
+  }
+  zzval_(Zprocessed)= qh->hull_dim+1;
+  qh_checkpolygon(qh, qh->facet_list);
+  qh_checkconvex(qh, qh->facet_list, qh_DATAfault);
+  if (qh->IStracing >= 1) {
+    qh_fprintf(qh, qh->ferr, 8105, "qh_initialhull: simplex constructed\n");
+  }
+} /* initialhull */
+
+/*---------------------------------
+
+  qh_initialvertices(qh, dim, maxpoints, points, numpoints )
+    determines a non-singular set of initial vertices
+    maxpoints may include duplicate points
+
+  returns:
+    temporary set of dim+1 vertices in descending order by vertex id
+    if qh.RANDOMoutside && !qh.ALLpoints
+      picks random points
+    if dim >= qh_INITIALmax,
+      uses min/max x and max points with non-zero determinants
+
+  notes:
+    unless qh.ALLpoints,
+      uses maxpoints as long as determinate is non-zero
+*/
+setT *qh_initialvertices(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints) {
+  pointT *point, **pointp;
+  setT *vertices, *simplex, *tested;
+  realT randr;
+  int idx, point_i, point_n, k;
+  boolT nearzero= False;
+
+  vertices= qh_settemp(qh, dim + 1);
+  simplex= qh_settemp(qh, dim + 1);
+  if (qh->ALLpoints)
+    qh_maxsimplex(qh, dim, NULL, points, numpoints, &simplex);
+  else if (qh->RANDOMoutside) {
+    while (qh_setsize(qh, simplex) != dim+1) {
+      randr= qh_RANDOMint;
+      randr= randr/(qh_RANDOMmax+1);
+      randr= floor(qh->num_points * randr);
+      idx= (int)randr;
+      while (qh_setin(simplex, qh_point(qh, idx))) {
+        idx++; /* in case qh_RANDOMint always returns the same value */
+        idx= idx < qh->num_points ? idx : 0;
+      }
+      qh_setappend(qh, &simplex, qh_point(qh, idx));
+    }
+  }else if (qh->hull_dim >= qh_INITIALmax) {
+    tested= qh_settemp(qh, dim+1);
+    qh_setappend(qh, &simplex, SETfirst_(maxpoints));   /* max and min X coord */
+    qh_setappend(qh, &simplex, SETsecond_(maxpoints));
+    qh_maxsimplex(qh, fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);
+    k= qh_setsize(qh, simplex);
+    FOREACHpoint_i_(qh, maxpoints) {
+      if (k >= dim)  /* qh_maxsimplex for last point */
+        break;
+      if (point_i & 0x1) {     /* first try up to dim, max. coord. points */
+        if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
+          qh_detsimplex(qh, point, simplex, k, &nearzero);
+          if (nearzero)
+            qh_setappend(qh, &tested, point);
+          else {
+            qh_setappend(qh, &simplex, point);
+            k++;
+          }
+        }
+      }
+    }
+    FOREACHpoint_i_(qh, maxpoints) {
+      if (k >= dim)  /* qh_maxsimplex for last point */
+        break;
+      if ((point_i & 0x1) == 0) {  /* then test min. coord points */
+        if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
+          qh_detsimplex(qh, point, simplex, k, &nearzero);
+          if (nearzero)
+            qh_setappend(qh, &tested, point);
+          else {
+            qh_setappend(qh, &simplex, point);
+            k++;
+          }
+        }
+      }
+    }
+    /* remove tested points from maxpoints */
+    FOREACHpoint_i_(qh, maxpoints) {
+      if (qh_setin(simplex, point) || qh_setin(tested, point))
+        SETelem_(maxpoints, point_i)= NULL;
+    }
+    qh_setcompact(qh, maxpoints);
+    idx= 0;
+    while (k < dim && (point= qh_point(qh, idx++))) {
+      if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
+        qh_detsimplex(qh, point, simplex, k, &nearzero);
+        if (!nearzero){
+          qh_setappend(qh, &simplex, point);
+          k++;
+        }
+      }
+    }
+    qh_settempfree(qh, &tested);
+    qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);
+  }else /* qh.hull_dim < qh_INITIALmax */
+    qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);
+  FOREACHpoint_(simplex)
+    qh_setaddnth(qh, &vertices, 0, qh_newvertex(qh, point)); /* descending order */
+  qh_settempfree(qh, &simplex);
+  return vertices;
+} /* initialvertices */
+
+
+/*---------------------------------
+
+  qh_isvertex( point, vertices )
+    returns vertex if point is in vertex set, else returns NULL
+
+  notes:
+    for qh.GOODvertex
+*/
+vertexT *qh_isvertex(pointT *point, setT *vertices) {
+  vertexT *vertex, **vertexp;
+
+  FOREACHvertex_(vertices) {
+    if (vertex->point == point)
+      return vertex;
+  }
+  return NULL;
+} /* isvertex */
+
+/*---------------------------------
+
+  qh_makenewfacets(qh, point )
+    make new facets from point and qh.visible_list
+
+  returns:
+    apex (point) of the new facets
+    qh.newfacet_list= list of new facets with hyperplanes and ->newfacet
+    qh.newvertex_list= list of vertices in new facets with ->newfacet set
+
+    if (qh.NEWtentative)
+      newfacets reference horizon facets, but not vice versa
+      ridges reference non-simplicial horizon ridges, but not vice versa
+      does not change existing facets
+    else
+      sets qh.NEWfacets
+      new facets attached to horizon facets and ridges
+      for visible facets,
+        visible->r.replace is corresponding new facet
+
+  see also:
+    qh_makenewplanes() -- make hyperplanes for facets
+    qh_attachnewfacets() -- attachnewfacets if not done here qh->NEWtentative
+    qh_matchnewfacets() -- match up neighbors
+    qh_update_vertexneighbors() -- update vertex neighbors and delvertices
+    qh_deletevisible() -- delete visible facets
+    qh_checkpolygon() --check the result
+    qh_triangulate() -- triangulate a non-simplicial facet
+
+  design:
+    for each visible facet
+      make new facets to its horizon facets
+      update its f.replace
+      clear its neighbor set
+*/
+vertexT *qh_makenewfacets(qhT *qh, pointT *point /* qh.visible_list */) {
+  facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;
+  vertexT *apex;
+  int numnew=0;
+
+  if (qh->CHECKfrequently) {
+    qh_checkdelridge(qh);
+  }
+  qh->newfacet_list= qh->facet_tail;
+  qh->newvertex_list= qh->vertex_tail;
+  apex= qh_newvertex(qh, point);
+  qh_appendvertex(qh, apex);
+  qh->visit_id++;
+  FORALLvisible_facets {
+    FOREACHneighbor_(visible)
+      neighbor->seen= False;
+    if (visible->ridges) {
+      visible->visitid= qh->visit_id;
+      newfacet2= qh_makenew_nonsimplicial(qh, visible, apex, &numnew);
+    }
+    if (visible->simplicial)
+      newfacet= qh_makenew_simplicial(qh, visible, apex, &numnew);
+    if (!qh->NEWtentative) {
+      if (newfacet2)  /* newfacet is null if all ridges defined */
+        newfacet= newfacet2;
+      if (newfacet)
+        visible->f.replace= newfacet;
+      else
+        zinc_(Zinsidevisible);
+      if (visible->ridges)      /* ridges and neighbors are no longer valid for visible facet */
+        SETfirst_(visible->ridges)= NULL;
+      SETfirst_(visible->neighbors)= NULL;
+    }
+  }
+  if (!qh->NEWtentative)
+    qh->NEWfacets= True;
+  trace1((qh, qh->ferr, 1032, "qh_makenewfacets: created %d new facets f%d..f%d from point p%d to horizon\n",
+    numnew, qh->first_newfacet, qh->facet_id-1, qh_pointid(qh, point)));
+  if (qh->IStracing >= 4)
+    qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);
+  return apex;
+} /* makenewfacets */
+
+#ifndef qh_NOmerge
+/*---------------------------------
+
+  qh_matchdupridge(qh, atfacet, atskip, hashsize, hashcount )
+    match duplicate ridges in qh.hash_table for atfacet@atskip
+    duplicates marked with ->dupridge and qh_DUPLICATEridge
+
+  returns:
+    vertex-facet distance (>0.0) for qh_MERGEridge ridge
+    updates hashcount
+    set newfacet, facet, matchfacet's hyperplane (removes from mergecycle of coplanarhorizon facets)
+
+  see also:
+    qh_matchneighbor
+
+  notes:
+    only called by qh_matchnewfacets for qh_buildcone and qh_triangulate_facet
+    assumes atfacet is simplicial
+    assumes atfacet->neighbors @ atskip == qh_DUPLICATEridge
+    usually keeps ridge with the widest merge
+    both MRGdupridge and MRGflipped are required merges -- rbox 100 C1,2e-13 D4 t1 | qhull d Qbb
+      can merge flipped f11842 skip 3 into f11862 skip 2 and vice versa (forced by goodmatch/goodmatch2)
+         blocks -- cannot merge f11862 skip 2 and f11863 skip2 (the widest merge)
+         must block -- can merge f11843 skip 3 into f11842 flipped skip 3, but not vice versa
+      can merge f11843 skip 3 into f11863 skip 2, but not vice versa
+    working/unused.h: [jan'19] Dropped qh_matchdupridge_coplanarhorizon, it was the same or slightly worse.  Complex addition, rarely occurs
+
+  design:
+    compute hash value for atfacet and atskip
+    repeat twice -- once to make best matches, once to match the rest
+      for each possible facet in qh.hash_table
+        if it is a matching facet with the same orientation and pass 2
+          make match
+          unless tricoplanar, mark match for merging (qh_MERGEridge)
+          [e.g., tricoplanar RBOX s 1000 t993602376 | QHULL C-1e-3 d Qbb FA Qt]
+        if it is a matching facet with the same orientation and pass 1
+          test if this is a better match
+      if pass 1,
+        make best match (it will not be merged)
+        set newfacet, facet, matchfacet's hyperplane (removes from mergecycle of coplanarhorizon facets)
+
+*/
+coordT qh_matchdupridge(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {
+  boolT same, ismatch, isduplicate= False;
+  int hash, scan;
+  facetT *facet, *newfacet, *nextfacet;
+  facetT *maxmatch= NULL, *maxmatch2= NULL, *goodmatch= NULL, *goodmatch2= NULL;
+  int skip, newskip, nextskip= 0, makematch;
+  int maxskip= 0, maxskip2= 0, goodskip= 0, goodskip2= 0;
+  coordT maxdist= -REALmax, maxdist2= 0.0, dupdist, dupdist2, low, high, maxgood, gooddist= 0.0;
+
+  maxgood= qh_WIDEdupridge * (qh->ONEmerge + qh->DISTround);
+  hash= qh_gethash(qh, hashsize, atfacet->vertices, qh->hull_dim, 1,
+                     SETelem_(atfacet->vertices, atskip));
+  trace2((qh, qh->ferr, 2046, "qh_matchdupridge: find dupridge matches for f%d skip %d hash %d hashcount %d\n",
+          atfacet->id, atskip, hash, *hashcount));
+  for (makematch=0; makematch < 2; makematch++) { /* makematch is false on the first pass and 1 on the second */
+    qh->visit_id++;
+    for (newfacet=atfacet, newskip=atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {
+      zinc_(Zhashlookup);
+      nextfacet= NULL; /* exit when ismatch found */
+      newfacet->visitid= qh->visit_id;
+      for (scan=hash; (facet= SETelemt_(qh->hash_table, scan, facetT));
+           scan= (++scan >= hashsize ? 0 : scan)) {
+        if (!facet->dupridge || facet->visitid == qh->visit_id)
+          continue;
+        zinc_(Zhashtests);
+        if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
+          if (SETelem_(newfacet->vertices, newskip) == SETelem_(facet->vertices, skip)) {
+            trace3((qh, qh->ferr, 3053, "qh_matchdupridge: duplicate ridge due to duplicate facets (f%d skip %d and f%d skip %d) previously reported as QH7084.  Maximize dupdist to force vertex merge\n",
+              newfacet->id, newskip, facet->id, skip));
+            isduplicate= True;
+          }
+          ismatch= (same == (boolT)(newfacet->toporient ^ facet->toporient));
+          if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {
+            if (!makematch) {  /* occurs if many merges, e.g., rbox 100 W0 C2,1e-13 D6 t1546872462 | qhull C0 Qt Tcv */
+              qh_fprintf(qh, qh->ferr, 6155, "qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f%d skip %d for new f%d skip %d hash %d ismatch %d.  Set by qh_matchneighbor\n",
+                facet->id, skip, newfacet->id, newskip, hash, ismatch);
+              qh_errexit2(qh, qh_ERRtopology, facet, newfacet);
+            }
+          }else if (!ismatch) {
+            nextfacet= facet;
+            nextskip= skip;
+          }else if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
+            if (makematch) {
+              if (newfacet->tricoplanar) {
+                SETelem_(facet->neighbors, skip)= newfacet;
+                SETelem_(newfacet->neighbors, newskip)= facet;
+                *hashcount -= 2; /* removed two unmatched facets */
+                trace2((qh, qh->ferr, 2075, "qh_matchdupridge: allow tricoplanar dupridge for new f%d skip %d and f%d skip %d\n",
+                    newfacet->id, newskip, facet->id, skip));
+              }else if (goodmatch && goodmatch2) {
+                SETelem_(goodmatch2->neighbors, goodskip2)= qh_MERGEridge;  /* undo selection of goodmatch */
+                SETelem_(facet->neighbors, skip)= newfacet;
+                SETelem_(newfacet->neighbors, newskip)= facet;
+                *hashcount -= 2; /* removed two unmatched facets */
+                trace2((qh, qh->ferr, 2105, "qh_matchdupridge: make good forced merge of dupridge f%d skip %d into f%d skip %d, keep new f%d skip %d and f%d skip %d, dist %4.4g\n",
+                  goodmatch->id, goodskip, goodmatch2->id, goodskip2, newfacet->id, newskip, facet->id, skip, gooddist));
+                goodmatch2= NULL;
+              }else {
+                SETelem_(facet->neighbors, skip)= newfacet;
+                SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;  /* resolved by qh_mark_dupridges */
+                *hashcount -= 2; /* removed two unmatched facets */
+                trace3((qh, qh->ferr, 3073, "qh_matchdupridge: make forced merge of dupridge for new f%d skip %d and f%d skip %d, maxdist %4.4g in qh_forcedmerges\n",
+                  newfacet->id, newskip, facet->id, skip, maxdist2));
+              }
+            }else { /* !makematch */
+              if (!facet->normal)
+                qh_setfacetplane(qh, facet); /* qh_mergecycle will ignore 'mergehorizon' facets with normals, too many cases otherwise */
+              if (!newfacet->normal)
+                qh_setfacetplane(qh, newfacet);
+              dupdist= qh_getdistance(qh, facet, newfacet, &low, &high); /* ignore low/high */
+              dupdist2= qh_getdistance(qh, newfacet, facet, &low, &high);
+              if (isduplicate) {
+                goodmatch= NULL;
+                minimize_(dupdist, dupdist2);
+                maxdist= dupdist;
+                maxdist2= REALmax/2;
+                maxmatch= facet;
+                maxskip= skip;
+                maxmatch2= newfacet;
+                maxskip2= newskip;
+                break; /* force maxmatch */
+              }else if (facet->flipped && !newfacet->flipped && dupdist < maxgood) {
+                if (!goodmatch || !goodmatch->flipped || dupdist < gooddist) {
+                  goodmatch= facet;
+                  goodskip= skip;
+                  goodmatch2= newfacet;
+                  goodskip2= newskip;
+                  gooddist= dupdist;
+                  trace3((qh, qh->ferr, 3070, "qh_matchdupridge: try good dupridge flipped f%d skip %d into new f%d skip %d at dist %2.2g otherdist %2.2g\n",
+                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist2));
+                }
+              }else if (newfacet->flipped && !facet->flipped && dupdist2 < maxgood) {
+                if (!goodmatch || !goodmatch->flipped || dupdist2 < gooddist) {
+                  goodmatch= newfacet;
+                  goodskip= newskip;
+                  goodmatch2= facet;
+                  goodskip2= skip;
+                  gooddist= dupdist2;
+                  trace3((qh, qh->ferr, 3071, "qh_matchdupridge: try good dupridge flipped new f%d skip %d into f%d skip %d at dist %2.2g otherdist %2.2g\n",
+                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist));
+                }
+              }else if (dupdist < maxgood && (!newfacet->flipped || facet->flipped)) { /* disallow not-flipped->flipped */
+                if (!goodmatch || (!goodmatch->flipped && dupdist < gooddist)) {
+                  goodmatch= facet;
+                  goodskip= skip;
+                  goodmatch2= newfacet;
+                  goodskip2= newskip;
+                  gooddist= dupdist;
+                  trace3((qh, qh->ferr, 3072, "qh_matchdupridge: try good dupridge f%d skip %d into new f%d skip %d at dist %2.2g otherdist %2.2g\n",
+                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist2));
+                }
+              }else if (dupdist2 < maxgood && (!facet->flipped || newfacet->flipped)) { /* disallow not-flipped->flipped */
+                if (!goodmatch || (!goodmatch->flipped && dupdist2 < gooddist)) {
+                  goodmatch= newfacet;
+                  goodskip= newskip;
+                  goodmatch2= facet;
+                  goodskip2= skip;
+                  gooddist= dupdist2;
+                  trace3((qh, qh->ferr, 3018, "qh_matchdupridge: try good dupridge new f%d skip %d into f%d skip %d at dist %2.2g otherdist %2.2g\n",
+                    goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist));
+                }
+              }else if (!goodmatch) { /* otherwise match the furthest apart facets */
+                if (!newfacet->flipped || facet->flipped) {
+                  minimize_(dupdist, dupdist2);
+                }
+                if (dupdist > maxdist) { /* could keep !flipped->flipped, but probably lost anyway */
+                  maxdist2= maxdist;
+                  maxdist= dupdist;
+                  maxmatch= facet;
+                  maxskip= skip;
+                  maxmatch2= newfacet;
+                  maxskip2= newskip;
+                  trace3((qh, qh->ferr, 3055, "qh_matchdupridge: try furthest dupridge f%d skip %d new f%d skip %d at dist %2.2g\n",
+                    maxmatch->id, maxskip, maxmatch2->id, maxskip2, maxdist));
+                }else if (dupdist > maxdist2)
+                  maxdist2= dupdist;
+              }
+            }
+          }
+        }
+      } /* end of foreach entry in qh.hash_table starting at 'hash' */
+      if (makematch && SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
+        qh_fprintf(qh, qh->ferr, 6156, "qhull internal error (qh_matchdupridge): no MERGEridge match for dupridge new f%d skip %d at hash %d..%d\n",
+                    newfacet->id, newskip, hash, scan);
+        qh_errexit(qh, qh_ERRqhull, newfacet, NULL);
+      }
+    } /* end of foreach newfacet at 'hash' */
+    if (!makematch) {
+      if (!maxmatch && !goodmatch) {
+        qh_fprintf(qh, qh->ferr, 6157, "qhull internal error (qh_matchdupridge): no maximum or good match for dupridge new f%d skip %d at hash %d..%d\n",
+          atfacet->id, atskip, hash, scan);
+        qh_errexit(qh, qh_ERRqhull, atfacet, NULL);
+      }
+      if (goodmatch) {
+        SETelem_(goodmatch->neighbors, goodskip)= goodmatch2;
+        SETelem_(goodmatch2->neighbors, goodskip2)= goodmatch;
+        *hashcount -= 2; /* removed two unmatched facets */
+        if (goodmatch->flipped) {
+          if (!goodmatch2->flipped) {
+            zzinc_(Zflipridge);
+          }else {
+            zzinc_(Zflipridge2);
+            /* qh_joggle_restart called by qh_matchneighbor if qh_DUPLICATEridge */
+          }
+        }
+        /* previously traced */
+      }else {
+        SETelem_(maxmatch->neighbors, maxskip)= maxmatch2; /* maxmatch!=NULL by QH6157 */
+        SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;
+        *hashcount -= 2; /* removed two unmatched facets */
+        zzinc_(Zmultiridge);
+        /* qh_joggle_restart called by qh_matchneighbor if qh_DUPLICATEridge */
+        trace0((qh, qh->ferr, 25, "qh_matchdupridge: keep dupridge f%d skip %d and f%d skip %d, dist %4.4g\n",
+          maxmatch2->id, maxskip2, maxmatch->id, maxskip, maxdist));
+      }
+    }
+  }
+  if (goodmatch)
+    return gooddist;
+  return maxdist2;
+} /* matchdupridge */
+
+#else /* qh_NOmerge */
+coordT qh_matchdupridge(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {
+  QHULL_UNUSED(qh)
+  QHULL_UNUSED(atfacet)
+  QHULL_UNUSED(atskip)
+  QHULL_UNUSED(hashsize)
+  QHULL_UNUSED(hashcount)
+
+  return 0.0;
+}
+#endif /* qh_NOmerge */
+
+/*---------------------------------
+
+  qh_nearcoplanar()
+    for all facets, remove near-inside points from facet->coplanarset
+    coplanar points defined by innerplane from qh_outerinner()
+
+  returns:
+    if qh->KEEPcoplanar && !qh->KEEPinside
+      facet->coplanarset only contains coplanar points
+    if qh.JOGGLEmax
+      drops inner plane by another qh.JOGGLEmax diagonal since a
+        vertex could shift out while a coplanar point shifts in
+
+  notes:
+    used for qh.PREmerge and qh.JOGGLEmax
+    must agree with computation of qh.NEARcoplanar in qh_detroundoff
+
+  design:
+    if not keeping coplanar or inside points
+      free all coplanar sets
+    else if not keeping both coplanar and inside points
+      remove !coplanar or !inside points from coplanar sets
+*/
+void qh_nearcoplanar(qhT *qh /* qh.facet_list */) {
+  facetT *facet;
+  pointT *point, **pointp;
+  int numpart;
+  realT dist, innerplane;
+
+  if (!qh->KEEPcoplanar && !qh->KEEPinside) {
+    FORALLfacets {
+      if (facet->coplanarset)
+        qh_setfree(qh, &facet->coplanarset);
+    }
+  }else if (!qh->KEEPcoplanar || !qh->KEEPinside) {
+    qh_outerinner(qh, NULL, NULL, &innerplane);
+    if (qh->JOGGLEmax < REALmax/2)
+      innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
+    numpart= 0;
+    FORALLfacets {
+      if (facet->coplanarset) {
+        FOREACHpoint_(facet->coplanarset) {
+          numpart++;
+          qh_distplane(qh, point, facet, &dist);
+          if (dist < innerplane) {
+            if (!qh->KEEPinside)
+              SETref_(point)= NULL;
+          }else if (!qh->KEEPcoplanar)
+            SETref_(point)= NULL;
+        }
+        qh_setcompact(qh, facet->coplanarset);
+      }
+    }
+    zzadd_(Zcheckpart, numpart);
+  }
+} /* nearcoplanar */
+
+/*---------------------------------
+
+  qh_nearvertex(qh, facet, point, bestdist )
+    return nearest vertex in facet to point
+
+  returns:
+    vertex and its distance
+
+  notes:
+    if qh.DELAUNAY
+      distance is measured in the input set
+    searches neighboring tricoplanar facets (requires vertexneighbors)
+      Slow implementation.  Recomputes vertex set for each point.
+    The vertex set could be stored in the qh.keepcentrum facet.
+*/
+vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp) {
+  realT bestdist= REALmax, dist;
+  vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;
+  coordT *center;
+  facetT *neighbor, **neighborp;
+  setT *vertices;
+  int dim= qh->hull_dim;
+
+  if (qh->DELAUNAY)
+    dim--;
+  if (facet->tricoplanar) {
+    if (!qh->VERTEXneighbors || !facet->center) {
+      qh_fprintf(qh, qh->ferr, 6158, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");
+      qh_errexit(qh, qh_ERRqhull, facet, NULL);
+    }
+    vertices= qh_settemp(qh, qh->TEMPsize);
+    apex= SETfirstt_(facet->vertices, vertexT);
+    center= facet->center;
+    FOREACHneighbor_(apex) {
+      if (neighbor->center == center) {
+        FOREACHvertex_(neighbor->vertices)
+          qh_setappend(qh, &vertices, vertex);
+      }
+    }
+  }else
+    vertices= facet->vertices;
+  FOREACHvertex_(vertices) {
+    dist= qh_pointdist(vertex->point, point, -dim);
+    if (dist < bestdist) {
+      bestdist= dist;
+      bestvertex= vertex;
+    }
+  }
+  if (facet->tricoplanar)
+    qh_settempfree(qh, &vertices);
+  *bestdistp= sqrt(bestdist);
+  if (!bestvertex) {
+      qh_fprintf(qh, qh->ferr, 6261, "qhull internal error (qh_nearvertex): did not find bestvertex for f%d p%d\n", facet->id, qh_pointid(qh, point));
+      qh_errexit(qh, qh_ERRqhull, facet, NULL);
+  }
+  trace3((qh, qh->ferr, 3019, "qh_nearvertex: v%d dist %2.2g for f%d p%d\n",
+        bestvertex->id, *bestdistp, facet->id, qh_pointid(qh, point))); /* bestvertex!=0 by QH2161 */
+  return bestvertex;
+} /* nearvertex */
+
+/*---------------------------------
+
+  qh_newhashtable(qh, newsize )
+    returns size of qh.hash_table of at least newsize slots
+
+  notes:
+    assumes qh.hash_table is NULL
+    qh_HASHfactor determines the number of extra slots
+    size is not divisible by 2, 3, or 5
+*/
+int qh_newhashtable(qhT *qh, int newsize) {
+  int size;
+
+  size= ((newsize+1)*qh_HASHfactor) | 0x1;  /* odd number */
+  while (True) {
+    if (newsize<0 || size<0) {
+        qh_fprintf(qh, qh->qhmem.ferr, 6236, "qhull error (qh_newhashtable): negative request (%d) or size (%d).  Did int overflow due to high-D?\n", newsize, size); /* WARN64 */
+        qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
+    }
+    if ((size%3) && (size%5))
+      break;
+    size += 2;
+    /* loop terminates because there is an infinite number of primes */
+  }
+  qh->hash_table= qh_setnew(qh, size);
+  qh_setzero(qh, qh->hash_table, 0, size);
+  return size;
+} /* newhashtable */
+
+/*---------------------------------
+
+  qh_newvertex(qh, point )
+    returns a new vertex for point
+*/
+vertexT *qh_newvertex(qhT *qh, pointT *point) {
+  vertexT *vertex;
+
+  zinc_(Ztotvertices);
+  vertex= (vertexT *)qh_memalloc(qh, (int)sizeof(vertexT));
+  memset((char *) vertex, (size_t)0, sizeof(vertexT));
+  if (qh->vertex_id == UINT_MAX) {
+    qh_memfree(qh, vertex, (int)sizeof(vertexT));
+    qh_fprintf(qh, qh->ferr, 6159, "qhull error: 2^32 or more vertices.  vertexT.id field overflows.  Vertices would not be sorted correctly.\n");
+    qh_errexit(qh, qh_ERRother, NULL, NULL);
+  }
+  if (qh->vertex_id == qh->tracevertex_id)
+    qh->tracevertex= vertex;
+  vertex->id= qh->vertex_id++;
+  vertex->point= point;
+  trace4((qh, qh->ferr, 4060, "qh_newvertex: vertex p%d(v%d) created\n", qh_pointid(qh, vertex->point),
+          vertex->id));
+  return(vertex);
+} /* newvertex */
+
+/*---------------------------------
+
+  qh_nextfacet2d( facet, &nextvertex )
+    return next facet and vertex for a 2d facet in qh_ORIENTclock order
+    returns NULL on error
+
+  notes:
+    in qh_ORIENTclock order (default counter-clockwise)
+    nextvertex is in between the two facets
+    does not use qhT or qh_errexit [QhullFacet.cpp]
+
+  design:
+    see io_r.c/qh_printextremes_2d
+*/
+facetT *qh_nextfacet2d(facetT *facet, vertexT **nextvertexp) {
+  facetT *nextfacet;
+
+  if (facet->toporient ^ qh_ORIENTclock) {
+    *nextvertexp= SETfirstt_(facet->vertices, vertexT);
+    nextfacet= SETfirstt_(facet->neighbors, facetT);
+  }else {
+    *nextvertexp= SETsecondt_(facet->vertices, vertexT);
+    nextfacet= SETsecondt_(facet->neighbors, facetT);
+  }
+  return nextfacet;
+} /* nextfacet2d */
+
+/*---------------------------------
+
+  qh_nextridge3d( atridge, facet, &vertex )
+    return next ridge and vertex for a 3d facet
+    returns NULL on error
+    [for QhullFacet::nextRidge3d] Does not call qh_errexit nor access qhT.
+
+  notes:
+    in qh_ORIENTclock order
+    this is a O(n^2) implementation to trace all ridges
+    be sure to stop on any 2nd visit
+    same as QhullRidge::nextRidge3d
+    does not use qhT or qh_errexit [QhullFacet.cpp]
+
+  design:
+    for each ridge
+      exit if it is the ridge after atridge
+*/
+ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) {
+  vertexT *atvertex, *vertex, *othervertex;
+  ridgeT *ridge, **ridgep;
+
+  if ((atridge->top == facet) ^ qh_ORIENTclock)
+    atvertex= SETsecondt_(atridge->vertices, vertexT);
+  else
+    atvertex= SETfirstt_(atridge->vertices, vertexT);
+  FOREACHridge_(facet->ridges) {
+    if (ridge == atridge)
+      continue;
+    if ((ridge->top == facet) ^ qh_ORIENTclock) {
+      othervertex= SETsecondt_(ridge->vertices, vertexT);
+      vertex= SETfirstt_(ridge->vertices, vertexT);
+    }else {
+      vertex= SETsecondt_(ridge->vertices, vertexT);
+      othervertex= SETfirstt_(ridge->vertices, vertexT);
+    }
+    if (vertex == atvertex) {
+      if (vertexp)
+        *vertexp= othervertex;
+      return ridge;
+    }
+  }
+  return NULL;
+} /* nextridge3d */
+
+/*---------------------------------
+
+  qh_opposite_vertex(qh, facetA, neighbor )
+    return the opposite vertex in facetA to neighbor
+
+*/
+vertexT *qh_opposite_vertex(qhT *qh, facetT *facetA,  facetT *neighbor) {
+    vertexT *opposite= NULL;
+    facetT *facet;
+    int facet_i, facet_n;
+
+    if (facetA->simplicial) {
+      FOREACHfacet_i_(qh, facetA->neighbors) {
+        if (facet == neighbor) {
+          opposite= SETelemt_(facetA->vertices, facet_i, vertexT);
+          break;
+        }
+      }
+    }
+    if (!opposite) {
+      qh_fprintf(qh, qh->ferr, 6396, "qhull internal error (qh_opposite_vertex): opposite vertex in facet f%d to neighbor f%d is not defined.  Either is facet is not simplicial or neighbor not found\n",
+        facetA->id, neighbor->id);
+      qh_errexit2(qh, qh_ERRqhull, facetA, neighbor);
+    }
+    return opposite;
+} /* opposite_vertex */
+
+/*---------------------------------
+
+  qh_outcoplanar()
+    move points from all facets' outsidesets to their coplanarsets
+
+  notes:
+    for post-processing under qh.NARROWhull
+
+  design:
+    for each facet
+      for each outside point for facet
+        partition point into coplanar set
+*/
+void qh_outcoplanar(qhT *qh /* facet_list */) {
+  pointT *point, **pointp;
+  facetT *facet;
+  realT dist;
+
+  trace1((qh, qh->ferr, 1033, "qh_outcoplanar: move outsideset to coplanarset for qh->NARROWhull\n"));
+  FORALLfacets {
+    FOREACHpoint_(facet->outsideset) {
+      qh->num_outside--;
+      if (qh->KEEPcoplanar || qh->KEEPnearinside) {
+        qh_distplane(qh, point, facet, &dist);
+        zinc_(Zpartition);
+        qh_partitioncoplanar(qh, point, facet, &dist, qh->findbestnew);
+      }
+    }
+    qh_setfree(qh, &facet->outsideset);
+  }
+} /* outcoplanar */
+
+/*---------------------------------
+
+  qh_point(qh, id )
+    return point for a point id, or NULL if unknown
+
+  alternative code:
+    return((pointT *)((unsigned long)qh.first_point
+           + (unsigned long)((id)*qh.normal_size)));
+*/
+pointT *qh_point(qhT *qh, int id) {
+
+  if (id < 0)
+    return NULL;
+  if (id < qh->num_points)
+    return qh->first_point + id * qh->hull_dim;
+  id -= qh->num_points;
+  if (id < qh_setsize(qh, qh->other_points))
+    return SETelemt_(qh->other_points, id, pointT);
+  return NULL;
+} /* point */
+
+/*---------------------------------
+
+  qh_point_add(qh, set, point, elem )
+    stores elem at set[point.id]
+
+  returns:
+    access function for qh_pointfacet and qh_pointvertex
+
+  notes:
+    checks point.id
+*/
+void qh_point_add(qhT *qh, setT *set, pointT *point, void *elem) {
+  int id, size;
+
+  SETreturnsize_(set, size);
+  if ((id= qh_pointid(qh, point)) < 0)
+    qh_fprintf(qh, qh->ferr, 7067, "qhull internal warning (point_add): unknown point %p id %d\n",
+      (void *) point, id);
+  else if (id >= size) {
+    qh_fprintf(qh, qh->ferr, 6160, "qhull internal error (point_add): point p%d is out of bounds(%d)\n",
+             id, size);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }else
+    SETelem_(set, id)= elem;
+} /* point_add */
+
+
+/*---------------------------------
+
+  qh_pointfacet()
+    return temporary set of facet for each point
+    the set is indexed by point id
+    at most one facet per point, arbitrary selection
+
+  notes:
+    each point is assigned to at most one of vertices, coplanarset, or outsideset
+    unassigned points are interior points or
+    vertices assigned to one of its facets
+    coplanarset assigned to the facet
+    outside set assigned to the facet
+    NULL if no facet for point (inside)
+      includes qh.GOODpointp
+
+  access:
+    FOREACHfacet_i_(qh, facets) { ... }
+    SETelem_(facets, i)
+
+  design:
+    for each facet
+      add each vertex
+      add each coplanar point
+      add each outside point
+*/
+setT *qh_pointfacet(qhT *qh /* qh.facet_list */) {
+  int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
+  setT *facets;
+  facetT *facet;
+  vertexT *vertex, **vertexp;
+  pointT *point, **pointp;
+
+  facets= qh_settemp(qh, numpoints);
+  qh_setzero(qh, facets, 0, numpoints);
+  qh->vertex_visit++;
+  FORALLfacets {
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh->vertex_visit) {
+        vertex->visitid= qh->vertex_visit;
+        qh_point_add(qh, facets, vertex->point, facet);
+      }
+    }
+    FOREACHpoint_(facet->coplanarset)
+      qh_point_add(qh, facets, point, facet);
+    FOREACHpoint_(facet->outsideset)
+      qh_point_add(qh, facets, point, facet);
+  }
+  return facets;
+} /* pointfacet */
+
+/*---------------------------------
+
+  qh_pointvertex(qh )
+    return temporary set of vertices indexed by point id
+    entry is NULL if no vertex for a point
+      this will include qh.GOODpointp
+
+  access:
+    FOREACHvertex_i_(qh, vertices) { ... }
+    SETelem_(vertices, i)
+*/
+setT *qh_pointvertex(qhT *qh /* qh.facet_list */) {
+  int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
+  setT *vertices;
+  vertexT *vertex;
+
+  vertices= qh_settemp(qh, numpoints);
+  qh_setzero(qh, vertices, 0, numpoints);
+  FORALLvertices
+    qh_point_add(qh, vertices, vertex->point, vertex);
+  return vertices;
+} /* pointvertex */
+
+
+/*---------------------------------
+
+  qh_prependfacet(qh, facet, facetlist )
+    prepend facet to the start of a facetlist
+
+  returns:
+    increments qh.numfacets
+    updates facetlist, qh.facet_list, facet_next
+
+  notes:
+    be careful of prepending since it can lose a pointer.
+      e.g., can lose _next by deleting and then prepending before _next
+*/
+void qh_prependfacet(qhT *qh, facetT *facet, facetT **facetlist) {
+  facetT *prevfacet, *list;
+
+  trace4((qh, qh->ferr, 4061, "qh_prependfacet: prepend f%d before f%d\n",
+          facet->id, getid_(*facetlist)));
+  if (!*facetlist)
+    (*facetlist)= qh->facet_tail;
+  list= *facetlist;
+  prevfacet= list->previous;
+  facet->previous= prevfacet;
+  if (prevfacet)
+    prevfacet->next= facet;
+  list->previous= facet;
+  facet->next= *facetlist;
+  if (qh->facet_list == list)  /* this may change *facetlist */
+    qh->facet_list= facet;
+  if (qh->facet_next == list)
+    qh->facet_next= facet;
+  *facetlist= facet;
+  qh->num_facets++;
+} /* prependfacet */
+
+
+/*---------------------------------
+
+  qh_printhashtable(qh, fp )
+    print hash table to fp
+
+  notes:
+    not in I/O to avoid bringing io_r.c in
+
+  design:
+    for each hash entry
+      if defined
+        if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)
+          print entry and neighbors
+*/
+void qh_printhashtable(qhT *qh, FILE *fp) {
+  facetT *facet, *neighbor;
+  int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;
+  vertexT *vertex, **vertexp;
+
+  FOREACHfacet_i_(qh, qh->hash_table) {
+    if (facet) {
+      FOREACHneighbor_i_(qh, facet) {
+        if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge)
+          break;
+      }
+      if (neighbor_i == neighbor_n)
+        continue;
+      qh_fprintf(qh, fp, 9283, "hash %d f%d ", facet_i, facet->id);
+      FOREACHvertex_(facet->vertices)
+        qh_fprintf(qh, fp, 9284, "v%d ", vertex->id);
+      qh_fprintf(qh, fp, 9285, "\n neighbors:");
+      FOREACHneighbor_i_(qh, facet) {
+        if (neighbor == qh_MERGEridge)
+          id= -3;
+        else if (neighbor == qh_DUPLICATEridge)
+          id= -2;
+        else
+          id= getid_(neighbor);
+        qh_fprintf(qh, fp, 9286, " %d", id);
+      }
+      qh_fprintf(qh, fp, 9287, "\n");
+    }
+  }
+} /* printhashtable */
+
+/*---------------------------------
+
+  qh_printlists(qh)
+    print out facet and vertex lists for debugging (without 'f/v' tags)
+
+  notes:
+    not in I/O to avoid bringing io_r.c in
+*/
+void qh_printlists(qhT *qh) {
+  facetT *facet;
+  vertexT *vertex;
+  int count= 0;
+
+  qh_fprintf(qh, qh->ferr, 3062, "qh_printlists: max_outside %2.2g all facets:", qh->max_outside);
+  FORALLfacets{
+    if (++count % 100 == 0)
+      qh_fprintf(qh, qh->ferr, 8109, "\n     ");
+    qh_fprintf(qh, qh->ferr, 8110, " %d", facet->id);
+  }
+    qh_fprintf(qh, qh->ferr, 8111, "\n  qh.visible_list f%d, newfacet_list f%d, facet_next f%d for qh_addpoint\n  qh.newvertex_list v%d all vertices:",
+      getid_(qh->visible_list), getid_(qh->newfacet_list), getid_(qh->facet_next), getid_(qh->newvertex_list));
+  count= 0;
+  FORALLvertices{
+    if (++count % 100 == 0)
+      qh_fprintf(qh, qh->ferr, 8112, "\n     ");
+    qh_fprintf(qh, qh->ferr, 8113, " %d", vertex->id);
+  }
+  qh_fprintf(qh, qh->ferr, 8114, "\n");
+} /* printlists */
+
+/*---------------------------------
+
+  qh_replacefacetvertex(qh, facet, oldvertex, newvertex )
+    replace oldvertex with newvertex in f.vertices
+    vertices are inverse sorted by vertex->id
+
+  returns:
+    toporient is flipped if an odd parity, position change
+
+  notes:
+    for simplicial facets in qh_rename_adjacentvertex
+    see qh_addfacetvertex
+*/
+void qh_replacefacetvertex(qhT *qh, facetT *facet, vertexT *oldvertex, vertexT *newvertex) {
+  vertexT *vertex;
+  facetT *neighbor;
+  int vertex_i, vertex_n= 0;
+  int old_i= -1, new_i= -1;
+
+  trace3((qh, qh->ferr, 3038, "qh_replacefacetvertex: replace v%d with v%d in f%d\n", oldvertex->id, newvertex->id, facet->id));
+  if (!facet->simplicial) {
+    qh_fprintf(qh, qh->ferr, 6283, "qhull internal error (qh_replacefacetvertex): f%d is not simplicial\n", facet->id);
+    qh_errexit(qh, qh_ERRqhull, facet, NULL);
+  }
+  FOREACHvertex_i_(qh, facet->vertices) {
+    if (new_i == -1 && vertex->id < newvertex->id) {
+      new_i= vertex_i;
+    }else if (vertex->id == newvertex->id) {
+      qh_fprintf(qh, qh->ferr, 6281, "qhull internal error (qh_replacefacetvertex): f%d already contains new v%d\n", facet->id, newvertex->id);
+      qh_errexit(qh, qh_ERRqhull, facet, NULL);
+    }
+    if (vertex->id == oldvertex->id) {
+      old_i= vertex_i;
+    }
+  }
+  if (old_i == -1) {
+    qh_fprintf(qh, qh->ferr, 6282, "qhull internal error (qh_replacefacetvertex): f%d does not contain old v%d\n", facet->id, oldvertex->id);
+    qh_errexit(qh, qh_ERRqhull, facet, NULL);
+  }
+  if (new_i == -1) {
+    new_i= vertex_n;
+  }
+  if (old_i < new_i)
+    new_i--;
+  if ((old_i & 0x1) != (new_i & 0x1))
+    facet->toporient ^= 1;
+  qh_setdelnthsorted(qh, facet->vertices, old_i);
+  qh_setaddnth(qh, &facet->vertices, new_i, newvertex);
+  neighbor= SETelemt_(facet->neighbors, old_i, facetT);
+  qh_setdelnthsorted(qh, facet->neighbors, old_i);
+  qh_setaddnth(qh, &facet->neighbors, new_i, neighbor);
+} /* replacefacetvertex */
+
+/*---------------------------------
+
+  qh_resetlists(qh, stats, qh_RESETvisible )
+    reset newvertex_list, newfacet_list, visible_list, NEWfacets, NEWtentative
+    if stats,
+      maintains statistics
+    if resetVisible,
+      visible_list is restored to facet_list
+      otherwise, f.visible/f.replace is retained
+
+  returns:
+    newvertex_list, newfacet_list, visible_list are NULL
+
+  notes:
+    To delete visible facets, call qh_deletevisible before qh_resetlists
+*/
+void qh_resetlists(qhT *qh, boolT stats, boolT resetVisible /* qh.newvertex_list newfacet_list visible_list */) {
+  vertexT *vertex;
+  facetT *newfacet, *visible;
+  int totnew=0, totver=0;
+
+  trace2((qh, qh->ferr, 2066, "qh_resetlists: reset newvertex_list v%d, newfacet_list f%d, visible_list f%d, facet_list f%d next f%d vertex_list v%d -- NEWfacets? %d, NEWtentative? %d, stats? %d\n",
+    getid_(qh->newvertex_list), getid_(qh->newfacet_list), getid_(qh->visible_list), getid_(qh->facet_list), getid_(qh->facet_next), getid_(qh->vertex_list), qh->NEWfacets, qh->NEWtentative, stats));
+  if (stats) {
+    FORALLvertex_(qh->newvertex_list)
+      totver++;
+    FORALLnew_facets
+      totnew++;
+    zadd_(Zvisvertextot, totver);
+    zmax_(Zvisvertexmax, totver);
+    zadd_(Znewfacettot, totnew);
+    zmax_(Znewfacetmax, totnew);
+  }
+  FORALLvertex_(qh->newvertex_list)
+    vertex->newfacet= False;
+  qh->newvertex_list= NULL;
+  qh->first_newfacet= 0;
+  FORALLnew_facets {
+    newfacet->newfacet= False;
+    newfacet->dupridge= False;
+  }
+  qh->newfacet_list= NULL;
+  if (resetVisible) {
+    FORALLvisible_facets {
+      visible->f.replace= NULL;
+      visible->visible= False;
+    }
+    qh->num_visible= 0;
+  }
+  qh->visible_list= NULL;
+  qh->NEWfacets= False;
+  qh->NEWtentative= False;
+} /* resetlists */
+
+/*---------------------------------
+
+  qh_setvoronoi_all(qh)
+    compute Voronoi centers for all facets
+    includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')
+
+  returns:
+    facet->center is the Voronoi center
+
+  notes:
+    unused/untested code: please email bradb@shore.net if this works ok for you
+
+  use:
+    FORALLvertices {...} to locate the vertex for a point.
+    FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.
+*/
+void qh_setvoronoi_all(qhT *qh) {
+  facetT *facet;
+
+  qh_clearcenters(qh, qh_ASvoronoi);
+  qh_vertexneighbors(qh);
+
+  FORALLfacets {
+    if (!facet->normal || !facet->upperdelaunay || qh->UPPERdelaunay) {
+      if (!facet->center)
+        facet->center= qh_facetcenter(qh, facet->vertices);
+    }
+  }
+} /* setvoronoi_all */
+
+#ifndef qh_NOmerge
+/*---------------------------------
+
+  qh_triangulate()
+    triangulate non-simplicial facets on qh.facet_list,
+    if qh->VORONOI, sets Voronoi centers of non-simplicial facets
+    nop if hasTriangulation
+
+  returns:
+    all facets simplicial
+    each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.
+    resets qh.newfacet_list and visible_list
+
+  notes:
+    called by qh_prepare_output and user_eg2_r.c
+    call after qh_check_output since may switch to Voronoi centers, and qh_checkconvex skips f.tricoplanar facets
+    Output may overwrite ->f.triowner with ->f.area
+    while running, 'triangulated_facet_list' is a list of
+       one non-simplicial facet followed by its 'f.tricoplanar' triangulated facets
+    See qh_buildcone
+*/
+void qh_triangulate(qhT *qh /* qh.facet_list */) {
+  facetT *facet, *nextfacet, *owner;
+  facetT *neighbor, *visible= NULL, *facet1, *facet2, *triangulated_facet_list= NULL;
+  facetT *orig_neighbor= NULL, *otherfacet;
+  vertexT *triangulated_vertex_list= NULL;
+  mergeT *merge;
+  mergeType mergetype;
+  int neighbor_i, neighbor_n;
+  boolT onlygood= qh->ONLYgood;
+
+  if (qh->hasTriangulation)
+      return;
+  trace1((qh, qh->ferr, 1034, "qh_triangulate: triangulate non-simplicial facets\n"));
+  if (qh->hull_dim == 2)
+    return;
+  if (qh->VORONOI) {  /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */
+    qh_clearcenters(qh, qh_ASvoronoi);
+    qh_vertexneighbors(qh);
+  }
+  qh->ONLYgood= False; /* for makenew_nonsimplicial */
+  qh->visit_id++;
+  qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
+  qh->newvertex_list= qh->vertex_tail;
+  for (facet=qh->facet_list; facet && facet->next; facet= nextfacet) { /* non-simplicial facets moved to end */
+    nextfacet= facet->next;
+    if (facet->visible || facet->simplicial)
+      continue;
+    /* triangulate all non-simplicial facets, otherwise merging does not work, e.g., RBOX c P-0.1 P+0.1 P+0.1 D3 | QHULL d Qt Tv */
+    if (!triangulated_facet_list)
+      triangulated_facet_list= facet;  /* will be first triangulated facet */
+    qh_triangulate_facet(qh, facet, &triangulated_vertex_list); /* qh_resetlists ! */
+  }
+  /* qh_checkpolygon invalid due to f.visible without qh.visible_list */
+  trace2((qh, qh->ferr, 2047, "qh_triangulate: delete null facets from facetlist f%d.  A null facet has the same first (apex) and second vertices\n", getid_(triangulated_facet_list)));
+  for (facet=triangulated_facet_list; facet && facet->next; facet= nextfacet) {
+    nextfacet= facet->next;
+    if (facet->visible)
+      continue;
+    if (facet->ridges) {
+      if (qh_setsize(qh, facet->ridges) > 0) {
+        qh_fprintf(qh, qh->ferr, 6161, "qhull internal error (qh_triangulate): ridges still defined for f%d\n", facet->id);
+        qh_errexit(qh, qh_ERRqhull, facet, NULL);
+      }
+      qh_setfree(qh, &facet->ridges);
+    }
+    if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) {
+      zinc_(Ztrinull);
+      qh_triangulate_null(qh, facet); /* will delete facet */
+    }
+  }
+  trace2((qh, qh->ferr, 2048, "qh_triangulate: delete %d or more mirrored facets.  Mirrored facets have the same vertices due to a null facet\n", qh_setsize(qh, qh->degen_mergeset)));
+  qh->visible_list= qh->facet_tail;
+  while ((merge= (mergeT *)qh_setdellast(qh->degen_mergeset))) {
+    facet1= merge->facet1;
+    facet2= merge->facet2;
+    mergetype= merge->mergetype;
+    qh_memfree(qh, merge, (int)sizeof(mergeT));
+    if (mergetype == MRGmirror) {
+      zinc_(Ztrimirror);
+      qh_triangulate_mirror(qh, facet1, facet2);  /* will delete both facets */
+    }
+  }
+  qh_freemergesets(qh);
+  trace2((qh, qh->ferr, 2049, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(triangulated_vertex_list)));
+  qh->newvertex_list= triangulated_vertex_list;  /* all vertices of triangulated facets */
+  qh->visible_list= NULL;
+  qh_update_vertexneighbors(qh /* qh.newvertex_list, empty newfacet_list and visible_list */);
+  qh_resetlists(qh, False, !qh_RESETvisible /* qh.newvertex_list, empty newfacet_list and visible_list */);
+
+  trace2((qh, qh->ferr, 2050, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(triangulated_facet_list)));
+  trace2((qh, qh->ferr, 2051, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));
+  FORALLfacet_(triangulated_facet_list) {
+    if (facet->tricoplanar && !facet->visible) {
+      FOREACHneighbor_i_(qh, facet) {
+        if (neighbor_i == 0) {  /* first iteration */
+          if (neighbor->tricoplanar)
+            orig_neighbor= neighbor->f.triowner;
+          else
+            orig_neighbor= neighbor;
+        }else {
+          if (neighbor->tricoplanar)
+            otherfacet= neighbor->f.triowner;
+          else
+            otherfacet= neighbor;
+          if (orig_neighbor == otherfacet) {
+            zinc_(Ztridegen);
+            facet->degenerate= True;
+            break;
+          }
+        }
+      }
+    }
+  }
+  if (qh->IStracing >= 4)
+    qh_printlists(qh);
+  trace2((qh, qh->ferr, 2052, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));
+  owner= NULL;
+  visible= NULL;
+  for (facet=triangulated_facet_list; facet && facet->next; facet= nextfacet) {
+    /* deleting facets, triangulated_facet_list is no longer valid */
+    nextfacet= facet->next;
+    if (facet->visible) {
+      if (facet->tricoplanar) { /* a null or mirrored facet */
+        qh_delfacet(qh, facet);
+        qh->num_visible--;
+      }else {  /* a non-simplicial facet followed by its tricoplanars */
+        if (visible && !owner) {
+          /*  RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */
+          trace2((qh, qh->ferr, 2053, "qh_triangulate: delete f%d.  All tricoplanar facets degenerate for non-simplicial facet\n",
+                       visible->id));
+          qh_delfacet(qh, visible);
+          qh->num_visible--;
+        }
+        visible= facet;
+        owner= NULL;
+      }
+    }else if (facet->tricoplanar) {
+      if (facet->f.triowner != visible || visible==NULL) {
+        qh_fprintf(qh, qh->ferr, 6162, "qhull internal error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible));
+        qh_errexit2(qh, qh_ERRqhull, facet, visible);
+      }
+      if (owner)
+        facet->f.triowner= owner;
+      else if (!facet->degenerate) {
+        owner= facet;
+        nextfacet= visible->next; /* rescan tricoplanar facets with owner, visible!=0 by QH6162 */
+        facet->keepcentrum= True;  /* one facet owns ->normal, etc. */
+        facet->coplanarset= visible->coplanarset;
+        facet->outsideset= visible->outsideset;
+        visible->coplanarset= NULL;
+        visible->outsideset= NULL;
+        if (!qh->TRInormals) { /* center and normal copied to tricoplanar facets */
+          visible->center= NULL;
+          visible->normal= NULL;
+        }
+        qh_delfacet(qh, visible);
+        qh->num_visible--;
+      }
+    }
+    facet->degenerate= False; /* reset f.degenerate set by qh_triangulate*/
+  }
+  if (visible && !owner) {
+    trace2((qh, qh->ferr, 2054, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",
+                 visible->id));
+    qh_delfacet(qh, visible);
+    qh->num_visible--;
+  }
+  qh->ONLYgood= onlygood; /* restore value */
+  if (qh->CHECKfrequently)
+    qh_checkpolygon(qh, qh->facet_list);
+  qh->hasTriangulation= True;
+} /* triangulate */
+
+
+/*---------------------------------
+
+  qh_triangulate_facet(qh, facetA, &firstVertex )
+    triangulate a non-simplicial facet
+      if qh.CENTERtype=qh_ASvoronoi, sets its Voronoi center
+  returns:
+    qh.newfacet_list == simplicial facets
+      facet->tricoplanar set and ->keepcentrum false
+      facet->degenerate set if duplicated apex
+      facet->f.trivisible set to facetA
+      facet->center copied from facetA (created if qh_ASvoronoi)
+        qh_eachvoronoi, qh_detvridge, qh_detvridge3 assume centers copied
+      facet->normal,offset,maxoutside copied from facetA
+
+  notes:
+      only called by qh_triangulate
+      qh_makenew_nonsimplicial uses neighbor->seen for the same
+      if qh.TRInormals, newfacet->normal will need qh_free
+        if qh.TRInormals and qh_AScentrum, newfacet->center will need qh_free
+        keepcentrum is also set on Zwidefacet in qh_mergefacet
+        freed by qh_clearcenters
+
+  see also:
+      qh_addpoint() -- add a point
+      qh_makenewfacets() -- construct a cone of facets for a new vertex
+
+  design:
+      if qh_ASvoronoi,
+         compute Voronoi center (facet->center)
+      select first vertex (highest ID to preserve ID ordering of ->vertices)
+      triangulate from vertex to ridges
+      copy facet->center, normal, offset
+      update vertex neighbors
+*/
+void qh_triangulate_facet(qhT *qh, facetT *facetA, vertexT **first_vertex) {
+  facetT *newfacet;
+  facetT *neighbor, **neighborp;
+  vertexT *apex;
+  int numnew=0;
+
+  trace3((qh, qh->ferr, 3020, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));
+
+  qh->first_newfacet= qh->facet_id;
+  if (qh->IStracing >= 4)
+    qh_printfacet(qh, qh->ferr, facetA);
+  FOREACHneighbor_(facetA) {
+    neighbor->seen= False;
+    neighbor->coplanarhorizon= False;
+  }
+  if (qh->CENTERtype == qh_ASvoronoi && !facetA->center  /* matches upperdelaunay in qh_setfacetplane() */
+  && fabs_(facetA->normal[qh->hull_dim -1]) >= qh->ANGLEround * qh_ZEROdelaunay) {
+    facetA->center= qh_facetcenter(qh, facetA->vertices);
+  }
+  qh->visible_list= qh->newfacet_list= qh->facet_tail;
+  facetA->visitid= qh->visit_id;
+  apex= SETfirstt_(facetA->vertices, vertexT);
+  qh_makenew_nonsimplicial(qh, facetA, apex, &numnew);
+  qh_willdelete(qh, facetA, NULL);
+  FORALLnew_facets {
+    newfacet->tricoplanar= True;
+    newfacet->f.trivisible= facetA;
+    newfacet->degenerate= False;
+    newfacet->upperdelaunay= facetA->upperdelaunay;
+    newfacet->good= facetA->good;
+    if (qh->TRInormals) { /* 'Q11' triangulate duplicates ->normal and ->center */
+      newfacet->keepcentrum= True;
+      if(facetA->normal){
+        newfacet->normal= (coordT *)qh_memalloc(qh, qh->normal_size);
+        memcpy((char *)newfacet->normal, facetA->normal, (size_t)qh->normal_size);
+      }
+      if (qh->CENTERtype == qh_AScentrum)
+        newfacet->center= qh_getcentrum(qh, newfacet);
+      else if (qh->CENTERtype == qh_ASvoronoi && facetA->center){
+        newfacet->center= (coordT *)qh_memalloc(qh, qh->center_size);
+        memcpy((char *)newfacet->center, facetA->center, (size_t)qh->center_size);
+      }
+    }else {
+      newfacet->keepcentrum= False;
+      /* one facet will have keepcentrum=True at end of qh_triangulate */
+      newfacet->normal= facetA->normal;
+      newfacet->center= facetA->center;
+    }
+    newfacet->offset= facetA->offset;
+#if qh_MAXoutside
+    newfacet->maxoutside= facetA->maxoutside;
+#endif
+  }
+  qh_matchnewfacets(qh /* qh.newfacet_list */); /* ignore returned value, maxdupdist */
+  zinc_(Ztricoplanar);
+  zadd_(Ztricoplanartot, numnew);
+  zmax_(Ztricoplanarmax, numnew);
+  if (!(*first_vertex))
+    (*first_vertex)= qh->newvertex_list;
+  qh->newvertex_list= NULL;
+  qh->visible_list= NULL;
+  /* only update v.neighbors for qh.newfacet_list.  qh.visible_list and qh.newvertex_list are NULL */
+  qh_update_vertexneighbors(qh /* qh.newfacet_list */);
+  qh_resetlists(qh, False, !qh_RESETvisible /* qh.newfacet_list */);
+} /* triangulate_facet */
+
+/*---------------------------------
+
+  qh_triangulate_link(qh, oldfacetA, facetA, oldfacetB, facetB)
+    relink facetA to facetB via null oldfacetA or mirrored oldfacetA and oldfacetB
+  returns:
+    if neighbors are already linked, will merge as MRGmirror (qh.degen_mergeset, 4-d and up)
+*/
+void qh_triangulate_link(qhT *qh, facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {
+  int errmirror= False;
+
+  if (oldfacetA == oldfacetB) {
+    trace3((qh, qh->ferr, 3052, "qh_triangulate_link: relink neighbors f%d and f%d of null facet f%d\n",
+      facetA->id, facetB->id, oldfacetA->id));
+  }else {
+    trace3((qh, qh->ferr, 3021, "qh_triangulate_link: relink neighbors f%d and f%d of mirrored facets f%d and f%d\n",
+      facetA->id, facetB->id, oldfacetA->id, oldfacetB->id));
+  }
+  if (qh_setin(facetA->neighbors, facetB)) {
+    if (!qh_setin(facetB->neighbors, facetA))
+      errmirror= True;
+    else if (!facetA->redundant || !facetB->redundant || !qh_hasmerge(qh->degen_mergeset, MRGmirror, facetA, facetB))
+      qh_appendmergeset(qh, facetA, facetB, MRGmirror, 0.0, 1.0);
+  }else if (qh_setin(facetB->neighbors, facetA))
+    errmirror= True;
+  if (errmirror) {
+    qh_fprintf(qh, qh->ferr, 6163, "qhull internal error (qh_triangulate_link): neighbors f%d and f%d do not match for null facet or mirrored facets f%d and f%d\n",
+       facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);
+    qh_errexit2(qh, qh_ERRqhull, facetA, facetB);
+  }
+  qh_setreplace(qh, facetB->neighbors, oldfacetB, facetA);
+  qh_setreplace(qh, facetA->neighbors, oldfacetA, facetB);
+} /* triangulate_link */
+
+/*---------------------------------
+
+  qh_triangulate_mirror(qh, facetA, facetB)
+    delete two mirrored facets identified by qh_triangulate_null() and itself
+      a mirrored facet shares the same vertices of a logical ridge
+  design:
+    since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
+    if they are already neighbors, the opposing neighbors become MRGmirror facets
+*/
+void qh_triangulate_mirror(qhT *qh, facetT *facetA, facetT *facetB) {
+  facetT *neighbor, *neighborB;
+  int neighbor_i, neighbor_n;
+
+  trace3((qh, qh->ferr, 3022, "qh_triangulate_mirror: delete mirrored facets f%d and f%d and link their neighbors\n",
+         facetA->id, facetB->id));
+  FOREACHneighbor_i_(qh, facetA) {
+    neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);
+    if (neighbor == facetB && neighborB == facetA)
+      continue; /* occurs twice */
+    else if (neighbor->redundant && neighborB->redundant) { /* also mirrored facets (D5+) */
+      if (qh_hasmerge(qh->degen_mergeset, MRGmirror, neighbor, neighborB))
+        continue;
+    }
+    if (neighbor->visible && neighborB->visible) /* previously deleted as mirrored facets */
+      continue;
+    qh_triangulate_link(qh, facetA, neighbor, facetB, neighborB);
+  }
+  qh_willdelete(qh, facetA, NULL);
+  qh_willdelete(qh, facetB, NULL);
+} /* triangulate_mirror */
+
+/*---------------------------------
+
+  qh_triangulate_null(qh, facetA)
+    remove null facetA from qh_triangulate_facet()
+      a null facet has vertex #1 (apex) == vertex #2
+  returns:
+    adds facetA to ->visible for deletion after qh_update_vertexneighbors
+    qh->degen_mergeset contains mirror facets (4-d and up only)
+  design:
+    since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
+    if they are already neighbors, the opposing neighbors will be merged (MRGmirror)
+*/
+void qh_triangulate_null(qhT *qh, facetT *facetA) {
+  facetT *neighbor, *otherfacet;
+
+  trace3((qh, qh->ferr, 3023, "qh_triangulate_null: delete null facet f%d\n", facetA->id));
+  neighbor= SETfirstt_(facetA->neighbors, facetT);
+  otherfacet= SETsecondt_(facetA->neighbors, facetT);
+  qh_triangulate_link(qh, facetA, neighbor, facetA, otherfacet);
+  qh_willdelete(qh, facetA, NULL);
+} /* triangulate_null */
+
+#else /* qh_NOmerge */
+void qh_triangulate(qhT *qh) {
+  QHULL_UNUSED(qh)
+}
+#endif /* qh_NOmerge */
+
+/*---------------------------------
+
+  qh_vertexintersect(qh, verticesA, verticesB )
+    intersects two vertex sets (inverse id ordered)
+    vertexsetA is a temporary set at the top of qh->qhmem.tempstack
+
+  returns:
+    replaces vertexsetA with the intersection
+
+  notes:
+    only called by qh_neighbor_intersections
+    if !qh.QHULLfinished, non-simplicial facets may have f.vertices with extraneous vertices
+      cleaned by qh_remove_extravertices in qh_reduce_vertices
+    could optimize by overwriting vertexsetA
+*/
+void qh_vertexintersect(qhT *qh, setT **vertexsetA, setT *vertexsetB) {
+  setT *intersection;
+
+  intersection= qh_vertexintersect_new(qh, *vertexsetA, vertexsetB);
+  qh_settempfree(qh, vertexsetA);
+  *vertexsetA= intersection;
+  qh_settemppush(qh, intersection);
+} /* vertexintersect */
+
+/*---------------------------------
+
+  qh_vertexintersect_new(qh, verticesA, verticesB )
+    intersects two vertex sets (inverse id ordered)
+
+  returns:
+    a new set
+
+  notes:
+    called by qh_checkfacet, qh_vertexintersect, qh_rename_sharedvertex, qh_findbest_pinchedvertex, qh_neighbor_intersections
+    if !qh.QHULLfinished, non-simplicial facets may have f.vertices with extraneous vertices
+       cleaned by qh_remove_extravertices in qh_reduce_vertices
+*/
+setT *qh_vertexintersect_new(qhT *qh, setT *vertexsetA, setT *vertexsetB) {
+  setT *intersection= qh_setnew(qh, qh->hull_dim - 1);
+  vertexT **vertexA= SETaddr_(vertexsetA, vertexT);
+  vertexT **vertexB= SETaddr_(vertexsetB, vertexT);
+
+  while (*vertexA && *vertexB) {
+    if (*vertexA  == *vertexB) {
+      qh_setappend(qh, &intersection, *vertexA);
+      vertexA++; vertexB++;
+    }else {
+      if ((*vertexA)->id > (*vertexB)->id)
+        vertexA++;
+      else
+        vertexB++;
+    }
+  }
+  return intersection;
+} /* vertexintersect_new */
+
+/*---------------------------------
+
+  qh_vertexneighbors(qh)
+    for each vertex in qh.facet_list,
+      determine its neighboring facets
+
+  returns:
+    sets qh.VERTEXneighbors
+      nop if qh.VERTEXneighbors already set
+      qh_addpoint() will maintain them
+
+  notes:
+    assumes all vertex->neighbors are NULL
+
+  design:
+    for each facet
+      for each vertex
+        append facet to vertex->neighbors
+*/
+void qh_vertexneighbors(qhT *qh /* qh.facet_list */) {
+  facetT *facet;
+  vertexT *vertex, **vertexp;
+
+  if (qh->VERTEXneighbors)
+    return;
+  trace1((qh, qh->ferr, 1035, "qh_vertexneighbors: determining neighboring facets for each vertex\n"));
+  qh->vertex_visit++;
+  FORALLfacets {
+    if (facet->visible)
+      continue;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh->vertex_visit) {
+        vertex->visitid= qh->vertex_visit;
+        vertex->neighbors= qh_setnew(qh, qh->hull_dim);
+      }
+      qh_setappend(qh, &vertex->neighbors, facet);
+    }
+  }
+  qh->VERTEXneighbors= True;
+} /* vertexneighbors */
+
+/*---------------------------------
+
+  qh_vertexsubset( vertexsetA, vertexsetB )
+    returns True if vertexsetA is a subset of vertexsetB
+    assumes vertexsets are sorted
+
+  note:
+    empty set is a subset of any other set
+*/
+boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) {
+  vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);
+  vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);
+
+  while (True) {
+    if (!*vertexA)
+      return True;
+    if (!*vertexB)
+      return False;
+    if ((*vertexA)->id > (*vertexB)->id)
+      return False;
+    if (*vertexA  == *vertexB)
+      vertexA++;
+    vertexB++;
+  }
+  return False; /* avoid warnings */
+} /* vertexsubset */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/poly_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/poly_r.c
new file mode 100644
index 00000000000..d6a5e7a3d8c
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/poly_r.c
@@ -0,0 +1,1448 @@
+/*
  ---------------------------------
+
+   poly_r.c
+   implements polygons and simplices
+
+   see qh-poly_r.htm, poly_r.h and libqhull_r.h
+
+   infrequent code is in poly2_r.c
+   (all but top 50 and their callers 12/3/95)
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/poly_r.c#8 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+*/
+
+#include "qhull_ra.h"
+
+/*======== functions in alphabetical order ==========*/
+
+/*---------------------------------
+
+  qh_appendfacet(qh, facet )
+    appends facet to end of qh.facet_list,
+
+  returns:
+    updates qh.newfacet_list, facet_next, facet_list
+    increments qh.numfacets
+
+  notes:
+    assumes qh.facet_list/facet_tail is defined (createsimplex)
+
+  see:
+    qh_removefacet()
+
+*/
+void qh_appendfacet(qhT *qh, facetT *facet) {
+  facetT *tail= qh->facet_tail;
+
+  if (tail == qh->newfacet_list) {
+    qh->newfacet_list= facet;
+    if (tail == qh->visible_list) /* visible_list is at or before newfacet_list */
+      qh->visible_list= facet;
+  }
+  if (tail == qh->facet_next)
+    qh->facet_next= facet;
+  facet->previous= tail->previous;
+  facet->next= tail;
+  if (tail->previous)
+    tail->previous->next= facet;
+  else
+    qh->facet_list= facet;
+  tail->previous= facet;
+  qh->num_facets++;
+  trace4((qh, qh->ferr, 4044, "qh_appendfacet: append f%d to facet_list\n", facet->id));
+} /* appendfacet */
+
+
+/*---------------------------------
+
+  qh_appendvertex(qh, vertex )
+    appends vertex to end of qh.vertex_list,
+
+  returns:
+    sets vertex->newfacet
+    updates qh.vertex_list, newvertex_list
+    increments qh.num_vertices
+
+  notes:
+    assumes qh.vertex_list/vertex_tail is defined (createsimplex)
+
+*/
+void qh_appendvertex(qhT *qh, vertexT *vertex) {
+  vertexT *tail= qh->vertex_tail;
+
+  if (tail == qh->newvertex_list)
+    qh->newvertex_list= vertex;
+  vertex->newfacet= True;
+  vertex->previous= tail->previous;
+  vertex->next= tail;
+  if (tail->previous)
+    tail->previous->next= vertex;
+  else
+    qh->vertex_list= vertex;
+  tail->previous= vertex;
+  qh->num_vertices++;
+  trace4((qh, qh->ferr, 4045, "qh_appendvertex: append v%d to qh.newvertex_list and set v.newfacet\n", vertex->id));
+} /* appendvertex */
+
+
+/*---------------------------------
+
+  qh_attachnewfacets(qh)
+    attach horizon facets to new facets in qh.newfacet_list
+    newfacets have neighbor and ridge links to horizon but not vice versa
+
+  returns:
+    clears qh.NEWtentative
+    set qh.NEWfacets
+    horizon facets linked to new facets
+      ridges changed from visible facets to new facets
+      simplicial ridges deleted
+    qh.visible_list, no ridges valid
+    facet->f.replace is a newfacet (if any)
+
+  notes:
+    used for qh.NEWtentative, otherwise see qh_makenew_nonsimplicial and qh_makenew_simplicial
+    qh_delridge_merge not needed (as tested by qh_checkdelridge)
+
+  design:
+    delete interior ridges and neighbor sets by
+      for each visible, non-simplicial facet
+        for each ridge
+          if last visit or if neighbor is simplicial
+            if horizon neighbor
+              delete ridge for horizon's ridge set
+            delete ridge
+        erase neighbor set
+    attach horizon facets and new facets by
+      for all new facets
+        if corresponding horizon facet is simplicial
+          locate corresponding visible facet {may be more than one}
+          link visible facet to new facet
+          replace visible facet with new facet in horizon
+        else it is non-simplicial
+          for all visible neighbors of the horizon facet
+            link visible neighbor to new facet
+            delete visible neighbor from horizon facet
+          append new facet to horizon's neighbors
+          the first ridge of the new facet is the horizon ridge
+          link the new facet into the horizon ridge
+*/
+void qh_attachnewfacets(qhT *qh /* qh.visible_list, qh.newfacet_list */) {
+  facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;
+  ridgeT *ridge, **ridgep;
+
+  trace3((qh, qh->ferr, 3012, "qh_attachnewfacets: delete interior ridges\n"));
+  if (qh->CHECKfrequently) {
+    qh_checkdelridge(qh);
+  }
+  qh->visit_id++;
+  FORALLvisible_facets {
+    visible->visitid= qh->visit_id;
+    if (visible->ridges) {
+      FOREACHridge_(visible->ridges) {
+        neighbor= otherfacet_(ridge, visible);
+        if (neighbor->visitid == qh->visit_id
+            || (!neighbor->visible && neighbor->simplicial)) {
+          if (!neighbor->visible)  /* delete ridge for simplicial horizon */
+            qh_setdel(neighbor->ridges, ridge);
+          qh_delridge(qh, ridge); /* delete on second visit */
+        }
+      }
+    }
+  }
+  trace1((qh, qh->ferr, 1017, "qh_attachnewfacets: attach horizon facets to new facets\n"));
+  FORALLnew_facets {
+    horizon= SETfirstt_(newfacet->neighbors, facetT);
+    if (horizon->simplicial) {
+      visible= NULL;
+      FOREACHneighbor_(horizon) {   /* may have more than one horizon ridge */
+        if (neighbor->visible) {
+          if (visible) {
+            if (qh_setequal_skip(newfacet->vertices, 0, horizon->vertices,
+                                  SETindex_(horizon->neighbors, neighbor))) {
+              visible= neighbor;
+              break;
+            }
+          }else
+            visible= neighbor;
+        }
+      }
+      if (visible) {
+        visible->f.replace= newfacet;
+        qh_setreplace(qh, horizon->neighbors, visible, newfacet);
+      }else {
+        qh_fprintf(qh, qh->ferr, 6102, "qhull internal error (qh_attachnewfacets): could not find visible facet for horizon f%d of newfacet f%d\n",
+                 horizon->id, newfacet->id);
+        qh_errexit2(qh, qh_ERRqhull, horizon, newfacet);
+      }
+    }else { /* non-simplicial, with a ridge for newfacet */
+      FOREACHneighbor_(horizon) {    /* may hold for many new facets */
+        if (neighbor->visible) {
+          neighbor->f.replace= newfacet;
+          qh_setdelnth(qh, horizon->neighbors, SETindex_(horizon->neighbors, neighbor));
+          neighborp--; /* repeat */
+        }
+      }
+      qh_setappend(qh, &horizon->neighbors, newfacet);
+      ridge= SETfirstt_(newfacet->ridges, ridgeT);
+      if (ridge->top == horizon) {
+        ridge->bottom= newfacet;
+        ridge->simplicialbot= True;
+      }else {
+        ridge->top= newfacet;
+        ridge->simplicialtop= True;
+      }
+    }
+  } /* newfacets */
+  trace4((qh, qh->ferr, 4094, "qh_attachnewfacets: clear f.ridges and f.neighbors for visible facets, may become invalid before qh_deletevisible\n"));
+  FORALLvisible_facets {
+    if (visible->ridges)
+      SETfirst_(visible->ridges)= NULL; 
+    SETfirst_(visible->neighbors)= NULL;
+  }
+  qh->NEWtentative= False;
+  qh->NEWfacets= True;
+  if (qh->PRINTstatistics) {
+    FORALLvisible_facets {
+      if (!visible->f.replace)
+        zinc_(Zinsidevisible);
+    }
+  }
+} /* attachnewfacets */
+
+/*---------------------------------
+
+  qh_checkflipped(qh, facet, dist, allerror )
+    checks facet orientation to interior point
+
+    if allerror set,
+      tests against -qh.DISTround
+    else
+      tests against 0.0 since tested against -qh.DISTround before
+
+  returns:
+    False if it flipped orientation (sets facet->flipped)
+    distance if non-NULL
+
+  notes:
+    called by qh_setfacetplane, qh_initialhull, and qh_checkflipped_all
+*/
+boolT qh_checkflipped(qhT *qh, facetT *facet, realT *distp, boolT allerror) {
+  realT dist;
+
+  if (facet->flipped && !distp)
+    return False;
+  zzinc_(Zdistcheck);
+  qh_distplane(qh, qh->interior_point, facet, &dist);
+  if (distp)
+    *distp= dist;
+  if ((allerror && dist >= -qh->DISTround) || (!allerror && dist > 0.0)) {
+    facet->flipped= True;
+    trace0((qh, qh->ferr, 19, "qh_checkflipped: facet f%d flipped, allerror? %d, distance= %6.12g during p%d\n",
+              facet->id, allerror, dist, qh->furthest_id));
+    if (qh->num_facets > qh->hull_dim+1) { /* qh_initialhull reverses orientation if !qh_checkflipped */
+      zzinc_(Zflippedfacets);
+      qh_joggle_restart(qh, "flipped facet");
+    }
+    return False;
+  }
+  return True;
+} /* checkflipped */
+
+/*---------------------------------
+
+  qh_delfacet(qh, facet )
+    removes facet from facet_list and frees up its memory
+
+  notes:
+    assumes vertices and ridges already freed or referenced elsewhere
+*/
+void qh_delfacet(qhT *qh, facetT *facet) {
+  void **freelistp; /* used if !qh_NOmem by qh_memfree_() */
+
+  trace3((qh, qh->ferr, 3057, "qh_delfacet: delete f%d\n", facet->id));
+  if (qh->CHECKfrequently || qh->VERIFYoutput) { 
+    if (!qh->NOerrexit) {
+      qh_checkdelfacet(qh, facet, qh->facet_mergeset);
+      qh_checkdelfacet(qh, facet, qh->degen_mergeset);
+      qh_checkdelfacet(qh, facet, qh->vertex_mergeset);
+    }
+  }
+  if (facet == qh->tracefacet)
+    qh->tracefacet= NULL;
+  if (facet == qh->GOODclosest)
+    qh->GOODclosest= NULL;
+  qh_removefacet(qh, facet);
+  if (!facet->tricoplanar || facet->keepcentrum) {
+    qh_memfree_(qh, facet->normal, qh->normal_size, freelistp);
+    if (qh->CENTERtype == qh_ASvoronoi) {   /* braces for macro calls */
+      qh_memfree_(qh, facet->center, qh->center_size, freelistp);
+    }else /* AScentrum */ {
+      qh_memfree_(qh, facet->center, qh->normal_size, freelistp);
+    }
+  }
+  qh_setfree(qh, &(facet->neighbors));
+  if (facet->ridges)
+    qh_setfree(qh, &(facet->ridges));
+  qh_setfree(qh, &(facet->vertices));
+  if (facet->outsideset)
+    qh_setfree(qh, &(facet->outsideset));
+  if (facet->coplanarset)
+    qh_setfree(qh, &(facet->coplanarset));
+  qh_memfree_(qh, facet, (int)sizeof(facetT), freelistp);
+} /* delfacet */
+
+
+/*---------------------------------
+
+  qh_deletevisible()
+    delete visible facets and vertices
+
+  returns:
+    deletes each facet and removes from facetlist
+    deletes vertices on qh.del_vertices and ridges in qh.del_ridges
+    at exit, qh.visible_list empty (== qh.newfacet_list)
+
+  notes:
+    called by qh_all_vertexmerges, qh_addpoint, and qh_qhull
+    ridges already deleted or moved elsewhere
+    deleted vertices on qh.del_vertices
+    horizon facets do not reference facets on qh.visible_list
+    new facets in qh.newfacet_list
+    uses   qh.visit_id;
+*/
+void qh_deletevisible(qhT *qh /* qh.visible_list */) {
+  facetT *visible, *nextfacet;
+  vertexT *vertex, **vertexp;
+  int numvisible= 0, numdel= qh_setsize(qh, qh->del_vertices);
+
+  trace1((qh, qh->ferr, 1018, "qh_deletevisible: delete %d visible facets and %d vertices\n",
+         qh->num_visible, numdel));
+  for (visible=qh->visible_list; visible && visible->visible;
+                visible= nextfacet) { /* deleting current */
+    nextfacet= visible->next;
+    numvisible++;
+    qh_delfacet(qh, visible);  /* f.ridges deleted or moved elsewhere, deleted f.vertices on qh.del_vertices */
+  }
+  if (numvisible != qh->num_visible) {
+    qh_fprintf(qh, qh->ferr, 6103, "qhull internal error (qh_deletevisible): qh->num_visible %d is not number of visible facets %d\n",
+             qh->num_visible, numvisible);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  qh->num_visible= 0;
+  zadd_(Zvisfacettot, numvisible);
+  zmax_(Zvisfacetmax, numvisible);
+  zzadd_(Zdelvertextot, numdel);
+  zmax_(Zdelvertexmax, numdel);
+  FOREACHvertex_(qh->del_vertices)
+    qh_delvertex(qh, vertex);
+  qh_settruncate(qh, qh->del_vertices, 0);
+} /* deletevisible */
+
+/*---------------------------------
+
+  qh_facetintersect(qh, facetA, facetB, skipa, skipB, prepend )
+    return vertices for intersection of two simplicial facets
+    may include 1 prepended entry (if more, need to settemppush)
+
+  returns:
+    returns set of qh.hull_dim-1 + prepend vertices
+    returns skipped index for each test and checks for exactly one
+
+  notes:
+    does not need settemp since set in quick memory
+
+  see also:
+    qh_vertexintersect and qh_vertexintersect_new
+    use qh_setnew_delnthsorted to get nth ridge (no skip information)
+
+  design:
+    locate skipped vertex by scanning facet A's neighbors
+    locate skipped vertex by scanning facet B's neighbors
+    intersect the vertex sets
+*/
+setT *qh_facetintersect(qhT *qh, facetT *facetA, facetT *facetB,
+                         int *skipA,int *skipB, int prepend) {
+  setT *intersect;
+  int dim= qh->hull_dim, i, j;
+  facetT **neighborsA, **neighborsB;
+
+  neighborsA= SETaddr_(facetA->neighbors, facetT);
+  neighborsB= SETaddr_(facetB->neighbors, facetT);
+  i= j= 0;
+  if (facetB == *neighborsA++)
+    *skipA= 0;
+  else if (facetB == *neighborsA++)
+    *skipA= 1;
+  else if (facetB == *neighborsA++)
+    *skipA= 2;
+  else {
+    for (i=3; i < dim; i++) {
+      if (facetB == *neighborsA++) {
+        *skipA= i;
+        break;
+      }
+    }
+  }
+  if (facetA == *neighborsB++)
+    *skipB= 0;
+  else if (facetA == *neighborsB++)
+    *skipB= 1;
+  else if (facetA == *neighborsB++)
+    *skipB= 2;
+  else {
+    for (j=3; j < dim; j++) {
+      if (facetA == *neighborsB++) {
+        *skipB= j;
+        break;
+      }
+    }
+  }
+  if (i >= dim || j >= dim) {
+    qh_fprintf(qh, qh->ferr, 6104, "qhull internal error (qh_facetintersect): f%d or f%d not in other's neighbors\n",
+            facetA->id, facetB->id);
+    qh_errexit2(qh, qh_ERRqhull, facetA, facetB);
+  }
+  intersect= qh_setnew_delnthsorted(qh, facetA->vertices, qh->hull_dim, *skipA, prepend);
+  trace4((qh, qh->ferr, 4047, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",
+          facetA->id, *skipA, facetB->id, *skipB));
+  return(intersect);
+} /* facetintersect */
+
+/*---------------------------------
+
+  qh_gethash(qh, hashsize, set, size, firstindex, skipelem )
+    return hashvalue for a set with firstindex and skipelem
+
+  notes:
+    returned hash is in [0,hashsize)
+    assumes at least firstindex+1 elements
+    assumes skipelem is NULL, in set, or part of hash
+
+    hashes memory addresses which may change over different runs of the same data
+    using sum for hash does badly in high d
+*/
+int qh_gethash(qhT *qh, int hashsize, setT *set, int size, int firstindex, void *skipelem) {
+  void **elemp= SETelemaddr_(set, firstindex, void);
+  ptr_intT hash= 0, elem;
+  unsigned int uresult;
+  int i;
+#ifdef _MSC_VER                   /* Microsoft Visual C++ -- warn about 64-bit issues */
+#pragma warning( push)            /* WARN64 -- ptr_intT holds a 64-bit pointer */
+#pragma warning( disable : 4311)  /* 'type cast': pointer truncation from 'void*' to 'ptr_intT' */
+#endif
+
+  switch (size-firstindex) {
+  case 1:
+    hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem;
+    break;
+  case 2:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem;
+    break;
+  case 3:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      - (ptr_intT) skipelem;
+    break;
+  case 4:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      + (ptr_intT)elemp[3] - (ptr_intT) skipelem;
+    break;
+  case 5:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      + (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem;
+    break;
+  case 6:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      + (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5]
+      - (ptr_intT) skipelem;
+    break;
+  default:
+    hash= 0;
+    i= 3;
+    do {     /* this is about 10% in 10-d */
+      if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) {
+        hash ^= (elem << i) + (elem >> (32-i));
+        i += 3;
+        if (i >= 32)
+          i -= 32;
+      }
+    }while (*elemp);
+    break;
+  }
+  if (hashsize<0) {
+    qh_fprintf(qh, qh->ferr, 6202, "qhull internal error: negative hashsize %d passed to qh_gethash [poly_r.c]\n", hashsize);
+    qh_errexit2(qh, qh_ERRqhull, NULL, NULL);
+  }
+  uresult= (unsigned int)hash;
+  uresult %= (unsigned int)hashsize;
+  /* result= 0; for debugging */
+  return (int)uresult;
+#ifdef _MSC_VER
+#pragma warning( pop)
+#endif
+} /* gethash */
+
+/*---------------------------------
+
+  qh_getreplacement(qh, visible )
+    get replacement for visible facet
+
+  returns:
+    valid facet from visible.replace (may be chained)
+*/
+facetT *qh_getreplacement(qhT *qh, facetT *visible) {
+  unsigned int count= 0;
+
+  facetT *result= visible;
+  while (result && result->visible) {
+    result= result->f.replace;
+    if (count++ > qh->facet_id)
+      qh_infiniteloop(qh, visible);
+  }
+  return result;
+}
+
+/*---------------------------------
+
+  qh_makenewfacet(qh, vertices, toporient, horizon )
+    creates a toporient? facet from vertices
+
+  returns:
+    returns newfacet
+      adds newfacet to qh.facet_list
+      newfacet->vertices= vertices
+      if horizon
+        newfacet->neighbor= horizon, but not vice versa
+    newvertex_list updated with vertices
+*/
+facetT *qh_makenewfacet(qhT *qh, setT *vertices, boolT toporient, facetT *horizon) {
+  facetT *newfacet;
+  vertexT *vertex, **vertexp;
+
+  FOREACHvertex_(vertices) {
+    if (!vertex->newfacet) {
+      qh_removevertex(qh, vertex);
+      qh_appendvertex(qh, vertex);
+    }
+  }
+  newfacet= qh_newfacet(qh);
+  newfacet->vertices= vertices;
+  if (toporient)
+    newfacet->toporient= True;
+  if (horizon)
+    qh_setappend(qh, &(newfacet->neighbors), horizon);
+  qh_appendfacet(qh, newfacet);
+  return(newfacet);
+} /* makenewfacet */
+
+
+/*---------------------------------
+
+  qh_makenewplanes()
+    make new hyperplanes for facets on qh.newfacet_list
+
+  returns:
+    all facets have hyperplanes or are marked for   merging
+    doesn't create hyperplane if horizon is coplanar (will merge)
+    updates qh.min_vertex if qh.JOGGLEmax
+
+  notes:
+    facet->f.samecycle is defined for facet->mergehorizon facets
+*/
+void qh_makenewplanes(qhT *qh /* qh.newfacet_list */) {
+  facetT *newfacet;
+
+  trace4((qh, qh->ferr, 4074, "qh_makenewplanes: make new hyperplanes for facets on qh.newfacet_list f%d\n",
+    qh->newfacet_list->id));
+  FORALLnew_facets {
+    if (!newfacet->mergehorizon)
+      qh_setfacetplane(qh, newfacet); /* updates Wnewvertexmax */
+  }
+  if (qh->JOGGLEmax < REALmax/2)
+    minimize_(qh->min_vertex, -wwval_(Wnewvertexmax));
+} /* makenewplanes */
+
+#ifndef qh_NOmerge
+/*---------------------------------
+
+  qh_makenew_nonsimplicial(qh, visible, apex, numnew )
+    make new facets for ridges of a visible facet
+
+  returns:
+    first newfacet, bumps numnew as needed
+    attaches new facets if !qh->NEWtentative
+    marks ridge neighbors for simplicial visible
+    if (qh.NEWtentative)
+      ridges on newfacet, horizon, and visible
+    else
+      ridge and neighbors between newfacet and horizon
+      visible facet's ridges are deleted
+      visible facet's f.neighbors is empty
+
+  notes:
+    called by qh_makenewfacets and qh_triangulatefacet
+    qh.visit_id if visible has already been processed
+    sets neighbor->seen for building f.samecycle
+      assumes all 'seen' flags initially false
+    qh_delridge_merge not needed (as tested by qh_checkdelridge in qh_makenewfacets)
+
+  design:
+    for each ridge of visible facet
+      get neighbor of visible facet
+      if neighbor was already processed
+        delete the ridge (will delete all visible facets later)
+      if neighbor is a horizon facet
+        create a new facet
+        if neighbor coplanar
+          adds newfacet to f.samecycle for later merging
+        else
+          updates neighbor's neighbor set
+          (checks for non-simplicial facet with multiple ridges to visible facet)
+        updates neighbor's ridge set
+        (checks for simplicial neighbor to non-simplicial visible facet)
+        (deletes ridge if neighbor is simplicial)
+
+*/
+facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {
+  void **freelistp; /* used if !qh_NOmem by qh_memfree_() */
+  ridgeT *ridge, **ridgep;
+  facetT *neighbor, *newfacet= NULL, *samecycle;
+  setT *vertices;
+  boolT toporient;
+  unsigned int ridgeid;
+
+  FOREACHridge_(visible->ridges) {
+    ridgeid= ridge->id;
+    neighbor= otherfacet_(ridge, visible);
+    if (neighbor->visible) {
+      if (!qh->NEWtentative) {
+        if (neighbor->visitid == qh->visit_id) {
+          if (qh->traceridge == ridge)
+            qh->traceridge= NULL;
+          qh_setfree(qh, &(ridge->vertices));  /* delete on 2nd visit */
+          qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
+        }
+      }
+    }else {  /* neighbor is an horizon facet */
+      toporient= (ridge->top == visible);
+      vertices= qh_setnew(qh, qh->hull_dim); /* makes sure this is quick */
+      qh_setappend(qh, &vertices, apex);
+      qh_setappend_set(qh, &vertices, ridge->vertices);
+      newfacet= qh_makenewfacet(qh, vertices, toporient, neighbor);
+      (*numnew)++;
+      if (neighbor->coplanarhorizon) {
+        newfacet->mergehorizon= True;
+        if (!neighbor->seen) {
+          newfacet->f.samecycle= newfacet;
+          neighbor->f.newcycle= newfacet;
+        }else {
+          samecycle= neighbor->f.newcycle;
+          newfacet->f.samecycle= samecycle->f.samecycle;
+          samecycle->f.samecycle= newfacet;
+        }
+      }
+      if (qh->NEWtentative) {
+        if (!neighbor->simplicial)
+          qh_setappend(qh, &(newfacet->ridges), ridge);
+      }else {  /* qh_attachnewfacets */
+        if (neighbor->seen) {
+          if (neighbor->simplicial) {
+            qh_fprintf(qh, qh->ferr, 6105, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n",
+                   neighbor->id, visible->id);
+            qh_errexit2(qh, qh_ERRqhull, neighbor, visible);
+          }
+          qh_setappend(qh, &(neighbor->neighbors), newfacet);
+        }else
+          qh_setreplace(qh, neighbor->neighbors, visible, newfacet);
+        if (neighbor->simplicial) {
+          qh_setdel(neighbor->ridges, ridge);
+          qh_delridge(qh, ridge);
+        }else {
+          qh_setappend(qh, &(newfacet->ridges), ridge);
+          if (toporient) {
+            ridge->top= newfacet;
+            ridge->simplicialtop= True;
+          }else {
+            ridge->bottom= newfacet;
+            ridge->simplicialbot= True;
+          }
+        }
+      }
+      trace4((qh, qh->ferr, 4048, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n",
+          newfacet->id, apex->id, ridgeid, neighbor->id));
+    }
+    neighbor->seen= True;
+  } /* for each ridge */
+  return newfacet;
+} /* makenew_nonsimplicial */
+
+#else /* qh_NOmerge */
+facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {
+  QHULL_UNUSED(qh)
+  QHULL_UNUSED(visible)
+  QHULL_UNUSED(apex)
+  QHULL_UNUSED(numnew)
+
+  return NULL;
+}
+#endif /* qh_NOmerge */
+
+/*---------------------------------
+
+  qh_makenew_simplicial(qh, visible, apex, numnew )
+    make new facets for simplicial visible facet and apex
+
+  returns:
+    attaches new facets if !qh.NEWtentative
+      neighbors between newfacet and horizon
+
+  notes:
+    nop if neighbor->seen or neighbor->visible(see qh_makenew_nonsimplicial)
+
+  design:
+    locate neighboring horizon facet for visible facet
+    determine vertices and orientation
+    create new facet
+    if coplanar,
+      add new facet to f.samecycle
+    update horizon facet's neighbor list
+*/
+facetT *qh_makenew_simplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {
+  facetT *neighbor, **neighborp, *newfacet= NULL;
+  setT *vertices;
+  boolT flip, toporient;
+  int horizonskip= 0, visibleskip= 0;
+
+  FOREACHneighbor_(visible) {
+    if (!neighbor->seen && !neighbor->visible) {
+      vertices= qh_facetintersect(qh, neighbor,visible, &horizonskip, &visibleskip, 1);
+      SETfirst_(vertices)= apex;
+      flip= ((horizonskip & 0x1) ^ (visibleskip & 0x1));
+      if (neighbor->toporient)
+        toporient= horizonskip & 0x1;
+      else
+        toporient= (horizonskip & 0x1) ^ 0x1;
+      newfacet= qh_makenewfacet(qh, vertices, toporient, neighbor);
+      (*numnew)++;
+      if (neighbor->coplanarhorizon && (qh->PREmerge || qh->MERGEexact)) {
+#ifndef qh_NOmerge
+        newfacet->f.samecycle= newfacet;
+        newfacet->mergehorizon= True;
+#endif
+      }
+      if (!qh->NEWtentative)
+        SETelem_(neighbor->neighbors, horizonskip)= newfacet;
+      trace4((qh, qh->ferr, 4049, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n",
+            newfacet->id, toporient, apex->id, neighbor->id, horizonskip,
+              neighbor->toporient, visible->id, visibleskip, flip));
+    }
+  }
+  return newfacet;
+} /* makenew_simplicial */
+
+/*---------------------------------
+
+  qh_matchneighbor(qh, newfacet, newskip, hashsize, hashcount )
+    either match subridge of newfacet with neighbor or add to hash_table
+
+  returns:
+    matched ridges of newfacet, except for duplicate ridges
+    duplicate ridges marked by qh_DUPLICATEridge for qh_matchdupridge
+
+  notes:
+    called by qh_matchnewfacets
+    assumes newfacet is simplicial
+    ridge is newfacet->vertices w/o newskip vertex
+    do not allocate memory (need to free hash_table cleanly)
+    uses linear hash chains
+    see qh_matchdupridge (poly2_r.c)
+
+  design:
+    for each possible matching facet in qh.hash_table
+      if vertices match
+        set ismatch, if facets have opposite orientation
+        if ismatch and matching facet doesn't have a match
+          match the facets by updating their neighbor sets
+        else
+          note: dupridge detected when a match 'f&d skip %d' has already been seen 
+                need to mark all of the dupridges for qh_matchdupridge
+          indicate a duplicate ridge by qh_DUPLICATEridge and f.dupridge
+          add facet to hashtable
+          unless the other facet was already a duplicate ridge
+            mark both facets with a duplicate ridge
+            add other facet (if defined) to hash table
+
+  state at "indicate a duplicate ridge":
+    newfacet@newskip= the argument
+    facet= the hashed facet@skip that has the same vertices as newfacet@newskip
+    same= true if matched vertices have the same orientation
+    matchfacet= neighbor at facet@skip
+    matchfacet=qh_DUPLICATEridge, matchfacet was previously detected as a dupridge of facet@skip
+    ismatch if 'vertex orientation (same) matches facet/newfacet orientation (toporient)
+    unknown facet will match later
+
+  details at "indicate a duplicate ridge":
+    if !ismatch and matchfacet,
+      dupridge is between hashed facet@skip/matchfacet@matchskip and arg newfacet@newskip/unknown 
+      set newfacet@newskip, facet@skip, and matchfacet@matchskip to qh_DUPLICATEridge
+      add newfacet and matchfacet to hash_table
+      if ismatch and matchfacet, 
+        same as !ismatch and matchfacet -- it matches facet instead of matchfacet
+      if !ismatch and !matchfacet
+        dupridge between hashed facet@skip/unknown and arg newfacet@newskip/unknown 
+        set newfacet@newskip and facet@skip to qh_DUPLICATEridge
+        add newfacet to hash_table
+      if ismatch and matchfacet==qh_DUPLICATEridge
+        dupridge with already duplicated hashed facet@skip and arg newfacet@newskip/unknown
+        set newfacet@newskip to qh_DUPLICATEridge
+        add newfacet to hash_table
+        facet's hyperplane already set
+*/
+void qh_matchneighbor(qhT *qh, facetT *newfacet, int newskip, int hashsize, int *hashcount) {
+  boolT newfound= False;   /* True, if new facet is already in hash chain */
+  boolT same, ismatch;
+  int hash, scan;
+  facetT *facet, *matchfacet;
+  int skip, matchskip;
+
+  hash= qh_gethash(qh, hashsize, newfacet->vertices, qh->hull_dim, 1,
+                     SETelem_(newfacet->vertices, newskip));
+  trace4((qh, qh->ferr, 4050, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n",
+          newfacet->id, newskip, hash, *hashcount));
+  zinc_(Zhashlookup);
+  for (scan=hash; (facet= SETelemt_(qh->hash_table, scan, facetT));
+       scan= (++scan >= hashsize ? 0 : scan)) {
+    if (facet == newfacet) {
+      newfound= True;
+      continue;
+    }
+    zinc_(Zhashtests);
+    if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
+      if (SETelem_(newfacet->vertices, newskip) == SETelem_(facet->vertices, skip)) {
+        qh_joggle_restart(qh, "two new facets with the same vertices");
+        /* duplicated for multiple skips, not easily avoided */
+        qh_fprintf(qh, qh->ferr, 7084, "qhull topology warning (qh_matchneighbor): will merge vertices to undo new facets -- f%d and f%d have the same vertices (skip %d, skip %d) and same horizon ridges to f%d and f%d\n",
+          facet->id, newfacet->id, skip, newskip, SETfirstt_(facet->neighbors, facetT)->id, SETfirstt_(newfacet->neighbors, facetT)->id);
+        /* will rename a vertex (QH3053).  The fault was duplicate ridges (same vertices) in different facets due to a previous rename.  Expensive to detect beforehand */
+      }
+      ismatch= (same == (boolT)((newfacet->toporient ^ facet->toporient)));
+      matchfacet= SETelemt_(facet->neighbors, skip, facetT);
+      if (ismatch && !matchfacet) {
+        SETelem_(facet->neighbors, skip)= newfacet;
+        SETelem_(newfacet->neighbors, newskip)= facet;
+        (*hashcount)--;
+        trace4((qh, qh->ferr, 4051, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n",
+           facet->id, skip, newfacet->id, newskip));
+        return;
+      }
+      if (!qh->PREmerge && !qh->MERGEexact) {
+        qh_joggle_restart(qh, "a ridge with more than two neighbors");
+        qh_fprintf(qh, qh->ferr, 6107, "qhull topology error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors.  Can not continue due to no qh.PREmerge and no 'Qx' (MERGEexact)\n",
+                 facet->id, newfacet->id, getid_(matchfacet));
+        qh_errexit2(qh, qh_ERRtopology, facet, newfacet);
+      }
+      SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge;
+      newfacet->dupridge= True;
+      qh_addhash(newfacet, qh->hash_table, hashsize, hash);
+      (*hashcount)++;
+      if (matchfacet != qh_DUPLICATEridge) {
+        SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge;
+        facet->dupridge= True;
+        if (matchfacet) {
+          matchskip= qh_setindex(matchfacet->neighbors, facet);
+          if (matchskip<0) {
+              qh_fprintf(qh, qh->ferr, 6260, "qhull topology error (qh_matchneighbor): matchfacet f%d is in f%d neighbors but not vice versa.  Can not continue.\n",
+                  matchfacet->id, facet->id);
+              qh_errexit2(qh, qh_ERRtopology, matchfacet, facet);
+          }
+          SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge; /* matchskip>=0 by QH6260 */
+          matchfacet->dupridge= True;
+          qh_addhash(matchfacet, qh->hash_table, hashsize, hash);
+          *hashcount += 2;
+        }
+      }
+      trace4((qh, qh->ferr, 4052, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n",
+           newfacet->id, newskip, facet->id, skip,
+           (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)),
+           ismatch, hash));
+      return; /* end of duplicate ridge */
+    }
+  }
+  if (!newfound)
+    SETelem_(qh->hash_table, scan)= newfacet;  /* same as qh_addhash */
+  (*hashcount)++;
+  trace4((qh, qh->ferr, 4053, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",
+           newfacet->id, newskip, hash));
+} /* matchneighbor */
+
+
+/*---------------------------------
+
+  qh_matchnewfacets(qh )
+    match new facets in qh.newfacet_list to their newfacet neighbors
+    all facets are simplicial
+
+  returns:
+    if dupridges and merging 
+      returns maxdupdist (>=0.0) from vertex to opposite facet
+      sets facet->dupridge
+      missing neighbor links identify dupridges to be merged (qh_DUPLICATEridge)
+    else  
+      qh.newfacet_list with full neighbor sets
+        vertices for the nth neighbor match all but the nth vertex
+    if not merging and qh.FORCEoutput
+      for facets with normals (i.e., with dupridges)
+      sets facet->flippped for flipped normals, also prevents point partitioning
+
+  notes:
+    called by qh_buildcone* and qh_triangulate_facet
+    neighbor[0] of new facets is the horizon facet
+    if NEWtentative, new facets not attached to the horizon
+    assumes qh.hash_table is NULL
+    vertex->neighbors has not been updated yet
+    do not allocate memory after qh.hash_table (need to free it cleanly)
+    
+  design:
+    truncate neighbor sets to horizon facet for all new facets
+    initialize a hash table
+    for all new facets
+      match facet with neighbors
+    if unmatched facets (due to duplicate ridges)
+      for each new facet with a duplicate ridge
+        try to match facets with the same coplanar horizon
+    if not all matched
+      for each new facet with a duplicate ridge
+        match it with a coplanar facet, or identify a pinched vertex
+    if not merging and qh.FORCEoutput
+      check for flipped facets
+*/
+coordT qh_matchnewfacets(qhT *qh /* qh.newfacet_list */) {
+  int numnew=0, hashcount=0, newskip;
+  facetT *newfacet, *neighbor;
+  coordT maxdupdist= 0.0, maxdist2;
+  int dim= qh->hull_dim, hashsize, neighbor_i, neighbor_n;
+  setT *neighbors;
+#ifndef qh_NOtrace
+  int facet_i, facet_n, numunused= 0;
+  facetT *facet;
+#endif
+
+  trace1((qh, qh->ferr, 1019, "qh_matchnewfacets: match neighbors for new facets.\n"));
+  FORALLnew_facets {
+    numnew++;
+    {  /* inline qh_setzero(qh, newfacet->neighbors, 1, qh->hull_dim); */
+      neighbors= newfacet->neighbors;
+      neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/
+      memset((char *)SETelemaddr_(neighbors, 1, void), 0, (size_t)(dim * SETelemsize));
+    }
+  }
+
+  qh_newhashtable(qh, numnew*(qh->hull_dim-1)); /* twice what is normally needed,
+                                     but every ridge could be DUPLICATEridge */
+  hashsize= qh_setsize(qh, qh->hash_table);
+  FORALLnew_facets {
+    if (!newfacet->simplicial) {
+      qh_fprintf(qh, qh->ferr, 6377, "qhull internal error (qh_matchnewfacets): expecting simplicial facets on qh.newfacet_list f%d for qh_matchneighbors, qh_matchneighbor, and qh_matchdupridge.  Got non-simplicial f%d\n",
+        qh->newfacet_list->id, newfacet->id);
+      qh_errexit2(qh, qh_ERRqhull, newfacet, qh->newfacet_list);
+    }
+    for (newskip=1; newskiphull_dim; newskip++) /* furthest/horizon already matched */
+      /* hashsize>0 because hull_dim>1 and numnew>0 */
+      qh_matchneighbor(qh, newfacet, newskip, hashsize, &hashcount);
+#if 0   /* use the following to trap hashcount errors */
+    {
+      int count= 0, k;
+      facetT *facet, *neighbor;
+
+      count= 0;
+      FORALLfacet_(qh->newfacet_list) {  /* newfacet already in use */
+        for (k=1; k < qh->hull_dim; k++) {
+          neighbor= SETelemt_(facet->neighbors, k, facetT);
+          if (!neighbor || neighbor == qh_DUPLICATEridge)
+            count++;
+        }
+        if (facet == newfacet)
+          break;
+      }
+      if (count != hashcount) {
+        qh_fprintf(qh, qh->ferr, 6266, "qhull error (qh_matchnewfacets): after adding facet %d, hashcount %d != count %d\n",
+                 newfacet->id, hashcount, count);
+        qh_errexit(qh, qh_ERRdebug, newfacet, NULL);
+      }
+    }
+#endif  /* end of trap code */
+  } /* end FORALLnew_facets */
+  if (hashcount) { /* all neighbors matched, except for qh_DUPLICATEridge neighbors */
+    qh_joggle_restart(qh, "ridge with multiple neighbors");
+    if (hashcount) {
+      FORALLnew_facets {
+        if (newfacet->dupridge) {
+          FOREACHneighbor_i_(qh, newfacet) {
+            if (neighbor == qh_DUPLICATEridge) {
+              maxdist2= qh_matchdupridge(qh, newfacet, neighbor_i, hashsize, &hashcount);
+              maximize_(maxdupdist, maxdist2);
+            }
+          }
+        }
+      }
+    }
+  }
+  if (hashcount) {
+    qh_fprintf(qh, qh->ferr, 6108, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n",
+        hashcount);
+    qh_printhashtable(qh, qh->ferr);
+    qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+#ifndef qh_NOtrace
+  if (qh->IStracing >= 3) {
+    FOREACHfacet_i_(qh, qh->hash_table) {
+      if (!facet)
+        numunused++;
+    }
+    qh_fprintf(qh, qh->ferr, 3063, "qh_matchnewfacets: maxdupdist %2.2g, new facets %d, unused hash entries %d, hashsize %d\n",
+             maxdupdist, numnew, numunused, qh_setsize(qh, qh->hash_table));
+  }
+#endif /* !qh_NOtrace */
+  qh_setfree(qh, &qh->hash_table);
+  if (qh->PREmerge || qh->MERGEexact) {
+    if (qh->IStracing >= 4)
+      qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);
+  }
+  return maxdupdist;
+} /* matchnewfacets */
+
+
+/*---------------------------------
+
+  qh_matchvertices(qh, firstindex, verticesA, skipA, verticesB, skipB, same )
+    tests whether vertices match with a single skip
+    starts match at firstindex since all new facets have a common vertex
+
+  returns:
+    true if matched vertices
+    skip index for skipB
+    sets same iff vertices have the same orientation
+
+  notes:
+    called by qh_matchneighbor and qh_matchdupridge
+    assumes skipA is in A and both sets are the same size
+
+  design:
+    set up pointers
+    scan both sets checking for a match
+    test orientation
+*/
+boolT qh_matchvertices(qhT *qh, int firstindex, setT *verticesA, int skipA,
+       setT *verticesB, int *skipB, boolT *same) {
+  vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp;
+
+  elemAp= SETelemaddr_(verticesA, firstindex, vertexT);
+  elemBp= SETelemaddr_(verticesB, firstindex, vertexT);
+  skipAp= SETelemaddr_(verticesA, skipA, vertexT);
+  do if (elemAp != skipAp) {
+    while (*elemAp != *elemBp++) {
+      if (skipBp)
+        return False;
+      skipBp= elemBp;  /* one extra like FOREACH */
+    }
+  }while (*(++elemAp));
+  if (!skipBp)
+    skipBp= ++elemBp;
+  *skipB= SETindex_(verticesB, skipB); /* i.e., skipBp - verticesB
+                                       verticesA and verticesB are the same size, otherwise trace4 may segfault */
+  *same= !((skipA & 0x1) ^ (*skipB & 0x1)); /* result is 0 or 1 */
+  trace4((qh, qh->ferr, 4054, "qh_matchvertices: matched by skip %d(v%d) and skip %d(v%d) same? %d\n",
+          skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same));
+  return(True);
+} /* matchvertices */
+
+/*---------------------------------
+
+  qh_newfacet(qh)
+    return a new facet
+
+  returns:
+    all fields initialized or cleared   (NULL)
+    preallocates neighbors set
+*/
+facetT *qh_newfacet(qhT *qh) {
+  facetT *facet;
+  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
+
+  qh_memalloc_(qh, (int)sizeof(facetT), freelistp, facet, facetT);
+  memset((char *)facet, (size_t)0, sizeof(facetT));
+  if (qh->facet_id == qh->tracefacet_id)
+    qh->tracefacet= facet;
+  facet->id= qh->facet_id++;
+  facet->neighbors= qh_setnew(qh, qh->hull_dim);
+#if !qh_COMPUTEfurthest
+  facet->furthestdist= 0.0;
+#endif
+#if qh_MAXoutside
+  if (qh->FORCEoutput && qh->APPROXhull)
+    facet->maxoutside= qh->MINoutside;
+  else
+    facet->maxoutside= qh->DISTround; /* same value as test for QH7082 */
+#endif
+  facet->simplicial= True;
+  facet->good= True;
+  facet->newfacet= True;
+  trace4((qh, qh->ferr, 4055, "qh_newfacet: created facet f%d\n", facet->id));
+  return(facet);
+} /* newfacet */
+
+
+/*---------------------------------
+
+  qh_newridge()
+    return a new ridge
+  notes:
+    caller sets qh.traceridge
+*/
+ridgeT *qh_newridge(qhT *qh) {
+  ridgeT *ridge;
+  void **freelistp;   /* used if !qh_NOmem by qh_memalloc_() */
+
+  qh_memalloc_(qh, (int)sizeof(ridgeT), freelistp, ridge, ridgeT);
+  memset((char *)ridge, (size_t)0, sizeof(ridgeT));
+  zinc_(Ztotridges);
+  if (qh->ridge_id == UINT_MAX) {
+    qh_fprintf(qh, qh->ferr, 7074, "qhull warning: more than 2^32 ridges.  Qhull results are OK.  Since the ridge ID wraps around to 0, two ridges may have the same identifier.\n");
+  }
+  ridge->id= qh->ridge_id++;
+  trace4((qh, qh->ferr, 4056, "qh_newridge: created ridge r%d\n", ridge->id));
+  return(ridge);
+} /* newridge */
+
+
+/*---------------------------------
+
+  qh_pointid(qh, point )
+    return id for a point,
+    returns qh_IDnone(-3) if null, qh_IDinterior(-2) if interior, or qh_IDunknown(-1) if not known
+
+  alternative code if point is in qh.first_point...
+    unsigned long id;
+    id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size;
+
+  notes:
+    Valid points are non-negative
+    WARN64 -- id truncated to 32-bits, at most 2G points
+    NOerrors returned (QhullPoint::id)
+    if point not in point array
+      the code does a comparison of unrelated pointers.
+*/
+int qh_pointid(qhT *qh, pointT *point) {
+  ptr_intT offset, id;
+
+  if (!point || !qh)
+    return qh_IDnone;
+  else if (point == qh->interior_point)
+    return qh_IDinterior;
+  else if (point >= qh->first_point
+  && point < qh->first_point + qh->num_points * qh->hull_dim) {
+    offset= (ptr_intT)(point - qh->first_point);
+    id= offset / qh->hull_dim;
+  }else if ((id= qh_setindex(qh->other_points, point)) != -1)
+    id += qh->num_points;
+  else
+    return qh_IDunknown;
+  return (int)id;
+} /* pointid */
+
+/*---------------------------------
+
+  qh_removefacet(qh, facet )
+    unlinks facet from qh.facet_list,
+
+  returns:
+    updates qh.facet_list .newfacet_list .facet_next visible_list
+    decrements qh.num_facets
+
+  see:
+    qh_appendfacet
+*/
+void qh_removefacet(qhT *qh, facetT *facet) {
+  facetT *next= facet->next, *previous= facet->previous; /* next is always defined */
+
+  if (facet == qh->newfacet_list)
+    qh->newfacet_list= next;
+  if (facet == qh->facet_next)
+    qh->facet_next= next;
+  if (facet == qh->visible_list)
+    qh->visible_list= next;
+  if (previous) {
+    previous->next= next;
+    next->previous= previous;
+  }else {  /* 1st facet in qh->facet_list */
+    qh->facet_list= next;
+    qh->facet_list->previous= NULL;
+  }
+  qh->num_facets--;
+  trace4((qh, qh->ferr, 4057, "qh_removefacet: removed f%d from facet_list, newfacet_list, and visible_list\n", facet->id));
+} /* removefacet */
+
+
+/*---------------------------------
+
+  qh_removevertex(qh, vertex )
+    unlinks vertex from qh.vertex_list,
+
+  returns:
+    updates qh.vertex_list .newvertex_list
+    decrements qh.num_vertices
+*/
+void qh_removevertex(qhT *qh, vertexT *vertex) {
+  vertexT *next= vertex->next, *previous= vertex->previous; /* next is always defined */
+
+  trace4((qh, qh->ferr, 4058, "qh_removevertex: remove v%d from qh.vertex_list\n", vertex->id));
+  if (vertex == qh->newvertex_list)
+    qh->newvertex_list= next;
+  if (previous) {
+    previous->next= next;
+    next->previous= previous;
+  }else {  /* 1st vertex in qh->vertex_list */
+    qh->vertex_list= next;
+    qh->vertex_list->previous= NULL;
+  }
+  qh->num_vertices--;
+} /* removevertex */
+
+
+/*---------------------------------
+
+  qh_update_vertexneighbors(qh )
+    update vertex neighbors and delete interior vertices
+
+  returns:
+    if qh.VERTEXneighbors, 
+      if qh.newvertex_list,
+         removes visible neighbors from vertex neighbors
+      if qh.newfacet_list
+         adds new facets to vertex neighbors
+      if qh.visible_list
+         interior vertices added to qh.del_vertices for later partitioning as coplanar points
+    if not qh.VERTEXneighbors (not merging)
+      interior vertices of visible facets added to qh.del_vertices for later partitioning as coplanar points
+  
+  notes
+    [jan'19] split off qh_update_vertexneighbors_cone.  Optimize the remaining cases in a future release
+    called by qh_triangulate_facet after triangulating a non-simplicial facet, followed by reset_lists
+    called by qh_triangulate after triangulating null and mirror facets
+    called by qh_all_vertexmerges after calling qh_merge_pinchedvertices
+
+  design:
+    if qh.VERTEXneighbors
+      for each vertex on newvertex_list (i.e., new vertices and vertices of new facets)
+        delete visible facets from vertex neighbors
+      for each new facet on newfacet_list
+        for each vertex of facet
+          append facet to vertex neighbors
+      for each visible facet on qh.visible_list
+        for each vertex of facet
+          if the vertex is not on a new facet and not itself deleted
+            if the vertex has a not-visible neighbor (due to merging)
+               remove the visible facet from the vertex's neighbors
+            otherwise
+               add the vertex to qh.del_vertices for later deletion
+
+    if not qh.VERTEXneighbors (not merging)
+      for each vertex of a visible facet
+        if the vertex is not on a new facet and not itself deleted
+           add the vertex to qh.del_vertices for later deletion
+*/
+void qh_update_vertexneighbors(qhT *qh /* qh.newvertex_list, newfacet_list, visible_list */) {
+  facetT *newfacet= NULL, *neighbor, **neighborp, *visible;
+  vertexT *vertex, **vertexp;
+  int neighborcount= 0;
+
+  if (qh->VERTEXneighbors) {
+    trace3((qh, qh->ferr, 3013, "qh_update_vertexneighbors: update v.neighbors for qh.newvertex_list (v%d) and qh.newfacet_list (f%d)\n",
+         getid_(qh->newvertex_list), getid_(qh->newfacet_list)));
+    FORALLvertex_(qh->newvertex_list) {
+      neighborcount= 0;
+      FOREACHneighbor_(vertex) {
+        if (neighbor->visible) {
+          neighborcount++;
+          SETref_(neighbor)= NULL;
+        }
+      }
+      if (neighborcount) {
+        trace4((qh, qh->ferr, 4046, "qh_update_vertexneighbors: delete %d of %d vertex neighbors for v%d.  Removes to-be-deleted, visible facets\n",
+          neighborcount, qh_setsize(qh, vertex->neighbors), vertex->id));
+        qh_setcompact(qh, vertex->neighbors);
+      }
+    }
+    FORALLnew_facets {
+      if (qh->first_newfacet && newfacet->id >= qh->first_newfacet) {
+        FOREACHvertex_(newfacet->vertices)
+          qh_setappend(qh, &vertex->neighbors, newfacet);
+      }else {  /* called after qh_merge_pinchedvertices.  In 7-D, many more neighbors than new facets.  qh_setin is expensive */
+        FOREACHvertex_(newfacet->vertices)
+          qh_setunique(qh, &vertex->neighbors, newfacet); 
+      }
+    }
+    trace3((qh, qh->ferr, 3058, "qh_update_vertexneighbors: delete interior vertices for qh.visible_list (f%d)\n",
+        getid_(qh->visible_list)));
+    FORALLvisible_facets {
+      FOREACHvertex_(visible->vertices) {
+        if (!vertex->newfacet && !vertex->deleted) {
+          FOREACHneighbor_(vertex) { /* this can happen under merging */
+            if (!neighbor->visible)
+              break;
+          }
+          if (neighbor)
+            qh_setdel(vertex->neighbors, visible);
+          else {
+            vertex->deleted= True;
+            qh_setappend(qh, &qh->del_vertices, vertex);
+            trace2((qh, qh->ferr, 2041, "qh_update_vertexneighbors: delete interior vertex p%d(v%d) of visible f%d\n",
+                  qh_pointid(qh, vertex->point), vertex->id, visible->id));
+          }
+        }
+      }
+    }
+  }else {  /* !VERTEXneighbors */
+    trace3((qh, qh->ferr, 3058, "qh_update_vertexneighbors: delete old vertices for qh.visible_list (f%d)\n",
+      getid_(qh->visible_list)));
+    FORALLvisible_facets {
+      FOREACHvertex_(visible->vertices) {
+        if (!vertex->newfacet && !vertex->deleted) {
+          vertex->deleted= True;
+          qh_setappend(qh, &qh->del_vertices, vertex);
+          trace2((qh, qh->ferr, 2042, "qh_update_vertexneighbors: will delete interior vertex p%d(v%d) of visible f%d\n",
+                  qh_pointid(qh, vertex->point), vertex->id, visible->id));
+        }
+      }
+    }
+  }
+} /* update_vertexneighbors */
+
+/*---------------------------------
+
+  qh_update_vertexneighbors_cone(qh )
+    update vertex neighbors for a cone of new facets and delete interior vertices
+
+  returns:
+    if qh.VERTEXneighbors, 
+      if qh.newvertex_list,
+         removes visible neighbors from vertex neighbors
+      if qh.newfacet_list
+         adds new facets to vertex neighbors
+      if qh.visible_list
+         interior vertices added to qh.del_vertices for later partitioning as coplanar points
+    if not qh.VERTEXneighbors (not merging)
+      interior vertices of visible facets added to qh.del_vertices for later partitioning as coplanar points
+  
+  notes
+    called by qh_addpoint after create cone and before premerge
+
+  design:
+    if qh.VERTEXneighbors
+      for each vertex on newvertex_list (i.e., new vertices and vertices of new facets)
+        delete visible facets from vertex neighbors
+      for each new facet on newfacet_list
+        for each vertex of facet
+          append facet to vertex neighbors
+      for each visible facet on qh.visible_list
+        for each vertex of facet
+          if the vertex is not on a new facet and not itself deleted
+            if the vertex has a not-visible neighbor (due to merging)
+               remove the visible facet from the vertex's neighbors
+            otherwise
+               add the vertex to qh.del_vertices for later deletion
+
+    if not qh.VERTEXneighbors (not merging)
+      for each vertex of a visible facet
+        if the vertex is not on a new facet and not itself deleted
+           add the vertex to qh.del_vertices for later deletion
+
+*/
+void qh_update_vertexneighbors_cone(qhT *qh /* qh.newvertex_list, newfacet_list, visible_list */) {
+  facetT *newfacet= NULL, *neighbor, **neighborp, *visible;
+  vertexT *vertex, **vertexp;
+  int delcount= 0;
+
+  if (qh->VERTEXneighbors) {
+    trace3((qh, qh->ferr, 3059, "qh_update_vertexneighbors_cone: update v.neighbors for qh.newvertex_list (v%d) and qh.newfacet_list (f%d)\n",
+         getid_(qh->newvertex_list), getid_(qh->newfacet_list)));
+    FORALLvertex_(qh->newvertex_list) {
+      delcount= 0;
+      FOREACHneighbor_(vertex) {
+        if (neighbor->visible) { /* alternative design is a loop over visible facets, but needs qh_setdel() */
+          delcount++;
+          qh_setdelnth(qh, vertex->neighbors, SETindex_(vertex->neighbors, neighbor));
+          neighborp--; /* repeat */
+        }
+      }
+      if (delcount) {
+        trace4((qh, qh->ferr, 4021, "qh_update_vertexneighbors_cone: deleted %d visible vertexneighbors of v%d\n",
+          delcount, vertex->id));
+      }
+    }
+    FORALLnew_facets {
+      FOREACHvertex_(newfacet->vertices)
+        qh_setappend(qh, &vertex->neighbors, newfacet);
+    }
+    trace3((qh, qh->ferr, 3065, "qh_update_vertexneighbors_cone: delete interior vertices, if any, for qh.visible_list (f%d)\n",
+        getid_(qh->visible_list)));
+    FORALLvisible_facets {
+      FOREACHvertex_(visible->vertices) {
+        if (!vertex->newfacet && !vertex->deleted) {
+          FOREACHneighbor_(vertex) { /* this can happen under merging, qh_checkfacet QH4025 */
+            if (!neighbor->visible)
+              break;
+          }
+          if (neighbor)
+            qh_setdel(vertex->neighbors, visible);
+          else {
+            vertex->deleted= True;
+            qh_setappend(qh, &qh->del_vertices, vertex);
+            trace2((qh, qh->ferr, 2102, "qh_update_vertexneighbors_cone: will delete interior vertex p%d(v%d) of visible f%d\n",
+              qh_pointid(qh, vertex->point), vertex->id, visible->id));
+          }
+        }
+      }
+    }
+  }else {  /* !VERTEXneighbors */
+    trace3((qh, qh->ferr, 3066, "qh_update_vertexneighbors_cone: delete interior vertices for qh.visible_list (f%d)\n",
+      getid_(qh->visible_list)));
+    FORALLvisible_facets {
+      FOREACHvertex_(visible->vertices) {
+        if (!vertex->newfacet && !vertex->deleted) {
+          vertex->deleted= True;
+          qh_setappend(qh, &qh->del_vertices, vertex);
+          trace2((qh, qh->ferr, 2059, "qh_update_vertexneighbors_cone: will delete interior vertex p%d(v%d) of visible f%d\n",
+                  qh_pointid(qh, vertex->point), vertex->id, visible->id));
+        }
+      }
+    }
+  }
+} /* update_vertexneighbors_cone */
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/poly_r.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/poly_r.h
new file mode 100644
index 00000000000..83c59140de7
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/poly_r.h
@@ -0,0 +1,310 @@
+/*
  ---------------------------------
+
+   poly_r.h
+   header file for poly_r.c and poly2_r.c
+
+   see qh-poly_r.htm, libqhull_r.h and poly_r.c
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/poly_r.h#5 $$Change: 2963 $
+   $DateTime: 2020/06/03 19:31:01 $$Author: bbarber $
+*/
+
+#ifndef qhDEFpoly
+#define qhDEFpoly 1
+
+#include "libqhull_r.h"
+
+/*===============   constants ========================== */
+
+/*----------------------------------
+
+  qh_ALGORITHMfault
+    use as argument to checkconvex() to report errors during buildhull
+*/
+#define qh_ALGORITHMfault 0
+
+/*----------------------------------
+
+  qh_DATAfault
+    use as argument to checkconvex() to report errors during initialhull
+*/
+#define qh_DATAfault 1
+
+/*----------------------------------
+
+  qh_DUPLICATEridge
+    special value for facet->neighbor to indicate a duplicate ridge
+
+  notes:
+    set by qh_matchneighbor for qh_matchdupridge
+*/
+#define qh_DUPLICATEridge (facetT *)1L
+
+/*----------------------------------
+
+  qh_MERGEridge       flag in facet
+    special value for facet->neighbor to indicate a duplicate ridge that needs merging
+
+  notes:
+    set by qh_matchnewfacets..qh_matchdupridge from qh_DUPLICATEridge
+    used by qh_mark_dupridges to set facet->mergeridge, facet->mergeridge2 from facet->dupridge
+*/
+#define qh_MERGEridge (facetT *)2L
+
+
+/*============ -structures- ====================*/
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+
+  FORALLfacet_( facetlist ) { ... }
+    assign 'facet' to each facet in facetlist
+
+  notes:
+    uses 'facetT *facet;'
+    assumes last facet is a sentinel
+
+  see:
+    FORALLfacets
+*/
+#define FORALLfacet_( facetlist ) if (facetlist) for ( facet=(facetlist); facet && facet->next; facet= facet->next )
+
+/*----------------------------------
+
+  FORALLnew_facets { ... }
+    assign 'newfacet' to each facet in qh.newfacet_list
+
+  notes:
+    uses 'facetT *newfacet;'
+    at exit, newfacet==NULL
+*/
+#define FORALLnew_facets for ( newfacet=qh->newfacet_list; newfacet && newfacet->next; newfacet=newfacet->next )
+
+/*----------------------------------
+
+  FORALLvertex_( vertexlist ) { ... }
+    assign 'vertex' to each vertex in vertexlist
+
+  notes:
+    uses 'vertexT *vertex;'
+    at exit, vertex==NULL
+*/
+#define FORALLvertex_( vertexlist ) for (vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next )
+
+/*----------------------------------
+
+  FORALLvisible_facets { ... }
+    assign 'visible' to each visible facet in qh.visible_list
+
+  notes:
+    uses 'vacetT *visible;'
+    at exit, visible==NULL
+*/
+#define FORALLvisible_facets for (visible=qh->visible_list; visible && visible->visible; visible= visible->next)
+
+/*----------------------------------
+
+  FORALLsame_( newfacet ) { ... }
+    assign 'same' to each facet in newfacet->f.samecycle
+
+  notes:
+    uses 'facetT *same;'
+    stops when it returns to newfacet
+*/
+#define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle)
+
+/*----------------------------------
+
+  FORALLsame_cycle_( newfacet ) { ... }
+    assign 'same' to each facet in newfacet->f.samecycle
+
+  notes:
+    uses 'facetT *same;'
+    at exit, same == NULL
+*/
+#define FORALLsame_cycle_(newfacet) \
+     for (same= newfacet->f.samecycle; \
+         same; same= (same == newfacet ?  NULL : same->f.samecycle))
+
+/*----------------------------------
+
+  FOREACHneighborA_( facet ) { ... }
+    assign 'neighborA' to each neighbor in facet->neighbors
+
+  FOREACHneighborA_( vertex ) { ... }
+    assign 'neighborA' to each neighbor in vertex->neighbors
+
+  declare:
+    facetT *neighborA, **neighborAp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHneighborA_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighborA)
+
+/*----------------------------------
+
+  FOREACHvisible_( facets ) { ... }
+    assign 'visible' to each facet in facets
+
+  notes:
+    uses 'facetT *facet, *facetp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)
+
+/*----------------------------------
+
+  FOREACHnewfacet_( facets ) { ... }
+    assign 'newfacet' to each facet in facets
+
+  notes:
+    uses 'facetT *newfacet, *newfacetp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)
+
+/*----------------------------------
+
+  FOREACHvertexA_( vertices ) { ... }
+    assign 'vertexA' to each vertex in vertices
+
+  notes:
+    uses 'vertexT *vertexA, *vertexAp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)
+
+/*----------------------------------
+
+  FOREACHvertexreverse12_( vertices ) { ... }
+    assign 'vertex' to each vertex in vertices
+    reverse order of first two vertices
+
+  notes:
+    uses 'vertexT *vertex, *vertexp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)
+
+
+/*=============== prototypes poly_r.c in alphabetical order ================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void    qh_appendfacet(qhT *qh, facetT *facet);
+void    qh_appendvertex(qhT *qh, vertexT *vertex);
+void    qh_attachnewfacets(qhT *qh /* qh.visible_list, qh.newfacet_list */);
+boolT   qh_checkflipped(qhT *qh, facetT *facet, realT *dist, boolT allerror);
+void    qh_delfacet(qhT *qh, facetT *facet);
+void    qh_deletevisible(qhT *qh /* qh.visible_list, qh.horizon_list */);
+setT   *qh_facetintersect(qhT *qh, facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra);
+int     qh_gethash(qhT *qh, int hashsize, setT *set, int size, int firstindex, void *skipelem);
+facetT *qh_getreplacement(qhT *qh, facetT *visible);
+facetT *qh_makenewfacet(qhT *qh, setT *vertices, boolT toporient, facetT *facet);
+void    qh_makenewplanes(qhT *qh /* qh.newfacet_list */);
+facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew);
+facetT *qh_makenew_simplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew);
+void    qh_matchneighbor(qhT *qh, facetT *newfacet, int newskip, int hashsize,
+                          int *hashcount);
+coordT  qh_matchnewfacets(qhT *qh);
+boolT   qh_matchvertices(qhT *qh, int firstindex, setT *verticesA, int skipA,
+                          setT *verticesB, int *skipB, boolT *same);
+facetT *qh_newfacet(qhT *qh);
+ridgeT *qh_newridge(qhT *qh);
+int     qh_pointid(qhT *qh, pointT *point);
+void    qh_removefacet(qhT *qh, facetT *facet);
+void    qh_removevertex(qhT *qh, vertexT *vertex);
+void    qh_update_vertexneighbors(qhT *qh);
+void    qh_update_vertexneighbors_cone(qhT *qh);
+
+
+/*========== -prototypes poly2_r.c in alphabetical order ===========*/
+
+boolT   qh_addfacetvertex(qhT *qh, facetT *facet, vertexT *newvertex);
+void    qh_addhash(void *newelem, setT *hashtable, int hashsize, int hash);
+void    qh_check_bestdist(qhT *qh);
+void    qh_check_maxout(qhT *qh);
+void    qh_check_output(qhT *qh);
+void    qh_check_point(qhT *qh, pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2, int *errcount);
+void    qh_check_points(qhT *qh);
+void    qh_checkconvex(qhT *qh, facetT *facetlist, int fault);
+void    qh_checkfacet(qhT *qh, facetT *facet, boolT newmerge, boolT *waserrorp);
+void    qh_checkflipped_all(qhT *qh, facetT *facetlist);
+boolT   qh_checklists(qhT *qh, facetT *facetlist);
+void    qh_checkpolygon(qhT *qh, facetT *facetlist);
+void    qh_checkvertex(qhT *qh, vertexT *vertex, boolT allchecks, boolT *waserrorp);
+void    qh_clearcenters(qhT *qh, qh_CENTER type);
+void    qh_createsimplex(qhT *qh, setT *vertices);
+void    qh_delridge(qhT *qh, ridgeT *ridge);
+void    qh_delvertex(qhT *qh, vertexT *vertex);
+setT   *qh_facet3vertex(qhT *qh, facetT *facet);
+facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside);
+facetT *qh_findbestlower(qhT *qh, facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart);
+facetT *qh_findfacet_all(qhT *qh, pointT *point, boolT noupper, realT *bestdist, boolT *isoutside,
+                          int *numpart);
+int     qh_findgood(qhT *qh, facetT *facetlist, int goodhorizon);
+void    qh_findgood_all(qhT *qh, facetT *facetlist);
+void    qh_furthestnext(qhT *qh /* qh.facet_list */);
+void    qh_furthestout(qhT *qh, facetT *facet);
+void    qh_infiniteloop(qhT *qh, facetT *facet);
+void    qh_initbuild(qhT *qh);
+void    qh_initialhull(qhT *qh, setT *vertices);
+setT   *qh_initialvertices(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints);
+vertexT *qh_isvertex(pointT *point, setT *vertices);
+vertexT *qh_makenewfacets(qhT *qh, pointT *point /* qh.horizon_list, visible_list */);
+coordT  qh_matchdupridge(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount);
+void    qh_nearcoplanar(qhT *qh /* qh.facet_list */);
+vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp);
+int     qh_newhashtable(qhT *qh, int newsize);
+vertexT *qh_newvertex(qhT *qh, pointT *point);
+facetT *qh_nextfacet2d(facetT *facet, vertexT **nextvertexp);
+ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp);
+vertexT *qh_opposite_vertex(qhT *qh, facetT *facetA,  facetT *neighbor);
+void    qh_outcoplanar(qhT *qh /* qh.facet_list */);
+pointT *qh_point(qhT *qh, int id);
+void    qh_point_add(qhT *qh, setT *set, pointT *point, void *elem);
+setT   *qh_pointfacet(qhT *qh /* qh.facet_list */);
+setT   *qh_pointvertex(qhT *qh /* qh.facet_list */);
+void    qh_prependfacet(qhT *qh, facetT *facet, facetT **facetlist);
+void    qh_printhashtable(qhT *qh, FILE *fp);
+void    qh_printlists(qhT *qh);
+void    qh_replacefacetvertex(qhT *qh, facetT *facet, vertexT *oldvertex, vertexT *newvertex);
+void    qh_resetlists(qhT *qh, boolT stats, boolT resetVisible /* qh.newvertex_list qh.newfacet_list qh.visible_list */);
+void    qh_setvoronoi_all(qhT *qh);
+void    qh_triangulate(qhT *qh /* qh.facet_list */);
+void    qh_triangulate_facet(qhT *qh, facetT *facetA, vertexT **first_vertex);
+void    qh_triangulate_link(qhT *qh, facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB);
+void    qh_triangulate_mirror(qhT *qh, facetT *facetA, facetT *facetB);
+void    qh_triangulate_null(qhT *qh, facetT *facetA);
+void    qh_vertexintersect(qhT *qh, setT **vertexsetA,setT *vertexsetB);
+setT   *qh_vertexintersect_new(qhT *qh, setT *vertexsetA,setT *vertexsetB);
+void    qh_vertexneighbors(qhT *qh /* qh.facet_list */);
+boolT   qh_vertexsubset(setT *vertexsetA, setT *vertexsetB);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* qhDEFpoly */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/qhull_ra.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/qhull_ra.h
new file mode 100644
index 00000000000..52ccd85a02a
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/qhull_ra.h
@@ -0,0 +1,161 @@
+/*
  ---------------------------------
+
+   qhull_ra.h
+   all header files for compiling qhull with reentrant code
+   included before C++ headers for user_r.h:QHULL_CRTDBG
+
+   see qh-qhull.htm
+
+   see libqhull_r.h for user-level definitions
+
+   see user_r.h for user-definable constants
+
+   defines internal functions for libqhull_r.c global_r.c
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/qhull_ra.h#2 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+
+   Notes:  grep for ((" and (" to catch fprintf("lkasdjf");
+           full parens around (x?y:z)
+           use '#include "libqhull_r/qhull_ra.h"' to avoid name clashes
+*/
+
+#ifndef qhDEFqhulla
+#define qhDEFqhulla 1
+
+#include "libqhull_r.h"  /* Includes user_r.h and data types */
+
+#include "stat_r.h"
+#include "random_r.h"
+#include "mem_r.h"
+#include "qset_r.h"
+#include "geom_r.h"
+#include "merge_r.h"
+#include "poly_r.h"
+#include "io_r.h"
+
+#include 
+#include 
+#include 
+#include     /* some compilers will not need float.h */
+#include 
+#include 
+#include 
+#include 
+#include 
+/*** uncomment here and qset_r.c
+     if string.h does not define memcpy()
+#include 
+*/
+
+#if qh_CLOCKtype == 2  /* defined in user_r.h from libqhull_r.h */
+#include 
+#include 
+#include 
+#endif
+
+#ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
+#pragma warning( disable : 4100)  /* unreferenced formal parameter */
+#pragma warning( disable : 4127)  /* conditional expression is constant */
+#pragma warning( disable : 4706)  /* assignment within conditional function */
+#pragma warning( disable : 4996)  /* function was declared deprecated(strcpy, localtime, etc.) */
+#endif
+
+/* ======= -macros- =========== */
+
+/*----------------------------------
+
+  traceN((qh, qh->ferr, 0Nnnn, "format\n", vars));
+    calls qh_fprintf if qh.IStracing >= N
+
+    Add debugging traps to the end of qh_fprintf
+
+  notes:
+    removing tracing reduces code size but doesn't change execution speed
+*/
+#ifndef qh_NOtrace
+#define trace0(args) {if (qh->IStracing) qh_fprintf args;}
+#define trace1(args) {if (qh->IStracing >= 1) qh_fprintf args;}
+#define trace2(args) {if (qh->IStracing >= 2) qh_fprintf args;}
+#define trace3(args) {if (qh->IStracing >= 3) qh_fprintf args;}
+#define trace4(args) {if (qh->IStracing >= 4) qh_fprintf args;}
+#define trace5(args) {if (qh->IStracing >= 5) qh_fprintf args;}
+#else /* qh_NOtrace */
+#define trace0(args) {}
+#define trace1(args) {}
+#define trace2(args) {}
+#define trace3(args) {}
+#define trace4(args) {}
+#define trace5(args) {}
+#endif /* qh_NOtrace */
+
+/*----------------------------------
+
+  Define an unused variable to avoid compiler warnings
+
+  Derived from Qt's corelib/global/qglobal.h
+
+*/
+
+#if defined(__cplusplus) && defined(__INTEL_COMPILER) && !defined(QHULL_OS_WIN)
+template 
+inline void qhullUnused(T &x) { (void)x; }
+#  define QHULL_UNUSED(x) qhullUnused(x);
+#else
+#  define QHULL_UNUSED(x) (void)x;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***** -libqhull_r.c prototypes (alphabetical after qhull) ********************/
+
+void    qh_qhull(qhT *qh);
+boolT   qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist);
+void    qh_build_withrestart(qhT *qh);
+vertexT *qh_buildcone(qhT *qh, pointT *furthest, facetT *facet, int goodhorizon, facetT **retryfacet);
+boolT   qh_buildcone_mergepinched(qhT *qh, vertexT *apex, facetT *facet, facetT **retryfacet);
+boolT   qh_buildcone_onlygood(qhT *qh, vertexT *apex, int goodhorizon);
+void    qh_buildhull(qhT *qh);
+void    qh_buildtracing(qhT *qh, pointT *furthest, facetT *facet);
+void    qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet);
+void    qh_findhorizon(qhT *qh, pointT *point, facetT *facet, int *goodvisible,int *goodhorizon);
+pointT *qh_nextfurthest(qhT *qh, facetT **visible);
+void    qh_partitionall(qhT *qh, setT *vertices, pointT *points,int npoints);
+void    qh_partitioncoplanar(qhT *qh, pointT *point, facetT *facet, realT *dist, boolT allnew);
+void    qh_partitionpoint(qhT *qh, pointT *point, facetT *facet);
+void    qh_partitionvisible(qhT *qh, boolT allpoints, int *numpoints);
+void    qh_joggle_restart(qhT *qh, const char *reason);
+void    qh_printsummary(qhT *qh, FILE *fp);
+
+/***** -global_r.c internal prototypes (alphabetical) ***********************/
+
+void    qh_appendprint(qhT *qh, qh_PRINT format);
+void    qh_freebuild(qhT *qh, boolT allmem);
+void    qh_freebuffers(qhT *qh);
+void    qh_initbuffers(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
+
+/***** -stat_r.c internal prototypes (alphabetical) ***********************/
+
+void    qh_allstatA(qhT *qh);
+void    qh_allstatB(qhT *qh);
+void    qh_allstatC(qhT *qh);
+void    qh_allstatD(qhT *qh);
+void    qh_allstatE(qhT *qh);
+void    qh_allstatE2(qhT *qh);
+void    qh_allstatF(qhT *qh);
+void    qh_allstatG(qhT *qh);
+void    qh_allstatH(qhT *qh);
+void    qh_freebuffers(qhT *qh);
+void    qh_initbuffers(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* qhDEFqhulla */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/qset_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/qset_r.c
new file mode 100644
index 00000000000..50cdb215c09
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/qset_r.c
@@ -0,0 +1,1383 @@
+/*
  ---------------------------------
+
+   qset_r.c
+   implements set manipulations needed for quickhull
+
+   see qh-set_r.htm and qset_r.h
+
+   Be careful of strict aliasing (two pointers of different types
+   that reference the same location).  The last slot of a set is
+   either the actual size of the set plus 1, or the NULL terminator
+   of the set (i.e., setelemT).
+
+   Only reference qh for qhmem or qhstat.  Otherwise the matching code in qset.c will bring in qhT
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/qset_r.c#8 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+*/
+
+#include "libqhull_r.h" /* for qhT and QHULL_CRTDBG */
+#include "qset_r.h"
+#include "mem_r.h"
+#include 
+#include 
+/*** uncomment here and qhull_ra.h
+     if string.h does not define memcpy()
+#include 
+*/
+
+#ifndef qhDEFlibqhull
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+void    qh_errexit(qhT *qh, int exitcode, facetT *, ridgeT *);
+void    qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
+#  ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
+#  pragma warning( disable : 4127)  /* conditional expression is constant */
+#  pragma warning( disable : 4706)  /* assignment within conditional function */
+#  endif
+#endif
+
+/*=============== internal macros ===========================*/
+
+/*============ functions in alphabetical order ===================*/
+
+/*----------------------------------
+
+  qh_setaddnth(qh, setp, nth, newelem )
+    adds newelem as n'th element of sorted or unsorted *setp
+
+  notes:
+    *setp and newelem must be defined
+    *setp may be a temp set
+    nth=0 is first element
+    errors if nth is out of bounds
+
+  design:
+    expand *setp if empty or full
+    move tail of *setp up one
+    insert newelem
+*/
+void qh_setaddnth(qhT *qh, setT **setp, int nth, void *newelem) {
+  int oldsize, i;
+  setelemT *sizep;          /* avoid strict aliasing */
+  setelemT *oldp, *newp;
+
+  if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
+    qh_setlarger(qh, setp);
+    sizep= SETsizeaddr_(*setp);
+  }
+  oldsize= sizep->i - 1;
+  if (nth < 0 || nth > oldsize) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint(qh, qh->qhmem.ferr, "", *setp);
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  sizep->i++;
+  oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void);   /* NULL */
+  newp= oldp+1;
+  for (i=oldsize-nth+1; i--; )  /* move at least NULL  */
+    (newp--)->p= (oldp--)->p;       /* may overwrite *sizep */
+  newp->p= newelem;
+} /* setaddnth */
+
+
+/*----------------------------------
+
+  setaddsorted( setp, newelem )
+    adds an newelem into sorted *setp
+
+  notes:
+    *setp and newelem must be defined
+    *setp may be a temp set
+    nop if newelem already in set
+
+  design:
+    find newelem's position in *setp
+    insert newelem
+*/
+void qh_setaddsorted(qhT *qh, setT **setp, void *newelem) {
+  int newindex=0;
+  void *elem, **elemp;
+
+  FOREACHelem_(*setp) {          /* could use binary search instead */
+    if (elem < newelem)
+      newindex++;
+    else if (elem == newelem)
+      return;
+    else
+      break;
+  }
+  qh_setaddnth(qh, setp, newindex, newelem);
+} /* setaddsorted */
+
+
+/*---------------------------------
+
+  qh_setappend(qh, setp, newelem )
+    append newelem to *setp
+
+  notes:
+    *setp may be a temp set
+    *setp and newelem may be NULL
+
+  design:
+    expand *setp if empty or full
+    append newelem to *setp
+
+*/
+void qh_setappend(qhT *qh, setT **setp, void *newelem) {
+  setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
+  setelemT *endp;
+  int count;
+
+  if (!newelem)
+    return;
+  if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
+    qh_setlarger(qh, setp);
+    sizep= SETsizeaddr_(*setp);
+  }
+  count= (sizep->i)++ - 1;
+  endp= (setelemT *)SETelemaddr_(*setp, count, void);
+  (endp++)->p= newelem;
+  endp->p= NULL;
+} /* setappend */
+
+/*---------------------------------
+
+  qh_setappend_set(qh, setp, setA )
+    appends setA to *setp
+
+  notes:
+    *setp can not be a temp set
+    *setp and setA may be NULL
+
+  design:
+    setup for copy
+    expand *setp if it is too small
+    append all elements of setA to *setp
+*/
+void qh_setappend_set(qhT *qh, setT **setp, setT *setA) {
+  int sizeA, size;
+  setT *oldset;
+  setelemT *sizep;
+
+  if (!setA)
+    return;
+  SETreturnsize_(setA, sizeA);
+  if (!*setp)
+    *setp= qh_setnew(qh, sizeA);
+  sizep= SETsizeaddr_(*setp);
+  if (!(size= sizep->i))
+    size= (*setp)->maxsize;
+  else
+    size--;
+  if (size + sizeA > (*setp)->maxsize) {
+    oldset= *setp;
+    *setp= qh_setcopy(qh, oldset, sizeA);
+    qh_setfree(qh, &oldset);
+    sizep= SETsizeaddr_(*setp);
+  }
+  if (sizeA > 0) {
+    sizep->i= size+sizeA+1;   /* memcpy may overwrite */
+    memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize);
+  }
+} /* setappend_set */
+
+
+/*---------------------------------
+
+  qh_setappend2ndlast(qh, setp, newelem )
+    makes newelem the next to the last element in *setp
+
+  notes:
+    *setp must have at least one element
+    newelem must be defined
+    *setp may be a temp set
+
+  design:
+    expand *setp if empty or full
+    move last element of *setp up one
+    insert newelem
+*/
+void qh_setappend2ndlast(qhT *qh, setT **setp, void *newelem) {
+    setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
+    setelemT *endp, *lastp;
+    int count;
+
+    if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
+        qh_setlarger(qh, setp);
+        sizep= SETsizeaddr_(*setp);
+    }
+    count= (sizep->i)++ - 1;
+    endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */
+    lastp= endp-1;
+    *(endp++)= *lastp;
+    endp->p= NULL;    /* may overwrite *sizep */
+    lastp->p= newelem;
+} /* setappend2ndlast */
+
+/*---------------------------------
+
+  qh_setcheck(qh, set, typename, id )
+    check set for validity
+    report errors with typename and id
+
+  design:
+    checks that maxsize, actual size, and NULL terminator agree
+*/
+void qh_setcheck(qhT *qh, setT *set, const char *tname, unsigned int id) {
+  int maxsize, size;
+  int waserr= 0;
+
+  if (!set)
+    return;
+  SETreturnsize_(set, size);
+  maxsize= set->maxsize;
+  if (size > maxsize || !maxsize) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",
+             size, tname, id, maxsize);
+    waserr= 1;
+  }else if (set->e[size].p) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n",
+             tname, id, size-1, maxsize);
+    waserr= 1;
+  }
+  if (waserr) {
+    qh_setprint(qh, qh->qhmem.ferr, "ERRONEOUS", set);
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+} /* setcheck */
+
+
+/*---------------------------------
+
+  qh_setcompact(qh, set )
+    remove internal NULLs from an unsorted set
+
+  returns:
+    updated set
+
+  notes:
+    set may be NULL
+    it would be faster to swap tail of set into holes, like qh_setdel
+
+  design:
+    setup pointers into set
+    skip NULLs while copying elements to start of set
+    update the actual size
+*/
+void qh_setcompact(qhT *qh, setT *set) {
+  int size;
+  void **destp, **elemp, **endp, **firstp;
+
+  if (!set)
+    return;
+  SETreturnsize_(set, size);
+  destp= elemp= firstp= SETaddr_(set, void);
+  endp= destp + size;
+  while (1) {
+    if (!(*destp++= *elemp++)) {
+      destp--;
+      if (elemp > endp)
+        break;
+    }
+  }
+  qh_settruncate(qh, set, (int)(destp-firstp));   /* WARN64 */
+} /* setcompact */
+
+
+/*---------------------------------
+
+  qh_setcopy(qh, set, extra )
+    make a copy of a sorted or unsorted set with extra slots
+
+  returns:
+    new set
+
+  design:
+    create a newset with extra slots
+    copy the elements to the newset
+
+*/
+setT *qh_setcopy(qhT *qh, setT *set, int extra) {
+  setT *newset;
+  int size;
+
+  if (extra < 0)
+    extra= 0;
+  SETreturnsize_(set, size);
+  newset= qh_setnew(qh, size+extra);
+  SETsizeaddr_(newset)->i= size+1;    /* memcpy may overwrite */
+  memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize);
+  return(newset);
+} /* setcopy */
+
+
+/*---------------------------------
+
+  qh_setdel(set, oldelem )
+    delete oldelem from an unsorted set
+
+  returns:
+    returns oldelem if found
+    returns NULL otherwise
+
+  notes:
+    set may be NULL
+    oldelem must not be NULL;
+    only deletes one copy of oldelem in set
+
+  design:
+    locate oldelem
+    update actual size if it was full
+    move the last element to the oldelem's location
+*/
+void *qh_setdel(setT *set, void *oldelem) {
+  setelemT *sizep;
+  setelemT *elemp;
+  setelemT *lastp;
+
+  if (!set)
+    return NULL;
+  elemp= (setelemT *)SETaddr_(set, void);
+  while (elemp->p != oldelem && elemp->p)
+    elemp++;
+  if (elemp->p) {
+    sizep= SETsizeaddr_(set);
+    if (!(sizep->i)--)         /*  if was a full set */
+      sizep->i= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
+    lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
+    elemp->p= lastp->p;      /* may overwrite itself */
+    lastp->p= NULL;
+    return oldelem;
+  }
+  return NULL;
+} /* setdel */
+
+
+/*---------------------------------
+
+  qh_setdellast( set )
+    return last element of set or NULL
+
+  notes:
+    deletes element from set
+    set may be NULL
+
+  design:
+    return NULL if empty
+    if full set
+      delete last element and set actual size
+    else
+      delete last element and update actual size
+*/
+void *qh_setdellast(setT *set) {
+  int setsize;  /* actually, actual_size + 1 */
+  int maxsize;
+  setelemT *sizep;
+  void *returnvalue;
+
+  if (!set || !(set->e[0].p))
+    return NULL;
+  sizep= SETsizeaddr_(set);
+  if ((setsize= sizep->i)) {
+    returnvalue= set->e[setsize - 2].p;
+    set->e[setsize - 2].p= NULL;
+    sizep->i--;
+  }else {
+    maxsize= set->maxsize;
+    returnvalue= set->e[maxsize - 1].p;
+    set->e[maxsize - 1].p= NULL;
+    sizep->i= maxsize;
+  }
+  return returnvalue;
+} /* setdellast */
+
+
+/*---------------------------------
+
+  qh_setdelnth(qh, set, nth )
+    deletes nth element from unsorted set
+    0 is first element
+
+  returns:
+    returns the element (needs type conversion)
+
+  notes:
+    errors if nth invalid
+
+  design:
+    setup points and check nth
+    delete nth element and overwrite with last element
+*/
+void *qh_setdelnth(qhT *qh, setT *set, int nth) {
+  void *elem;
+  setelemT *sizep;
+  setelemT *elemp, *lastp;
+
+  sizep= SETsizeaddr_(set);
+  if ((sizep->i--)==0)         /*  if was a full set */
+    sizep->i= set->maxsize;    /*    *sizep= (maxsize-1)+ 1 */
+  if (nth < 0 || nth >= sizep->i) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint(qh, qh->qhmem.ferr, "", set);
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  elemp= (setelemT *)SETelemaddr_(set, nth, void); /* nth valid by QH6174 */
+  lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
+  elem= elemp->p;
+  elemp->p= lastp->p;      /* may overwrite itself */
+  lastp->p= NULL;
+  return elem;
+} /* setdelnth */
+
+/*---------------------------------
+
+  qh_setdelnthsorted(qh, set, nth )
+    deletes nth element from sorted set
+
+  returns:
+    returns the element (use type conversion)
+
+  notes:
+    errors if nth invalid
+
+  see also:
+    setnew_delnthsorted
+
+  design:
+    setup points and check nth
+    copy remaining elements down one
+    update actual size
+*/
+void *qh_setdelnthsorted(qhT *qh, setT *set, int nth) {
+  void *elem;
+  setelemT *sizep;
+  setelemT *newp, *oldp;
+
+  sizep= SETsizeaddr_(set);
+  if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint(qh, qh->qhmem.ferr, "", set);
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  newp= (setelemT *)SETelemaddr_(set, nth, void);
+  elem= newp->p;
+  oldp= newp+1;
+  while (((newp++)->p= (oldp++)->p))
+    ; /* copy remaining elements and NULL */
+  if ((sizep->i--)==0)         /*  if was a full set */
+    sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
+  return elem;
+} /* setdelnthsorted */
+
+
+/*---------------------------------
+
+  qh_setdelsorted( set, oldelem )
+    deletes oldelem from sorted set
+
+  returns:
+    returns oldelem if it was deleted
+
+  notes:
+    set may be NULL
+
+  design:
+    locate oldelem in set
+    copy remaining elements down one
+    update actual size
+*/
+void *qh_setdelsorted(setT *set, void *oldelem) {
+  setelemT *sizep;
+  setelemT *newp, *oldp;
+
+  if (!set)
+    return NULL;
+  newp= (setelemT *)SETaddr_(set, void);
+  while(newp->p != oldelem && newp->p)
+    newp++;
+  if (newp->p) {
+    oldp= newp+1;
+    while (((newp++)->p= (oldp++)->p))
+      ; /* copy remaining elements */
+    sizep= SETsizeaddr_(set);
+    if ((sizep->i--)==0)    /*  if was a full set */
+      sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
+    return oldelem;
+  }
+  return NULL;
+} /* setdelsorted */
+
+
+/*---------------------------------
+
+  qh_setduplicate(qh, set, elemsize )
+    duplicate a set of elemsize elements
+
+  notes:
+    use setcopy if retaining old elements
+
+  design:
+    create a new set
+    for each elem of the old set
+      create a newelem
+      append newelem to newset
+*/
+setT *qh_setduplicate(qhT *qh, setT *set, int elemsize) {
+  void          *elem, **elemp, *newElem;
+  setT          *newSet;
+  int           size;
+
+  if (!(size= qh_setsize(qh, set)))
+    return NULL;
+  newSet= qh_setnew(qh, size);
+  FOREACHelem_(set) {
+    newElem= qh_memalloc(qh, elemsize);
+    memcpy(newElem, elem, (size_t)elemsize);
+    qh_setappend(qh, &newSet, newElem);
+  }
+  return newSet;
+} /* setduplicate */
+
+
+/*---------------------------------
+
+  qh_setendpointer( set )
+    Returns pointer to NULL terminator of a set's elements
+    set can not be NULL
+
+*/
+void **qh_setendpointer(setT *set) {
+
+  setelemT *sizep= SETsizeaddr_(set);
+  int n= sizep->i;
+  return (n ? &set->e[n-1].p : &sizep->p);
+} /* qh_setendpointer */
+
+/*---------------------------------
+
+  qh_setequal( setA, setB )
+    returns 1 if two sorted sets are equal, otherwise returns 0
+
+  notes:
+    either set may be NULL
+
+  design:
+    check size of each set
+    setup pointers
+    compare elements of each set
+*/
+int qh_setequal(setT *setA, setT *setB) {
+  void **elemAp, **elemBp;
+  int sizeA= 0, sizeB= 0;
+
+  if (setA) {
+    SETreturnsize_(setA, sizeA);
+  }
+  if (setB) {
+    SETreturnsize_(setB, sizeB);
+  }
+  if (sizeA != sizeB)
+    return 0;
+  if (!sizeA)
+    return 1;
+  elemAp= SETaddr_(setA, void);
+  elemBp= SETaddr_(setB, void);
+  if (!memcmp((char *)elemAp, (char *)elemBp, (size_t)(sizeA * SETelemsize)))
+    return 1;
+  return 0;
+} /* setequal */
+
+
+/*---------------------------------
+
+  qh_setequal_except( setA, skipelemA, setB, skipelemB )
+    returns 1 if sorted setA and setB are equal except for skipelemA & B
+
+  returns:
+    false if either skipelemA or skipelemB are missing
+
+  notes:
+    neither set may be NULL
+
+    if skipelemB is NULL,
+      can skip any one element of setB
+
+  design:
+    setup pointers
+    search for skipelemA, skipelemB, and mismatches
+    check results
+*/
+int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
+  void **elemA, **elemB;
+  int skip=0;
+
+  elemA= SETaddr_(setA, void);
+  elemB= SETaddr_(setB, void);
+  while (1) {
+    if (*elemA == skipelemA) {
+      skip++;
+      elemA++;
+    }
+    if (skipelemB) {
+      if (*elemB == skipelemB) {
+        skip++;
+        elemB++;
+      }
+    }else if (*elemA != *elemB) {
+      skip++;
+      if (!(skipelemB= *elemB++))
+        return 0;
+    }
+    if (!*elemA)
+      break;
+    if (*elemA++ != *elemB++)
+      return 0;
+  }
+  if (skip != 2 || *elemB)
+    return 0;
+  return 1;
+} /* setequal_except */
+
+
+/*---------------------------------
+
+  qh_setequal_skip( setA, skipA, setB, skipB )
+    returns 1 if sorted setA and setB are equal except for elements skipA & B
+
+  returns:
+    false if different size
+
+  notes:
+    neither set may be NULL
+
+  design:
+    setup pointers
+    search for mismatches while skipping skipA and skipB
+*/
+int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) {
+  void **elemA, **elemB, **skipAp, **skipBp;
+
+  elemA= SETaddr_(setA, void);
+  elemB= SETaddr_(setB, void);
+  skipAp= SETelemaddr_(setA, skipA, void);
+  skipBp= SETelemaddr_(setB, skipB, void);
+  while (1) {
+    if (elemA == skipAp)
+      elemA++;
+    if (elemB == skipBp)
+      elemB++;
+    if (!*elemA)
+      break;
+    if (*elemA++ != *elemB++)
+      return 0;
+  }
+  if (*elemB)
+    return 0;
+  return 1;
+} /* setequal_skip */
+
+
+/*---------------------------------
+
+  qh_setfree(qh, setp )
+    frees the space occupied by a sorted or unsorted set
+
+  returns:
+    sets setp to NULL
+
+  notes:
+    set may be NULL
+
+  design:
+    free array
+    free set
+*/
+void qh_setfree(qhT *qh, setT **setp) {
+  int size;
+  void **freelistp;  /* used if !qh_NOmem by qh_memfree_() */
+
+  if (*setp) {
+    size= SETbasesize + ((*setp)->maxsize)*SETelemsize;
+    if (size <= qh->qhmem.LASTsize) {
+      qh_memfree_(qh, *setp, size, freelistp);
+    }else
+      qh_memfree(qh, *setp, size);
+    *setp= NULL;
+  }
+} /* setfree */
+
+
+/*---------------------------------
+
+  qh_setfree2(qh, setp, elemsize )
+    frees the space occupied by a set and its elements
+
+  notes:
+    set may be NULL
+
+  design:
+    free each element
+    free set
+*/
+void qh_setfree2(qhT *qh, setT **setp, int elemsize) {
+  void          *elem, **elemp;
+
+  FOREACHelem_(*setp)
+    qh_memfree(qh, elem, elemsize);
+  qh_setfree(qh, setp);
+} /* setfree2 */
+
+
+
+/*---------------------------------
+
+  qh_setfreelong(qh, setp )
+    frees a set only if it's in long memory
+
+  returns:
+    sets setp to NULL if it is freed
+
+  notes:
+    set may be NULL
+
+  design:
+    if set is large
+      free it
+*/
+void qh_setfreelong(qhT *qh, setT **setp) {
+  int size;
+
+  if (*setp) {
+    size= SETbasesize + ((*setp)->maxsize)*SETelemsize;
+    if (size > qh->qhmem.LASTsize) {
+      qh_memfree(qh, *setp, size);
+      *setp= NULL;
+    }
+  }
+} /* setfreelong */
+
+
+/*---------------------------------
+
+  qh_setin( set, setelem )
+    returns 1 if setelem is in a set, 0 otherwise
+
+  notes:
+    set may be NULL or unsorted
+
+  design:
+    scans set for setelem
+*/
+int qh_setin(setT *set, void *setelem) {
+  void *elem, **elemp;
+
+  FOREACHelem_(set) {
+    if (elem == setelem)
+      return 1;
+  }
+  return 0;
+} /* setin */
+
+
+/*---------------------------------
+
+  qh_setindex(set, atelem )
+    returns the index of atelem in set.
+    returns -1, if not in set or maxsize wrong
+
+  notes:
+    set may be NULL and may contain nulls.
+    NOerrors returned (qh_pointid, QhullPoint::id)
+
+  design:
+    checks maxsize
+    scans set for atelem
+*/
+int qh_setindex(setT *set, void *atelem) {
+  void **elem;
+  int size, i;
+
+  if (!set)
+    return -1;
+  SETreturnsize_(set, size);
+  if (size > set->maxsize)
+    return -1;
+  elem= SETaddr_(set, void);
+  for (i=0; i < size; i++) {
+    if (*elem++ == atelem)
+      return i;
+  }
+  return -1;
+} /* setindex */
+
+
+/*---------------------------------
+
+  qh_setlarger(qh, oldsetp )
+    returns a larger set that contains all elements of *oldsetp
+
+  notes:
+    if long memory,
+      the new set is 2x larger
+    if qhmem.LASTsize is between 1.5x and 2x
+      the new set is qhmem.LASTsize
+    otherwise use quick memory,
+      the new set is 2x larger, rounded up to next qh_memsize
+       
+    if temp set, updates qh->qhmem.tempstack
+
+  design:
+    creates a new set
+    copies the old set to the new set
+    updates pointers in tempstack
+    deletes the old set
+*/
+void qh_setlarger(qhT *qh, setT **oldsetp) {
+  int setsize= 1, newsize;
+  setT *newset, *set, **setp, *oldset;
+  setelemT *sizep;
+  setelemT *newp, *oldp;
+
+  if (*oldsetp) {
+    oldset= *oldsetp;
+    SETreturnsize_(oldset, setsize);
+    qh->qhmem.cntlarger++;
+    qh->qhmem.totlarger += setsize+1;
+    qh_setlarger_quick(qh, setsize, &newsize);
+    newset= qh_setnew(qh, newsize);
+    oldp= (setelemT *)SETaddr_(oldset, void);
+    newp= (setelemT *)SETaddr_(newset, void);
+    memcpy((char *)newp, (char *)oldp, (size_t)(setsize+1) * SETelemsize);
+    sizep= SETsizeaddr_(newset);
+    sizep->i= setsize+1;
+    FOREACHset_((setT *)qh->qhmem.tempstack) {
+      if (set == oldset)
+        *(setp-1)= newset;
+    }
+    qh_setfree(qh, oldsetp);
+  }else
+    newset= qh_setnew(qh, 3);
+  *oldsetp= newset;
+} /* setlarger */
+
+
+/*---------------------------------
+
+  qh_setlarger_quick(qh, setsize, newsize )
+    determine newsize for setsize
+    returns True if newsize fits in quick memory
+
+  design:
+    if 2x fits into quick memory
+      return True, 2x
+    if x+4 does not fit into quick memory
+      return False, 2x
+    if x+x/3 fits into quick memory
+      return True, the last quick set
+    otherwise
+      return False, 2x
+*/
+int qh_setlarger_quick(qhT *qh, int setsize, int *newsize) {
+    int lastquickset;
+
+    *newsize= 2 * setsize;
+    lastquickset= (qh->qhmem.LASTsize - SETbasesize) / SETelemsize; /* matches size computation in qh_setnew */
+    if (*newsize <= lastquickset)
+      return 1;
+    if (setsize + 4 > lastquickset)
+      return 0;
+    if (setsize + setsize/3 <= lastquickset) {
+      *newsize= lastquickset;
+      return 1;
+    }
+    return 0;
+} /* setlarger_quick */
+
+/*---------------------------------
+
+  qh_setlast( set )
+    return last element of set or NULL (use type conversion)
+
+  notes:
+    set may be NULL
+
+  design:
+    return last element
+*/
+void *qh_setlast(setT *set) {
+  int size;
+
+  if (set) {
+    size= SETsizeaddr_(set)->i;
+    if (!size)
+      return SETelem_(set, set->maxsize - 1);
+    else if (size > 1)
+      return SETelem_(set, size - 2);
+  }
+  return NULL;
+} /* setlast */
+
+
+/*---------------------------------
+
+  qh_setnew(qh, setsize )
+    creates and allocates space for a set
+
+  notes:
+    setsize means the number of elements (!including the NULL terminator)
+    use qh_settemp/qh_setfreetemp if set is temporary
+
+  design:
+    allocate memory for set
+    roundup memory if small set
+    initialize as empty set
+*/
+setT *qh_setnew(qhT *qh, int setsize) {
+  setT *set;
+  int sizereceived; /* used if !qh_NOmem */
+  int size;
+  void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
+
+  if (!setsize)
+    setsize++;
+  size= SETbasesize + setsize * SETelemsize; /* setT includes NULL terminator, see qh.LASTquickset */
+  if (size>0 && size <= qh->qhmem.LASTsize) {
+    qh_memalloc_(qh, size, freelistp, set, setT);
+#ifndef qh_NOmem
+    sizereceived= qh->qhmem.sizetable[ qh->qhmem.indextable[size]];
+    if (sizereceived > size)
+      setsize += (sizereceived - size)/SETelemsize;
+#endif
+  }else
+    set= (setT *)qh_memalloc(qh, size);
+  set->maxsize= setsize;
+  set->e[setsize].i= 1;
+  set->e[0].p= NULL;
+  return(set);
+} /* setnew */
+
+
+/*---------------------------------
+
+  qh_setnew_delnthsorted(qh, set, size, nth, prepend )
+    creates a sorted set not containing nth element
+    if prepend, the first prepend elements are undefined
+
+  notes:
+    set must be defined
+    checks nth
+    see also: setdelnthsorted
+
+  design:
+    create new set
+    setup pointers and allocate room for prepend'ed entries
+    append head of old set to new set
+    append tail of old set to new set
+*/
+setT *qh_setnew_delnthsorted(qhT *qh, setT *set, int size, int nth, int prepend) {
+  setT *newset;
+  void **oldp, **newp;
+  int tailsize= size - nth -1, newsize;
+
+  if (tailsize < 0) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint(qh, qh->qhmem.ferr, "", set);
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  newsize= size-1 + prepend;
+  newset= qh_setnew(qh, newsize);
+  newset->e[newset->maxsize].i= newsize+1;  /* may be overwritten */
+  oldp= SETaddr_(set, void);
+  newp= SETaddr_(newset, void) + prepend;
+  switch (nth) {
+  case 0:
+    break;
+  case 1:
+    *(newp++)= *oldp++;
+    break;
+  case 2:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 3:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 4:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  default:
+    memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize);
+    newp += nth;
+    oldp += nth;
+    break;
+  }
+  oldp++;
+  switch (tailsize) {
+  case 0:
+    break;
+  case 1:
+    *(newp++)= *oldp++;
+    break;
+  case 2:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 3:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 4:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  default:
+    memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize);
+    newp += tailsize;
+  }
+  *newp= NULL;
+  return(newset);
+} /* setnew_delnthsorted */
+
+
+/*---------------------------------
+
+  qh_setprint(qh, fp, string, set )
+    print set elements to fp with identifying string
+
+  notes:
+    never errors
+*/
+void qh_setprint(qhT *qh, FILE *fp, const char* string, setT *set) {
+  int size, k;
+
+  if (!set)
+    qh_fprintf(qh, fp, 9346, "%s set is null\n", string);
+  else {
+    SETreturnsize_(set, size);
+    qh_fprintf(qh, fp, 9347, "%s set=%p maxsize=%d size=%d elems=",
+             string, (void *) set, set->maxsize, size);
+    if (size > set->maxsize)
+      size= set->maxsize+1;
+    for (k=0; k < size; k++)
+      qh_fprintf(qh, fp, 9348, " %p", (void *) set->e[k].p);
+    qh_fprintf(qh, fp, 9349, "\n");
+  }
+} /* setprint */
+
+/*---------------------------------
+
+  qh_setreplace(qh, set, oldelem, newelem )
+    replaces oldelem in set with newelem
+
+  notes:
+    errors if oldelem not in the set
+    newelem may be NULL, but it turns the set into an indexed set (no FOREACH)
+
+  design:
+    find oldelem
+    replace with newelem
+*/
+void qh_setreplace(qhT *qh, setT *set, void *oldelem, void *newelem) {
+  void **elemp;
+
+  elemp= SETaddr_(set, void);
+  while (*elemp != oldelem && *elemp)
+    elemp++;
+  if (*elemp)
+    *elemp= newelem;
+  else {
+    qh_fprintf(qh, qh->qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n",
+       oldelem);
+    qh_setprint(qh, qh->qhmem.ferr, "", set);
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+} /* setreplace */
+
+
+/*---------------------------------
+
+  qh_setsize(qh, set )
+    returns the size of a set
+
+  notes:
+    errors if set's maxsize is incorrect
+    same as SETreturnsize_(set)
+    same code for qh_setsize [qset_r.c] and QhullSetBase::count
+    if first element is NULL, SETempty_() is True but qh_setsize may be greater than 0
+
+  design:
+    determine actual size of set from maxsize
+*/
+int qh_setsize(qhT *qh, setT *set) {
+  int size;
+  setelemT *sizep;
+
+  if (!set)
+    return(0);
+  sizep= SETsizeaddr_(set);
+  if ((size= sizep->i)) {
+    size--;
+    if (size > set->maxsize) {
+      qh_fprintf(qh, qh->qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",
+               size, set->maxsize);
+      qh_setprint(qh, qh->qhmem.ferr, "set: ", set);
+      qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+    }
+  }else
+    size= set->maxsize;
+  return size;
+} /* setsize */
+
+/*---------------------------------
+
+  qh_settemp(qh, setsize )
+    return a stacked, temporary set of up to setsize elements
+
+  notes:
+    use settempfree or settempfree_all to release from qh->qhmem.tempstack
+    see also qh_setnew
+
+  design:
+    allocate set
+    append to qh->qhmem.tempstack
+
+*/
+setT *qh_settemp(qhT *qh, int setsize) {
+  setT *newset;
+
+  newset= qh_setnew(qh, setsize);
+  qh_setappend(qh, &qh->qhmem.tempstack, newset);
+  if (qh->qhmem.IStracing >= 5)
+    qh_fprintf(qh, qh->qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n",
+       (void *) newset, newset->maxsize, qh_setsize(qh, qh->qhmem.tempstack));
+  return newset;
+} /* settemp */
+
+/*---------------------------------
+
+  qh_settempfree(qh, set )
+    free temporary set at top of qh->qhmem.tempstack
+
+  notes:
+    nop if set is NULL
+    errors if set not from previous   qh_settemp
+
+  to locate errors:
+    use 'T2' to find source and then find mis-matching qh_settemp
+
+  design:
+    check top of qh->qhmem.tempstack
+    free it
+*/
+void qh_settempfree(qhT *qh, setT **set) {
+  setT *stackedset;
+
+  if (!*set)
+    return;
+  stackedset= qh_settemppop(qh);
+  if (stackedset != *set) {
+    qh_settemppush(qh, stackedset);
+    qh_fprintf(qh, qh->qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n",
+             (void *) *set, qh_setsize(qh, *set), qh_setsize(qh, qh->qhmem.tempstack)+1,
+             (void *) stackedset, qh_setsize(qh, stackedset));
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  qh_setfree(qh, set);
+} /* settempfree */
+
+/*---------------------------------
+
+  qh_settempfree_all(qh)
+    free all temporary sets in qh->qhmem.tempstack
+
+  design:
+    for each set in tempstack
+      free set
+    free qh->qhmem.tempstack
+*/
+void qh_settempfree_all(qhT *qh) {
+  setT *set, **setp;
+
+  FOREACHset_(qh->qhmem.tempstack)
+    qh_setfree(qh, &set);
+  qh_setfree(qh, &qh->qhmem.tempstack);
+} /* settempfree_all */
+
+/*---------------------------------
+
+  qh_settemppop(qh)
+    pop and return temporary set from qh->qhmem.tempstack
+
+  notes:
+    the returned set is permanent
+
+  design:
+    pop and check top of qh->qhmem.tempstack
+*/
+setT *qh_settemppop(qhT *qh) {
+  setT *stackedset;
+
+  stackedset= (setT *)qh_setdellast(qh->qhmem.tempstack);
+  if (!stackedset) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  if (qh->qhmem.IStracing >= 5)
+    qh_fprintf(qh, qh->qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n",
+       qh_setsize(qh, qh->qhmem.tempstack)+1, (void *) stackedset, qh_setsize(qh, stackedset));
+  return stackedset;
+} /* settemppop */
+
+/*---------------------------------
+
+  qh_settemppush(qh, set )
+    push temporary set unto qh->qhmem.tempstack (makes it temporary)
+
+  notes:
+    duplicates settemp() for tracing
+
+  design:
+    append set to tempstack
+*/
+void qh_settemppush(qhT *qh, setT *set) {
+  if (!set) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6267, "qhull error (qh_settemppush): can not push a NULL temp\n");
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  qh_setappend(qh, &qh->qhmem.tempstack, set);
+  if (qh->qhmem.IStracing >= 5)
+    qh_fprintf(qh, qh->qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n",
+      qh_setsize(qh, qh->qhmem.tempstack), (void *) set, qh_setsize(qh, set));
+} /* settemppush */
+
+
+/*---------------------------------
+
+  qh_settruncate(qh, set, size )
+    truncate set to size elements
+
+  notes:
+    set must be defined
+
+  see:
+    SETtruncate_
+
+  design:
+    check size
+    update actual size of set
+*/
+void qh_settruncate(qhT *qh, setT *set, int size) {
+
+  if (size < 0 || size > set->maxsize) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);
+    qh_setprint(qh, qh->qhmem.ferr, "", set);
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  set->e[set->maxsize].i= size+1;   /* maybe overwritten */
+  set->e[size].p= NULL;
+} /* settruncate */
+
+/*---------------------------------
+
+  qh_setunique(qh, set, elem )
+    add elem to unsorted set unless it is already in set
+
+  notes:
+    returns 1 if it is appended
+
+  design:
+    if elem not in set
+      append elem to set
+*/
+int qh_setunique(qhT *qh, setT **set, void *elem) {
+
+  if (!qh_setin(*set, elem)) {
+    qh_setappend(qh, set, elem);
+    return 1;
+  }
+  return 0;
+} /* setunique */
+
+/*---------------------------------
+
+  qh_setzero(qh, set, index, size )
+    zero elements from index on
+    set actual size of set to size
+
+  notes:
+    set must be defined
+    the set becomes an indexed set (can not use FOREACH...)
+
+  see also:
+    qh_settruncate
+
+  design:
+    check index and size
+    update actual size
+    zero elements starting at e[index]
+*/
+void qh_setzero(qhT *qh, setT *set, int idx, int size) {
+  int count;
+
+  if (idx < 0 || idx >= size || size > set->maxsize) {
+    qh_fprintf(qh, qh->qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size);
+    qh_setprint(qh, qh->qhmem.ferr, "", set);
+    qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
+  }
+  set->e[set->maxsize].i=  size+1;  /* may be overwritten */
+  count= size - idx + 1;   /* +1 for NULL terminator */
+  memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize);
+} /* setzero */
+
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/qset_r.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/qset_r.h
new file mode 100644
index 00000000000..bc0298ed086
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/qset_r.h
@@ -0,0 +1,515 @@
+/*
  ---------------------------------
+
+   qset_r.h
+     header file for qset_r.c that implements set
+
+   see qh-set_r.htm and qset_r.c
+
+   only uses mem_r.c, malloc/free
+
+   for error handling, writes message and calls
+      qh_errexit(qhT *qh, qhmem_ERRqhull, NULL, NULL);
+
+   set operations satisfy the following properties:
+    - sets have a max size, the actual size (if different) is stored at the end
+    - every set is NULL terminated
+    - sets may be sorted or unsorted, the caller must distinguish this
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/qset_r.h#4 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+*/
+
+#ifndef qhDEFset
+#define qhDEFset 1
+
+#include 
+
+/*================= -structures- ===============*/
+
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;   /* a set is a sorted or unsorted array of pointers */
+#endif
+
+#ifndef DEFqhT
+#define DEFqhT 1
+typedef struct qhT qhT;          /* defined in libqhull_r.h */
+#endif
+
+/* [jan'15] Decided not to use countT.  Most sets are small.  The code uses signed tests */
+
+/*------------------------------------------
+
+setT
+  a set or list of pointers with maximum size and actual size.
+
+variations:
+  unsorted, unique   -- a list of unique pointers with NULL terminator
+                           user guarantees uniqueness
+  sorted             -- a sorted list of unique pointers with NULL terminator
+                           qset_r.c guarantees uniqueness
+  unsorted           -- a list of pointers terminated with NULL
+  indexed            -- an array of pointers with NULL elements
+
+structure for set of n elements:
+
+        --------------
+        |  maxsize
+        --------------
+        |  e[0] - a pointer, may be NULL for indexed sets
+        --------------
+        |  e[1]
+
+        --------------
+        |  ...
+        --------------
+        |  e[n-1]
+        --------------
+        |  e[n] = NULL
+        --------------
+        |  ...
+        --------------
+        |  e[maxsize] - n+1 or NULL (determines actual size of set)
+        --------------
+
+*/
+
+/*-- setelemT -- internal type to allow both pointers and indices
+*/
+typedef union setelemT setelemT;
+union setelemT {
+  void    *p;
+  int   i;         /* integer used for e[maxSize] */
+};
+
+struct setT {
+  int maxsize;          /* maximum number of elements (except NULL) */
+  setelemT e[];        /* array of pointers, tail is NULL */
+                        /* last slot (unless NULL) is actual size+1
+                           e[maxsize]==NULL or e[e[maxsize]-1]==NULL */
+                        /* this may generate a warning since e[] contains
+                           maxsize elements */
+};
+
+/*=========== -constants- =========================*/
+
+/*-------------------------------------
+
+  SETelemsize
+    size of a set element in bytes
+*/
+#define SETelemsize ((int)sizeof(setelemT))
+
+/*
+   SETbasesize - size of setT with a single element
+   in e[]. Before C99, setT has been declared with e[1], so
+   sizeof(setT) included already space for one element, but with e[]
+   (C99), it does not. All instances of (int)sizeof(setT) have been
+   replaced with SETbasesize throughout the code -- Tomas Kalibera,
+   2025-01-09 */
+#define SETbasesize ((int)sizeof(setT) + SETelemsize)
+
+
+/*=========== -macros- =========================*/
+
+/*-------------------------------------
+
+   FOREACHsetelement_(type, set, variable)
+     define FOREACH iterator
+
+   declare:
+     assumes *variable and **variablep are declared
+     no space in "variable)" [DEC Alpha cc compiler]
+
+   each iteration:
+     variable is set element
+     variablep is one beyond variable.
+
+   to repeat an element:
+     variablep--; / *repeat* /
+
+   at exit:
+     variable is NULL at end of loop
+
+   example:
+     #define FOREACHfacet_(facets) FOREACHsetelement_(facetT, facets, facet)
+
+   notes:
+     use FOREACHsetelement_i_() if need index or include NULLs
+     assumes set is not modified
+
+   WARNING:
+     nested loops can't use the same variable (define another FOREACH)
+
+     needs braces if nested inside another FOREACH
+     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
+*/
+#define FOREACHsetelement_(type, set, variable) \
+        if (((variable= NULL), set)) for (\
+          variable##p= (type **)&((set)->e[0].p); \
+          (variable= *variable##p++);)
+
+/*------------------------------------------
+
+   FOREACHsetelement_i_(qh, type, set, variable)
+     define indexed FOREACH iterator
+
+   declare:
+     type *variable, variable_n, variable_i;
+
+   each iteration:
+     variable is set element, may be NULL
+     variable_i is index, variable_n is qh_setsize()
+
+   to repeat an element:
+     variable_i--; variable_n-- repeats for deleted element
+
+   at exit:
+     variable==NULL and variable_i==variable_n
+
+   example:
+     #define FOREACHfacet_i_(qh, facets) FOREACHsetelement_i_(qh, facetT, facets, facet)
+
+   WARNING:
+     nested loops can't use the same variable (define another FOREACH)
+
+     needs braces if nested inside another FOREACH
+     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
+*/
+#define FOREACHsetelement_i_(qh, type, set, variable) \
+        if (((variable= NULL), set)) for (\
+          variable##_i= 0, variable= (type *)((set)->e[0].p), \
+                   variable##_n= qh_setsize(qh, set);\
+          variable##_i < variable##_n;\
+          variable= (type *)((set)->e[++variable##_i].p) )
+
+/*----------------------------------------
+
+   FOREACHsetelementreverse_(qh, type, set, variable)-
+     define FOREACH iterator in reverse order
+
+   declare:
+     assumes *variable and **variablep are declared
+     also declare 'int variabletemp'
+
+   each iteration:
+     variable is set element
+
+   to repeat an element:
+     variabletemp++; / *repeat* /
+
+   at exit:
+     variable is NULL
+
+   example:
+     #define FOREACHvertexreverse_(vertices) FOREACHsetelementreverse_(vertexT, vertices, vertex)
+
+   notes:
+     use FOREACHsetelementreverse12_() to reverse first two elements
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHsetelementreverse_(qh, type, set, variable) \
+        if (((variable= NULL), set)) for (\
+           variable##temp= qh_setsize(qh, set)-1, variable= qh_setlast(qh, set);\
+           variable; variable= \
+           ((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL))
+
+/*-------------------------------------
+
+   FOREACHsetelementreverse12_(type, set, variable)-
+     define FOREACH iterator with e[1] and e[0] reversed
+
+   declare:
+     assumes *variable and **variablep are declared
+
+   each iteration:
+     variable is set element
+     variablep is one after variable.
+
+   to repeat an element:
+     variablep--; / *repeat* /
+
+   at exit:
+     variable is NULL at end of loop
+
+   example
+     #define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)
+
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHsetelementreverse12_(type, set, variable) \
+        if (((variable= NULL), set)) for (\
+          variable##p= (type **)&((set)->e[1].p); \
+          (variable= *variable##p); \
+          variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \
+              (variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++))
+
+/*-------------------------------------
+
+   FOREACHelem_( set )-
+     iterate elements in a set
+
+   declare:
+     void *elem, *elemp;
+
+   each iteration:
+     elem is set element
+     elemp is one beyond
+
+   to repeat an element:
+     elemp--; / *repeat* /
+
+   at exit:
+     elem == NULL at end of loop
+
+   example:
+     FOREACHelem_(set) {
+
+   notes:
+     assumes set is not modified
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHelem_(set) FOREACHsetelement_(void, set, elem)
+
+/*-------------------------------------
+
+   FOREACHset_( set )-
+     iterate a set of sets
+
+   declare:
+     setT *set, **setp;
+
+   each iteration:
+     set is set element
+     setp is one beyond
+
+   to repeat an element:
+     setp--; / *repeat* /
+
+   at exit:
+     set == NULL at end of loop
+
+   example
+     FOREACHset_(sets) {
+
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set)
+
+/*-------------------------------------------
+
+   SETindex_( set, elem )
+     return index of elem in set
+
+   notes:
+     for use with FOREACH iteration
+     WARN64 -- Maximum set size is 2G
+
+   example:
+     i= SETindex_(ridges, ridge)
+*/
+#define SETindex_(set, elem) ((int)((void **)elem##p - (void **)&(set)->e[1].p))
+
+/*-----------------------------------------
+
+   SETref_( elem )
+     l.h.s. for modifying the current element in a FOREACH iteration
+
+   example:
+     SETref_(ridge)= anotherridge;
+*/
+#define SETref_(elem) (elem##p[-1])
+
+/*-----------------------------------------
+
+   SETelem_(set, n)
+     return the n'th element of set
+
+   notes:
+      assumes that n is valid [0..size] and that set is defined
+      use SETelemt_() for type cast
+*/
+#define SETelem_(set, n)           ((set)->e[n].p)
+
+/*-----------------------------------------
+
+   SETelemt_(set, n, type)
+     return the n'th element of set as a type
+
+   notes:
+      assumes that n is valid [0..size] and that set is defined
+*/
+#define SETelemt_(set, n, type)    ((type *)((set)->e[n].p))
+
+/*-----------------------------------------
+
+   SETelemaddr_(set, n, type)
+     return address of the n'th element of a set
+
+   notes:
+      assumes that n is valid [0..size] and set is defined
+*/
+#define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p)))
+
+/*-----------------------------------------
+
+   SETfirst_(set)
+     return first element of set
+
+*/
+#define SETfirst_(set)             ((set)->e[0].p)
+
+/*-----------------------------------------
+
+   SETfirstt_(set, type)
+     return first element of set as a type
+
+*/
+#define SETfirstt_(set, type)      ((type *)((set)->e[0].p))
+
+/*-----------------------------------------
+
+   SETsecond_(set)
+     return second element of set
+
+*/
+#define SETsecond_(set)            ((set)->e[1].p)
+
+/*-----------------------------------------
+
+   SETsecondt_(set, type)
+     return second element of set as a type
+*/
+#define SETsecondt_(set, type)     ((type *)((set)->e[1].p))
+
+/*-----------------------------------------
+
+   SETaddr_(set, type)
+       return address of set's elements
+*/
+#define SETaddr_(set,type)         ((type **)(&((set)->e[0].p)))
+
+/*-----------------------------------------
+
+   SETreturnsize_(set, size)
+     return size of a set
+
+   notes:
+      set must be defined
+      use qh_setsize(qhT *qh, set) unless speed is critical
+*/
+#define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize))
+
+/*-----------------------------------------
+
+   SETempty_(set)
+     return true(1) if set is empty (i.e., FOREACHsetelement_ is empty)
+
+   notes:
+      set may be NULL
+      qh_setsize may be non-zero if first element is NULL
+*/
+#define SETempty_(set)            (!set || (SETfirst_(set) ? 0 : 1))
+
+/*---------------------------------
+
+  SETsizeaddr_(set)
+    return pointer to 'actual size+1' of set (set CANNOT be NULL!!)
+    Its type is setelemT* for strict aliasing
+    All SETelemaddr_ must be cast to setelemT
+
+
+  notes:
+    *SETsizeaddr==NULL or e[*SETsizeaddr-1].p==NULL
+*/
+#define SETsizeaddr_(set) (&((set)->e[(set)->maxsize]))
+
+/*-----------------------------------------
+
+   SETtruncate_(set, size)
+     truncate set to size
+
+   see:
+     qh_settruncate()
+
+*/
+#define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \
+      set->e[size].p= NULL;}
+
+/*======= prototypes in alphabetical order ============*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void  qh_setaddsorted(qhT *qh, setT **setp, void *elem);
+void  qh_setaddnth(qhT *qh, setT **setp, int nth, void *newelem);
+void  qh_setappend(qhT *qh, setT **setp, void *elem);
+void  qh_setappend_set(qhT *qh, setT **setp, setT *setA);
+void  qh_setappend2ndlast(qhT *qh, setT **setp, void *elem);
+void  qh_setcheck(qhT *qh, setT *set, const char *tname, unsigned int id);
+void  qh_setcompact(qhT *qh, setT *set);
+setT *qh_setcopy(qhT *qh, setT *set, int extra);
+void *qh_setdel(setT *set, void *elem);
+void *qh_setdellast(setT *set);
+void *qh_setdelnth(qhT *qh, setT *set, int nth);
+void *qh_setdelnthsorted(qhT *qh, setT *set, int nth);
+void *qh_setdelsorted(setT *set, void *newelem);
+setT *qh_setduplicate(qhT *qh, setT *set, int elemsize);
+void **qh_setendpointer(setT *set);
+int   qh_setequal(setT *setA, setT *setB);
+int   qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB);
+int   qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB);
+void  qh_setfree(qhT *qh, setT **set);
+void  qh_setfree2(qhT *qh, setT **setp, int elemsize);
+void  qh_setfreelong(qhT *qh, setT **set);
+int   qh_setin(setT *set, void *setelem);
+int   qh_setindex(setT *set, void *setelem);
+void  qh_setlarger(qhT *qh, setT **setp);
+int   qh_setlarger_quick(qhT *qh, int setsize, int *newsize);
+void *qh_setlast(setT *set);
+setT *qh_setnew(qhT *qh, int size);
+setT *qh_setnew_delnthsorted(qhT *qh, setT *set, int size, int nth, int prepend);
+void  qh_setprint(qhT *qh, FILE *fp, const char* string, setT *set);
+void  qh_setreplace(qhT *qh, setT *set, void *oldelem, void *newelem);
+int   qh_setsize(qhT *qh, setT *set);
+setT *qh_settemp(qhT *qh, int setsize);
+void  qh_settempfree(qhT *qh, setT **set);
+void  qh_settempfree_all(qhT *qh);
+setT *qh_settemppop(qhT *qh);
+void  qh_settemppush(qhT *qh, setT *set);
+void  qh_settruncate(qhT *qh, setT *set, int size);
+int   qh_setunique(qhT *qh, setT **set, void *elem);
+void  qh_setzero(qhT *qh, setT *set, int idx, int size);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* qhDEFset */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/random_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/random_r.c
new file mode 100644
index 00000000000..7eecd30e094
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/random_r.c
@@ -0,0 +1,249 @@
+/*
  ---------------------------------
+
+   random_r.c and utilities
+     Park & Miller's minimimal standard random number generator
+     argc/argv conversion
+
+     Used by rbox.  Do not use 'qh' 
+*/
+
+#include "libqhull_r.h"
+#include "random_r.h"
+
+#include 
+#include 
+#include 
+
+#ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
+#pragma warning( disable : 4706)  /* assignment within conditional function */
+#pragma warning( disable : 4996)  /* function was declared deprecated(strcpy, localtime, etc.) */
+#endif
+
+/*---------------------------------
+
+  qh_argv_to_command( argc, argv, command, max_size )
+
+    build command from argc/argv
+    max_size is at least
+
+  returns:
+    a space-delimited string of options (just as typed)
+    returns false if max_size is too short
+
+  notes:
+    silently removes
+    makes option string easy to input and output
+    matches qh_argv_to_command_size
+    argc may be 0
+*/
+int qh_argv_to_command(int argc, char *argv[], char* command, int max_size) {
+  int i, remaining;
+  char *s;
+  *command= '\0';  /* max_size > 0 */
+
+  if (argc) {
+    if ((s= strrchr( argv[0], '\\')) /* get filename w/o .exe extension */
+    || (s= strrchr( argv[0], '/')))
+        s++;
+    else
+        s= argv[0];
+    if ((int)strlen(s) < max_size)   /* WARN64 */
+        strcpy(command, s);
+    else
+        goto error_argv;
+    if ((s= strstr(command, ".EXE"))
+    ||  (s= strstr(command, ".exe")))
+        *s= '\0';
+  }
+  for (i=1; i < argc; i++) {
+    s= argv[i];
+    remaining= max_size - (int)strlen(command) - (int)strlen(s) - 2;   /* WARN64 */
+    if (!*s || strchr(s, ' ')) {
+      char *t= command + strlen(command);
+      remaining -= 2;
+      if (remaining < 0) {
+        goto error_argv;
+      }
+      *t++= ' ';
+      *t++= '"';
+      while (*s) {
+        if (*s == '"') {
+          if (--remaining < 0)
+            goto error_argv;
+          *t++= '\\';
+        }
+        *t++= *s++;
+      }
+      *t++= '"';
+      *t= '\0';
+    }else if (remaining < 0) {
+      goto error_argv;
+    }else {
+      strcat(command, " ");
+      strcat(command, s);
+    }
+  }
+  return 1;
+
+error_argv:
+  return 0;
+} /* argv_to_command */
+
+/*---------------------------------
+
+  qh_argv_to_command_size( argc, argv )
+
+    return size to allocate for qh_argv_to_command()
+
+  notes:
+    only called from rbox with qh_errexit not enabled
+    caller should report error if returned size is less than 1
+    argc may be 0
+    actual size is usually shorter
+*/
+int qh_argv_to_command_size(int argc, char *argv[]) {
+    int count= 1; /* null-terminator if argc==0 */
+    int i;
+    char *s;
+
+    for (i=0; i0 && strchr(argv[i], ' ')) {
+        count += 2;  /* quote delimiters */
+        for (s=argv[i]; *s; s++) {
+          if (*s == '"') {
+            count++;
+          }
+        }
+      }
+    }
+    return count;
+} /* argv_to_command_size */
+
+/*---------------------------------
+
+  qh_rand()
+  qh_srand(qh, seed )
+    generate pseudo-random number between 1 and 2^31 -2
+
+  notes:
+    For qhull and rbox, called from qh_RANDOMint(),etc. [user_r.h]
+
+    From Park & Miller's minimal standard random number generator
+      Communications of the ACM, 31:1192-1201, 1988.
+    Does not use 0 or 2^31 -1
+      this is silently enforced by qh_srand()
+    Can make 'Rn' much faster by moving qh_rand to qh_distplane
+*/
+
+/* Global variables and constants */
+
+#define qh_rand_a 16807
+#define qh_rand_m 2147483647
+#define qh_rand_q 127773  /* m div a */
+#define qh_rand_r 2836    /* m mod a */
+
+int qh_rand(qhT *qh) {
+    int lo, hi, test;
+    int seed= qh->last_random;
+
+    hi= seed / qh_rand_q;  /* seed div q */
+    lo= seed % qh_rand_q;  /* seed mod q */
+    test= qh_rand_a * lo - qh_rand_r * hi;
+    if (test > 0)
+        seed= test;
+    else
+        seed= test + qh_rand_m;
+    qh->last_random= seed;
+    /* seed= seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax;  for testing */
+    /* seed= qh_RANDOMmax;  for testing */
+    return seed;
+} /* rand */
+
+void qh_srand(qhT *qh, int seed) {
+    if (seed < 1)
+        qh->last_random= 1;
+    else if (seed >= qh_rand_m)
+        qh->last_random= qh_rand_m - 1;
+    else
+        qh->last_random= seed;
+} /* qh_srand */
+
+/*---------------------------------
+
+qh_randomfactor(qh, scale, offset )
+  return a random factor r * scale + offset
+
+notes:
+  qh.RANDOMa/b are defined in global_r.c
+  qh_RANDOMint requires 'qh'
+*/
+realT qh_randomfactor(qhT *qh, realT scale, realT offset) {
+    realT randr;
+
+    randr= qh_RANDOMint;
+    return randr * scale + offset;
+} /* randomfactor */
+
+/*---------------------------------
+
+  qh_randommatrix(qh, buffer, dim, rows )
+    generate a random dim X dim matrix in range [-1,1]
+    assumes buffer is [dim+1, dim]
+
+  returns:
+    sets buffer to random numbers
+    sets rows to rows of buffer
+    sets row[dim] as scratch row
+
+  notes:
+    qh_RANDOMint requires 'qh'
+*/
+void qh_randommatrix(qhT *qh, realT *buffer, int dim, realT **rows) {
+    int i, k;
+    realT **rowi, *coord, realr;
+
+    coord= buffer;
+    rowi= rows;
+    for (i=0; i < dim; i++) {
+        *(rowi++)= coord;
+        for (k=0; k < dim; k++) {
+            realr= qh_RANDOMint;
+            *(coord++)= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;
+        }
+    }
+    *rowi= coord;
+} /* randommatrix */
+
+/*---------------------------------
+
+  qh_strtol( s, endp) qh_strtod( s, endp)
+    internal versions of strtol() and strtod()
+    does not skip trailing spaces
+  notes:
+    some implementations of strtol()/strtod() skip trailing spaces
+*/
+double qh_strtod(const char *s, char **endp) {
+  double result;
+
+  result= strtod(s, endp);
+  if (s < (*endp) && (*endp)[-1] == ' ')
+    (*endp)--;
+  return result;
+} /* strtod */
+
+int qh_strtol(const char *s, char **endp) {
+  int result;
+
+  result= (int) strtol(s, endp, 10);     /* WARN64 */
+  if (s< (*endp) && (*endp)[-1] == ' ')
+    (*endp)--;
+  return result;
+} /* strtol */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/random_r.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/random_r.h
new file mode 100644
index 00000000000..a17549d3b93
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/random_r.h
@@ -0,0 +1,41 @@
+/*
  ---------------------------------
+
+  random_r.h
+    header file for random and utility routines
+
+   see qh-geom_r.htm and random_r.c
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/random_r.h#3 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+*/
+
+#ifndef qhDEFrandom
+#define qhDEFrandom 1
+
+#include "libqhull_r.h"
+
+/*============= prototypes in alphabetical order ======= */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int     qh_argv_to_command(int argc, char *argv[], char* command, int max_size);
+int     qh_argv_to_command_size(int argc, char *argv[]);
+int     qh_rand(qhT *qh);
+void    qh_srand(qhT *qh, int seed);
+realT   qh_randomfactor(qhT *qh, realT scale, realT offset);
+void    qh_randommatrix(qhT *qh, realT *buffer, int dim, realT **row);
+int     qh_strtol(const char *s, char **endp);
+double  qh_strtod(const char *s, char **endp);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* qhDEFrandom */
+
+
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/rboxlib_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/rboxlib_r.c
new file mode 100644
index 00000000000..67e39984115
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/rboxlib_r.c
@@ -0,0 +1,854 @@
+/*
  ---------------------------------
+
+   rboxlib_r.c
+     Generate input points
+
+   notes:
+     For documentation, see prompt[] of rbox_r.c
+     50 points generated for 'rbox D4'
+
+   WARNING:
+     incorrect range if qh_RANDOMmax is defined wrong (user_r.h)
+*/
+
+#include "libqhull_r.h"  /* First for user_r.h */
+#include "random_r.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifdef _MSC_VER  /* Microsoft Visual C++ */
+#pragma warning( disable : 4706)  /* assignment within conditional expression. */
+#pragma warning( disable : 4996)  /* this function (strncat,sprintf,strcpy) or variable may be unsafe. */
+#endif
+
+#define MAXdim 200
+#define PI 3.1415926535897932384
+
+/* ------------------------------ prototypes ----------------*/
+int qh_roundi(qhT *qh, double a);
+void qh_out1(qhT *qh, double a);
+void qh_out2n(qhT *qh, double a, double b);
+void qh_out3n(qhT *qh, double a, double b, double c);
+void qh_outcoord(qhT *qh, int iscdd, double *coord, int dim);
+void qh_outcoincident(qhT *qh, int coincidentpoints, double radius, int iscdd, double *coord, int dim);
+void qh_rboxpoints2(qhT *qh, char* rbox_command, double **simplex);
+
+void    qh_fprintf_rbox(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
+void    qh_free(void *mem);
+void   *qh_malloc(size_t size);
+int     qh_rand(qhT *qh);
+void    qh_srand(qhT *qh, int seed);
+
+/*---------------------------------
+
+  qh_rboxpoints(qh, rbox_command )
+    Generate points to qh.fout according to rbox options
+    Report errors on qh.ferr
+
+  returns:
+    0 (qh_ERRnone) on success
+    1 (qh_ERRinput) on input error
+    4 (qh_ERRmem) on memory error
+    5 (qh_ERRqhull) on internal error
+
+  notes:
+    To avoid using stdio, redefine qh_malloc, qh_free, and qh_fprintf_rbox (user_r.c)
+    Split out qh_rboxpoints2() to avoid -Wclobbered
+
+  design:
+    Straight line code (consider defining a struct and functions):
+
+    Parse arguments into variables
+    Determine the number of points
+    Generate the points
+*/
+int qh_rboxpoints(qhT *qh, char* rbox_command) {
+  int exitcode;
+  double *simplex;
+
+  simplex= NULL;
+  exitcode= setjmp(qh->rbox_errexit);
+  if (exitcode) {
+    /* same code for error exit and normal return.  qh.NOerrexit is set */
+    if (simplex)
+      qh_free(simplex);
+    return exitcode;
+  }
+  qh_rboxpoints2(qh, rbox_command, &simplex);
+  /* same code for error exit and normal return */
+  if (simplex)
+    qh_free(simplex);
+  return qh_ERRnone;
+} /* rboxpoints */
+
+void qh_rboxpoints2(qhT *qh, char* rbox_command, double **simplex) {
+  int i,j,k;
+  int gendim;
+  int coincidentcount=0, coincidenttotal=0, coincidentpoints=0;
+  int cubesize, diamondsize, seed=0, count, apex;
+  int dim=3, numpoints=0, totpoints, addpoints=0;
+  int issphere=0, isaxis=0,  iscdd=0, islens=0, isregular=0, iswidth=0, addcube=0;
+  int isgap=0, isspiral=0, NOcommand=0, adddiamond=0;
+  int israndom=0, istime=0;
+  int isbox=0, issimplex=0, issimplex2=0, ismesh=0;
+  double width=0.0, gap=0.0, radius=0.0, coincidentradius=0.0;
+  double coord[MAXdim], offset, meshm=3.0, meshn=4.0, meshr=5.0;
+  double *coordp, *simplexp;
+  int nthroot, mult[MAXdim];
+  double norm, factor, randr, rangap, tempr, lensangle=0, lensbase=1;
+  double anglediff, angle, x, y, cube=0.0, diamond=0.0;
+  double box= qh_DEFAULTbox; /* scale all numbers before output */
+  double randmax= qh_RANDOMmax;
+  char command[250], seedbuf[50];
+  char *s=command, *t, *first_point=NULL;
+  time_t timedata;
+
+  *command= '\0';
+  strncat(command, rbox_command, sizeof(command)-sizeof(seedbuf)-strlen(command)-1);
+
+  while (*s && !isspace(*s))  /* skip program name */
+    s++;
+  while (*s) {
+    while (*s && isspace(*s))
+      s++;
+    if (*s == '-')
+      s++;
+    if (!*s)
+      break;
+    if (isdigit(*s)) {
+      numpoints= qh_strtol(s, &s);
+      continue;
+    }
+    /* ============= read flags =============== */
+    switch (*s++) {
+    case 'c':
+      addcube= 1;
+      t= s;
+      while (isspace(*t))
+        t++;
+      if (*t == 'G')
+        cube= qh_strtod(++t, &s);
+      break;
+    case 'd':
+      adddiamond= 1;
+      t= s;
+      while (isspace(*t))
+        t++;
+      if (*t == 'G')
+        diamond= qh_strtod(++t, &s);
+      break;
+    case 'h':
+      iscdd= 1;
+      break;
+    case 'l':
+      isspiral= 1;
+      break;
+    case 'n':
+      NOcommand= 1;
+      break;
+    case 'r':
+      isregular= 1;
+      break;
+    case 's':
+      issphere= 1;
+      break;
+    case 't':
+      istime= 1;
+      if (isdigit(*s)) {
+        seed= qh_strtol(s, &s);
+        israndom= 0;
+      }else
+        israndom= 1;
+      break;
+    case 'x':
+      issimplex= 1;
+      break;
+    case 'y':
+      issimplex2= 1;
+      break;
+    case 'z':
+      qh->rbox_isinteger= 1;
+      break;
+    case 'B':
+      box= qh_strtod(s, &s);
+      isbox= 1;
+      break;
+    case 'C':
+      if (*s)
+        coincidentpoints=  qh_strtol(s, &s);
+      if (*s == ',') {
+        ++s;
+        coincidentradius=  qh_strtod(s, &s);
+      }
+      if (*s == ',') {
+        ++s;
+        coincidenttotal=  qh_strtol(s, &s);
+      }
+      if (*s && !isspace(*s)) {
+        qh_fprintf_rbox(qh, qh->ferr, 7080, "rbox error: arguments for 'Cn,r,m' are not 'int', 'float', and 'int'.  Remaining string is '%s'\n", s);
+        qh_errexit_rbox(qh, qh_ERRinput);
+      }
+      if (coincidentpoints==0){
+        qh_fprintf_rbox(qh, qh->ferr, 6268, "rbox error: missing arguments for 'Cn,r,m' where n is the number of coincident points, r is the radius (default 0.0), and m is the number of points\n");
+        qh_errexit_rbox(qh, qh_ERRinput);
+      }
+      if (coincidentpoints<0 || coincidenttotal<0 || coincidentradius<0.0){
+        qh_fprintf_rbox(qh, qh->ferr, 6269, "rbox error: negative arguments for 'Cn,m,r' where n (%d) is the number of coincident points, m (%d) is the number of points, and r (%.2g) is the radius (default 0.0)\n", coincidentpoints, coincidenttotal, coincidentradius);
+        qh_errexit_rbox(qh, qh_ERRinput);
+      }
+      break;
+    case 'D':
+      dim= qh_strtol(s, &s);
+      if (dim < 1
+      || dim > MAXdim) {
+        qh_fprintf_rbox(qh, qh->ferr, 6189, "rbox error: dimension, D%d, out of bounds (>=%d or <=0)\n", dim, MAXdim);
+        qh_errexit_rbox(qh, qh_ERRinput);
+      }
+      break;
+    case 'G':
+      if (isdigit(*s))
+        gap= qh_strtod(s, &s);
+      else
+        gap= 0.5;
+      isgap= 1;
+      break;
+    case 'L':
+      if (isdigit(*s))
+        radius= qh_strtod(s, &s);
+      else
+        radius= 10;
+      islens= 1;
+      break;
+    case 'M':
+      ismesh= 1;
+      if (*s)
+        meshn= qh_strtod(s, &s);
+      if (*s == ',') {
+        ++s;
+        meshm= qh_strtod(s, &s);
+      }else
+        meshm= 0.0;
+      if (*s == ',') {
+        ++s;
+        meshr= qh_strtod(s, &s);
+      }else
+        meshr= sqrt(meshn*meshn + meshm*meshm);
+      if (*s && !isspace(*s)) {
+        qh_fprintf_rbox(qh, qh->ferr, 7069, "rbox warning: assuming 'M3,4,5' since mesh args are not integers or reals\n");
+        meshn= 3.0, meshm=4.0, meshr=5.0;
+      }
+      break;
+    case 'O':
+      qh->rbox_out_offset= qh_strtod(s, &s);
+      break;
+    case 'P':
+      if (!first_point)
+        first_point= s - 1;
+      addpoints++;
+      while (*s && !isspace(*s))   /* read points later */
+        s++;
+      break;
+    case 'W':
+      width= qh_strtod(s, &s);
+      iswidth= 1;
+      break;
+    case 'Z':
+      if (isdigit(*s))
+        radius= qh_strtod(s, &s);
+      else
+        radius= 1.0;
+      isaxis= 1;
+      break;
+    default:
+      qh_fprintf_rbox(qh, qh->ferr, 6352, "rbox error: unknown flag at '%s'.\nExecute 'rbox' without arguments for documentation.\n", s - 1);
+      qh_errexit_rbox(qh, qh_ERRinput);
+    }
+    if (*s && !isspace(*s)) {
+      qh_fprintf_rbox(qh, qh->ferr, 6353, "rbox error: missing space between flags at %s.\n", s);
+      qh_errexit_rbox(qh, qh_ERRinput);
+    }
+  }
+
+  /* ============= defaults, constants, and sizes =============== */
+  if (qh->rbox_isinteger && !isbox)
+    box= qh_DEFAULTzbox;
+  if (addcube) {
+    tempr= floor(ldexp(1.0,dim)+0.5);
+    cubesize= (int)tempr;
+    if (cube == 0.0)
+      cube= box;
+  }else
+    cubesize= 0;
+  if (adddiamond) {
+    diamondsize= 2*dim;
+    if (diamond == 0.0)
+      diamond= box;
+  }else
+    diamondsize= 0;
+  if (islens) {
+    if (isaxis) {
+        qh_fprintf_rbox(qh, qh->ferr, 6190, "rbox error: can not combine 'Ln' with 'Zn'\n");
+        qh_errexit_rbox(qh, qh_ERRinput);
+    }
+    if (radius <= 1.0) {
+        qh_fprintf_rbox(qh, qh->ferr, 6191, "rbox error: lens radius %.2g should be greater than 1.0\n",
+               radius);
+        qh_errexit_rbox(qh, qh_ERRinput);
+    }
+    lensangle= asin(1.0/radius);
+    lensbase= radius * cos(lensangle);
+  }
+
+  if (!numpoints) {
+    if (issimplex2)
+        ; /* ok */
+    else if (isregular + issimplex + islens + issphere + isaxis + isspiral + iswidth + ismesh) {
+        qh_fprintf_rbox(qh, qh->ferr, 6192, "rbox error: missing count\n");
+        qh_errexit_rbox(qh, qh_ERRinput);
+    }else if (adddiamond + addcube + addpoints)
+        ; /* ok */
+    else {
+        numpoints= 50;  /* ./rbox D4 is the test case */
+        issphere= 1;
+    }
+  }
+  if ((issimplex + islens + isspiral + ismesh > 1)
+  || (issimplex + issphere + isspiral + ismesh > 1)) {
+    qh_fprintf_rbox(qh, qh->ferr, 6193, "rbox error: can only specify one of 'l', 's', 'x', 'Ln', or 'Mn,m,r' ('Ln s' is ok).\n");
+    qh_errexit_rbox(qh, qh_ERRinput);
+  }
+  if (coincidentpoints>0 && (numpoints == 0 || coincidenttotal > numpoints)) {
+    qh_fprintf_rbox(qh, qh->ferr, 6270, "rbox error: 'Cn,r,m' requested n coincident points for each of m points.  Either there is no points or m (%d) is greater than the number of points (%d).\n", coincidenttotal, numpoints);
+    qh_errexit_rbox(qh, qh_ERRinput);
+  }
+  if (coincidentpoints > 0 && isregular) {
+    qh_fprintf_rbox(qh, qh->ferr, 6423, "rbox error: 'Cn,r,m' is not implemented for regular points ('r')\n");
+    qh_errexit_rbox(qh, qh_ERRinput);
+  }
+
+  if (coincidenttotal == 0)
+    coincidenttotal= numpoints;
+
+  /* ============= print header with total points =============== */
+  if (issimplex || ismesh)
+    totpoints= numpoints;
+  else if (issimplex2)
+    totpoints= numpoints+dim+1;
+  else if (isregular) {
+    totpoints= numpoints;
+    if (dim == 2) {
+        if (islens)
+          totpoints += numpoints - 2;
+    }else if (dim == 3) {
+        if (islens)
+          totpoints += 2 * numpoints;
+      else if (isgap)
+        totpoints += 1 + numpoints;
+      else
+        totpoints += 2;
+    }
+  }else
+    totpoints= numpoints + isaxis;
+  totpoints += cubesize + diamondsize + addpoints;
+  totpoints += coincidentpoints*coincidenttotal;
+
+  /* ============= seed randoms =============== */
+  if (istime == 0) {
+    for (s=command; *s; s++) {
+      if (issimplex2 && *s == 'y') /* make 'y' same seed as 'x' */
+        i= 'x';
+      else
+        i= *s;
+      seed= 11*seed + i;
+    }
+  }else if (israndom) {
+    seed= (int)time(&timedata);
+    snprintf(seedbuf, sizeof(seedbuf) / sizeof(seedbuf[0]), " t%d", seed);  /* appends an extra t, not worth removing */
+    strncat(command, seedbuf, sizeof(command) - strlen(command) - 1);
+    t= strstr(command, " t ");
+    if (t)
+      strcpy(t+1, t+3); /* remove " t " */
+  } /* else, seed explicitly set to n */
+  qh_RANDOMseed_(qh, seed);
+
+  /* ============= print header =============== */
+
+  if (iscdd)
+      qh_fprintf_rbox(qh, qh->fout, 9391, "%s\nbegin\n        %d %d %s\n",
+      NOcommand ? "" : command,
+      totpoints, dim+1,
+      qh->rbox_isinteger ? "integer" : "real");
+  else if (NOcommand)
+      qh_fprintf_rbox(qh, qh->fout, 9392, "%d\n%d\n", dim, totpoints);
+  else
+      /* qh_fprintf_rbox special cases 9393 to append 'command' to the RboxPoints.comment() */
+      qh_fprintf_rbox(qh, qh->fout, 9393, "%d %s\n%d\n", dim, command, totpoints);
+
+  /* ============= explicit points =============== */
+  if ((s= first_point)) {
+    while (s && *s) { /* 'P' */
+      count= 0;
+      if (iscdd)
+        qh_out1(qh, 1.0);
+      while (*++s) {
+        qh_out1(qh, qh_strtod(s, &s));
+        count++;
+        if (isspace(*s) || !*s)
+          break;
+        if (*s != ',') {
+          qh_fprintf_rbox(qh, qh->ferr, 6194, "rbox error: missing comma after coordinate in %s\n\n", s);
+          qh_errexit_rbox(qh, qh_ERRinput);
+        }
+      }
+      if (count < dim) {
+        for (k=dim-count; k--; )
+          qh_out1(qh, 0.0);
+      }else if (count > dim) {
+        qh_fprintf_rbox(qh, qh->ferr, 6195, "rbox error: %d coordinates instead of %d coordinates in %s\n\n",
+                  count, dim, s);
+        qh_errexit_rbox(qh, qh_ERRinput);
+      }
+      qh_fprintf_rbox(qh, qh->fout, 9394, "\n");
+      while ((s= strchr(s, 'P'))) {
+        if (isspace(s[-1]))
+          break;
+      }
+    }
+  }
+
+  /* ============= simplex distribution =============== */
+  if (issimplex+issimplex2) {
+    if (!(*simplex= (double *)qh_malloc( (size_t)(dim * (dim+1)) * sizeof(double)))) {
+      qh_fprintf_rbox(qh, qh->ferr, 6196, "rbox error: insufficient memory for simplex\n");
+      qh_errexit_rbox(qh, qh_ERRmem); /* qh_ERRmem */
+    }
+    simplexp= *simplex;
+    if (isregular) {
+      for (i=0; ifout, 9395, "\n");
+      }
+    }
+    for (j=0; jferr, 6197, "rbox error: regular points can be used only in 2-d and 3-d\n\n");
+      qh_errexit_rbox(qh, qh_ERRinput);
+    }
+    if (!isaxis || radius == 0.0) {
+      isaxis= 1;
+      radius= 1.0;
+    }
+    if (dim == 3) {
+      if (iscdd)
+        qh_out1(qh, 1.0);
+      qh_out3n(qh, 0.0, 0.0, -box);
+      if (!isgap) {
+        if (iscdd)
+          qh_out1(qh, 1.0);
+        qh_out3n(qh, 0.0, 0.0, box);
+      }
+    }
+    angle= 0.0;
+    anglediff= 2.0 * PI/numpoints;
+    for (i=0; i < numpoints; i++) {
+      angle += anglediff;
+      x= radius * cos(angle);
+      y= radius * sin(angle);
+      if (dim == 2) {
+        if (iscdd)
+          qh_out1(qh, 1.0);
+        qh_out2n(qh, x*box, y*box);
+      }else {
+        norm= sqrt(1.0 + x*x + y*y);
+        if (iscdd)
+          qh_out1(qh, 1.0);
+        qh_out3n(qh, box*x/norm, box*y/norm, box/norm);
+        if (isgap) {
+          x *= 1-gap;
+          y *= 1-gap;
+          norm= sqrt(1.0 + x*x + y*y);
+          if (iscdd)
+            qh_out1(qh, 1.0);
+          qh_out3n(qh, box*x/norm, box*y/norm, box/norm);
+        }
+      }
+    }
+  }
+  /* ============= regular points for 'r Ln D2' =============== */
+  else if (isregular && islens && dim == 2) {
+    double cos_0;
+
+    angle= lensangle;
+    anglediff= 2 * lensangle/(numpoints - 1);
+    cos_0= cos(lensangle);
+    for (i=0; i < numpoints; i++, angle -= anglediff) {
+      x= radius * sin(angle);
+      y= radius * (cos(angle) - cos_0);
+      if (iscdd)
+        qh_out1(qh, 1.0);
+      qh_out2n(qh, x*box, y*box);
+      if (i != 0 && i != numpoints - 1) {
+        if (iscdd)
+          qh_out1(qh, 1.0);
+        qh_out2n(qh, x*box, -y*box);
+      }
+    }
+  }
+  /* ============= regular points for 'r Ln D3' =============== */
+  else if (isregular && islens && dim != 2) {
+    if (dim != 3) {
+      qh_fprintf_rbox(qh, qh->ferr, 6198, "rbox error: regular points can be used only in 2-d and 3-d\n\n");
+      qh_errexit_rbox(qh, qh_ERRinput);
+    }
+    angle= 0.0;
+    anglediff= 2* PI/numpoints;
+    if (!isgap) {
+      isgap= 1;
+      gap= 0.5;
+    }
+    offset= sqrt(radius * radius - (1-gap)*(1-gap)) - lensbase;
+    for (i=0; i < numpoints; i++, angle += anglediff) {
+      x= cos(angle);
+      y= sin(angle);
+      if (iscdd)
+        qh_out1(qh, 1.0);
+      qh_out3n(qh, box*x, box*y, 0.0);
+      x *= 1-gap;
+      y *= 1-gap;
+      if (iscdd)
+        qh_out1(qh, 1.0);
+      qh_out3n(qh, box*x, box*y, box * offset);
+      if (iscdd)
+        qh_out1(qh, 1.0);
+      qh_out3n(qh, box*x, box*y, -box * offset);
+    }
+  }
+  /* ============= apex of 'Zn' distribution + gendim =============== */
+  else {
+    if (isaxis) {
+      gendim= dim-1;
+      if (iscdd)
+        qh_out1(qh, 1.0);
+      for (j=0; j < gendim; j++)
+        qh_out1(qh, 0.0);
+      qh_out1(qh, -box);
+      qh_fprintf_rbox(qh, qh->fout, 9398, "\n");
+    }else if (islens)
+      gendim= dim-1;
+    else
+      gendim= dim;
+    /* ============= generate random point in unit cube =============== */
+    for (i=0; i < numpoints; i++) {
+      norm= 0.0;
+      for (j=0; j < gendim; j++) {
+        randr= qh_RANDOMint;
+        coord[j]= 2.0 * randr/randmax - 1.0;
+        norm += coord[j] * coord[j];
+      }
+      norm= sqrt(norm);
+      /* ============= dim-1 point of 'Zn' distribution ========== */
+      if (isaxis) {
+        if (!isgap) {
+          isgap= 1;
+          gap= 1.0;
+        }
+        randr= qh_RANDOMint;
+        rangap= 1.0 - gap * randr/randmax;
+        factor= radius * rangap / norm;
+        for (j=0; jferr, 6199, "rbox error: spiral distribution is available only in 3d\n\n");
+          qh_errexit_rbox(qh, qh_ERRinput);
+        }
+        coord[0]= cos(2*PI*i/(numpoints - 1));
+        coord[1]= sin(2*PI*i/(numpoints - 1));
+        coord[2]= 2.0*(double)i/(double)(numpoints - 1) - 1.0;
+      /* ============= point of 's' distribution =============== */
+      }else if (issphere) {
+        factor= 1.0/norm;
+        if (iswidth) {
+          randr= qh_RANDOMint;
+          factor *= 1.0 - width * randr/randmax;
+        }
+        for (j=0; j randmax/2)
+          coord[dim-1]= -coord[dim-1];
+      /* ============= project 'Wn' point toward boundary =============== */
+      }else if (iswidth && !issphere) {
+        j= qh_RANDOMint % gendim;
+        if (coord[j] < 0)
+          coord[j]= -1.0 - coord[j] * width;
+        else
+          coord[j]= 1.0 - coord[j] * width;
+      }
+      /* ============= scale point to box =============== */
+      for (k=0; k=0; k--) {
+        if (j & ( 1 << k))
+          qh_out1(qh, cube);
+        else
+          qh_out1(qh, -cube);
+      }
+      qh_fprintf_rbox(qh, qh->fout, 9400, "\n");
+    }
+  }
+
+  /* ============= write diamond vertices =============== */
+  if (adddiamond) {
+    for (j=0; j=0; k--) {
+        if (j/2 != k)
+          qh_out1(qh, 0.0);
+        else if (j & 0x1)
+          qh_out1(qh, diamond);
+        else
+          qh_out1(qh, -diamond);
+      }
+      qh_fprintf_rbox(qh, qh->fout, 9401, "\n");
+    }
+  }
+
+  if (iscdd)
+    qh_fprintf_rbox(qh, qh->fout, 9402, "end\nhull\n");
+} /* rboxpoints2 */
+
+/*------------------------------------------------
+outxxx - output functions for qh_rboxpoints
+*/
+int qh_roundi(qhT *qh, double a) {
+  if (a < 0.0) {
+    if (a - 0.5 < INT_MIN) {
+      qh_fprintf_rbox(qh, qh->ferr, 6200, "rbox input error: negative coordinate %2.2g is too large.  Reduce 'Bn'\n", a);
+      qh_errexit_rbox(qh, qh_ERRinput);
+    }
+    return (int)(a - 0.5);
+  }else {
+    if (a + 0.5 > INT_MAX) {
+      qh_fprintf_rbox(qh, qh->ferr, 6201, "rbox input error: coordinate %2.2g is too large.  Reduce 'Bn'\n", a);
+      qh_errexit_rbox(qh, qh_ERRinput);
+    }
+    return (int)(a + 0.5);
+  }
+} /* qh_roundi */
+
+void qh_out1(qhT *qh, double a) {
+
+  if (qh->rbox_isinteger)
+    qh_fprintf_rbox(qh, qh->fout, 9403, "%d ", qh_roundi(qh, a+qh->rbox_out_offset));
+  else
+    qh_fprintf_rbox(qh, qh->fout, 9404, qh_REAL_1, a+qh->rbox_out_offset);
+} /* qh_out1 */
+
+void qh_out2n(qhT *qh, double a, double b) {
+
+  if (qh->rbox_isinteger)
+    qh_fprintf_rbox(qh, qh->fout, 9405, "%d %d\n", qh_roundi(qh, a+qh->rbox_out_offset), qh_roundi(qh, b+qh->rbox_out_offset));
+  else
+    qh_fprintf_rbox(qh, qh->fout, 9406, qh_REAL_2n, a+qh->rbox_out_offset, b+qh->rbox_out_offset);
+} /* qh_out2n */
+
+void qh_out3n(qhT *qh, double a, double b, double c) {
+
+  if (qh->rbox_isinteger)
+    qh_fprintf_rbox(qh, qh->fout, 9407, "%d %d %d\n", qh_roundi(qh, a+qh->rbox_out_offset), qh_roundi(qh, b+qh->rbox_out_offset), qh_roundi(qh, c+qh->rbox_out_offset));
+  else
+    qh_fprintf_rbox(qh, qh->fout, 9408, qh_REAL_3n, a+qh->rbox_out_offset, b+qh->rbox_out_offset, c+qh->rbox_out_offset);
+} /* qh_out3n */
+
+void qh_outcoord(qhT *qh, int iscdd, double *coord, int dim) {
+    double *p= coord;
+    int k;
+
+    if (iscdd)
+      qh_out1(qh, 1.0);
+    for (k=0; k < dim; k++)
+      qh_out1(qh, *(p++));
+    qh_fprintf_rbox(qh, qh->fout, 9396, "\n");
+} /* qh_outcoord */
+
+void qh_outcoincident(qhT *qh, int coincidentpoints, double radius, int iscdd, double *coord, int dim) {
+  double *p;
+  double randr, delta;
+  int i,k;
+  double randmax= qh_RANDOMmax;
+
+  for (i=0; ifout, 9410, "\n");
+  }
+} /* qh_outcoincident */
+
+/*------------------------------------------------
+   Only called from qh_rboxpoints2 or qh_fprintf_rbox
+   qh_fprintf_rbox is only called from qh_rboxpoints2
+   The largest exitcode is '255' for compatibility with exit()
+*/
+void qh_errexit_rbox(qhT *qh, int exitcode)
+{
+    longjmp(qh->rbox_errexit, exitcode);
+} /* qh_errexit_rbox */
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/stat_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/stat_r.c
new file mode 100644
index 00000000000..edc9c2fb3a3
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/stat_r.c
@@ -0,0 +1,727 @@
+/*
  ---------------------------------
+
+   stat_r.c
+   contains all statistics that are collected for qhull
+
+   see qh-stat_r.htm and stat_r.h
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/stat_r.c#9 $$Change: 3037 $
+   $DateTime: 2020/09/03 17:28:32 $$Author: bbarber $
+*/
+
+#include "qhull_ra.h"
+
+/*========== functions in alphabetic order ================*/
+
+/*---------------------------------
+
+  qh_allstatA()
+    define statistics in groups of 20
+
+  notes:
+    (otherwise, 'gcc -O2' uses too much memory)
+    uses qhstat.next
+*/
+void qh_allstatA(qhT *qh) {
+
+   /* zdef_(type,name,doc,average) */
+  zzdef_(zdoc, Zdoc2, "precision statistics", -1);
+  zdef_(zinc, Znewvertex, NULL, -1);
+  zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet", Znewvertex);
+  zzdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1);
+  zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1);
+  zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1);
+  zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1);
+
+  qh->qhstat.precision= qh->qhstat.next;  /* usually call qh_joggle_restart, printed if Q0 or QJn */
+  zzdef_(zdoc, Zdoc3, "precision problems (corrected unless 'Q0' or an error)", -1);
+  zzdef_(zinc, Zcoplanarridges, "coplanar half ridges in output", -1);
+  zzdef_(zinc, Zconcaveridges, "concave half ridges in output", -1);
+  zzdef_(zinc, Zflippedfacets, "flipped facets", -1);
+  zzdef_(zinc, Zcoplanarhorizon, "coplanar horizon facets for new vertices", -1);
+  zzdef_(zinc, Zcoplanarpart, "coplanar points during partitioning", -1);
+  zzdef_(zinc, Zminnorm, "degenerate hyperplanes recomputed with gaussian elimination", -1);
+  zzdef_(zinc, Znearlysingular, "nearly singular or axis-parallel hyperplanes", -1);
+  zzdef_(zinc, Zback0, "zero divisors during back substitute", -1);
+  zzdef_(zinc, Zgauss0, "zero divisors during gaussian elimination", -1);
+  zzdef_(zinc, Zmultiridge, "dupridges with multiple neighbors", -1);
+  zzdef_(zinc, Zflipridge, "dupridges with flip facet into good neighbor", -1);
+  zzdef_(zinc, Zflipridge2, "dupridges with flip facet into good flip neighbor", -1);
+}
+void qh_allstatB(qhT *qh) {
+  zzdef_(zdoc, Zdoc1, "summary information", -1);
+  zdef_(zinc, Zvertices, "number of vertices in output", -1);
+  zdef_(zinc, Znumfacets, "number of facets in output", -1);
+  zdef_(zinc, Znonsimplicial, "number of non-simplicial facets in output", -1);
+  zdef_(zinc, Znowsimplicial, "simplicial facets that were non-simplicial", -1);
+  zdef_(zinc, Znumridges, "number of ridges in output", -1);
+  zdef_(zadd, Znumridges, "average number of ridges per facet", Znumfacets);
+  zdef_(zmax, Zmaxridges, "maximum number of ridges", -1);
+  zdef_(zadd, Znumneighbors, "average number of neighbors per facet", Znumfacets);
+  zdef_(zmax, Zmaxneighbors, "maximum number of neighbors", -1);
+  zdef_(zadd, Znumvertices, "average number of vertices per facet", Znumfacets);
+  zdef_(zmax, Zmaxvertices, "maximum number of vertices", -1);
+  zdef_(zadd, Znumvneighbors, "average number of neighbors per vertex", Zvertices);
+  zdef_(zmax, Zmaxvneighbors, "maximum number of neighbors", -1);
+  zdef_(wadd, Wcpu, "cpu seconds for qhull after input", -1);
+  zdef_(zinc, Ztotvertices, "vertices created altogether", -1);
+  zzdef_(zinc, Zsetplane, "facets created altogether", -1);
+  zdef_(zinc, Ztotridges, "ridges created altogether", -1);
+  zdef_(zinc, Zpostfacets, "facets before post merge", -1);
+  zdef_(zadd, Znummergetot, "average merges per facet (at most 511)", Znumfacets);
+  zdef_(zmax, Znummergemax, "  maximum merges for a facet (at most 511)", -1);
+  zdef_(zinc, Zangle, NULL, -1);
+  zdef_(wadd, Wangle, "average cosine (angle) of facet normals for all ridges", Zangle);
+  zdef_(wmax, Wanglemax, "  maximum cosine of facet normals (flatest) across a ridge", -1);
+  zdef_(wmin, Wanglemin, "  minimum cosine of facet normals (sharpest) across a ridge", -1);
+  zdef_(wadd, Wareatot, "total area of facets", -1);
+  zdef_(wmax, Wareamax, "  maximum facet area", -1);
+  zdef_(wmin, Wareamin, "  minimum facet area", -1);
+}
+void qh_allstatC(qhT *qh) {
+  zdef_(zdoc, Zdoc9, "build hull statistics", -1);
+  zzdef_(zinc, Zprocessed, "points processed", -1);
+  zzdef_(zinc, Zretry, "retries due to precision problems", -1);
+  zdef_(wmax, Wretrymax, "  max. random joggle", -1);
+  zdef_(zmax, Zmaxvertex, "max. vertices at any one time", -1);
+  zdef_(zinc, Ztotvisible, "ave. visible facets per iteration", Zprocessed);
+  zdef_(zinc, Zinsidevisible, "  ave. visible facets without an horizon neighbor", Zprocessed);
+  zdef_(zadd, Zvisfacettot,  "  ave. facets deleted per iteration", Zprocessed);
+  zdef_(zmax, Zvisfacetmax,  "    maximum", -1);
+  zdef_(zadd, Zvisvertextot, "ave. visible vertices per iteration", Zprocessed);
+  zdef_(zmax, Zvisvertexmax, "    maximum", -1);
+  zdef_(zinc, Ztothorizon, "ave. horizon facets per iteration", Zprocessed);
+  zdef_(zadd, Znewfacettot,  "ave. new or merged facets per iteration", Zprocessed);
+  zdef_(zmax, Znewfacetmax,  "    maximum (includes initial simplex)", -1);
+  zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed);
+  zdef_(wadd, Wnewbalance2, "  standard deviation", -1);
+  zdef_(wadd, Wpbalance, "average partition balance", Zpbalance);
+  zdef_(wadd, Wpbalance2, "  standard deviation", -1);
+  zdef_(zinc, Zpbalance,  "  count", -1);
+  zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);
+  zdef_(zinc, Zdetfacetarea, "determinants for facet area", -1);
+  zdef_(zinc, Znoarea, "  determinants not computed because vertex too low", -1);
+  zdef_(zinc, Zdetsimplex, "determinants for initial hull or voronoi vertices", -1);
+  zdef_(zinc, Znotmax, "points ignored (!above max_outside)", -1);
+  zdef_(zinc, Zpinchedapex, "points ignored (pinched apex)", -1);
+  zdef_(zinc, Znotgood, "points ignored (!above a good facet)", -1);
+  zdef_(zinc, Znotgoodnew, "points ignored (didn't create a good new facet)", -1);
+  zdef_(zinc, Zgoodfacet, "good facets found", -1);
+  zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);
+  zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1);
+  zzdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);
+  zzdef_(zinc, Zcheckpart, "  ave. distance tests per check", Ztotcheck);
+}
+void qh_allstatD(qhT *qh) {
+  zdef_(zinc, Zvisit, "resets of visit_id", -1);
+  zdef_(zinc, Zvvisit, "  resets of vertex_visit", -1);
+  zdef_(zmax, Zvisit2max, "  max visit_id/2", -1);
+  zdef_(zmax, Zvvisit2max, "  max vertex_visit/2", -1);
+
+  zdef_(zdoc, Zdoc4, "partitioning statistics (see previous for outer planes)", -1);
+  zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1);
+  zdef_(zmax, Zdelvertexmax, "    maximum vertices deleted per iteration", -1);
+  zdef_(zinc, Zfindbest, "calls to findbest", -1);
+  zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest);
+  zdef_(zmax, Zfindbestmax, " max. facets tested", -1);
+  zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest);
+  zdef_(zinc, Zfindnew, "calls to findbestnew", -1);
+  zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew);
+  zdef_(zmax, Zfindnewmax, " max. facets tested", -1);
+  zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew);
+  zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1);
+  zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1);
+  zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon);
+  zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1);
+  zdef_(zinc, Zfindjump,       " ave. clearly better", Zfindhorizon);
+  zdef_(zinc, Znewbesthorizon, " new bestfacets during qh_findbesthorizon", -1);
+  zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1);
+  zdef_(zinc, Zpartcorner, "  repartitioned coplanar points above a corner facet", -1);
+  zdef_(zinc, Zparthidden, "  repartitioned coplanar points above a hidden facet", -1);
+  zdef_(zinc, Zparttwisted, "  repartitioned coplanar points above a twisted facet", -1);
+}
+void qh_allstatE(qhT *qh) {
+  zdef_(zinc, Zpartinside, "inside points", -1);
+  zdef_(zinc, Zpartnear, "  near inside points kept with a facet", -1);
+  zdef_(zinc, Zcoplanarinside, "  inside points that were coplanar with a facet", -1);
+  zdef_(zinc, Zbestlower, "calls to findbestlower", -1);
+  zdef_(zinc, Zbestlowerv, "  with search of vertex neighbors", -1);
+  zdef_(zinc, Zbestlowerall, "  with rare search of all facets", -1);
+  zdef_(zmax, Zbestloweralln, "  facets per search of all facets", -1);
+  zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1);
+  zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);
+  zdef_(zinc, Ztotpartition, "partitions of a point", -1);
+  zzdef_(zinc, Zpartition, "distance tests for partitioning", -1);
+  zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1);
+  zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1);
+  zdef_(zinc, Zdistgood, "distance tests for checking good point", -1);
+  zdef_(zinc, Zdistio, "distance tests for output", -1);
+  zdef_(zinc, Zdiststat, "distance tests for statistics", -1);
+  zzdef_(zinc, Zdistplane, "total number of distance tests", -1);
+  zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1);
+  zzdef_(zinc, Zpartcoplanar, "   distance tests for these partitions", -1);
+  zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1);
+}
+void qh_allstatE2(qhT *qh) {
+  zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1);
+  zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1);
+  zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup);
+  zdef_(zinc, Zhashridge, "total lookups of subridges (duplicates and boundary)", -1);
+  zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge);
+  zdef_(zinc, Zdupsame, "duplicated ridges in same merge cycle", -1);
+  zdef_(zinc, Zdupflip, "duplicated ridges with flipped facets", -1);
+
+  zdef_(zdoc, Zdoc6, "statistics for determining merges", -1);
+  zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1);
+  zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices",-1);
+  zzdef_(zinc, Zbestdist, "distance tests for best merge", -1);
+  zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1);
+  zzdef_(zinc, Zvertextests, "distance tests for vertex convexity", -1);
+  zzdef_(zinc, Zdistzero, "distance tests for checking simplicial convexity", -1);
+  zdef_(zinc, Zcoplanarangle, "coplanar angles in getmergeset", -1);
+  zdef_(zinc, Zcoplanarcentrum, "coplanar centrums or vertices in getmergeset", -1);
+  zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);
+  zdef_(zinc, Zconcavecoplanarridge, "concave-coplanar ridges in getmergeset", -1);
+  zdef_(zinc, Ztwistedridge, "twisted ridges in getmergeset", -1);
+}
+void qh_allstatF(qhT *qh) {
+  zdef_(zdoc, Zdoc7, "statistics for merging", -1);
+  zdef_(zinc, Zpremergetot, "merge iterations", -1);
+  zdef_(zadd, Zmergeinittot, "ave. initial non-convex ridges per iteration", Zpremergetot);
+  zdef_(zadd, Zmergeinitmax, "  maximum", -1);
+  zdef_(zadd, Zmergesettot, "  ave. additional non-convex ridges per iteration", Zpremergetot);
+  zdef_(zadd, Zmergesetmax, "  maximum additional in one pass", -1);
+  zdef_(zadd, Zmergeinittot2, "initial non-convex ridges for post merging", -1);
+  zdef_(zadd, Zmergesettot2, "  additional non-convex ridges", -1);
+  zdef_(wmax, Wmaxoutside, "max distance of vertex or coplanar point above facet (w/roundoff)", -1);
+  zdef_(wmin, Wminvertex, "max distance of vertex below facet (or roundoff)", -1);
+  zdef_(zinc, Zwidefacet, "centrums frozen due to a wide merge", -1);
+  zdef_(zinc, Zwidevertices, "centrums frozen due to extra vertices", -1);
+  zzdef_(zinc, Ztotmerge, "total number of facets or cycles of facets merged", -1);
+  zdef_(zinc, Zmergesimplex, "merged a simplex", -1);
+  zdef_(zinc, Zonehorizon, "simplices merged into coplanar horizon", -1);
+  zzdef_(zinc, Zcyclehorizon, "cycles of facets merged into coplanar horizon", -1);
+  zzdef_(zadd, Zcyclefacettot, "  ave. facets per cycle", Zcyclehorizon);
+  zdef_(zmax, Zcyclefacetmax, "  max. facets", -1);
+  zdef_(zinc, Zmergeintocoplanar, "new facets merged into coplanar horizon", -1);
+  zdef_(zinc, Zmergeintohorizon, "new facets merged into horizon", -1);
+  zdef_(zinc, Zmergenew, "new facets merged", -1);
+  zdef_(zinc, Zmergehorizon, "horizon facets merged into new facets", -1);
+  zdef_(zinc, Zmergevertex, "vertices deleted by merging", -1);
+  zdef_(zinc, Zcyclevertex, "vertices deleted by merging into coplanar horizon", -1);
+  zdef_(zinc, Zdegenvertex, "vertices deleted by degenerate facet", -1);
+  zdef_(zinc, Zmergeflipdup, "merges due to flipped facets in duplicated ridge", -1);
+  zdef_(zinc, Zredundant, "merges due to redundant neighbors", -1);
+  zdef_(zinc, Zredundantmerge, "  detected by qh_test_nonsimplicial_merge instead of qh_test_redundant_neighbors", -1);
+  zdef_(zadd, Ztestvneighbor, "non-convex vertex neighbors", -1);
+}
+void qh_allstatG(qhT *qh) {
+  zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1);
+  zdef_(wadd, Wacoplanartot, "  average merge distance", Zacoplanar);
+  zdef_(wmax, Wacoplanarmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1);
+  zdef_(wadd, Wcoplanartot, "  average merge distance", Zcoplanar);
+  zdef_(wmax, Wcoplanarmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zconcave, "merges due to concave facets", -1);
+  zdef_(wadd, Wconcavetot, "  average merge distance", Zconcave);
+  zdef_(wmax, Wconcavemax, "  maximum merge distance", -1);
+  zdef_(zinc, Zconcavecoplanar, "merges due to concave-coplanar facets", -1);
+  zdef_(wadd, Wconcavecoplanartot, "  average merge distance", Zconcavecoplanar);
+  zdef_(wmax, Wconcavecoplanarmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zavoidold, "coplanar/concave merges due to avoiding old merge", -1);
+  zdef_(wadd, Wavoidoldtot, "  average merge distance", Zavoidold);
+  zdef_(wmax, Wavoidoldmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zdegen, "merges due to degenerate facets", -1);
+  zdef_(wadd, Wdegentot, "  average merge distance", Zdegen);
+  zdef_(wmax, Wdegenmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zflipped, "merges due to removing flipped facets", -1);
+  zdef_(wadd, Wflippedtot, "  average merge distance", Zflipped);
+  zdef_(wmax, Wflippedmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zduplicate, "merges due to dupridges", -1);
+  zdef_(wadd, Wduplicatetot, "  average merge distance", Zduplicate);
+  zdef_(wmax, Wduplicatemax, "  maximum merge distance", -1);
+  zdef_(zinc, Ztwisted, "merges due to twisted facets", -1);
+  zdef_(wadd, Wtwistedtot, "  average merge distance", Ztwisted);
+  zdef_(wmax, Wtwistedmax, "  maximum merge distance", -1);
+}
+void qh_allstatH(qhT *qh) {
+  zdef_(zdoc, Zdoc8, "statistics for vertex merges", -1);
+  zzdef_(zinc, Zpinchduplicate, "merge pinched vertices for a duplicate ridge", -1);
+  zzdef_(zinc, Zpinchedvertex, "merge pinched vertices for a dupridge", -1);
+  zdef_(zinc, Zrenameshare, "renamed vertices shared by two facets", -1);
+  zdef_(zinc, Zrenamepinch, "renamed vertices in a pinched facet", -1);
+  zdef_(zinc, Zrenameall, "renamed vertices shared by multiple facets", -1);
+  zdef_(zinc, Zfindfail, "rename failures due to duplicated ridges", -1);
+  zdef_(zinc, Znewvertexridge, "  found new vertex in ridge", -1);
+  zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);
+  zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);
+  zdef_(zinc, Zdropdegen, "merge degenerate facets due to dropped neighbors", -1);
+  zdef_(zinc, Zdelfacetdup, "  facets deleted because of no neighbors", -1);
+  zdef_(zinc, Zremvertex, "vertices removed from facets due to no ridges", -1);
+  zdef_(zinc, Zremvertexdel, "  deleted", -1);
+  zdef_(zinc, Zretryadd, "retry qh_addpoint after merge pinched vertex", -1);
+  zdef_(zadd, Zretryaddtot, "  tot. merge pinched vertex due to dupridge", -1);
+  zdef_(zmax, Zretryaddmax, "  max. merge pinched vertex for a qh_addpoint", -1);
+  zdef_(zinc, Zintersectnum, "vertex intersections for locating redundant vertices", -1);
+  zdef_(zinc, Zintersectfail, "intersections failed to find a redundant vertex", -1);
+  zdef_(zinc, Zintersect, "intersections found redundant vertices", -1);
+  zdef_(zadd, Zintersecttot, "   ave. number found per vertex", Zintersect);
+  zdef_(zmax, Zintersectmax, "   max. found for a vertex", -1);
+  zdef_(zinc, Zvertexridge, NULL, -1);
+  zdef_(zadd, Zvertexridgetot, "  ave. number of ridges per tested vertex", Zvertexridge);
+  zdef_(zmax, Zvertexridgemax, "  max. number of ridges per tested vertex", -1);
+
+  zdef_(zdoc, Zdoc10, "memory usage statistics (in bytes)", -1);
+  zdef_(zadd, Zmemfacets, "for facets and their normals, neighbor and vertex sets", -1);
+  zdef_(zadd, Zmemvertices, "for vertices and their neighbor sets", -1);
+  zdef_(zadd, Zmempoints, "for input points, outside and coplanar sets, and qhT",-1);
+  zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);
+} /* allstat */
+
+void qh_allstatI(qhT *qh) {
+  qh->qhstat.vridges= qh->qhstat.next; /* printed in qh_produce_output2 if non-zero Zridge or Zridgemid */
+  zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1);
+  zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1);
+  zzdef_(wadd, Wridge, "  ave. distance to ridge", Zridge);
+  zzdef_(wmax, Wridgemax, "  max. distance to ridge", -1);
+  zzdef_(zinc, Zridgemid, "bounded ridges", -1);
+  zzdef_(wadd, Wridgemid, "  ave. distance of midpoint to ridge", Zridgemid);
+  zzdef_(wmax, Wridgemidmax, "  max. distance of midpoint to ridge", -1);
+  zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1);
+  zzdef_(wadd, Wridgeok, "  ave. angle to ridge", Zridgeok);
+  zzdef_(wmax, Wridgeokmax, "  max. angle to ridge", -1);
+  zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1);
+  zzdef_(wadd, Wridge0, "  ave. angle to ridge", Zridge0);
+  zzdef_(wmax, Wridge0max, "  max. angle to ridge", -1);
+
+  zdef_(zdoc, Zdoc12, "Triangulation statistics ('Qt')", -1);
+  zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1);
+  zdef_(zadd, Ztricoplanartot, "  ave. new facets created (may be deleted)", Ztricoplanar);
+  zdef_(zmax, Ztricoplanarmax, "  max. new facets created", -1);
+  zdef_(zinc, Ztrinull, "null new facets deleted (duplicated vertex)", -1);
+  zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted (same vertices)", -1);
+  zdef_(zinc, Ztridegen, "degenerate new facets in output (same ridge)", -1);
+} /* allstat */
+
+/*---------------------------------
+
+  qh_allstatistics()
+    reset printed flag for all statistics
+*/
+void qh_allstatistics(qhT *qh) {
+  int i;
+
+  for(i=ZEND; i--; )
+    qh->qhstat.printed[i]= False;
+} /* allstatistics */
+
+#if qh_KEEPstatistics
+/*---------------------------------
+
+  qh_collectstatistics()
+    collect statistics for qh.facet_list
+
+*/
+void qh_collectstatistics(qhT *qh) {
+  facetT *facet, *neighbor, **neighborp;
+  vertexT *vertex, **vertexp;
+  realT dotproduct, dist;
+  int sizneighbors, sizridges, sizvertices, i;
+
+  qh->old_randomdist= qh->RANDOMdist;
+  qh->RANDOMdist= False;
+  zval_(Zmempoints)= qh->num_points * qh->normal_size + (int)sizeof(qhT);
+  zval_(Zmemfacets)= 0;
+  zval_(Zmemridges)= 0;
+  zval_(Zmemvertices)= 0;
+  zval_(Zangle)= 0;
+  wval_(Wangle)= 0.0;
+  zval_(Znumridges)= 0;
+  zval_(Znumfacets)= 0;
+  zval_(Znumneighbors)= 0;
+  zval_(Znumvertices)= 0;
+  zval_(Znumvneighbors)= 0;
+  zval_(Znummergetot)= 0;
+  zval_(Znummergemax)= 0;
+  zval_(Zvertices)= qh->num_vertices - qh_setsize(qh, qh->del_vertices);
+  if (qh->MERGING || qh->APPROXhull || qh->JOGGLEmax < REALmax/2)
+    wmax_(Wmaxoutside, qh->max_outside);
+  if (qh->MERGING)
+    wmin_(Wminvertex, qh->min_vertex);
+  if (!qh_checklists(qh, qh->facet_list)) {
+    qh_fprintf(qh, qh->ferr, 6373, "qhull internal error: qh_checklists failed on qh_collectstatistics\n");
+    if (!qh->ERREXITcalled)
+      qh_errexit(qh, qh_ERRqhull, NULL, NULL);
+  }
+  FORALLfacets
+    facet->seen= False;
+  if (qh->DELAUNAY) {
+    FORALLfacets {
+      if (facet->upperdelaunay != qh->UPPERdelaunay)
+        facet->seen= True; /* remove from angle statistics */
+    }
+  }
+  FORALLfacets {
+    if (facet->visible && qh->NEWfacets)
+      continue;
+    sizvertices= qh_setsize(qh, facet->vertices);
+    sizneighbors= qh_setsize(qh, facet->neighbors);
+    sizridges= qh_setsize(qh, facet->ridges);
+    zinc_(Znumfacets);
+    zadd_(Znumvertices, sizvertices);
+    zmax_(Zmaxvertices, sizvertices);
+    zadd_(Znumneighbors, sizneighbors);
+    zmax_(Zmaxneighbors, sizneighbors);
+    zadd_(Znummergetot, facet->nummerge);
+    i= facet->nummerge; /* avoid warnings */
+    zmax_(Znummergemax, i);
+    if (!facet->simplicial) {
+      if (sizvertices == qh->hull_dim) {
+        zinc_(Znowsimplicial);
+      }else {
+        zinc_(Znonsimplicial);
+      }
+    }
+    if (sizridges) {
+      zadd_(Znumridges, sizridges);
+      zmax_(Zmaxridges, sizridges);
+    }
+    zadd_(Zmemfacets, (int)sizeof(facetT) + qh->normal_size + 2*SETbasesize
+       + SETelemsize * (sizneighbors + sizvertices));
+    if (facet->ridges) {
+      zadd_(Zmemridges,
+        SETbasesize + SETelemsize * sizridges + sizridges *
+         ((int)sizeof(ridgeT) + SETbasesize + SETelemsize * (qh->hull_dim-1))/2);
+    }
+    if (facet->outsideset)
+      zadd_(Zmempoints, SETbasesize + SETelemsize * qh_setsize(qh, facet->outsideset));
+    if (facet->coplanarset)
+      zadd_(Zmempoints, SETbasesize + SETelemsize * qh_setsize(qh, facet->coplanarset));
+    if (facet->seen) /* Delaunay upper envelope */
+      continue;
+    facet->seen= True;
+    FOREACHneighbor_(facet) {
+      if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge
+          || neighbor->seen || !facet->normal || !neighbor->normal)
+        continue;
+      dotproduct= qh_getangle(qh, facet->normal, neighbor->normal);
+      zinc_(Zangle);
+      wadd_(Wangle, dotproduct);
+      wmax_(Wanglemax, dotproduct)
+      wmin_(Wanglemin, dotproduct)
+    }
+    if (facet->normal) {
+      FOREACHvertex_(facet->vertices) {
+        zinc_(Zdiststat);
+        qh_distplane(qh, vertex->point, facet, &dist);
+        wmax_(Wvertexmax, dist);
+        wmin_(Wvertexmin, dist);
+      }
+    }
+  }
+  FORALLvertices {
+    if (vertex->deleted)
+      continue;
+    zadd_(Zmemvertices, (int)sizeof(vertexT));
+    if (vertex->neighbors) {
+      sizneighbors= qh_setsize(qh, vertex->neighbors);
+      zadd_(Znumvneighbors, sizneighbors);
+      zmax_(Zmaxvneighbors, sizneighbors);
+      zadd_(Zmemvertices, (int)sizeof(vertexT) + SETelemsize * sizneighbors);
+    }
+  }
+  qh->RANDOMdist= qh->old_randomdist;
+} /* collectstatistics */
+#endif /* qh_KEEPstatistics */
+
+/*---------------------------------
+
+  qh_initstatistics(qh)
+    initialize statistics
+
+  notes:
+    NOerrors -- qh_initstatistics can not use qh_errexit(), qh_fprintf, or qh.ferr
+    On first call, only qhmem.ferr is defined.  qh_memalloc is not setup.
+    Also invoked by QhullQh().
+*/
+void qh_initstatistics(qhT *qh) {
+  int i;
+  realT realx;
+  int intx;
+
+  qh_allstatistics(qh);
+  qh->qhstat.next= 0;
+  qh_allstatA(qh);
+  qh_allstatB(qh);
+  qh_allstatC(qh);
+  qh_allstatD(qh);
+  qh_allstatE(qh);
+  qh_allstatE2(qh);
+  qh_allstatF(qh);
+  qh_allstatG(qh);
+  qh_allstatH(qh);
+  qh_allstatI(qh);
+  if (qh->qhstat.next > (int)sizeof(qh->qhstat.id)) {
+    qh_fprintf_stderr(6184, "qhull internal error (qh_initstatistics): increase size of qhstat.id[].  qhstat.next %d should be <= sizeof(qh->qhstat.id) %d\n", 
+          qh->qhstat.next, (int)sizeof(qh->qhstat.id));
+#if 0 /* for locating error, Znumridges should be duplicated */
+    for(i=0; i < ZEND; i++) {
+      int j;
+      for(j=i+1; j < ZEND; j++) {
+        if (qh->qhstat.id[i] == qh->qhstat.id[j]) {
+          qh_fprintf_stderr(6185, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n",
+              qh->qhstat.id[i], i, j);
+        }
+      }
+    }
+#endif
+    qh_exit(qh_ERRqhull);  /* can not use qh_errexit() */
+  }
+  qh->qhstat.init[zinc].i= 0;
+  qh->qhstat.init[zadd].i= 0;
+  qh->qhstat.init[zmin].i= INT_MAX;
+  qh->qhstat.init[zmax].i= INT_MIN;
+  qh->qhstat.init[wadd].r= 0;
+  qh->qhstat.init[wmin].r= REALmax;
+  qh->qhstat.init[wmax].r= -REALmax;
+  for(i=0; i < ZEND; i++) {
+    if (qh->qhstat.type[i] > ZTYPEreal) {
+      realx= qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].r;
+      qh->qhstat.stats[i].r= realx;
+    }else if (qh->qhstat.type[i] != zdoc) {
+      intx= qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].i;
+      qh->qhstat.stats[i].i= intx;
+    }
+  }
+} /* initstatistics */
+
+/*---------------------------------
+
+  qh_newstats(qh )
+    returns True if statistics for zdoc
+
+  returns:
+    next zdoc
+*/
+boolT qh_newstats(qhT *qh, int idx, int *nextindex) {
+  boolT isnew= False;
+  int start, i;
+
+  if (qh->qhstat.type[qh->qhstat.id[idx]] == zdoc)
+    start= idx+1;
+  else
+    start= idx;
+  for(i= start; i < qh->qhstat.next && qh->qhstat.type[qh->qhstat.id[i]] != zdoc; i++) {
+    if (!qh_nostatistic(qh, qh->qhstat.id[i]) && !qh->qhstat.printed[qh->qhstat.id[i]])
+        isnew= True;
+  }
+  *nextindex= i;
+  return isnew;
+} /* newstats */
+
+/*---------------------------------
+
+  qh_nostatistic(qh, index )
+    true if no statistic to print
+*/
+boolT qh_nostatistic(qhT *qh, int i) {
+
+  if ((qh->qhstat.type[i] > ZTYPEreal
+       &&qh->qhstat.stats[i].r == qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].r)
+      || (qh->qhstat.type[i] < ZTYPEreal
+          &&qh->qhstat.stats[i].i == qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].i))
+    return True;
+  return False;
+} /* nostatistic */
+
+#if qh_KEEPstatistics
+/*---------------------------------
+
+  qh_printallstatistics(qh, fp, string )
+    print all statistics with header 'string'
+*/
+void qh_printallstatistics(qhT *qh, FILE *fp, const char *string) {
+
+  qh_allstatistics(qh);
+  qh_collectstatistics(qh);
+  qh_printstatistics(qh, fp, string);
+  qh_memstatistics(qh, fp);
+}
+
+
+/*---------------------------------
+
+  qh_printstatistics(qh, fp, string )
+    print statistics to a file with header 'string'
+    skips statistics with qhstat.printed[] (reset with qh_allstatistics)
+
+  see:
+    qh_printallstatistics()
+*/
+void qh_printstatistics(qhT *qh, FILE *fp, const char *string) {
+  int i, k;
+  realT ave; /* ignored */
+
+  if (qh->num_points != qh->num_vertices || zval_(Zpbalance) == 0) {
+    wval_(Wpbalance)= 0.0;
+    wval_(Wpbalance2)= 0.0;
+  }else
+    wval_(Wpbalance2)= qh_stddev(qh, zval_(Zpbalance), wval_(Wpbalance),
+                                 wval_(Wpbalance2), &ave);
+  if (zval_(Zprocessed) == 0)
+    wval_(Wnewbalance2)= 0.0;
+  else
+    wval_(Wnewbalance2)= qh_stddev(qh, zval_(Zprocessed), wval_(Wnewbalance),
+                                 wval_(Wnewbalance2), &ave);
+  qh_fprintf(qh, fp, 9350, "\n\
+%s\n\
+qhull invoked by: %s | %s\n  %s with options:\n%s\n", 
+    string, qh->rbox_command, qh->qhull_command, qh_version, qh->qhull_options);
+
+  qh_fprintf(qh, fp, 9351, "\nprecision constants:\n\
+ %6.2g max. abs. coordinate in the (transformed) input ('Qbd:n')\n\
+ %6.2g max. roundoff error for distance computation ('En')\n\
+ %6.2g max. roundoff error for angle computations\n\
+ %6.2g min. distance for outside points ('Wn')\n\
+ %6.2g min. distance for visible facets ('Vn')\n\
+ %6.2g max. distance for coplanar facets ('Un')\n\
+ %6.2g max. facet width for recomputing centrum and area\n\
+",
+  qh->MAXabs_coord, qh->DISTround, qh->ANGLEround, qh->MINoutside,
+        qh->MINvisible, qh->MAXcoplanar, qh->WIDEfacet);
+  if (qh->KEEPnearinside)
+    qh_fprintf(qh, fp, 9352, "\
+ %6.2g max. distance for near-inside points\n", qh->NEARinside);
+  if (qh->premerge_cos < REALmax/2) qh_fprintf(qh, fp, 9353, "\
+ %6.2g max. cosine for pre-merge angle\n", qh->premerge_cos);
+  if (qh->PREmerge) qh_fprintf(qh, fp, 9354, "\
+ %6.2g radius of pre-merge centrum\n", qh->premerge_centrum);
+  if (qh->postmerge_cos < REALmax/2) qh_fprintf(qh, fp, 9355, "\
+ %6.2g max. cosine for post-merge angle\n", qh->postmerge_cos);
+  if (qh->POSTmerge) qh_fprintf(qh, fp, 9356, "\
+ %6.2g radius of post-merge centrum\n", qh->postmerge_centrum);
+  qh_fprintf(qh, fp, 9357, "\
+ %6.2g max. distance for merging two simplicial facets\n\
+ %6.2g max. roundoff error for arithmetic operations\n\
+ %6.2g min. denominator for division\n\
+  zero diagonal for Gauss: ", qh->ONEmerge, REALepsilon, qh->MINdenom);
+  for(k=0; k < qh->hull_dim; k++)
+    qh_fprintf(qh, fp, 9358, "%6.2e ", qh->NEARzero[k]);
+  qh_fprintf(qh, fp, 9359, "\n\n");
+  for(i=0 ; i < qh->qhstat.next; )
+    qh_printstats(qh, fp, i, &i);
+} /* printstatistics */
+#endif /* qh_KEEPstatistics */
+
+/*---------------------------------
+
+  qh_printstatlevel(qh, fp, id )
+    print level information for a statistic
+
+  notes:
+    nop if id >= ZEND, printed, or same as initial value
+*/
+void qh_printstatlevel(qhT *qh, FILE *fp, int id) {
+
+  if (id >= ZEND || qh->qhstat.printed[id])
+    return;
+  if (qh->qhstat.type[id] == zdoc) {
+    qh_fprintf(qh, fp, 9360, "%s\n", qh->qhstat.doc[id]);
+    return;
+  }
+  if (qh_nostatistic(qh, id) || !qh->qhstat.doc[id])
+    return;
+  qh->qhstat.printed[id]= True;
+  if (qh->qhstat.count[id] != -1
+      && qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i == 0)
+    qh_fprintf(qh, fp, 9361, " *0 cnt*");
+  else if (qh->qhstat.type[id] >= ZTYPEreal && qh->qhstat.count[id] == -1)
+    qh_fprintf(qh, fp, 9362, "%7.2g", qh->qhstat.stats[id].r);
+  else if (qh->qhstat.type[id] >= ZTYPEreal && qh->qhstat.count[id] != -1)
+    qh_fprintf(qh, fp, 9363, "%7.2g", qh->qhstat.stats[id].r/ qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i);
+  else if (qh->qhstat.type[id] < ZTYPEreal && qh->qhstat.count[id] == -1)
+    qh_fprintf(qh, fp, 9364, "%7d", qh->qhstat.stats[id].i);
+  else if (qh->qhstat.type[id] < ZTYPEreal && qh->qhstat.count[id] != -1)
+    qh_fprintf(qh, fp, 9365, "%7.3g", (realT) qh->qhstat.stats[id].i / qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i);
+  qh_fprintf(qh, fp, 9366, " %s\n", qh->qhstat.doc[id]);
+} /* printstatlevel */
+
+
+/*---------------------------------
+
+  qh_printstats(qh, fp, index, nextindex )
+    print statistics for a zdoc group
+
+  returns:
+    next zdoc if non-null
+*/
+void qh_printstats(qhT *qh, FILE *fp, int idx, int *nextindex) {
+  int j, nexti;
+
+  if (qh_newstats(qh, idx, &nexti)) {
+    qh_fprintf(qh, fp, 9367, "\n");
+    for (j=idx; jqhstat.id[j]);
+  }
+  if (nextindex)
+    *nextindex= nexti;
+} /* printstats */
+
+#if qh_KEEPstatistics
+
+/*---------------------------------
+
+  qh_stddev(qh, num, tot, tot2, ave )
+    compute the standard deviation and average from statistics
+
+    tot2 is the sum of the squares
+  notes:
+    computes r.m.s.:
+      (x-ave)^2
+      == x^2 - 2x tot/num +   (tot/num)^2
+      == tot2 - 2 tot tot/num + tot tot/num
+      == tot2 - tot ave
+*/
+realT qh_stddev(qhT *qh, int num, realT tot, realT tot2, realT *ave) {
+  realT stddev;
+
+  if (num <= 0) {
+    qh_fprintf(qh, qh->ferr, 7101, "qhull warning (qh_stddev): expecting num > 0.  Got num %d, tot %4.4g, tot2 %4.4g.  Returning 0.0\n",
+      num, tot, tot2);
+    return 0.0;
+  }
+  *ave= tot/num;
+  stddev= sqrt(fabs(tot2/num - *ave * *ave));
+  return stddev;
+} /* stddev */
+#else
+realT qh_stddev(qhT *qh, int num, realT tot, realT tot2, realT *ave) { /* for qhull_r-exports.def */
+  QHULL_UNUSED(qh)
+  QHULL_UNUSED(num)
+  QHULL_UNUSED(tot)
+  QHULL_UNUSED(tot2)
+  QHULL_UNUSED(ave)
+
+  return 0.0;
+}
+#endif /* qh_KEEPstatistics */
+
+#if !qh_KEEPstatistics
+void    qh_collectstatistics(qhT *qh) {}
+void    qh_printallstatistics(qhT *qh, FILE *fp, const char *string) {}
+void    qh_printstatistics(qhT *qh, FILE *fp, const char *string) {}
+#endif
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/stat_r.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/stat_r.h
new file mode 100644
index 00000000000..41b6e5171dd
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/stat_r.h
@@ -0,0 +1,563 @@
+/*
  ---------------------------------
+
+   stat_r.h
+     contains all statistics that are collected for qhull
+
+   see qh-stat_r.htm and stat_r.c
+
+   Copyright (c) 1993-2020 The Geometry Center.
+   $Id: //main/2019/qhull/src/libqhull_r/stat_r.h#4 $$Change: 2953 $
+   $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
+
+   recompile qhull if you change this file
+
+   Integer statistics are Z* while real statistics are W*.
+
+   define MAYdebugx to call a routine at every statistic event
+
+*/
+
+#ifndef qhDEFstat
+#define qhDEFstat 1
+
+/* Depends on realT.  Do not include "libqhull_r" to avoid circular dependency */
+
+#ifndef DEFqhT
+#define DEFqhT 1
+typedef struct qhT qhT;         /* Defined by libqhull_r.h */
+#endif
+
+#ifndef DEFqhstatT
+#define DEFqhstatT 1
+typedef struct qhstatT qhstatT; /* Defined here */
+#endif
+
+/*---------------------------------
+
+  qh_KEEPstatistics
+    0 turns off statistic reporting and gathering (except zzdef/zzinc/zzadd/zzval/wwval)
+
+  set qh_KEEPstatistics in user_r.h to 0 to turn off statistics
+*/
+#ifndef qh_KEEPstatistics
+#define qh_KEEPstatistics 1
+#endif
+
+/*---------------------------------
+
+  Zxxx for integers, Wxxx for reals
+
+  notes:
+    be sure that all statistics are defined in stat_r.c
+      otherwise initialization may core dump
+    can pick up all statistics by:
+      grep '[zw].*_[(][ZW]' *.c >z.x
+    remove trailers with query">-
+    remove leaders with  query-replace-regexp [ ^I]+  (
+*/
+#if qh_KEEPstatistics
+enum qh_statistics {     /* alphabetical after Z/W */
+    Zacoplanar,
+    Wacoplanarmax,
+    Wacoplanartot,
+    Zangle,
+    Wangle,
+    Wanglemax,
+    Wanglemin,
+    Zangletests,
+    Wareatot,
+    Wareamax,
+    Wareamin,
+    Zavoidold,
+    Wavoidoldmax,
+    Wavoidoldtot,
+    Zback0,
+    Zbestcentrum,
+    Zbestdist,
+    Zbestlower,
+    Zbestlowerall,
+    Zbestloweralln,
+    Zbestlowerv,
+    Zcentrumtests,
+    Zcheckpart,
+    Zcomputefurthest,
+    Zconcave,
+    Wconcavemax,
+    Wconcavetot,
+    Zconcavecoplanar,
+    Wconcavecoplanarmax,
+    Wconcavecoplanartot,
+    Zconcavecoplanarridge,
+    Zconcaveridge,
+    Zconcaveridges,
+    Zcoplanar,
+    Wcoplanarmax,
+    Wcoplanartot,
+    Zcoplanarangle,
+    Zcoplanarcentrum,
+    Zcoplanarhorizon,
+    Zcoplanarinside,
+    Zcoplanarpart,
+    Zcoplanarridges,
+    Wcpu,
+    Zcyclefacetmax,
+    Zcyclefacettot,
+    Zcyclehorizon,
+    Zcyclevertex,
+    Zdegen,
+    Wdegenmax,
+    Wdegentot,
+    Zdegenvertex,
+    Zdelfacetdup,
+    Zdelridge,
+    Zdelvertextot,
+    Zdelvertexmax,
+    Zdetfacetarea,
+    Zdetsimplex,
+    Zdistcheck,
+    Zdistconvex,
+    Zdistgood,
+    Zdistio,
+    Zdistplane,
+    Zdiststat,
+    Zdistvertex,
+    Zdistzero,
+    Zdoc1,
+    Zdoc2,
+    Zdoc3,
+    Zdoc4,
+    Zdoc5,
+    Zdoc6,
+    Zdoc7,
+    Zdoc8,
+    Zdoc9,
+    Zdoc10,
+    Zdoc11,
+    Zdoc12,
+    Zdropdegen,
+    Zdropneighbor,
+    Zdupflip,
+    Zduplicate,
+    Wduplicatemax,
+    Wduplicatetot,
+    Zdupsame,
+    Zflipped,
+    Wflippedmax,
+    Wflippedtot,
+    Zflippedfacets,
+    Zflipridge,
+    Zflipridge2,
+    Zfindbest,
+    Zfindbestmax,
+    Zfindbesttot,
+    Zfindcoplanar,
+    Zfindfail,
+    Zfindhorizon,
+    Zfindhorizonmax,
+    Zfindhorizontot,
+    Zfindjump,
+    Zfindnew,
+    Zfindnewmax,
+    Zfindnewtot,
+    Zfindnewjump,
+    Zfindnewsharp,
+    Zgauss0,
+    Zgoodfacet,
+    Zhashlookup,
+    Zhashridge,
+    Zhashridgetest,
+    Zhashtests,
+    Zinsidevisible,
+    Zintersect,
+    Zintersectfail,
+    Zintersectmax,
+    Zintersectnum,
+    Zintersecttot,
+    Zmaxneighbors,
+    Wmaxout,
+    Wmaxoutside,
+    Zmaxridges,
+    Zmaxvertex,
+    Zmaxvertices,
+    Zmaxvneighbors,
+    Zmemfacets,
+    Zmempoints,
+    Zmemridges,
+    Zmemvertices,
+    Zmergeflipdup,
+    Zmergehorizon,
+    Zmergeinittot,
+    Zmergeinitmax,
+    Zmergeinittot2,
+    Zmergeintocoplanar,
+    Zmergeintohorizon,
+    Zmergenew,
+    Zmergesettot,
+    Zmergesetmax,
+    Zmergesettot2,
+    Zmergesimplex,
+    Zmergevertex,
+    Wmindenom,
+    Wminvertex,
+    Zminnorm,
+    Zmultiridge,
+    Znearlysingular,
+    Zredundant,
+    Wnewbalance,
+    Wnewbalance2,
+    Znewbesthorizon,
+    Znewfacettot,
+    Znewfacetmax,
+    Znewvertex,
+    Wnewvertex,
+    Wnewvertexmax,
+    Znewvertexridge,
+    Znoarea,
+    Znonsimplicial,
+    Znowsimplicial,
+    Znotgood,
+    Znotgoodnew,
+    Znotmax,
+    Znumfacets,
+    Znummergemax,
+    Znummergetot,
+    Znumneighbors,
+    Znumridges,
+    Znumvertices,
+    Znumvisibility,
+    Znumvneighbors,
+    Zonehorizon,
+    Zpartangle,
+    Zpartcoplanar,
+    Zpartcorner,
+    Zparthidden,
+    Zpartinside,
+    Zpartition,
+    Zpartitionall,
+    Zpartnear,
+    Zparttwisted,
+    Zpbalance,
+    Wpbalance,
+    Wpbalance2,
+    Zpinchduplicate,
+    Zpinchedapex,
+    Zpinchedvertex,
+    Zpostfacets,
+    Zpremergetot,
+    Zprocessed,
+    Zremvertex,
+    Zremvertexdel,
+    Zredundantmerge,
+    Zrenameall,
+    Zrenamepinch,
+    Zrenameshare,
+    Zretry,
+    Wretrymax,
+    Zretryadd,
+    Zretryaddmax,
+    Zretryaddtot,
+    Zridge,
+    Wridge,
+    Wridgemax,
+    Zridge0,
+    Wridge0,
+    Wridge0max,
+    Zridgemid,
+    Wridgemid,
+    Wridgemidmax,
+    Zridgeok,
+    Wridgeok,
+    Wridgeokmax,
+    Zsearchpoints,
+    Zsetplane,
+    Ztestvneighbor,
+    Ztotcheck,
+    Ztothorizon,
+    Ztotmerge,
+    Ztotpartcoplanar,
+    Ztotpartition,
+    Ztotridges,
+    Ztotvertices,
+    Ztotvisible,
+    Ztricoplanar,
+    Ztricoplanarmax,
+    Ztricoplanartot,
+    Ztridegen,
+    Ztrimirror,
+    Ztrinull,
+    Ztwisted,
+    Wtwistedtot,
+    Wtwistedmax,
+    Ztwistedridge,
+    Zvertextests,
+    Wvertexmax,
+    Wvertexmin,
+    Zvertexridge,
+    Zvertexridgetot,
+    Zvertexridgemax,
+    Zvertices,
+    Zvisfacettot,
+    Zvisfacetmax,
+    Zvisit,
+    Zvisit2max,
+    Zvisvertextot,
+    Zvisvertexmax,
+    Zvvisit,
+    Zvvisit2max,
+    Zwidefacet,
+    Zwidevertices,
+    ZEND};
+
+/*---------------------------------
+
+  Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0
+
+  notes:
+    be sure to use zzdef, zzinc, etc. with these statistics (no double checking!)
+*/
+#else
+enum qh_statistics {     /* for zzdef etc. macros */
+  Zback0,
+  Zbestdist,
+  Zcentrumtests,
+  Zcheckpart,
+  Zconcaveridges,
+  Zcoplanarhorizon,
+  Zcoplanarpart,
+  Zcoplanarridges,
+  Zcyclefacettot,
+  Zcyclehorizon,
+  Zdelvertextot,
+  Zdistcheck,
+  Zdistconvex,
+  Zdistplane,
+  Zdistzero,
+  Zdoc1,
+  Zdoc2,
+  Zdoc3,
+  Zdoc11,
+  Zflippedfacets,
+  Zflipridge,
+  Zflipridge2,
+  Zgauss0,
+  Zminnorm,
+  Zmultiridge,
+  Znearlysingular,
+  Wnewvertexmax,
+  Znumvisibility,
+  Zpartcoplanar,
+  Zpartition,
+  Zpartitionall,
+  Zpinchduplicate,
+  Zpinchedvertex,
+  Zprocessed,
+  Zretry,
+  Zridge,
+  Wridge,
+  Wridgemax,
+  Zridge0,
+  Wridge0,
+  Wridge0max,
+  Zridgemid,
+  Wridgemid,
+  Wridgemidmax,
+  Zridgeok,
+  Wridgeok,
+  Wridgeokmax,
+  Zsetplane,
+  Ztotcheck,
+  Ztotmerge,
+  Zvertextests,
+  ZEND};
+#endif
+
+/*---------------------------------
+
+  ztype
+    the type of a statistic sets its initial value.
+
+  notes:
+    The type should be the same as the macro for collecting the statistic
+*/
+enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend};
+
+/*========== macros and constants =============*/
+
+/*----------------------------------
+
+  MAYdebugx
+    define as maydebug() to be called frequently for error trapping
+*/
+#define MAYdebugx
+
+/*----------------------------------
+
+  zzdef_, zdef_( type, name, doc, -1)
+    define a statistic (assumes 'qhstat.next= 0;')
+
+  zdef_( type, name, doc, count)
+    define an averaged statistic
+    printed as name/count
+*/
+#define zzdef_(stype,name,string,cnt) qh->qhstat.id[qh->qhstat.next++]=name; \
+   qh->qhstat.doc[name]= string; qh->qhstat.count[name]= cnt; qh->qhstat.type[name]= stype
+#if qh_KEEPstatistics
+#define zdef_(stype,name,string,cnt) qh->qhstat.id[qh->qhstat.next++]=name; \
+   qh->qhstat.doc[name]= string; qh->qhstat.count[name]= cnt; qh->qhstat.type[name]= stype
+#else
+#define zdef_(type,name,doc,count)
+#endif
+
+/*----------------------------------
+
+  zzinc_( name ), zinc_( name)
+    increment an integer statistic
+*/
+#define zzinc_(id) {MAYdebugx; qh->qhstat.stats[id].i++;}
+#if qh_KEEPstatistics
+#define zinc_(id) {MAYdebugx; qh->qhstat.stats[id].i++;}
+#else
+#define zinc_(id) {}
+#endif
+
+/*----------------------------------
+
+  zzadd_( name, value ), zadd_( name, value ), wadd_( name, value )
+    add value to an integer or real statistic
+*/
+#define zzadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].i += (val);}
+#define wwadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].r += (val);}
+#if qh_KEEPstatistics
+#define zadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].i += (val);}
+#define wadd_(id, val) {MAYdebugx; qh->qhstat.stats[id].r += (val);}
+#else
+#define zadd_(id, val) {}
+#define wadd_(id, val) {}
+#endif
+
+/*----------------------------------
+
+  zzval_( name ), zval_( name ), wwval_( name )
+    set or return value of a statistic
+*/
+#define zzval_(id) ((qh->qhstat.stats[id]).i)
+#define wwval_(id) ((qh->qhstat.stats[id]).r)
+#if qh_KEEPstatistics
+#define zval_(id) ((qh->qhstat.stats[id]).i)
+#define wval_(id) ((qh->qhstat.stats[id]).r)
+#else
+#define zval_(id) qh->qhstat.tempi
+#define wval_(id) qh->qhstat.tempr
+#endif
+
+/*----------------------------------
+
+  zmax_( id, val ), wmax_( id, value )
+    maximize id with val
+*/
+#define wwmax_(id, val) {MAYdebugx; maximize_(qh->qhstat.stats[id].r,(val));}
+#if qh_KEEPstatistics
+#define zmax_(id, val) {MAYdebugx; maximize_(qh->qhstat.stats[id].i,(val));}
+#define wmax_(id, val) {MAYdebugx; maximize_(qh->qhstat.stats[id].r,(val));}
+#else
+#define zmax_(id, val) {}
+#define wmax_(id, val) {}
+#endif
+
+/*----------------------------------
+
+  zmin_( id, val ), wmin_( id, value )
+    minimize id with val
+*/
+#if qh_KEEPstatistics
+#define zmin_(id, val) {MAYdebugx; minimize_(qh->qhstat.stats[id].i,(val));}
+#define wmin_(id, val) {MAYdebugx; minimize_(qh->qhstat.stats[id].r,(val));}
+#else
+#define zmin_(id, val) {}
+#define wmin_(id, val) {}
+#endif
+
+/*================== stat_r.h types ==============*/
+
+
+/*----------------------------------
+
+  intrealT
+    union of integer and real, used for statistics
+*/
+typedef union intrealT intrealT;    /* union of int and realT */
+union intrealT {
+    int i;
+    realT r;
+};
+
+/*----------------------------------
+
+  qhstat
+    Data structure for statistics, similar to qh and qhrbox
+
+    Allocated as part of qhT (libqhull_r.h)
+*/
+
+struct qhstatT {
+  intrealT   stats[ZEND];     /* integer and real statistics */
+  unsigned char id[ZEND+10];  /* id's in print order */
+  const char *doc[ZEND];      /* array of documentation strings */
+  short int  count[ZEND];     /* -1 if none, else index of count to use */
+  char       type[ZEND];      /* type, see ztypes above */
+  char       printed[ZEND];   /* true, if statistic has been printed */
+  intrealT   init[ZTYPEend];  /* initial values by types, set initstatistics */
+
+  int        next;            /* next index for zdef_ */
+  int        precision;       /* index for precision problems, printed on qh_errexit and qh_produce_output2/Q0/QJn */
+  int        vridges;         /* index for Voronoi ridges, printed on qh_produce_output2 */
+  int        tempi;
+  realT      tempr;
+};
+
+/*========== function prototypes ===========*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void    qh_allstatA(qhT *qh);
+void    qh_allstatB(qhT *qh);
+void    qh_allstatC(qhT *qh);
+void    qh_allstatD(qhT *qh);
+void    qh_allstatE(qhT *qh);
+void    qh_allstatE2(qhT *qh);
+void    qh_allstatF(qhT *qh);
+void    qh_allstatG(qhT *qh);
+void    qh_allstatH(qhT *qh);
+void    qh_allstatI(qhT *qh);
+void    qh_allstatistics(qhT *qh);
+void    qh_collectstatistics(qhT *qh);
+void    qh_initstatistics(qhT *qh);
+boolT   qh_newstats(qhT *qh, int idx, int *nextindex);
+boolT   qh_nostatistic(qhT *qh, int i);
+void    qh_printallstatistics(qhT *qh, FILE *fp, const char *string);
+void    qh_printstatistics(qhT *qh, FILE *fp, const char *string);
+void    qh_printstatlevel(qhT *qh, FILE *fp, int id);
+void    qh_printstats(qhT *qh, FILE *fp, int idx, int *nextindex);
+realT   qh_stddev(qhT *qh, int num, realT tot, realT tot2, realT *ave);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif   /* qhDEFstat */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/user_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/user_r.c
new file mode 100644
index 00000000000..70eab8b156e
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/user_r.c
@@ -0,0 +1,617 @@
+/*
  ---------------------------------
+
+   user_r.c
+   user redefinable functions
+
+   see user2_r.c for qh_fprintf, qh_malloc, qh_free
+
+   see README.txt  see COPYING.txt for copyright information.
+
+   see libqhull_r.h for data structures, macros, and user-callable functions.
+
+   see user_eg_r.c, user_eg2_r.c, and unix_r.c for examples.
+
+   see user_r.h for user-definable constants
+
+      use qh_NOmem in mem_r.h to turn off memory management
+      use qh_NOmerge in user_r.h to turn off facet merging
+      set qh_KEEPstatistics in user_r.h to 0 to turn off statistics
+
+   This is unsupported software.  You're welcome to make changes,
+   but you're on your own if something goes wrong.  Use 'Tc' to
+   check frequently.  Usually qhull will report an error if
+   a data structure becomes inconsistent.  If so, it also reports
+   the last point added to the hull, e.g., 102.  You can then trace
+   the execution of qhull with "T4P102".
+
+   Please report any errors that you fix to qhull@qhull.org
+
+   Qhull-template is a template for calling qhull from within your application
+
+   if you recompile and load this module, then user.o will not be loaded
+   from qhull.a
+
+   you can add additional quick allocation sizes in qh_user_memsizes
+
+   if the other functions here are redefined to not use qh_print...,
+   then io.o will not be loaded from qhull.a.  See user_eg_r.c for an
+   example.  We recommend keeping io.o for the extra debugging
+   information it supplies.
+*/
+
+#include "qhull_ra.h"
+
+#include 
+
+/*---------------------------------
+
+  Qhull-template
+    Template for calling qhull from inside your program
+
+  returns:
+    exit code(see qh_ERR... in libqhull_r.h)
+    all memory freed
+
+  notes:
+    This can be called any number of times.
+*/
+#if 0
+{
+  int dim;                  /* dimension of points */
+  int numpoints;            /* number of points */
+  coordT *points;           /* array of coordinates for each point */
+  boolT ismalloc;           /* True if qhull should free points in qh_freeqhull() or reallocation */
+  char flags[]= "qhull Tv"; /* option flags for qhull, see html/qh-quick.htm */
+  FILE *outfile= stdout;    /* output from qh_produce_output
+                               use NULL to skip qh_produce_output */
+  FILE *errfile= stderr;    /* error messages from qhull code */
+  int exitcode;             /* 0 if no error from qhull */
+  facetT *facet;            /* set by FORALLfacets */
+  int curlong, totlong;     /* memory remaining after qh_memfreeshort */
+
+  qhT qh_qh;                /* Qhull's data structure.  First argument of most calls */
+  qhT *qh= &qh_qh;          /* Alternatively -- qhT *qh= (qhT *)malloc(sizeof(qhT)) */
+
+  QHULL_LIB_CHECK /* Check for compatible library */
+
+  qh_zero(qh, errfile);
+
+  /* initialize dim, numpoints, points[], ismalloc here */
+  exitcode= qh_new_qhull(qh, dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile);
+  if (!exitcode) {                  /* if no error */
+    /* 'qh->facet_list' contains the convex hull */
+    FORALLfacets {
+       /* ... your code ... */
+    }
+  }
+  qh_freeqhull(qh, !qh_ALL);
+  qh_memfreeshort(qh, &curlong, &totlong);
+  if (curlong || totlong)
+    qh_fprintf(qh, errfile, 7079, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n", totlong, curlong);
+}
+#endif
+
+/*---------------------------------
+
+  qh_new_qhull(qh, dim, numpoints, points, ismalloc, qhull_cmd, outfile, errfile )
+    Run qhull
+    Before first call, either call qh_zero(qh, errfile), or set qh to all zero.
+
+  returns:
+    results in qh
+    exitcode (0 if no errors).
+
+  notes:
+    do not modify points until finished with results.
+      The qhull data structure contains pointers into the points array.
+    do not call qhull functions before qh_new_qhull().
+      The qhull data structure is not initialized until qh_new_qhull().
+    do not call qh_init_A (global_r.c)
+
+    Default errfile is stderr, outfile may be null
+    qhull_cmd must start with "qhull "
+    projects points to a new point array for Delaunay triangulations ('d' and 'v')
+    transforms points into a new point array for halfspace intersection ('H')
+
+  see:
+    Qhull-template at the beginning of this file.
+    An example of using qh_new_qhull is user_eg_r.c
+*/
+int qh_new_qhull(qhT *qh, int dim, int numpoints, coordT *points, boolT ismalloc,
+                char *qhull_cmd, FILE *outfile, FILE *errfile) {
+  /* gcc may issue a "might be clobbered" warning for dim, points, and ismalloc [-Wclobbered].
+     These parameters are not referenced after a longjmp() and hence not clobbered.
+     See http://stackoverflow.com/questions/7721854/what-sense-do-these-clobbered-variable-warnings-make */
+  int exitcode, hulldim;
+  boolT new_ismalloc;
+  coordT *new_points;
+
+  if(!errfile){
+    errfile= stderr;
+  }
+  if (!qh->qhmem.ferr) {
+    qh_meminit(qh, errfile);
+  } else {
+    qh_memcheck(qh);
+  }
+  if (strncmp(qhull_cmd, "qhull ", (size_t)6) && strcmp(qhull_cmd, "qhull") != 0) {
+    qh_fprintf(qh, errfile, 6186, "qhull error (qh_new_qhull): start qhull_cmd argument with \"qhull \" or set to \"qhull\"\n");
+    return qh_ERRinput;
+  }
+  qh_initqhull_start(qh, NULL, outfile, errfile);
+  if(numpoints==0 && points==NULL){
+      trace1((qh, qh->ferr, 1047, "qh_new_qhull: initialize Qhull\n"));
+      return 0;
+  }
+  trace1((qh, qh->ferr, 1044, "qh_new_qhull: build new Qhull for %d %d-d points with %s\n", numpoints, dim, qhull_cmd));
+  exitcode= setjmp(qh->errexit);
+  if (!exitcode) {
+    qh->NOerrexit= False;
+    qh_initflags(qh, qhull_cmd);
+    if (qh->DELAUNAY)
+      qh->PROJECTdelaunay= True;
+    if (qh->HALFspace) {
+      /* points is an array of halfspaces,
+         the last coordinate of each halfspace is its offset */
+      hulldim= dim-1;
+      qh_setfeasible(qh, hulldim);
+      new_points= qh_sethalfspace_all(qh, dim, numpoints, points, qh->feasible_point);
+      new_ismalloc= True;
+      if (ismalloc)
+        qh_free(points);
+    }else {
+      hulldim= dim;
+      new_points= points;
+      new_ismalloc= ismalloc;
+    }
+    qh_init_B(qh, new_points, numpoints, hulldim, new_ismalloc);
+    qh_qhull(qh);
+    qh_check_output(qh);
+    if (outfile) {
+      qh_produce_output(qh);
+    }else {
+      qh_prepare_output(qh);
+    }
+    if (qh->VERIFYoutput && !qh->FORCEoutput && !qh->STOPadd && !qh->STOPcone && !qh->STOPpoint)
+      qh_check_points(qh);
+  }
+  qh->NOerrexit= True;
+  return exitcode;
+} /* new_qhull */
+
+/*---------------------------------
+
+  qh_errexit(qh, exitcode, facet, ridge )
+    report and exit from an error
+    report facet and ridge if non-NULL
+    reports useful information such as last point processed
+    set qh.FORCEoutput to print neighborhood of facet
+
+  see:
+    qh_errexit2() in libqhull_r.c for printing 2 facets
+
+  design:
+    check for error within error processing
+    compute qh.hulltime
+    print facet and ridge (if any)
+    report commandString, options, qh.furthest_id
+    print summary and statistics (including precision statistics)
+    if qh_ERRsingular
+      print help text for singular data set
+    exit program via long jump (if defined) or exit()
+*/
+void qh_errexit(qhT *qh, int exitcode, facetT *facet, ridgeT *ridge) {
+
+  qh->tracefacet= NULL;  /* avoid infinite recursion through qh_fprintf */
+  qh->traceridge= NULL;
+  qh->tracevertex= NULL;
+  if (qh->ERREXITcalled) {
+    qh_fprintf(qh, qh->ferr, 8126, "\nqhull error while handling previous error in qh_errexit.  Exit program\n");
+    qh_exit(qh_ERRother);
+  }
+  qh->ERREXITcalled= True;
+  if (!qh->QHULLfinished)
+    qh->hulltime= qh_CPUclock - qh->hulltime;
+  qh_errprint(qh, "ERRONEOUS", facet, NULL, ridge, NULL);
+  qh_option(qh, "_maxoutside", NULL, &qh->MAXoutside);
+  qh_fprintf(qh, qh->ferr, 8127, "\nWhile executing: %s | %s\n", qh->rbox_command, qh->qhull_command);
+  qh_fprintf(qh, qh->ferr, 8128, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);
+  if (qh->furthest_id >= 0) {
+    qh_fprintf(qh, qh->ferr, 8129, "Last point added to hull was p%d.", qh->furthest_id);
+    if (zzval_(Ztotmerge))
+      qh_fprintf(qh, qh->ferr, 8130, "  Last merge was #%d.", zzval_(Ztotmerge));
+    if (qh->QHULLfinished)
+      qh_fprintf(qh, qh->ferr, 8131, "\nQhull has finished constructing the hull.");
+    else if (qh->POSTmerging)
+      qh_fprintf(qh, qh->ferr, 8132, "\nQhull has started post-merging.");
+    qh_fprintf(qh, qh->ferr, 8133, "\n");
+  }
+  if (qh->FORCEoutput && (qh->QHULLfinished || (!facet && !ridge)))
+    qh_produce_output(qh);
+  else if (exitcode != qh_ERRinput) {
+    if (exitcode != qh_ERRsingular && zzval_(Zsetplane) > qh->hull_dim+1) {
+      qh_fprintf(qh, qh->ferr, 8134, "\nAt error exit:\n");
+      qh_printsummary(qh, qh->ferr);
+      if (qh->PRINTstatistics) {
+        qh_collectstatistics(qh);
+        qh_allstatistics(qh);
+        qh_printstatistics(qh, qh->ferr, "at error exit");
+        qh_memstatistics(qh, qh->ferr);
+      }
+    }
+    if (qh->PRINTprecision)
+      qh_printstats(qh, qh->ferr, qh->qhstat.precision, NULL);
+  }
+  if (!exitcode)
+    exitcode= qh_ERRother;
+  else if (exitcode == qh_ERRprec && !qh->PREmerge)
+    qh_printhelp_degenerate(qh, qh->ferr);
+  else if (exitcode == qh_ERRqhull)
+    qh_printhelp_internal(qh, qh->ferr);
+  else if (exitcode == qh_ERRsingular)
+    qh_printhelp_singular(qh, qh->ferr);
+  else if (exitcode == qh_ERRdebug)
+    qh_fprintf(qh, qh->ferr, 8016, "qhull exit due to qh_ERRdebug\n");
+  else if (exitcode == qh_ERRtopology || exitcode == qh_ERRwide || exitcode == qh_ERRprec) {
+    if (qh->NOpremerge && !qh->MERGING)
+      qh_printhelp_degenerate(qh, qh->ferr);
+    else if (exitcode == qh_ERRtopology)
+      qh_printhelp_topology(qh, qh->ferr);
+    else if (exitcode == qh_ERRwide)
+      qh_printhelp_wide(qh, qh->ferr);
+  }else if (exitcode > 255) {
+    qh_fprintf(qh, qh->ferr, 6426, "qhull internal error (qh_errexit): exit code %d is greater than 255.  Invalid argument for exit().  Replaced with 255\n", exitcode);
+    exitcode= 255;
+  }
+  if (qh->NOerrexit) {
+    qh_fprintf(qh, qh->ferr, 6187, "qhull internal error (qh_errexit): either error while reporting error QH%d, or qh.NOerrexit not cleared after setjmp(). Exit program with error status %d\n",
+         qh->last_errcode, exitcode);
+    qh_exit(exitcode);
+  }
+  qh->ERREXITcalled= False;
+  qh->NOerrexit= True;
+  qh->ALLOWrestart= False;  /* longjmp will undo qh_build_withrestart */
+  longjmp(qh->errexit, exitcode);
+} /* errexit */
+
+/*---------------------------------
+
+  qh_errprint(qh, fp, string, atfacet, otherfacet, atridge, atvertex )
+    prints out the information of facets and ridges to fp
+    also prints neighbors and geomview output
+
+  notes:
+    except for string, any parameter may be NULL
+*/
+void qh_errprint(qhT *qh, const char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {
+  int i;
+
+  if (atvertex) {
+    qh_fprintf(qh, qh->ferr, 8138, "%s VERTEX:\n", string);
+    qh_printvertex(qh, qh->ferr, atvertex);
+  }
+  if (atridge) {
+    qh_fprintf(qh, qh->ferr, 8137, "%s RIDGE:\n", string);
+    qh_printridge(qh, qh->ferr, atridge);
+    if (!atfacet)
+      atfacet= atridge->top;
+    if (!otherfacet)
+      otherfacet= otherfacet_(atridge, atfacet);
+    if (atridge->top && atridge->top != atfacet && atridge->top != otherfacet)
+      qh_printfacet(qh, qh->ferr, atridge->top);
+    if (atridge->bottom && atridge->bottom != atfacet && atridge->bottom != otherfacet)
+      qh_printfacet(qh, qh->ferr, atridge->bottom);
+  }
+  if (atfacet) {
+    qh_fprintf(qh, qh->ferr, 8135, "%s FACET:\n", string);
+    qh_printfacet(qh, qh->ferr, atfacet);
+  }
+  if (otherfacet) {
+    qh_fprintf(qh, qh->ferr, 8136, "%s OTHER FACET:\n", string);
+    qh_printfacet(qh, qh->ferr, otherfacet);
+  }
+  if (qh->fout && qh->FORCEoutput && atfacet && !qh->QHULLfinished && !qh->IStracing) {
+    qh_fprintf(qh, qh->ferr, 8139, "ERRONEOUS and NEIGHBORING FACETS to output\n");
+    for (i=0; i < qh_PRINTEND; i++)  /* use fout for geomview output */
+      qh_printneighborhood(qh, qh->fout, qh->PRINTout[i], atfacet, otherfacet,
+                            !qh_ALL);
+  }
+} /* errprint */
+
+
+/*---------------------------------
+
+  qh_printfacetlist(qh, fp, facetlist, facets, printall )
+    print all fields for a facet list and/or set of facets to fp
+    if !printall,
+      only prints good facets
+
+  notes:
+    also prints all vertices
+*/
+void qh_printfacetlist(qhT *qh, facetT *facetlist, setT *facets, boolT printall) {
+  facetT *facet, **facetp;
+
+  if (facetlist)
+    qh_checklists(qh, facetlist);
+  qh_fprintf(qh, qh->ferr, 9424, "printfacetlist: vertices\n");
+  qh_printbegin(qh, qh->ferr, qh_PRINTfacets, facetlist, facets, printall);
+  if (facetlist) {
+    qh_fprintf(qh, qh->ferr, 9413, "printfacetlist: facetlist\n");
+    FORALLfacet_(facetlist)
+      qh_printafacet(qh, qh->ferr, qh_PRINTfacets, facet, printall);
+  }
+  if (facets) {
+    qh_fprintf(qh, qh->ferr, 9414, "printfacetlist: %d facets\n", qh_setsize(qh, facets));
+    FOREACHfacet_(facets)
+      qh_printafacet(qh, qh->ferr, qh_PRINTfacets, facet, printall);
+  }
+  qh_fprintf(qh, qh->ferr, 9412, "printfacetlist: end\n");
+  qh_printend(qh, qh->ferr, qh_PRINTfacets, facetlist, facets, printall);
+} /* printfacetlist */
+
+
+/*---------------------------------
+
+  qh_printhelp_degenerate(qh, fp )
+    prints descriptive message for precision error with qh_ERRprec
+
+  notes:
+    no message if qh_QUICKhelp
+*/
+void qh_printhelp_degenerate(qhT *qh, FILE *fp) {
+
+  if (qh->MERGEexact || qh->PREmerge || qh->JOGGLEmax < REALmax/2)
+    qh_fprintf(qh, fp, 9368, "\n\
+A Qhull error has occurred.  Qhull should have corrected the above\n\
+precision error.  Please send the input and all of the output to\n\
+qhull_bug@qhull.org\n");
+  else if (!qh_QUICKhelp) {
+    qh_fprintf(qh, fp, 9369, "\n\
+Precision problems were detected during construction of the convex hull.\n\
+This occurs because convex hull algorithms assume that calculations are\n\
+exact, but floating-point arithmetic has roundoff errors.\n\
+\n\
+To correct for precision problems, do not use 'Q0'.  By default, Qhull\n\
+selects 'C-0' or 'Qx' and merges non-convex facets.  With option 'QJ',\n\
+Qhull joggles the input to prevent precision problems.  See \"Imprecision\n\
+in Qhull\" (qh-impre.htm).\n\
+\n\
+If you use 'Q0', the output may include\n\
+coplanar ridges, concave ridges, and flipped facets.  In 4-d and higher,\n\
+Qhull may produce a ridge with four neighbors or two facets with the same \n\
+vertices.  Qhull reports these events when they occur.  It stops when a\n\
+concave ridge, flipped facet, or duplicate facet occurs.\n");
+#if REALfloat
+    qh_fprintf(qh, fp, 9370, "\
+\n\
+Qhull is currently using single precision arithmetic.  The following\n\
+will probably remove the precision problems:\n\
+  - recompile qhull for realT precision(#define REALfloat 0 in user_r.h).\n");
+#endif
+    if (qh->DELAUNAY && !qh->SCALElast && qh->MAXabs_coord > 1e4)
+      qh_fprintf(qh, fp, 9371, "\
+\n\
+When computing the Delaunay triangulation of coordinates > 1.0,\n\
+  - use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");
+    if (qh->DELAUNAY && !qh->ATinfinity)
+      qh_fprintf(qh, fp, 9372, "\
+When computing the Delaunay triangulation:\n\
+  - use 'Qz' to add a point at-infinity.  This reduces precision problems.\n");
+
+    qh_fprintf(qh, fp, 9373, "\
+\n\
+If you need triangular output:\n\
+  - use option 'Qt' to triangulate the output\n\
+  - use option 'QJ' to joggle the input points and remove precision errors\n\
+  - use option 'Ft'.  It triangulates non-simplicial facets with added points.\n\
+\n\
+If you must use 'Q0',\n\
+try one or more of the following options.  They can not guarantee an output.\n\
+  - use 'QbB' to scale the input to a cube.\n\
+  - use 'Po' to produce output and prevent partitioning for flipped facets\n\
+  - use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\
+  - use 'En' to specify a maximum roundoff error less than %2.2g.\n\
+  - options 'Qf', 'Qbb', and 'QR0' may also help\n",
+               qh->DISTround);
+    qh_fprintf(qh, fp, 9374, "\
+\n\
+To guarantee simplicial output:\n\
+  - use option 'Qt' to triangulate the output\n\
+  - use option 'QJ' to joggle the input points and remove precision errors\n\
+  - use option 'Ft' to triangulate the output by adding points\n\
+  - use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\
+");
+  }
+} /* printhelp_degenerate */
+
+/*---------------------------------
+
+  qh_printhelp_internal(qh, fp )
+    prints descriptive message for qhull internal error with qh_ERRqhull
+
+  notes:
+    no message if qh_QUICKhelp
+*/
+void qh_printhelp_internal(qhT *qh, FILE *fp) {
+
+  if (!qh_QUICKhelp) {
+    qh_fprintf(qh, fp, 9426, "\n\
+A Qhull internal error has occurred.  Please send the input and output to\n\
+qhull_bug@qhull.org. If you can duplicate the error with logging ('T4z'), please\n\
+include the log file.\n");
+  }
+} /* printhelp_internal */
+
+/*---------------------------------
+
+  qh_printhelp_narrowhull(qh, minangle )
+    Warn about a narrow hull
+
+  notes:
+    Alternatively, reduce qh_WARNnarrow in user_r.h
+
+*/
+void qh_printhelp_narrowhull(qhT *qh, FILE *fp, realT minangle) {
+
+    qh_fprintf(qh, fp, 7089, "qhull precision warning: The initial hull is narrow.  Is the input lower\n\
+dimensional (e.g., a square in 3-d instead of a cube)?  Cosine of the minimum\n\
+angle is %.16f.  If so, Qhull may produce a wide facet.\n\
+Options 'Qs' (search all points), 'Qbb' (scale last coordinate), or\n\
+'QbB' (scale to unit box) may remove this warning.\n\
+See 'Limitations' in qh-impre.htm.  Use 'Pp' to skip this warning.\n",
+          -minangle);   /* convert from angle between normals to angle between facets */
+} /* printhelp_narrowhull */
+
+/*---------------------------------
+
+  qh_printhelp_singular(qh, fp )
+    prints descriptive message for singular input
+*/
+void qh_printhelp_singular(qhT *qh, FILE *fp) {
+  facetT *facet;
+  vertexT *vertex, **vertexp;
+  realT min, max, *coord, dist;
+  int i,k;
+
+  qh_fprintf(qh, fp, 9376, "\n\
+The input to qhull appears to be less than %d dimensional, or a\n\
+computation has overflowed.\n\n\
+Qhull could not construct a clearly convex simplex from points:\n",
+           qh->hull_dim);
+  qh_printvertexlist(qh, fp, "", qh->facet_list, NULL, qh_ALL);
+  if (!qh_QUICKhelp)
+    qh_fprintf(qh, fp, 9377, "\n\
+The center point is coplanar with a facet, or a vertex is coplanar\n\
+with a neighboring facet.  The maximum round off error for\n\
+computing distances is %2.2g.  The center point, facets and distances\n\
+to the center point are as follows:\n\n", qh->DISTround);
+  qh_printpointid(qh, fp, "center point", qh->hull_dim, qh->interior_point, qh_IDunknown);
+  qh_fprintf(qh, fp, 9378, "\n");
+  FORALLfacets {
+    qh_fprintf(qh, fp, 9379, "facet");
+    FOREACHvertex_(facet->vertices)
+      qh_fprintf(qh, fp, 9380, " p%d", qh_pointid(qh, vertex->point));
+    zinc_(Zdistio);
+    qh_distplane(qh, qh->interior_point, facet, &dist);
+    qh_fprintf(qh, fp, 9381, " distance= %4.2g\n", dist);
+  }
+  if (!qh_QUICKhelp) {
+    if (qh->HALFspace)
+      qh_fprintf(qh, fp, 9382, "\n\
+These points are the dual of the given halfspaces.  They indicate that\n\
+the intersection is degenerate.\n");
+    qh_fprintf(qh, fp, 9383,"\n\
+These points either have a maximum or minimum x-coordinate, or\n\
+they maximize the determinant for k coordinates.  Trial points\n\
+are first selected from points that maximize a coordinate.\n");
+    if (qh->hull_dim >= qh_INITIALmax)
+      qh_fprintf(qh, fp, 9384, "\n\
+Because of the high dimension, the min x-coordinate and max-coordinate\n\
+points are used if the determinant is non-zero.  Option 'Qs' will\n\
+do a better, though much slower, job.  Instead of 'Qs', you can change\n\
+the points by randomly rotating the input with 'QR0'.\n");
+  }
+  qh_fprintf(qh, fp, 9385, "\nThe min and max coordinates for each dimension are:\n");
+  for (k=0; k < qh->hull_dim; k++) {
+    min= REALmax;
+    max= -REALmax;
+    for (i=qh->num_points, coord= qh->first_point+k; i--; coord += qh->hull_dim) {
+      maximize_(max, *coord);
+      minimize_(min, *coord);
+    }
+    qh_fprintf(qh, fp, 9386, "  %d:  %8.4g  %8.4g  difference= %4.4g\n", k, min, max, max-min);
+  }
+  if (!qh_QUICKhelp) {
+    qh_fprintf(qh, fp, 9387, "\n\
+If the input should be full dimensional, you have several options that\n\
+may determine an initial simplex:\n\
+  - use 'QJ'  to joggle the input and make it full dimensional\n\
+  - use 'QbB' to scale the points to the unit cube\n\
+  - use 'QR0' to randomly rotate the input for different maximum points\n\
+  - use 'Qs'  to search all points for the initial simplex\n\
+  - use 'En'  to specify a maximum roundoff error less than %2.2g.\n\
+  - trace execution with 'T3' to see the determinant for each point.\n",
+                     qh->DISTround);
+#if REALfloat
+    qh_fprintf(qh, fp, 9388, "\
+  - recompile qhull for realT precision(#define REALfloat 0 in libqhull_r.h).\n");
+#endif
+    qh_fprintf(qh, fp, 9389, "\n\
+If the input is lower dimensional:\n\
+  - use 'QJ' to joggle the input and make it full dimensional\n\
+  - use 'Qbk:0Bk:0' to delete coordinate k from the input.  You should\n\
+    pick the coordinate with the least range.  The hull will have the\n\
+    correct topology.\n\
+  - determine the flat containing the points, rotate the points\n\
+    into a coordinate plane, and delete the other coordinates.\n\
+  - add one or more points to make the input full dimensional.\n\
+");
+  }
+} /* printhelp_singular */
+
+/*---------------------------------
+
+  qh_printhelp_topology(qh, fp )
+    prints descriptive message for qhull topology error with qh_ERRtopology
+
+  notes:
+    no message if qh_QUICKhelp
+*/
+void qh_printhelp_topology(qhT *qh, FILE *fp) {
+
+  if (!qh_QUICKhelp) {
+    qh_fprintf(qh, fp, 9427, "\n\
+A Qhull topology error has occurred.  Qhull did not recover from facet merges and vertex merges.\n\
+This usually occurs when the input is nearly degenerate and substantial merging has occurred.\n\
+See http://www.qhull.org/html/qh-impre.htm#limit\n");
+  }
+} /* printhelp_topology */
+
+/*---------------------------------
+
+  qh_printhelp_wide(qh, fp )
+    prints descriptive message for qhull wide facet with qh_ERRwide
+
+  notes:
+    no message if qh_QUICKhelp
+*/
+void qh_printhelp_wide(qhT *qh, FILE *fp) {
+
+  if (!qh_QUICKhelp) {
+    qh_fprintf(qh, fp, 9428, "\n\
+A wide merge error has occurred.  Qhull has produced a wide facet due to facet merges and vertex merges.\n\
+This usually occurs when the input is nearly degenerate and substantial merging has occurred.\n\
+See http://www.qhull.org/html/qh-impre.htm#limit\n");
+  }
+} /* printhelp_wide */
+
+/*---------------------------------
+
+  qh_user_memsizes(qh)
+    allocate up to 10 additional, quick allocation sizes
+
+  notes:
+    increase maximum number of allocations in qh_initqhull_mem()
+*/
+void qh_user_memsizes(qhT *qh) {
+
+  QHULL_UNUSED(qh)
+  /* qh_memsize(qh, size); */
+} /* user_memsizes */
+
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/user_r.h b/src/vendor/cigraph/vendor/qhull/libqhull_r/user_r.h
new file mode 100644
index 00000000000..523c179dc03
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/user_r.h
@@ -0,0 +1,1061 @@
+/*
  ---------------------------------
+
+   user_r.h
+   user redefinable constants
+
+   for each source file, user_r.h is included first
+
+   see qh-user_r.htm.  see COPYING for copyright information.
+
+   See user_r.c for sample code.
+
+   before reading any code, review libqhull_r.h for data structure definitions
+
+Sections:
+   ============= qhull library constants ======================
+   ============= data types and configuration macros ==========
+   ============= performance related constants ================
+   ============= memory constants =============================
+   ============= joggle constants =============================
+   ============= conditional compilation ======================
+   ============= merge constants ==============================
+   ============= Microsoft DevStudio ==========================
+
+Code flags --
+  NOerrors -- the code does not call qh_errexit()
+  WARN64 -- the code may be incompatible with 64-bit pointers
+
+*/
+
+#include 
+#include 
+#include 
+
+#ifndef qhDEFuser
+#define qhDEFuser 1
+
+/* Derived from Qt's corelib/global/qglobal.h */
+#if !defined(SAG_COM) && !defined(__CYGWIN__) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
+#   define QHULL_OS_WIN
+#elif defined(__MWERKS__) && defined(__INTEL__) /* Metrowerks discontinued before the release of Intel Macs */
+#   define QHULL_OS_WIN
+#endif
+
+/*============================================================*/
+/*============= qhull library constants ======================*/
+/*============================================================*/
+
+/*----------------------------------
+
+  FILENAMElen -- max length for TI and TO filenames
+
+*/
+
+#define qh_FILENAMElen 500
+
+/*----------------------------------
+
+  msgcode -- Unique message codes for qh_fprintf
+
+  If add new messages, assign these values and increment in user.h and user_r.h
+  See QhullError.h for 10000 error codes.
+  Cannot use '0031' since it would be octal
+
+  def counters =  [31/32/33/38, 1067, 2113, 3079, 4097, 5006,
+     6429, 7027/7028/7035/7068/7070/7102, 8163, 9428, 10000, 11034]
+
+  See: qh_ERR* [libqhull_r.h]
+*/
+
+#define MSG_TRACE0     0   /* always include if logging ('Tn') */
+#define MSG_TRACE1  1000
+#define MSG_TRACE2  2000
+#define MSG_TRACE3  3000
+#define MSG_TRACE4  4000
+#define MSG_TRACE5  5000
+#define MSG_ERROR   6000   /* errors written to qh.ferr */
+#define MSG_WARNING 7000
+#define MSG_STDERR  8000   /* log messages Written to qh.ferr */
+#define MSG_OUTPUT  9000
+#define MSG_QHULL_ERROR 10000 /* errors thrown by QhullError.cpp (QHULLlastError is in QhullError.h) */
+#define MSG_FIX    11000   /* Document as 'QH11... FIX: ...' */
+#define MSG_MAXLEN  3000   /* qh_printhelp_degenerate() in user_r.c */
+
+
+/*----------------------------------
+
+  qh_OPTIONline -- max length of an option line 'FO'
+*/
+#define qh_OPTIONline 80
+
+/*============================================================*/
+/*============= data types and configuration macros ==========*/
+/*============================================================*/
+
+/*----------------------------------
+
+  realT
+    set the size of floating point numbers
+
+  qh_REALdigits
+    maximum number of significant digits
+
+  qh_REAL_1, qh_REAL_2n, qh_REAL_3n
+    format strings for printf
+
+  REALmax, REALmin
+    maximum and minimum (near zero) values
+
+  REALepsilon
+    machine roundoff.  Maximum roundoff error for addition and multiplication.
+
+  notes:
+   Select whether to store floating point numbers in single precision (float)
+   or double precision (double).
+
+   Use 'float' to save about 8% in time and 25% in space.  This is particularly
+   helpful if high-d where convex hulls are space limited.  Using 'float' also
+   reduces the printed size of Qhull's output since numbers have 8 digits of
+   precision.
+
+   Use 'double' when greater arithmetic precision is needed.  This is needed
+   for Delaunay triangulations and Voronoi diagrams when you are not merging
+   facets.
+
+   If 'double' gives insufficient precision, your data probably includes
+   degeneracies.  If so you should use facet merging (done by default)
+   or exact arithmetic (see imprecision section of manual, qh-impre.htm).
+   You may also use option 'Po' to force output despite precision errors.
+
+   You may use 'long double', but many format statements need to be changed
+   and you may need a 'long double' square root routine.  S. Grundmann
+   (sg@eeiwzb.et.tu-dresden.de) has done this.  He reports that the code runs
+   much slower with little gain in precision.
+
+   WARNING: on some machines,    int f(){realT a= REALmax;return (a == REALmax);}
+      returns False.  Use (a > REALmax/2) instead of (a == REALmax).
+
+   REALfloat =   1      all numbers are 'float' type
+             =   0      all numbers are 'double' type
+*/
+#define REALfloat 0
+
+#if (REALfloat == 1)
+#define realT float
+#define REALmax FLT_MAX
+#define REALmin FLT_MIN
+#define REALepsilon FLT_EPSILON
+#define qh_REALdigits 8   /* maximum number of significant digits */
+#define qh_REAL_1 "%6.8g "
+#define qh_REAL_2n "%6.8g %6.8g\n"
+#define qh_REAL_3n "%6.8g %6.8g %6.8g\n"
+
+#elif (REALfloat == 0)
+#define realT double
+#define REALmax DBL_MAX
+#define REALmin DBL_MIN
+#define REALepsilon DBL_EPSILON
+#define qh_REALdigits 16    /* maximum number of significant digits */
+#define qh_REAL_1 "%6.16g "
+#define qh_REAL_2n "%6.16g %6.16g\n"
+#define qh_REAL_3n "%6.16g %6.16g %6.16g\n"
+
+#else
+#error unknown float option
+#endif
+
+/*----------------------------------
+
+  countT
+    The type for counts and identifiers (e.g., the number of points, vertex identifiers)
+    Currently used by C++ code-only.  Decided against using it for setT because most sets are small.
+
+    Defined as 'int' for C-code compatibility and QH11026
+
+    QH11026 FIX: countT may be defined as a 'unsigned int', but several code issues need to be solved first.  See countT in Changes.txt
+*/
+
+#ifndef DEFcountT
+#define DEFcountT 1
+typedef int countT;
+#endif
+#define COUNTmax INT_MAX
+
+/*----------------------------------
+
+  qh_POINTSmax
+    Maximum number of points for qh.num_points and point allocation in qh_readpoints
+*/
+#define qh_POINTSmax (INT_MAX-16)
+
+/*----------------------------------
+
+  qh_CPUclock
+    define the clock() function for reporting the total time spent by Qhull
+    returns CPU ticks as a 'long int'
+    qh_CPUclock is only used for reporting the total time spent by Qhull
+
+  qh_SECticks
+    the number of clock ticks per second
+
+  notes:
+    looks for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or assumes microseconds
+    to define a custom clock, set qh_CLOCKtype to 0
+
+    if your system does not use clock() to return CPU ticks, replace
+    qh_CPUclock with the corresponding function.  It is converted
+    to 'unsigned long' to prevent wrap-around during long runs.  By default,
+     defines clock_t as 'long'
+
+   Set qh_CLOCKtype to
+
+     1          for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or microsecond
+                Note:  may fail if more than 1 hour elapsed time
+
+     2          use qh_clock() with POSIX times() (see global_r.c)
+*/
+#define qh_CLOCKtype 1  /* change to the desired number */
+
+#if (qh_CLOCKtype == 1)
+
+#if defined(CLOCKS_PER_SECOND)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock, may be converted to approximate double */
+#define qh_SECticks CLOCKS_PER_SECOND
+
+#elif defined(CLOCKS_PER_SEC)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock, may be converted to approximate double */
+#define qh_SECticks CLOCKS_PER_SEC
+
+#elif defined(CLK_TCK)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock, may be converted to approximate double */
+#define qh_SECticks CLK_TCK
+
+#else
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock, may be converted to approximate double */
+#define qh_SECticks 1E6
+#endif
+
+#elif (qh_CLOCKtype == 2)
+#define qh_CPUclock    qh_clock()  /* return CPU clock, may be converted to approximate double */
+#define qh_SECticks 100
+
+#else /* qh_CLOCKtype == ? */
+#error unknown clock option
+#endif
+
+/*----------------------------------
+
+  qh_RANDOMtype, qh_RANDOMmax, qh_RANDOMseed
+    define random number generator
+
+    qh_RANDOMint generates a random integer between 0 and qh_RANDOMmax.
+    qh_RANDOMseed sets the random number seed for qh_RANDOMint
+
+  Set qh_RANDOMtype (default 5) to:
+    1       for random() with 31 bits (UCB)
+    2       for rand() with RAND_MAX or 15 bits (system 5)
+    3       for rand() with 31 bits (Sun)
+    4       for lrand48() with 31 bits (Solaris)
+    5       for qh_rand(qh) with 31 bits (included with Qhull, requires 'qh')
+
+  notes:
+    Random numbers are used by rbox to generate point sets.  Random
+    numbers are used by Qhull to rotate the input ('QRn' option),
+    simulate a randomized algorithm ('Qr' option), and to simulate
+    roundoff errors ('Rn' option).
+
+    Random number generators differ between systems.  Most systems provide
+    rand() but the period varies.  The period of rand() is not critical
+    since qhull does not normally use random numbers.
+
+    The default generator is Park & Miller's minimal standard random
+    number generator [CACM 31:1195 '88].  It is included with Qhull.
+
+    If qh_RANDOMmax is wrong, qhull will report a warning and Geomview
+    output will likely be invisible.
+*/
+#define qh_RANDOMtype 5   /* *** change to the desired number *** */
+
+#if (qh_RANDOMtype == 1)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, random()/MAX */
+#define qh_RANDOMint random()
+#define qh_RANDOMseed_(qh, seed) srandom(seed);
+
+#elif (qh_RANDOMtype == 2)
+#ifdef RAND_MAX
+#define qh_RANDOMmax ((realT)RAND_MAX)
+#else
+#define qh_RANDOMmax ((realT)32767)   /* 15 bits (System 5) */
+#endif
+#define qh_RANDOMint  rand()
+#define qh_RANDOMseed_(qh, seed) srand((unsigned int)seed);
+
+#elif (qh_RANDOMtype == 3)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, Sun */
+#define qh_RANDOMint  rand()
+#define qh_RANDOMseed_(qh, seed) srand((unsigned int)seed);
+
+#elif (qh_RANDOMtype == 4)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, lrand38()/MAX */
+#define qh_RANDOMint lrand48()
+#define qh_RANDOMseed_(qh, seed) srand48(seed);
+
+#elif (qh_RANDOMtype == 5)  /* 'qh' is an implicit parameter */
+#define qh_RANDOMmax ((realT)2147483646UL)  /* 31 bits, qh_rand/MAX */
+#define qh_RANDOMint qh_rand(qh)
+#define qh_RANDOMseed_(qh, seed) qh_srand(qh, seed);
+/* unlike rand(), never returns 0 */
+
+#else
+#error: unknown random option
+#endif
+
+/*----------------------------------
+
+  qh_ORIENTclock
+    0 for inward pointing normals by Geomview convention
+*/
+#define qh_ORIENTclock 0
+
+/*----------------------------------
+
+  qh_RANDOMdist
+    define for random perturbation of qh_distplane and qh_setfacetplane (qh.RANDOMdist, 'QRn')
+
+  For testing qh.DISTround.  Qhull should not depend on computations always producing the same roundoff error
+
+  #define qh_RANDOMdist 1e-13
+*/
+
+/*============================================================*/
+/*============= joggle constants =============================*/
+/*============================================================*/
+
+/*----------------------------------
+
+  qh_JOGGLEdefault
+    default qh.JOGGLEmax is qh.DISTround * qh_JOGGLEdefault
+
+  notes:
+    rbox s r 100 | qhull QJ1e-15 QR0 generates 90% faults at distround 7e-16
+    rbox s r 100 | qhull QJ1e-14 QR0 generates 70% faults
+    rbox s r 100 | qhull QJ1e-13 QR0 generates 35% faults
+    rbox s r 100 | qhull QJ1e-12 QR0 generates 8% faults
+    rbox s r 100 | qhull QJ1e-11 QR0 generates 1% faults
+    rbox s r 100 | qhull QJ1e-10 QR0 generates 0% faults
+    rbox 1000 W0 | qhull QJ1e-12 QR0 generates 86% faults
+    rbox 1000 W0 | qhull QJ1e-11 QR0 generates 20% faults
+    rbox 1000 W0 | qhull QJ1e-10 QR0 generates 2% faults
+    the later have about 20 points per facet, each of which may interfere
+
+    pick a value large enough to avoid retries on most inputs
+*/
+#define qh_JOGGLEdefault 30000.0
+
+/*----------------------------------
+
+  qh_JOGGLEincrease
+    factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain
+*/
+#define qh_JOGGLEincrease 10.0
+
+/*----------------------------------
+
+  qh_JOGGLEretry
+    if ZZretry = qh_JOGGLEretry, increase qh.JOGGLEmax
+
+notes:
+try twice at the original value in case of bad luck the first time
+*/
+#define qh_JOGGLEretry 2
+
+/*----------------------------------
+
+  qh_JOGGLEagain
+    every following qh_JOGGLEagain, increase qh.JOGGLEmax
+
+  notes:
+    1 is OK since it's already failed qh_JOGGLEretry times
+*/
+#define qh_JOGGLEagain 1
+
+/*----------------------------------
+
+  qh_JOGGLEmaxincrease
+    maximum qh.JOGGLEmax due to qh_JOGGLEincrease
+    relative to qh.MAXwidth
+
+  notes:
+    qh.joggleinput will retry at this value until qh_JOGGLEmaxretry
+*/
+#define qh_JOGGLEmaxincrease 1e-2
+
+/*----------------------------------
+
+  qh_JOGGLEmaxretry
+    stop after qh_JOGGLEmaxretry attempts
+*/
+#define qh_JOGGLEmaxretry 50
+
+/*============================================================*/
+/*============= performance related constants ================*/
+/*============================================================*/
+
+/*----------------------------------
+
+  qh_HASHfactor
+    total hash slots / used hash slots.  Must be at least 1.1.
+
+  notes:
+    =2 for at worst 50% occupancy for qh.hash_table and normally 25% occupancy
+*/
+#define qh_HASHfactor 2
+
+/*----------------------------------
+
+  qh_VERIFYdirect
+    with 'Tv' verify all points against all facets if op count is smaller
+
+  notes:
+    if greater, calls qh_check_bestdist() instead
+*/
+#define qh_VERIFYdirect 1000000
+
+/*----------------------------------
+
+  qh_INITIALsearch
+     if qh_INITIALmax, search points up to this dimension
+*/
+#define qh_INITIALsearch 6
+
+/*----------------------------------
+
+  qh_INITIALmax
+    if dim >= qh_INITIALmax, use min/max coordinate points for initial simplex
+
+  notes:
+    from points with non-zero determinants
+    use option 'Qs' to override (much slower)
+*/
+#define qh_INITIALmax 8
+
+/*============================================================*/
+/*============= memory constants =============================*/
+/*============================================================*/
+
+/*----------------------------------
+
+  qh_MEMalign
+    memory alignment for qh_meminitbuffers() in global_r.c
+
+  notes:
+    to avoid bus errors, memory allocation must consider alignment requirements.
+    malloc() automatically takes care of alignment.   Since mem_r.c manages
+    its own memory, we need to explicitly specify alignment in
+    qh_meminitbuffers().
+
+    A safe choice is sizeof(double).  sizeof(float) may be used if doubles
+    do not occur in data structures and pointers are the same size.  Be careful
+    of machines (e.g., DEC Alpha) with large pointers.
+
+    If using gcc, best alignment is [fmax_() is defined in geom_r.h]
+              #define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *))
+*/
+#define qh_MEMalign ((int)(fmax_(sizeof(realT), sizeof(void *))))
+
+/*----------------------------------
+
+  qh_MEMbufsize
+    size of additional memory buffers
+
+  notes:
+    used for qh_meminitbuffers() in global_r.c
+*/
+#define qh_MEMbufsize 0x10000       /* allocate 64K memory buffers */
+
+/*----------------------------------
+
+  qh_MEMinitbuf
+    size of initial memory buffer
+
+  notes:
+    use for qh_meminitbuffers() in global_r.c
+*/
+#define qh_MEMinitbuf 0x20000      /* initially allocate 128K buffer */
+
+/*----------------------------------
+
+  qh_INFINITE
+    on output, indicates Voronoi center at infinity
+*/
+#define qh_INFINITE  -10.101
+
+/*----------------------------------
+
+  qh_DEFAULTbox
+    default box size (Geomview expects 0.5)
+
+  qh_DEFAULTbox
+    default box size for integer coorindate (rbox only)
+*/
+#define qh_DEFAULTbox 0.5
+#define qh_DEFAULTzbox 1e6
+
+/*============================================================*/
+/*============= conditional compilation ======================*/
+/*============================================================*/
+
+/*----------------------------------
+
+  __cplusplus
+    defined by C++ compilers
+
+  __MSC_VER
+    defined by Microsoft Visual C++
+
+  __MWERKS__ && __INTEL__
+    defined by Metrowerks when compiling for Windows (not Intel-based Macintosh)
+
+  __MWERKS__ && __POWERPC__
+    defined by Metrowerks when compiling for PowerPC-based Macintosh
+
+  __STDC__
+    defined for strict ANSI C
+*/
+
+/*----------------------------------
+
+  qh_COMPUTEfurthest
+    compute furthest distance to an outside point instead of storing it with the facet
+    =1 to compute furthest
+
+  notes:
+    computing furthest saves memory but costs time
+      about 40% more distance tests for partitioning
+      removes facet->furthestdist
+*/
+#define qh_COMPUTEfurthest 0
+
+/*----------------------------------
+
+  qh_KEEPstatistics
+    =0 removes most of statistic gathering and reporting
+
+  notes:
+    if 0, code size is reduced by about 4%.
+*/
+#define qh_KEEPstatistics 0
+
+/*----------------------------------
+
+  qh_MAXoutside
+    record outer plane for each facet
+    =1 to record facet->maxoutside
+
+  notes:
+    this takes a realT per facet and slightly slows down qhull
+    it produces better outer planes for geomview output
+*/
+#define qh_MAXoutside 1
+
+/*----------------------------------
+
+  qh_NOmerge
+    disables facet merging if defined
+    For MSVC compiles, use qhull_r-exports-nomerge.def instead of qhull_r-exports.def
+
+  notes:
+    This saves about 25% space, 30% space in combination with qh_NOtrace,
+    and 36% with qh_NOtrace and qh_KEEPstatistics 0
+
+    Unless option 'Q0' is used
+      qh_NOmerge sets 'QJ' to avoid precision errors
+
+  see:
+    qh_NOmem in mem_r.h
+
+    see user_r.c/user_eg.c for removing io_r.o
+
+  #define qh_NOmerge
+*/
+
+/*----------------------------------
+
+  qh_NOtrace
+    no tracing if defined
+    disables 'Tn', 'TMn', 'TPn' and 'TWn'
+    override with 'Qw' for qh_addpoint tracing and various other items
+
+  notes:
+    This saves about 15% space.
+    Removes all traceN((...)) code and substantial sections of qh.IStracing code
+
+  #define qh_NOtrace
+*/
+#define qh_NOtrace
+
+#if 0  /* sample code */
+    exitcode= qh_new_qhull(qhT *qh, dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile);
+    qh_freeqhull(qhT *qh, !qh_ALL); /* frees long memory used by second call */
+    qh_memfreeshort(qhT *qh, &curlong, &totlong);  /* frees short memory and memory allocator */
+#endif
+
+/*----------------------------------
+
+  qh_QUICKhelp
+    =1 to use abbreviated help messages, e.g., for degenerate inputs
+*/
+#define qh_QUICKhelp    0
+
+/*============================================================*/
+/*============= merge constants ==============================*/
+/*============================================================*/
+/*
+   These constants effect facet merging.  You probably will not need
+   to modify them.  They effect the performance of facet merging.
+*/
+
+/*----------------------------------
+
+  qh_BESTcentrum
+     if > 2*dim+n vertices, qh_findbestneighbor() tests centrums (faster)
+     else, qh_findbestneighbor() tests all vertices (much better merges)
+
+  qh_BESTcentrum2
+     if qh_BESTcentrum2 * DIM3 + BESTcentrum < #vertices tests centrums
+*/
+#define qh_BESTcentrum 20
+#define qh_BESTcentrum2 2
+
+/*----------------------------------
+
+  qh_BESTnonconvex
+    if > dim+n neighbors, qh_findbestneighbor() tests nonconvex ridges.
+
+  notes:
+    It is needed because qh_findbestneighbor is slow for large facets
+*/
+#define qh_BESTnonconvex 15
+
+/*----------------------------------
+
+  qh_COPLANARratio
+    for 3-d+ merging, qh.MINvisible is n*premerge_centrum
+
+  notes:
+    for non-merging, it's DISTround
+*/
+#define qh_COPLANARratio 3
+
+/*----------------------------------
+
+  qh_DIMmergeVertex
+    max dimension for vertex merging (it is not effective in high-d)
+*/
+#define qh_DIMmergeVertex 6
+
+/*----------------------------------
+
+  qh_DIMreduceBuild
+     max dimension for vertex reduction during build (slow in high-d)
+*/
+#define qh_DIMreduceBuild 5
+
+/*----------------------------------
+
+  qh_DISToutside
+    When is a point clearly outside of a facet?
+    Stops search in qh_findbestnew or qh_partitionall
+    qh_findbest uses qh.MINoutside since since it is only called if no merges.
+
+  notes:
+    'Qf' always searches for best facet
+    if !qh.MERGING, same as qh.MINoutside.
+    if qh_USEfindbestnew, increase value since neighboring facets may be ill-behaved
+      [Note: Zdelvertextot occurs normally with interior points]
+            RBOX 1000 s Z1 G1e-13 t1001188774 | QHULL Tv
+    When there is a sharp edge, need to move points to a
+    clearly good facet; otherwise may be lost in another partitioning.
+    if too big then O(n^2) behavior for partitioning in cone
+    if very small then important points not processed
+    Needed in qh_partitionall for
+      RBOX 1000 s Z1 G1e-13 t1001032651 | QHULL Tv
+    Needed in qh_findbestnew for many instances of
+      RBOX 1000 s Z1 G1e-13 t | QHULL Tv
+
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_DISToutside ((qh_USEfindbestnew ? 2 : 1) * \
+     fmax_((qh->MERGING ? 2 : 1)*qh->MINoutside, qh->max_outside))
+
+/*----------------------------------
+
+  qh_MAXcheckpoint
+    Report up to qh_MAXcheckpoint errors per facet in qh_check_point ('Tv')
+*/
+#define qh_MAXcheckpoint 10
+
+/*----------------------------------
+
+  qh_MAXcoplanarcentrum
+    if pre-merging with qh.MERGEexact ('Qx') and f.nummerge > qh_MAXcoplanarcentrum
+      use f.maxoutside instead of qh.centrum_radius for coplanarity testing
+
+  notes:
+    see qh_test_nonsimplicial_merges
+    with qh.MERGEexact, a coplanar ridge is ignored until post-merging
+    otherwise a large facet with many merges may take all the facets
+*/
+#define qh_MAXcoplanarcentrum 10
+
+/*----------------------------------
+
+  qh_MAXnewcentrum
+    if <= dim+n vertices (n approximates the number of merges),
+      reset the centrum in qh_updatetested() and qh_mergecycle_facets()
+
+  notes:
+    needed to reduce cost and because centrums may move too much if
+    many vertices in high-d
+*/
+#define qh_MAXnewcentrum 5
+
+/*----------------------------------
+
+  qh_MAXnewmerges
+    if >n newmerges, qh_merge_nonconvex() calls qh_reducevertices_centrums.
+
+  notes:
+    It is needed because postmerge can merge many facets at once
+*/
+#define qh_MAXnewmerges 2
+
+/*----------------------------------
+
+  qh_RATIOconcavehorizon
+    ratio of horizon vertex distance to max_outside for concave, twisted new facets in qh_test_nonsimplicial_merge
+    if too small, end up with vertices far below merged facets
+*/
+#define qh_RATIOconcavehorizon 20.0
+
+/*----------------------------------
+
+  qh_RATIOconvexmerge
+    ratio of vertex distance to qh.min_vertex for clearly convex new facets in qh_test_nonsimplicial_merge
+
+  notes:
+    must be convex for MRGtwisted
+*/
+#define qh_RATIOconvexmerge 10.0
+
+/*----------------------------------
+
+  qh_RATIOcoplanarapex
+    ratio of best distance for coplanar apex vs. vertex merge in qh_getpinchedmerges
+
+  notes:
+    A coplanar apex always works, while a vertex merge may fail
+*/
+#define qh_RATIOcoplanarapex 3.0
+
+/*----------------------------------
+
+  qh_RATIOcoplanaroutside
+    qh.MAXoutside ratio to repartition a coplanar point in qh_partitioncoplanar and qh_check_maxout
+
+  notes:
+    combines several tests, see qh_partitioncoplanar
+
+*/
+#define qh_RATIOcoplanaroutside 30.0
+
+/*----------------------------------
+
+  qh_RATIOmaxsimplex
+    ratio of max determinate to estimated determinate for searching all points in qh_maxsimplex
+
+  notes:
+    As each point is added to the simplex, the max determinate is should approximate the previous determinate * qh.MAXwidth
+    If maxdet is significantly less, the simplex may not be full-dimensional.
+    If so, all points are searched, stopping at 10 times qh_RATIOmaxsimplex
+*/
+#define qh_RATIOmaxsimplex 1.0e-3
+
+/*----------------------------------
+
+  qh_RATIOnearinside
+    ratio of qh.NEARinside to qh.ONEmerge for retaining inside points for
+    qh_check_maxout().
+
+  notes:
+    This is overkill since do not know the correct value.
+    It effects whether 'Qc' reports all coplanar points
+    Not used for 'd' since non-extreme points are coplanar, nearly incident points
+*/
+#define qh_RATIOnearinside 5
+
+/*----------------------------------
+
+  qh_RATIOpinchedsubridge
+    ratio to qh.ONEmerge to accept vertices in qh_findbest_pinchedvertex
+    skips search of neighboring vertices
+    facet width may increase by this ratio
+*/
+#define qh_RATIOpinchedsubridge 10.0
+
+/*----------------------------------
+
+  qh_RATIOtrypinched
+    ratio to qh.ONEmerge to try qh_getpinchedmerges in qh_buildcone_mergepinched
+    otherwise a duplicate ridge will increase facet width by this amount
+*/
+#define qh_RATIOtrypinched 4.0
+
+/*----------------------------------
+
+  qh_RATIOtwisted
+    maximum ratio to qh.ONEmerge to merge twisted facets in qh_merge_twisted
+*/
+#define qh_RATIOtwisted 20.0
+
+/*----------------------------------
+
+  qh_SEARCHdist
+    When is a facet coplanar with the best facet?
+    qh_findbesthorizon: all coplanar facets of the best facet need to be searched.
+        increases minsearch if ischeckmax and more than 100 neighbors (is_5x_minsearch)
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_SEARCHdist ((qh_USEfindbestnew ? 2 : 1) * \
+      (qh->max_outside + 2 * qh->DISTround + fmax_( qh->MINvisible, qh->MAXcoplanar)));
+
+/*----------------------------------
+
+  qh_USEfindbestnew
+     Always use qh_findbestnew for qh_partitionpoint, otherwise use
+     qh_findbestnew if merged new facet or sharpnewfacets.
+
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_USEfindbestnew (zzval_(Ztotmerge) > 50)
+
+/*----------------------------------
+
+  qh_MAXnarrow
+    max. cosine in initial hull that sets qh.NARROWhull
+
+  notes:
+    If qh.NARROWhull, the initial partition does not make
+    coplanar points.  If narrow, a coplanar point can be
+    coplanar to two facets of opposite orientations and
+    distant from the exact convex hull.
+
+    Conservative estimate.  Don't actually see problems until it is -1.0
+*/
+#define qh_MAXnarrow -0.99999999
+
+/*----------------------------------
+
+  qh_WARNnarrow
+    max. cosine in initial hull to warn about qh.NARROWhull
+
+  notes:
+    this is a conservative estimate.
+    Don't actually see problems until it is -1.0.  See qh-impre.htm
+*/
+#define qh_WARNnarrow -0.999999999999999
+
+/*----------------------------------
+
+  qh_WIDEcoplanar
+    n*MAXcoplanar or n*MINvisible for a WIDEfacet
+
+    if vertex is further than qh.WIDEfacet from the hyperplane
+    then its ridges are not counted in computing the area, and
+    the facet's centrum is frozen.
+
+  notes:
+    qh.WIDEfacet= max(qh.MAXoutside,qh_WIDEcoplanar*qh.MAXcoplanar,
+    qh_WIDEcoplanar * qh.MINvisible);
+*/
+#define qh_WIDEcoplanar 6
+
+/*----------------------------------
+
+  qh_WIDEduplicate
+    merge ratio for errexit from qh_forcedmerges due to duplicate ridge
+    Override with option Q12-allow-wide
+
+  Notes:
+    Merging a duplicate ridge can lead to very wide facets.
+*/
+#define qh_WIDEduplicate 100
+
+/*----------------------------------
+
+  qh_WIDEdupridge
+    Merge ratio for selecting a forced dupridge merge
+
+  Notes:
+    Merging a dupridge can lead to very wide facets.
+*/
+#define qh_WIDEdupridge 50
+
+/*----------------------------------
+
+  qh_WIDEmaxoutside
+    Precision ratio for maximum increase for qh.max_outside in qh_check_maxout
+    Precision errors while constructing the hull, may lead to very wide facets when checked in qh_check_maxout
+    Nearly incident points in 4-d and higher is the most likely culprit
+    Skip qh_check_maxout with 'Q5' (no-check-outer)
+    Do not error with option 'Q12' (allow-wide)
+    Do not warn with options 'Q12 Pp'
+*/
+#define qh_WIDEmaxoutside 100
+
+/*----------------------------------
+
+  qh_WIDEmaxoutside2
+    Precision ratio for maximum qh.max_outside in qh_check_maxout
+    Skip qh_check_maxout with 'Q5' no-check-outer
+    Do not error with option 'Q12' allow-wide
+*/
+#define qh_WIDEmaxoutside2 (10*qh_WIDEmaxoutside)
+
+
+/*----------------------------------
+
+  qh_WIDEpinched
+    Merge ratio for distance between pinched vertices compared to current facet width for qh_getpinchedmerges and qh_next_vertexmerge
+    Reports warning and merges duplicate ridges instead
+    Enable these attempts with option Q14 merge-pinched-vertices
+
+  notes:
+    Merging pinched vertices should prevent duplicate ridges (see qh_WIDEduplicate)
+    Merging the duplicate ridges may be better than merging the pinched vertices
+    Found up to 45x ratio for qh_pointdist -- for ((i=1; i<20; i++)); do rbox 175 C1,6e-13 t | qhull d T4 2>&1 | tee x.1 | grep  -E 'QH|non-simplicial|Statis|pinched'; done
+    Actual distance to facets is a third to a tenth of the qh_pointdist (T1)
+*/
+#define qh_WIDEpinched 100
+
+/*----------------------------------
+
+  qh_ZEROdelaunay
+    a zero Delaunay facet occurs for input sites coplanar with their convex hull
+    the last normal coefficient of a zero Delaunay facet is within
+        qh_ZEROdelaunay * qh.ANGLEround of 0
+
+  notes:
+    qh_ZEROdelaunay does not allow for joggled input ('QJ').
+
+    You can avoid zero Delaunay facets by surrounding the input with a box.
+
+    Use option 'PDk:-n' to explicitly define zero Delaunay facets
+      k= dimension of input sites (e.g., 3 for 3-d Delaunay triangulation)
+      n= the cutoff for zero Delaunay facets (e.g., 'PD3:-1e-12')
+*/
+#define qh_ZEROdelaunay 2
+
+/*============================================================*/
+/*============= Microsoft DevStudio ==========================*/
+/*============================================================*/
+
+/*
+   Finding Memory Leaks Using the CRT Library
+   https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.100).aspx
+
+   Reports enabled in qh_lib_check for Debug window and stderr
+
+   From 2005=>msvcr80d, 2010=>msvcr100d, 2012=>msvcr110d
+
+   Watch: {,,msvcr80d.dll}_crtBreakAlloc  Value from {n} in the leak report
+   _CrtSetBreakAlloc(689); // qh_lib_check() [global_r.c]
+
+   Examples
+     http://free-cad.sourceforge.net/SrcDocu/d2/d7f/MemDebug_8cpp_source.html
+     https://github.com/illlust/Game/blob/master/library/MemoryLeak.cpp
+*/
+#if 0   /* off (0) by default for QHULL_CRTDBG */
+#define QHULL_CRTDBG
+#endif
+
+#if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG)
+#define _CRTDBG_MAP_ALLOC
+#include 
+#include 
+#endif
+
+#endif /* qh_DEFuser */
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/usermem_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/usermem_r.c
new file mode 100644
index 00000000000..27563cff4a7
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/usermem_r.c
@@ -0,0 +1,102 @@
+/*
  ---------------------------------
+
+   usermem_r.c
+   user redefinable functions -- qh_exit, qh_free, and qh_malloc
+
+   See README.txt.
+
+   If you redefine one of these functions you must redefine all of them.
+   If you recompile and load this file, then usermem.o will not be loaded
+   from qhull.a or qhull.lib
+
+   See libqhull_r.h for data structures, macros, and user-callable functions.
+   See user_r.c for qhull-related, redefinable functions
+   see user_r.h for user-definable constants
+   See userprintf_r.c for qh_fprintf and userprintf_rbox_r.c for qh_fprintf_rbox
+
+   Please report any errors that you fix to qhull@qhull.org
+*/
+
+#include "libqhull_r.h"
+
+#include "igraph_error.h"
+
+#include 
+#include 
+
+/*---------------------------------
+
+  qh_exit( exitcode )
+    exit program
+    the exitcode must be 255 or less.  Zero indicates success.
+    Note: Exit status ('$?') in bash reports 256 as 0
+
+  notes:
+    qh_exit() is called when qh_errexit() and longjmp() are not available.
+
+    This is the only use of exit() in Qhull
+    To replace qh_exit with 'throw', see libqhullcpp/usermem_r-cpp.cpp
+*/
+void qh_exit(int exitcode) {
+    /* exit(exitcode); */
+    /* This code is not reachable. We comment out exit() to ensure
+     * that the igraph shared library does not reference it. */
+    IGRAPH_FATALF("Qhull called exit() with exit code %d.", exitcode);
+} /* exit */
+
+/*---------------------------------
+
+  qh_fprintf_stderr( msgcode, format, list of args )
+    fprintf to stderr with msgcode (non-zero)
+
+  notes:
+    qh_fprintf_stderr() is called when qh.ferr is not defined, usually due to an initialization error
+    if msgcode is a MSG_ERROR (6000), caller should set qh.last_errcode (like qh_fprintf) or variable 'last_errcode'
+    
+    It is typically followed by qh_errexit().
+
+    Redefine this function to avoid using stderr
+
+    Use qh_fprintf [userprintf_r.c] for normal printing
+*/
+void qh_fprintf_stderr(int msgcode, const char *fmt, ... ) {
+    va_list args;
+
+    va_start(args, fmt);
+    if(msgcode)
+      fprintf(stderr, "QH%.4d ", msgcode);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+} /* fprintf_stderr */
+
+/*---------------------------------
+
+  qh_free(qh, mem )
+    free memory
+
+  notes:
+    same as free()
+    No calls to qh_errexit() 
+*/
+void qh_free(void *mem) {
+    free(mem);
+} /* free */
+
+/*---------------------------------
+
+    qh_malloc( mem )
+      allocate memory
+
+    notes:
+      same as malloc()
+*/
+void *qh_malloc(size_t size) {
+    return malloc(size);
+} /* malloc */
+
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/userprintf_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/userprintf_r.c
new file mode 100644
index 00000000000..7eb3600b34f
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/userprintf_r.c
@@ -0,0 +1,68 @@
+/*
  ---------------------------------
+
+  userprintf_r.c
+  user redefinable function -- qh_fprintf
+
+  see README.txt  see COPYING.txt for copyright information.
+
+  If you recompile and load this file, then userprintf_r.o will not be loaded
+  from qhull_r.a or qhull_r.lib
+
+  See libqhull_r.h for data structures, macros, and user-callable functions.
+  See user_r.c for qhull-related, redefinable functions
+  see user_r.h for user-definable constants
+  See usermem_r.c for qh_exit(), qh_free(), and qh_malloc()
+  see Qhull.cpp and RboxPoints.cpp for examples.
+
+  qh_printf is a good location for debugging traps, checked on each log line
+
+  Please report any errors that you fix to qhull@qhull.org
+*/
+
+#include "libqhull_r.h"
+#include "poly_r.h" /* for qh.tracefacet */
+
+#include 
+#include 
+#include 
+
+/*---------------------------------
+
+  qh_fprintf(qh, fp, msgcode, format, list of args )
+    print arguments to *fp according to format
+    Use qh_fprintf_rbox() for rboxlib_r.c
+
+  notes:
+    sets qh.last_errcode if msgcode is error 6000..6999
+    same as fprintf()
+    fgets() is not trapped like fprintf()
+    exit qh_fprintf via qh_errexit()
+    may be called for errors in qh_initstatistics and qh_meminit
+*/
+
+void qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... ) {
+    va_list args;
+    if (qh) {
+        if (msgcode >= MSG_ERROR && msgcode < MSG_WARNING) {
+            qh->last_errcode = msgcode;
+        }
+        if (qh->FLUSHprint) {
+            fflush(fp);
+        }
+    }
+    if (!fp) {
+        return;
+    }
+    if ((qh && qh->ANNOTATEoutput) || msgcode < MSG_TRACE4) {
+        fprintf(fp, "[QH%.4d]", msgcode);
+    } else if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR ) {
+        fprintf(fp, "QH%.4d ", msgcode);
+    }
+    va_start(args, fmt);
+    vfprintf(fp, fmt, args);
+    va_end(args);
+
+} /* qh_fprintf */
+
diff --git a/src/vendor/cigraph/vendor/qhull/libqhull_r/userprintf_rbox_r.c b/src/vendor/cigraph/vendor/qhull/libqhull_r/userprintf_rbox_r.c
new file mode 100644
index 00000000000..64c16cb57b8
--- /dev/null
+++ b/src/vendor/cigraph/vendor/qhull/libqhull_r/userprintf_rbox_r.c
@@ -0,0 +1,53 @@
+/*
  ---------------------------------
+
+   userprintf_rbox_r.c
+   user redefinable function -- qh_fprintf_rbox
+
+   see README.txt  see COPYING.txt for copyright information.
+
+   If you recompile and load this file, then userprintf_rbox_r.o will not be loaded
+   from qhull.a or qhull.lib
+
+   See libqhull_r.h for data structures, macros, and user-callable functions.
+   See user_r.c for qhull-related, redefinable functions
+   see user_r.h for user-definable constants
+   See usermem_r.c for qh_exit(), qh_free(), and qh_malloc()
+   see Qhull.cpp and RboxPoints.cpp for examples.
+
+   Please report any errors that you fix to qhull@qhull.org
+*/
+
+#include "libqhull_r.h"
+
+#include 
+#include 
+#include 
+
+/*---------------------------------
+
+   qh_fprintf_rbox(qh, fp, msgcode, format, list of args )
+     print arguments to *fp according to format
+     Use qh_fprintf_rbox() for rboxlib_r.c
+
+   notes:
+     same as fprintf()
+     fgets() is not trapped like fprintf()
+     exit qh_fprintf_rbox via qh_errexit_rbox()
+*/
+
+void qh_fprintf_rbox(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... ) {
+    va_list args;
+
+    if (!fp) {
+      qh_fprintf_stderr(6231, "qhull internal error (userprintf_rbox_r.c): fp is 0.  Wrong qh_fprintf_rbox called.\n");
+      qh_errexit_rbox(qh, qh_ERRqhull);
+    }
+    if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR)
+      fprintf(fp, "QH%.4d ", msgcode);
+    va_start(args, fmt);
+    vfprintf(fp, fmt, args);
+    va_end(args);
+} /* qh_fprintf_rbox */
+
diff --git a/src/vendor/igraph_config.h b/src/vendor/igraph_config.h
index 5c0f62d9f8a..397d8af7c06 100644
--- a/src/vendor/igraph_config.h
+++ b/src/vendor/igraph_config.h
@@ -25,7 +25,7 @@
 
 #include "igraph_decls.h"
 
-__BEGIN_DECLS
+IGRAPH_BEGIN_C_DECLS
 
 /**
  * \define IGRAPH_INTEGER_SIZE
@@ -50,6 +50,6 @@ __BEGIN_DECLS
  */
 #define IGRAPH_BOOL_TYPE int
 
-__END_DECLS
+IGRAPH_END_C_DECLS
 
 #endif
diff --git a/src/vendor/igraph_threading.h b/src/vendor/igraph_threading.h
index ebbdb1780c0..415d8cf01ab 100644
--- a/src/vendor/igraph_threading.h
+++ b/src/vendor/igraph_threading.h
@@ -1,8 +1,6 @@
-/* -*- mode: C -*-  */
 /*
-   IGraph library.
-   Copyright (C) 2011-2012  Gabor Csardi 
-   334 Harvard street, Cambridge, MA 02139 USA
+   igraph library.
+   Copyright (C) 2011-2025  The igraph development team 
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -15,10 +13,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301 USA
-
+   along with this program.  If not, see .
 */
 
 #ifndef IGRAPH_THREADING_H
@@ -26,7 +21,7 @@
 
 #include "igraph_decls.h"
 
-__BEGIN_DECLS
+IGRAPH_BEGIN_C_DECLS
 
 /**
  * \define IGRAPH_THREAD_SAFE
@@ -42,6 +37,6 @@ __BEGIN_DECLS
 
 #define IGRAPH_THREAD_SAFE 0
 
-__END_DECLS
+IGRAPH_END_C_DECLS
 
 #endif
diff --git a/src/vendor/igraph_version.h b/src/vendor/igraph_version.h
index 2610fa02d7e..3d39de0b742 100644
--- a/src/vendor/igraph_version.h
+++ b/src/vendor/igraph_version.h
@@ -1,8 +1,6 @@
-/* -*- mode: C -*-  */
 /*
-   IGraph library.
-   Copyright (C) 2010-2012  Gabor Csardi 
-   334 Harvard street, Cambridge, MA 02139 USA
+   igraph library.
+   Copyright (C) 2010-2025  The igraph development team 
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -15,10 +13,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301 USA
-
+   along with this program.  If not, see .
 */
 
 #ifndef IGRAPH_VERSION_H
@@ -26,19 +21,19 @@
 
 #include "igraph_decls.h"
 
-__BEGIN_DECLS
+IGRAPH_BEGIN_C_DECLS
 
-#define IGRAPH_VERSION "0.10.17"
-#define IGRAPH_VERSION_MAJOR 0
-#define IGRAPH_VERSION_MINOR 10
-#define IGRAPH_VERSION_PATCH 17
-#define IGRAPH_VERSION_PRERELEASE "cmake-experimental"
+#define IGRAPH_VERSION "1.0.0-37-gdafef9909"
+#define IGRAPH_VERSION_MAJOR 1
+#define IGRAPH_VERSION_MINOR 0
+#define IGRAPH_VERSION_PATCH 0
+#define IGRAPH_VERSION_PRERELEASE "37-gdafef9909"
 
 IGRAPH_EXPORT void igraph_version(const char **version_string,
                                   int *major,
                                   int *minor,
-                                  int *subminor);
+                                  int *patch);
 
-__END_DECLS
+IGRAPH_END_C_DECLS
 
 #endif
diff --git a/src/vendor/io/dl-lexer.c b/src/vendor/io/dl-lexer.c
index 4844b12f2e1..6814eaf0a33 100644
--- a/src/vendor/io/dl-lexer.c
+++ b/src/vendor/io/dl-lexer.c
@@ -837,7 +837,7 @@ static const flex_int32_t yy_rule_can_match_eol[25] =
 #define YY_RESTORE_YY_MORE_OFFSET
 #line 1 "src/vendor/cigraph/src/io/dl-lexer.l"
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2007-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
@@ -860,7 +860,7 @@ static const flex_int32_t yy_rule_can_match_eol[25] =
 #line 24 "src/vendor/cigraph/src/io/dl-lexer.l"
 
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2007-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
diff --git a/src/vendor/io/dl-parser.c b/src/vendor/io/dl-parser.c
index b3cb901766e..4b810f27290 100644
--- a/src/vendor/io/dl-parser.c
+++ b/src/vendor/io/dl-parser.c
@@ -76,7 +76,7 @@
 
 
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2009-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
@@ -107,12 +107,12 @@ int igraph_dl_yyerror(YYLTYPE* locp, igraph_i_dl_parsedata_t* context,
                       const char *s);
 static igraph_error_t igraph_i_dl_add_str(char *newstr, yy_size_t length,
                         igraph_i_dl_parsedata_t *context);
-static igraph_error_t igraph_i_dl_add_edge(igraph_integer_t from, igraph_integer_t to,
+static igraph_error_t igraph_i_dl_add_edge(igraph_int_t from, igraph_int_t to,
                          igraph_i_dl_parsedata_t *context);
-static igraph_error_t igraph_i_dl_add_edge_w(igraph_integer_t from, igraph_integer_t to,
+static igraph_error_t igraph_i_dl_add_edge_w(igraph_int_t from, igraph_int_t to,
                            igraph_real_t weight,
                            igraph_i_dl_parsedata_t *context);
-static igraph_error_t igraph_i_dl_check_vid(igraph_integer_t dl_vid);
+static igraph_error_t igraph_i_dl_check_vid(igraph_int_t dl_vid);
 
 #define scanner context->scanner
 
@@ -1848,7 +1848,7 @@ YYLTYPE yylloc = yyloc_default;
   case 40: /* edgelist1dataline: integer integer weight "end of line"  */
 #line 197 "src/vendor/cigraph/src/io/dl-parser.y"
                                                   {
-                    igraph_integer_t from = (yyvsp[-3].integer), to = (yyvsp[-2].integer);
+                    igraph_int_t from = (yyvsp[-3].integer), to = (yyvsp[-2].integer);
                     IGRAPH_YY_CHECK(igraph_i_dl_check_vid(from));
                     IGRAPH_YY_CHECK(igraph_i_dl_check_vid(to));
                     IGRAPH_YY_CHECK(igraph_i_dl_add_edge_w(from-1, to-1, (yyvsp[-1].real), context)); }
@@ -1858,7 +1858,7 @@ YYLTYPE yylloc = yyloc_default;
   case 41: /* edgelist1dataline: integer integer "end of line"  */
 #line 202 "src/vendor/cigraph/src/io/dl-parser.y"
                                            {
-                    igraph_integer_t from = (yyvsp[-2].integer), to = (yyvsp[-1].integer);
+                    igraph_int_t from = (yyvsp[-2].integer), to = (yyvsp[-1].integer);
                     IGRAPH_YY_CHECK(igraph_i_dl_check_vid(from));
                     IGRAPH_YY_CHECK(igraph_i_dl_check_vid(to));
                     IGRAPH_YY_CHECK(igraph_i_dl_add_edge(from-1, to-1, context));
@@ -1869,7 +1869,7 @@ YYLTYPE yylloc = yyloc_default;
   case 42: /* integer: "number"  */
 #line 209 "src/vendor/cigraph/src/io/dl-parser.y"
              {
-    igraph_integer_t val;
+    igraph_int_t val;
     IGRAPH_YY_CHECK(igraph_i_parse_integer(igraph_dl_yyget_text(scanner),
                                            igraph_dl_yyget_leng(scanner),
                                            &val));
@@ -1920,11 +1920,11 @@ YYLTYPE yylloc = yyloc_default;
   case 48: /* elabel: "label"  */
 #line 235 "src/vendor/cigraph/src/io/dl-parser.y"
               {
-  igraph_integer_t trie_id;
+  igraph_int_t trie_id;
 
   /* Copy label list to trie, if needed */
   if (igraph_strvector_size(&context->labels) != 0) {
-    igraph_integer_t i, id, n=igraph_strvector_size(&context->labels);
+    igraph_int_t i, id, n=igraph_strvector_size(&context->labels);
     for (i=0; itrie, igraph_strvector_get(&context->labels, i), &id));
     }
@@ -2012,7 +2012,7 @@ YYLTYPE yylloc = yyloc_default;
   case 60: /* tolist: tolist integer  */
 #line 276 "src/vendor/cigraph/src/io/dl-parser.y"
                             {
-  igraph_integer_t to = (yyvsp[0].integer);
+  igraph_int_t to = (yyvsp[0].integer);
   IGRAPH_YY_CHECK(igraph_i_dl_check_vid(to));
   IGRAPH_YY_CHECK(igraph_vector_int_push_back(&context->edges,
                                               context->from-1));
@@ -2305,7 +2305,7 @@ static igraph_error_t igraph_i_dl_add_str(char *newstr, yy_size_t length,
   return IGRAPH_SUCCESS;
 }
 
-static igraph_error_t igraph_i_dl_add_edge(igraph_integer_t from, igraph_integer_t to,
+static igraph_error_t igraph_i_dl_add_edge(igraph_int_t from, igraph_int_t to,
                          igraph_i_dl_parsedata_t *context) {
   //IGRAPH_CHECK(igraph_i_dl_check_vid(from+1));
   //IGRAPH_CHECK(igraph_i_dl_check_vid(to+1));
@@ -2314,11 +2314,11 @@ static igraph_error_t igraph_i_dl_add_edge(igraph_integer_t from, igraph_integer
   return IGRAPH_SUCCESS;
 }
 
-static igraph_error_t igraph_i_dl_add_edge_w(igraph_integer_t from, igraph_integer_t to,
+static igraph_error_t igraph_i_dl_add_edge_w(igraph_int_t from, igraph_int_t to,
                            igraph_real_t weight,
                            igraph_i_dl_parsedata_t *context) {
-  igraph_integer_t n=igraph_vector_size(&context->weights);
-  igraph_integer_t n2=igraph_vector_int_size(&context->edges)/2;
+  igraph_int_t n=igraph_vector_size(&context->weights);
+  igraph_int_t n2=igraph_vector_int_size(&context->edges)/2;
   if (n != n2) {
     IGRAPH_CHECK(igraph_vector_resize(&context->weights, n2));
     for (; n
    334 Harvard st, Cambridge, MA, 02138 USA
 
diff --git a/src/vendor/io/gml-parser.c b/src/vendor/io/gml-parser.c
index 66a809a3b61..c9fe95bd9c6 100644
--- a/src/vendor/io/gml-parser.c
+++ b/src/vendor/io/gml-parser.c
@@ -76,7 +76,7 @@
 
 
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2009-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
@@ -1893,7 +1893,7 @@ static igraph_error_t igraph_i_gml_make_numeric(const char *name,
   IGRAPH_FINALLY(igraph_free, t);
 
   /* The GML spec only requires support for 32-bit signed integers,
-   * but igraph tries to support the same range as igraph_integer_t,
+   * but igraph tries to support the same range as igraph_int_t,
    * so that it can read/write all graphs it can represent.
    * We treat anything out of that range as real. These values end
    * up as igraph_real_t anyway, as igraph does not currently support
diff --git a/src/vendor/io/lgl-lexer.c b/src/vendor/io/lgl-lexer.c
index d202b600b82..547946952d4 100644
--- a/src/vendor/io/lgl-lexer.c
+++ b/src/vendor/io/lgl-lexer.c
@@ -682,7 +682,7 @@ static const flex_int32_t yy_rule_can_match_eol[7] =
 #define YY_RESTORE_YY_MORE_OFFSET
 #line 1 "src/vendor/cigraph/src/io/lgl-lexer.l"
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2007-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
@@ -705,7 +705,7 @@ static const flex_int32_t yy_rule_can_match_eol[7] =
 #line 24 "src/vendor/cigraph/src/io/lgl-lexer.l"
 
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2007-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
diff --git a/src/vendor/io/lgl-parser.c b/src/vendor/io/lgl-parser.c
index 1218a8a3fb7..76904374aa3 100644
--- a/src/vendor/io/lgl-parser.c
+++ b/src/vendor/io/lgl-parser.c
@@ -76,7 +76,7 @@
 
 
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2006-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
@@ -1517,7 +1517,7 @@ YYLTYPE yylloc = yyloc_default;
                                     {
              IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, context->actvertex));
              IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[-1].edgenum)));
-             IGRAPH_YY_CHECK(igraph_vector_push_back(context->weights, 0));
+             IGRAPH_YY_CHECK(igraph_vector_push_back(context->weights, 1.0));
            }
 #line 1523 "src/vendor/io/lgl-parser.c"
     break;
@@ -1536,7 +1536,7 @@ YYLTYPE yylloc = yyloc_default;
   case 11: /* edgeid: "alphanumeric"  */
 #line 117 "src/vendor/cigraph/src/io/lgl-parser.y"
                 {
-  igraph_integer_t trie_id;
+  igraph_int_t trie_id;
   IGRAPH_YY_CHECK(igraph_trie_get_len(context->trie,
     igraph_lgl_yyget_text(scanner),
     igraph_lgl_yyget_leng(scanner),
diff --git a/src/vendor/io/ncol-lexer.c b/src/vendor/io/ncol-lexer.c
index 393423e5f4d..2d83aca793a 100644
--- a/src/vendor/io/ncol-lexer.c
+++ b/src/vendor/io/ncol-lexer.c
@@ -682,7 +682,7 @@ static const flex_int32_t yy_rule_can_match_eol[6] =
 #define YY_RESTORE_YY_MORE_OFFSET
 #line 1 "src/vendor/cigraph/src/io/ncol-lexer.l"
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2006-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
@@ -705,7 +705,7 @@ static const flex_int32_t yy_rule_can_match_eol[6] =
 #line 24 "src/vendor/cigraph/src/io/ncol-lexer.l"
 
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2006-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
diff --git a/src/vendor/io/ncol-parser.c b/src/vendor/io/ncol-parser.c
index 15916ec4094..d60a9f24737 100644
--- a/src/vendor/io/ncol-parser.c
+++ b/src/vendor/io/ncol-parser.c
@@ -76,7 +76,7 @@
 
 
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2006-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
@@ -1502,7 +1502,7 @@ YYLTYPE yylloc = yyloc_default;
   case 5: /* edge: endpoints "end of line"  */
 #line 97 "src/vendor/cigraph/src/io/ncol-parser.y"
                            {
-           IGRAPH_YY_CHECK(igraph_vector_push_back(context->weights, 0.0));
+           IGRAPH_YY_CHECK(igraph_vector_push_back(context->weights, 1.0));
        }
 #line 1508 "src/vendor/io/ncol-parser.c"
     break;
@@ -1528,7 +1528,7 @@ YYLTYPE yylloc = yyloc_default;
   case 8: /* edgeid: "alphanumeric"  */
 #line 111 "src/vendor/cigraph/src/io/ncol-parser.y"
                 {
-  igraph_integer_t trie_id;
+  igraph_int_t trie_id;
   IGRAPH_YY_CHECK(igraph_trie_get_len(context->trie,
     igraph_ncol_yyget_text(scanner),
     igraph_ncol_yyget_leng(scanner),
diff --git a/src/vendor/io/pajek-lexer.c b/src/vendor/io/pajek-lexer.c
index 781f2e869e1..dd12ab7ae5d 100644
--- a/src/vendor/io/pajek-lexer.c
+++ b/src/vendor/io/pajek-lexer.c
@@ -835,7 +835,7 @@ static const flex_int32_t yy_rule_can_match_eol[58] =
 #define YY_RESTORE_YY_MORE_OFFSET
 #line 1 "src/vendor/cigraph/src/io/pajek-lexer.l"
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2006-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
@@ -858,7 +858,7 @@ static const flex_int32_t yy_rule_can_match_eol[58] =
 #line 24 "src/vendor/cigraph/src/io/pajek-lexer.l"
 
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2006-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
diff --git a/src/vendor/io/pajek-parser.c b/src/vendor/io/pajek-parser.c
index e62631deb5b..ce2bdf8b804 100644
--- a/src/vendor/io/pajek-parser.c
+++ b/src/vendor/io/pajek-parser.c
@@ -76,7 +76,7 @@
 
 
 /*
-   IGraph library.
+   igraph library.
    Copyright (C) 2006-2012  Gabor Csardi 
    334 Harvard st, Cambridge, MA, 02138 USA
 
@@ -131,18 +131,20 @@ static igraph_error_t add_numeric_edge_attribute(const char *name,
                                               igraph_real_t value,
                                               igraph_i_pajek_parsedata_t *context);
 static igraph_error_t add_numeric_attribute(igraph_trie_t *names,
-                                         igraph_vector_ptr_t *attrs,
-                                         igraph_integer_t count,
+                                         igraph_attribute_record_list_t *attrs,
+                                         igraph_int_t count,
                                          const char *attrname,
-                                         igraph_integer_t vid,
+                                         igraph_real_t default_value,
+                                         igraph_int_t vid,
                                          igraph_real_t number);
 static igraph_error_t add_string_attribute(igraph_trie_t *names,
-                                        igraph_vector_ptr_t *attrs,
-                                        igraph_integer_t count,
+                                        igraph_attribute_record_list_t *attrs,
+                                        igraph_int_t count,
                                         const char *attrname,
-                                        igraph_integer_t vid,
+                                        const char *default_value,
+                                        igraph_int_t vid,
                                         const char *str,
-                                        igraph_integer_t str_len);
+                                        igraph_int_t str_len);
 
 static igraph_error_t add_bipartite_type(igraph_i_pajek_parsedata_t *context);
 static igraph_error_t check_bipartite(igraph_i_pajek_parsedata_t *context);
@@ -151,11 +153,15 @@ static igraph_error_t make_dynstr(const char *src, size_t len, char **res);
 static igraph_bool_t is_standard_vattr(const char *attrname);
 static igraph_bool_t is_standard_eattr(const char *attrname);
 static igraph_error_t deconflict_attrname(char **attrname);
+static igraph_real_t get_default_value_for_numeric_vattr(const char *attrname);
+static igraph_real_t get_default_value_for_numeric_eattr(const char *attrname);
+static const char* get_default_value_for_string_vattr(const char *attrname);
+static const char* get_default_value_for_string_eattr(const char *attrname);
 
 #define scanner context->scanner
 
 
-#line 159 "src/vendor/io/pajek-parser.c"
+#line 165 "src/vendor/io/pajek-parser.c"
 
 # ifndef YY_CAST
 #  ifdef __cplusplus
@@ -678,18 +684,18 @@ static const yytype_int8 yytranslate[] =
 /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_int16 yyrline[] =
 {
-       0,   188,   188,   199,   199,   201,   201,   203,   205,   216,
-     235,   235,   237,   238,   238,   248,   267,   272,   273,   277,
-     283,   283,   287,   287,   290,   291,   294,   297,   300,   303,
-     306,   309,   312,   315,   318,   323,   326,   329,   332,   335,
-     338,   353,   353,   353,   353,   353,   353,   355,   356,   358,
-     358,   360,   360,   365,   366,   368,   368,   370,   370,   375,
-     375,   379,   379,   382,   383,   386,   389,   392,   395,   398,
-     401,   404,   407,   410,   413,   416,   419,   422,   427,   430,
-     433,   436,   439,   442,   445,   460,   462,   462,   464,   466,
-     466,   468,   470,   475,   477,   477,   479,   481,   481,   483,
-     485,   492,   494,   499,   499,   501,   503,   503,   505,   525,
-     533,   541,   545,   547,   549,   551
+       0,   194,   194,   205,   205,   207,   207,   209,   211,   222,
+     241,   241,   243,   244,   244,   254,   273,   277,   278,   282,
+     288,   288,   292,   292,   295,   296,   299,   302,   305,   308,
+     311,   314,   317,   320,   323,   328,   331,   334,   337,   340,
+     343,   358,   358,   358,   358,   358,   358,   360,   361,   363,
+     363,   365,   365,   370,   371,   373,   373,   375,   375,   380,
+     380,   384,   384,   387,   388,   391,   394,   397,   400,   403,
+     406,   409,   412,   415,   418,   421,   424,   427,   432,   435,
+     438,   441,   444,   447,   450,   465,   467,   467,   469,   471,
+     471,   473,   475,   480,   482,   482,   484,   486,   486,   488,
+     490,   497,   499,   504,   504,   506,   508,   508,   510,   530,
+     538,   546,   550,   552,   554,   556
 };
 #endif
 
@@ -1486,9 +1492,9 @@ yydestruct (const char *yymsg,
   switch (yykind)
     {
     case YYSYMBOL_parname: /* parname  */
-#line 133 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 139 "src/vendor/cigraph/src/io/pajek-parser.y"
             { free(((*yyvaluep).dynstr)); }
-#line 1492 "src/vendor/io/pajek-parser.c"
+#line 1498 "src/vendor/io/pajek-parser.c"
         break;
 
       default:
@@ -1792,7 +1798,7 @@ YYLTYPE yylloc = yyloc_default;
   switch (yyn)
     {
   case 2: /* input: nethead vertices edgeblock final_newlines  */
-#line 188 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 194 "src/vendor/cigraph/src/io/pajek-parser.y"
                                                  {
   if (context->vcount2 > 0) { check_bipartite(context); }
   if (! context->eof) {
@@ -1803,11 +1809,11 @@ YYLTYPE yylloc = yyloc_default;
   }
   YYACCEPT; /* stop parsing even if there is more data in the file. */
  }
-#line 1807 "src/vendor/io/pajek-parser.c"
+#line 1813 "src/vendor/io/pajek-parser.c"
     break;
 
   case 8: /* verticeshead: "*Vertices line" integer  */
-#line 205 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 211 "src/vendor/cigraph/src/io/pajek-parser.y"
                                    {
   context->vcount=(yyvsp[0].intnum);
   context->vcount2=0;
@@ -1819,11 +1825,11 @@ YYLTYPE yylloc = yyloc_default;
   }
   IGRAPH_YY_CHECK(igraph_bitset_resize(context->seen, context->vcount));
             }
-#line 1823 "src/vendor/io/pajek-parser.c"
+#line 1829 "src/vendor/io/pajek-parser.c"
     break;
 
   case 9: /* verticeshead: "*Vertices line" integer integer  */
-#line 216 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 222 "src/vendor/cigraph/src/io/pajek-parser.y"
                                            {
   context->vcount=(yyvsp[-1].intnum);
   context->vcount2=(yyvsp[0].intnum);
@@ -1842,32 +1848,32 @@ YYLTYPE yylloc = yyloc_default;
   IGRAPH_YY_CHECK(add_bipartite_type(context));
   IGRAPH_YY_CHECK(igraph_bitset_resize(context->seen, context->vcount));
 }
-#line 1846 "src/vendor/io/pajek-parser.c"
+#line 1852 "src/vendor/io/pajek-parser.c"
     break;
 
   case 13: /* $@1: %empty  */
-#line 238 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 244 "src/vendor/cigraph/src/io/pajek-parser.y"
                    { context->actvertex=(yyvsp[0].intnum); }
-#line 1852 "src/vendor/io/pajek-parser.c"
+#line 1858 "src/vendor/io/pajek-parser.c"
     break;
 
   case 14: /* vertexline: vertex $@1 vertexid vertexcoords shape vertparams "end of line"  */
-#line 238 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 244 "src/vendor/cigraph/src/io/pajek-parser.y"
                                                                                              {
-              igraph_integer_t v = (yyvsp[-6].intnum)-1; /* zero-based vertex ID */
+              igraph_int_t v = (yyvsp[-6].intnum)-1; /* zero-based vertex ID */
               if (IGRAPH_BIT_TEST(*context->seen, v)) {
                 IGRAPH_WARNINGF("Vertex ID %" IGRAPH_PRId " appears twice in Pajek file. Duplicate attributes will be overwritten.", v+1);
               } else {
                 IGRAPH_BIT_SET(*context->seen, v);
               }
             }
-#line 1865 "src/vendor/io/pajek-parser.c"
+#line 1871 "src/vendor/io/pajek-parser.c"
     break;
 
   case 15: /* vertex: integer  */
-#line 248 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 254 "src/vendor/cigraph/src/io/pajek-parser.y"
                 {
-  igraph_integer_t v = (yyvsp[0].intnum);
+  igraph_int_t v = (yyvsp[0].intnum);
   /* Per feedback from Pajek's authors, negative signs should be ignored for vertex IDs.
    * See https://nascol.discourse.group/t/pajek-arcslist-edgelist-format/44/2
    * This applies to all of *Edges, *Arcs, *Edgeslist, *Arcslist and *Vertices section.
@@ -1884,167 +1890,166 @@ YYLTYPE yylloc = yyloc_default;
   }
   (yyval.intnum) = v;
 }
-#line 1888 "src/vendor/io/pajek-parser.c"
+#line 1894 "src/vendor/io/pajek-parser.c"
     break;
 
   case 16: /* vertexid: word  */
-#line 267 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 273 "src/vendor/cigraph/src/io/pajek-parser.y"
                {
-  IGRAPH_YY_CHECK(add_string_vertex_attribute("id", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
   IGRAPH_YY_CHECK(add_string_vertex_attribute("name", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
 }
-#line 1897 "src/vendor/io/pajek-parser.c"
+#line 1902 "src/vendor/io/pajek-parser.c"
     break;
 
   case 18: /* vertexcoords: number number  */
-#line 273 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 278 "src/vendor/cigraph/src/io/pajek-parser.y"
                             {
   IGRAPH_YY_CHECK(add_numeric_vertex_attribute("x", (yyvsp[-1].realnum), context));
   IGRAPH_YY_CHECK(add_numeric_vertex_attribute("y", (yyvsp[0].realnum), context));
             }
-#line 1906 "src/vendor/io/pajek-parser.c"
+#line 1911 "src/vendor/io/pajek-parser.c"
     break;
 
   case 19: /* vertexcoords: number number number  */
-#line 277 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 282 "src/vendor/cigraph/src/io/pajek-parser.y"
                                    {
   IGRAPH_YY_CHECK(add_numeric_vertex_attribute("x", (yyvsp[-2].realnum), context));
   IGRAPH_YY_CHECK(add_numeric_vertex_attribute("y", (yyvsp[-1].realnum), context));
   IGRAPH_YY_CHECK(add_numeric_vertex_attribute("z", (yyvsp[0].realnum), context));
             }
-#line 1916 "src/vendor/io/pajek-parser.c"
+#line 1921 "src/vendor/io/pajek-parser.c"
     break;
 
   case 21: /* shape: word  */
-#line 283 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 288 "src/vendor/cigraph/src/io/pajek-parser.y"
                           {
   IGRAPH_YY_CHECK(add_string_vertex_attribute("shape", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
 }
-#line 1924 "src/vendor/io/pajek-parser.c"
+#line 1929 "src/vendor/io/pajek-parser.c"
     break;
 
   case 25: /* vertparam: VP_X_FACT number  */
-#line 291 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 296 "src/vendor/cigraph/src/io/pajek-parser.y"
                         {
          IGRAPH_YY_CHECK(add_numeric_vertex_attribute("xfact", (yyvsp[0].realnum), context));
        }
-#line 1932 "src/vendor/io/pajek-parser.c"
+#line 1937 "src/vendor/io/pajek-parser.c"
     break;
 
   case 26: /* vertparam: VP_Y_FACT number  */
-#line 294 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 299 "src/vendor/cigraph/src/io/pajek-parser.y"
                         {
          IGRAPH_YY_CHECK(add_numeric_vertex_attribute("yfact", (yyvsp[0].realnum), context));
        }
-#line 1940 "src/vendor/io/pajek-parser.c"
+#line 1945 "src/vendor/io/pajek-parser.c"
     break;
 
   case 27: /* vertparam: VP_LR number  */
-#line 297 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 302 "src/vendor/cigraph/src/io/pajek-parser.y"
                     {
          IGRAPH_YY_CHECK(add_numeric_vertex_attribute("labeldist", (yyvsp[0].realnum), context));
      }
-#line 1948 "src/vendor/io/pajek-parser.c"
+#line 1953 "src/vendor/io/pajek-parser.c"
     break;
 
   case 28: /* vertparam: VP_LPHI number  */
-#line 300 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 305 "src/vendor/cigraph/src/io/pajek-parser.y"
                       {
          IGRAPH_YY_CHECK(add_numeric_vertex_attribute("labeldegree2", (yyvsp[0].realnum), context));
      }
-#line 1956 "src/vendor/io/pajek-parser.c"
+#line 1961 "src/vendor/io/pajek-parser.c"
     break;
 
   case 29: /* vertparam: VP_BW number  */
-#line 303 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 308 "src/vendor/cigraph/src/io/pajek-parser.y"
                     {
          IGRAPH_YY_CHECK(add_numeric_vertex_attribute("framewidth", (yyvsp[0].realnum), context));
      }
-#line 1964 "src/vendor/io/pajek-parser.c"
+#line 1969 "src/vendor/io/pajek-parser.c"
     break;
 
   case 30: /* vertparam: VP_FOS number  */
-#line 306 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 311 "src/vendor/cigraph/src/io/pajek-parser.y"
                      {
          IGRAPH_YY_CHECK(add_numeric_vertex_attribute("fontsize", (yyvsp[0].realnum), context));
      }
-#line 1972 "src/vendor/io/pajek-parser.c"
+#line 1977 "src/vendor/io/pajek-parser.c"
     break;
 
   case 31: /* vertparam: VP_PHI number  */
-#line 309 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 314 "src/vendor/cigraph/src/io/pajek-parser.y"
                      {
          IGRAPH_YY_CHECK(add_numeric_vertex_attribute("rotation", (yyvsp[0].realnum), context));
      }
-#line 1980 "src/vendor/io/pajek-parser.c"
+#line 1985 "src/vendor/io/pajek-parser.c"
     break;
 
   case 32: /* vertparam: VP_R number  */
-#line 312 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 317 "src/vendor/cigraph/src/io/pajek-parser.y"
                    {
          IGRAPH_YY_CHECK(add_numeric_vertex_attribute("radius", (yyvsp[0].realnum), context));
      }
-#line 1988 "src/vendor/io/pajek-parser.c"
+#line 1993 "src/vendor/io/pajek-parser.c"
     break;
 
   case 33: /* vertparam: VP_Q number  */
-#line 315 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 320 "src/vendor/cigraph/src/io/pajek-parser.y"
                    {
          IGRAPH_YY_CHECK(add_numeric_vertex_attribute("diamondratio", (yyvsp[0].realnum), context));
      }
-#line 1996 "src/vendor/io/pajek-parser.c"
+#line 2001 "src/vendor/io/pajek-parser.c"
     break;
 
   case 34: /* vertparam: VP_LA number  */
-#line 318 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 323 "src/vendor/cigraph/src/io/pajek-parser.y"
                     {
          IGRAPH_YY_CHECK(add_numeric_vertex_attribute("labeldegree", (yyvsp[0].realnum), context));
      }
-#line 2004 "src/vendor/io/pajek-parser.c"
+#line 2009 "src/vendor/io/pajek-parser.c"
     break;
 
   case 35: /* vpword: VP_FONT parstrval  */
-#line 323 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 328 "src/vendor/cigraph/src/io/pajek-parser.y"
                           {
          IGRAPH_YY_CHECK(add_string_vertex_attribute("font", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
      }
-#line 2012 "src/vendor/io/pajek-parser.c"
+#line 2017 "src/vendor/io/pajek-parser.c"
     break;
 
   case 36: /* vpword: VP_URL parstrval  */
-#line 326 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 331 "src/vendor/cigraph/src/io/pajek-parser.y"
                         {
          IGRAPH_YY_CHECK(add_string_vertex_attribute("url", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
      }
-#line 2020 "src/vendor/io/pajek-parser.c"
+#line 2025 "src/vendor/io/pajek-parser.c"
     break;
 
   case 37: /* vpword: VP_IC parstrval  */
-#line 329 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 334 "src/vendor/cigraph/src/io/pajek-parser.y"
                        {
          IGRAPH_YY_CHECK(add_string_vertex_attribute("color", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
      }
-#line 2028 "src/vendor/io/pajek-parser.c"
+#line 2033 "src/vendor/io/pajek-parser.c"
     break;
 
   case 38: /* vpword: VP_BC parstrval  */
-#line 332 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 337 "src/vendor/cigraph/src/io/pajek-parser.y"
                        {
          IGRAPH_YY_CHECK(add_string_vertex_attribute("framecolor", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
      }
-#line 2036 "src/vendor/io/pajek-parser.c"
+#line 2041 "src/vendor/io/pajek-parser.c"
     break;
 
   case 39: /* vpword: VP_LC parstrval  */
-#line 335 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 340 "src/vendor/cigraph/src/io/pajek-parser.y"
                        {
          IGRAPH_YY_CHECK(add_string_vertex_attribute("labelcolor", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
      }
-#line 2044 "src/vendor/io/pajek-parser.c"
+#line 2049 "src/vendor/io/pajek-parser.c"
     break;
 
   case 40: /* vpword: parname parstrval  */
-#line 338 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 343 "src/vendor/cigraph/src/io/pajek-parser.y"
                          {
          IGRAPH_FINALLY(igraph_free, (yyvsp[-1].dynstr));
          if (is_standard_vattr((yyvsp[-1].dynstr))) {
@@ -2058,231 +2063,231 @@ YYLTYPE yylloc = yyloc_default;
          IGRAPH_FREE((yyvsp[-1].dynstr));
          IGRAPH_FINALLY_CLEAN(1);
      }
-#line 2062 "src/vendor/io/pajek-parser.c"
+#line 2067 "src/vendor/io/pajek-parser.c"
     break;
 
   case 47: /* arcs: "*Arcs line" "end of line" arcsdefs  */
-#line 355 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 360 "src/vendor/cigraph/src/io/pajek-parser.y"
                                          { context->directed=true; }
-#line 2068 "src/vendor/io/pajek-parser.c"
+#line 2073 "src/vendor/io/pajek-parser.c"
     break;
 
   case 48: /* arcs: "*Arcs line" number "end of line" arcsdefs  */
-#line 356 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 361 "src/vendor/cigraph/src/io/pajek-parser.y"
                                          { context->directed=true; }
-#line 2074 "src/vendor/io/pajek-parser.c"
+#line 2079 "src/vendor/io/pajek-parser.c"
     break;
 
   case 51: /* $@2: %empty  */
-#line 360 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 365 "src/vendor/cigraph/src/io/pajek-parser.y"
                         { context->actedge++; }
-#line 2080 "src/vendor/io/pajek-parser.c"
+#line 2085 "src/vendor/io/pajek-parser.c"
     break;
 
   case 52: /* arcsline: vertex vertex $@2 weight edgeparams "end of line"  */
-#line 360 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 365 "src/vendor/cigraph/src/io/pajek-parser.y"
                                                                            {
   IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[-5].intnum)-1));
   IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[-4].intnum)-1)); }
-#line 2088 "src/vendor/io/pajek-parser.c"
+#line 2093 "src/vendor/io/pajek-parser.c"
     break;
 
   case 53: /* edges: "*Edges line" "end of line" edgesdefs  */
-#line 365 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 370 "src/vendor/cigraph/src/io/pajek-parser.y"
                                      { context->directed=0; }
-#line 2094 "src/vendor/io/pajek-parser.c"
+#line 2099 "src/vendor/io/pajek-parser.c"
     break;
 
   case 54: /* edges: "*Edges line" number "end of line" edgesdefs  */
-#line 366 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 371 "src/vendor/cigraph/src/io/pajek-parser.y"
                                             { context->directed=0; }
-#line 2100 "src/vendor/io/pajek-parser.c"
+#line 2105 "src/vendor/io/pajek-parser.c"
     break;
 
   case 57: /* $@3: %empty  */
-#line 370 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 375 "src/vendor/cigraph/src/io/pajek-parser.y"
                          { context->actedge++; }
-#line 2106 "src/vendor/io/pajek-parser.c"
+#line 2111 "src/vendor/io/pajek-parser.c"
     break;
 
   case 58: /* edgesline: vertex vertex $@3 weight edgeparams "end of line"  */
-#line 370 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 375 "src/vendor/cigraph/src/io/pajek-parser.y"
                                                                            {
   IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[-5].intnum)-1));
   IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[-4].intnum)-1)); }
-#line 2114 "src/vendor/io/pajek-parser.c"
+#line 2119 "src/vendor/io/pajek-parser.c"
     break;
 
   case 60: /* weight: number  */
-#line 375 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 380 "src/vendor/cigraph/src/io/pajek-parser.y"
                              {
   IGRAPH_YY_CHECK(add_numeric_edge_attribute("weight", (yyvsp[0].realnum), context));
 }
-#line 2122 "src/vendor/io/pajek-parser.c"
+#line 2127 "src/vendor/io/pajek-parser.c"
     break;
 
   case 64: /* edgeparam: EP_S number  */
-#line 383 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 388 "src/vendor/cigraph/src/io/pajek-parser.y"
                  {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("arrowsize", (yyvsp[0].realnum), context));
    }
-#line 2130 "src/vendor/io/pajek-parser.c"
+#line 2135 "src/vendor/io/pajek-parser.c"
     break;
 
   case 65: /* edgeparam: EP_W number  */
-#line 386 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 391 "src/vendor/cigraph/src/io/pajek-parser.y"
                  {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("edgewidth", (yyvsp[0].realnum), context));
    }
-#line 2138 "src/vendor/io/pajek-parser.c"
+#line 2143 "src/vendor/io/pajek-parser.c"
     break;
 
   case 66: /* edgeparam: EP_H1 number  */
-#line 389 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 394 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("hook1", (yyvsp[0].realnum), context));
    }
-#line 2146 "src/vendor/io/pajek-parser.c"
+#line 2151 "src/vendor/io/pajek-parser.c"
     break;
 
   case 67: /* edgeparam: EP_H2 number  */
-#line 392 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 397 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("hook2", (yyvsp[0].realnum), context));
    }
-#line 2154 "src/vendor/io/pajek-parser.c"
+#line 2159 "src/vendor/io/pajek-parser.c"
     break;
 
   case 68: /* edgeparam: EP_A1 number  */
-#line 395 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 400 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("angle1", (yyvsp[0].realnum), context));
    }
-#line 2162 "src/vendor/io/pajek-parser.c"
+#line 2167 "src/vendor/io/pajek-parser.c"
     break;
 
   case 69: /* edgeparam: EP_A2 number  */
-#line 398 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 403 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("angle2", (yyvsp[0].realnum), context));
    }
-#line 2170 "src/vendor/io/pajek-parser.c"
+#line 2175 "src/vendor/io/pajek-parser.c"
     break;
 
   case 70: /* edgeparam: EP_K1 number  */
-#line 401 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 406 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("velocity1", (yyvsp[0].realnum), context));
    }
-#line 2178 "src/vendor/io/pajek-parser.c"
+#line 2183 "src/vendor/io/pajek-parser.c"
     break;
 
   case 71: /* edgeparam: EP_K2 number  */
-#line 404 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 409 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("velocity2", (yyvsp[0].realnum), context));
    }
-#line 2186 "src/vendor/io/pajek-parser.c"
+#line 2191 "src/vendor/io/pajek-parser.c"
     break;
 
   case 72: /* edgeparam: EP_AP number  */
-#line 407 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 412 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("arrowpos", (yyvsp[0].realnum), context));
    }
-#line 2194 "src/vendor/io/pajek-parser.c"
+#line 2199 "src/vendor/io/pajek-parser.c"
     break;
 
   case 73: /* edgeparam: EP_LP number  */
-#line 410 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 415 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("labelpos", (yyvsp[0].realnum), context));
    }
-#line 2202 "src/vendor/io/pajek-parser.c"
+#line 2207 "src/vendor/io/pajek-parser.c"
     break;
 
   case 74: /* edgeparam: EP_LR number  */
-#line 413 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 418 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("labelangle", (yyvsp[0].realnum), context));
    }
-#line 2210 "src/vendor/io/pajek-parser.c"
+#line 2215 "src/vendor/io/pajek-parser.c"
     break;
 
   case 75: /* edgeparam: EP_LPHI number  */
-#line 416 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 421 "src/vendor/cigraph/src/io/pajek-parser.y"
                     {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("labelangle2", (yyvsp[0].realnum), context));
    }
-#line 2218 "src/vendor/io/pajek-parser.c"
+#line 2223 "src/vendor/io/pajek-parser.c"
     break;
 
   case 76: /* edgeparam: EP_LA number  */
-#line 419 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 424 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("labeldegree", (yyvsp[0].realnum), context));
    }
-#line 2226 "src/vendor/io/pajek-parser.c"
+#line 2231 "src/vendor/io/pajek-parser.c"
     break;
 
   case 77: /* edgeparam: EP_FOS number  */
-#line 422 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 427 "src/vendor/cigraph/src/io/pajek-parser.y"
                    {
        IGRAPH_YY_CHECK(add_numeric_edge_attribute("fontsize", (yyvsp[0].realnum), context));
    }
-#line 2234 "src/vendor/io/pajek-parser.c"
+#line 2239 "src/vendor/io/pajek-parser.c"
     break;
 
   case 78: /* epword: EP_A parstrval  */
-#line 427 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 432 "src/vendor/cigraph/src/io/pajek-parser.y"
                        {
       IGRAPH_YY_CHECK(add_string_edge_attribute("arrowtype", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
     }
-#line 2242 "src/vendor/io/pajek-parser.c"
+#line 2247 "src/vendor/io/pajek-parser.c"
     break;
 
   case 79: /* epword: EP_P parstrval  */
-#line 430 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 435 "src/vendor/cigraph/src/io/pajek-parser.y"
                      {
       IGRAPH_YY_CHECK(add_string_edge_attribute("linepattern", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
     }
-#line 2250 "src/vendor/io/pajek-parser.c"
+#line 2255 "src/vendor/io/pajek-parser.c"
     break;
 
   case 80: /* epword: EP_L parstrval  */
-#line 433 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 438 "src/vendor/cigraph/src/io/pajek-parser.y"
                      {
       IGRAPH_YY_CHECK(add_string_edge_attribute("label", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
     }
-#line 2258 "src/vendor/io/pajek-parser.c"
+#line 2263 "src/vendor/io/pajek-parser.c"
     break;
 
   case 81: /* epword: EP_LC parstrval  */
-#line 436 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 441 "src/vendor/cigraph/src/io/pajek-parser.y"
                       {
       IGRAPH_YY_CHECK(add_string_edge_attribute("labelcolor", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
     }
-#line 2266 "src/vendor/io/pajek-parser.c"
+#line 2271 "src/vendor/io/pajek-parser.c"
     break;
 
   case 82: /* epword: EP_C parstrval  */
-#line 439 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 444 "src/vendor/cigraph/src/io/pajek-parser.y"
                      {
       IGRAPH_YY_CHECK(add_string_edge_attribute("color", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
     }
-#line 2274 "src/vendor/io/pajek-parser.c"
+#line 2279 "src/vendor/io/pajek-parser.c"
     break;
 
   case 83: /* epword: EP_FONT parstrval  */
-#line 442 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 447 "src/vendor/cigraph/src/io/pajek-parser.y"
                         {
       IGRAPH_YY_CHECK(add_string_edge_attribute("font", (yyvsp[0].string).str, (yyvsp[0].string).len, context));
     }
-#line 2282 "src/vendor/io/pajek-parser.c"
+#line 2287 "src/vendor/io/pajek-parser.c"
     break;
 
   case 84: /* epword: parname parstrval  */
-#line 445 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 450 "src/vendor/cigraph/src/io/pajek-parser.y"
                         {
         IGRAPH_FINALLY(igraph_free, (yyvsp[-1].dynstr));
         if (is_standard_eattr((yyvsp[-1].dynstr))) {
@@ -2296,68 +2301,68 @@ YYLTYPE yylloc = yyloc_default;
         IGRAPH_FREE((yyvsp[-1].dynstr));
         IGRAPH_FINALLY_CLEAN(1);
      }
-#line 2300 "src/vendor/io/pajek-parser.c"
+#line 2305 "src/vendor/io/pajek-parser.c"
     break;
 
   case 85: /* arcslist: "*Arcslist line" "end of line" arcslistlines  */
-#line 460 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 465 "src/vendor/cigraph/src/io/pajek-parser.y"
                                              { context->directed=true; }
-#line 2306 "src/vendor/io/pajek-parser.c"
+#line 2311 "src/vendor/io/pajek-parser.c"
     break;
 
   case 91: /* arclistfrom: vertex  */
-#line 468 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 473 "src/vendor/cigraph/src/io/pajek-parser.y"
                     { context->actfrom=(yyvsp[0].intnum)-1; }
-#line 2312 "src/vendor/io/pajek-parser.c"
+#line 2317 "src/vendor/io/pajek-parser.c"
     break;
 
   case 92: /* arclistto: vertex  */
-#line 470 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 475 "src/vendor/cigraph/src/io/pajek-parser.y"
                   {
   IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, context->actfrom));
   IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[0].intnum)-1));
 }
-#line 2321 "src/vendor/io/pajek-parser.c"
+#line 2326 "src/vendor/io/pajek-parser.c"
     break;
 
   case 93: /* edgeslist: "*Edgeslist line" "end of line" edgelistlines  */
-#line 475 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 480 "src/vendor/cigraph/src/io/pajek-parser.y"
                                                { context->directed=0; }
-#line 2327 "src/vendor/io/pajek-parser.c"
+#line 2332 "src/vendor/io/pajek-parser.c"
     break;
 
   case 99: /* edgelistfrom: vertex  */
-#line 483 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 488 "src/vendor/cigraph/src/io/pajek-parser.y"
                      { context->actfrom=(yyvsp[0].intnum)-1; }
-#line 2333 "src/vendor/io/pajek-parser.c"
+#line 2338 "src/vendor/io/pajek-parser.c"
     break;
 
   case 100: /* edgelistto: vertex  */
-#line 485 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 490 "src/vendor/cigraph/src/io/pajek-parser.y"
                    {
   IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, context->actfrom));
   IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[0].intnum)-1));
 }
-#line 2342 "src/vendor/io/pajek-parser.c"
+#line 2347 "src/vendor/io/pajek-parser.c"
     break;
 
   case 102: /* matrixline: "*Matrix line"  */
-#line 494 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 499 "src/vendor/cigraph/src/io/pajek-parser.y"
                        { context->actfrom=0;
                          context->actto=0;
                          context->directed=(context->vcount2==0);
                        }
-#line 2351 "src/vendor/io/pajek-parser.c"
+#line 2356 "src/vendor/io/pajek-parser.c"
     break;
 
   case 105: /* adjmatrixline: adjmatrixnumbers "end of line"  */
-#line 501 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 506 "src/vendor/cigraph/src/io/pajek-parser.y"
                                         { context->actfrom++; context->actto=0; }
-#line 2357 "src/vendor/io/pajek-parser.c"
+#line 2362 "src/vendor/io/pajek-parser.c"
     break;
 
   case 108: /* adjmatrixentry: number  */
-#line 505 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 510 "src/vendor/cigraph/src/io/pajek-parser.y"
                        {
   if ((yyvsp[0].realnum) != 0) {
     if (context->vcount2==0) {
@@ -2375,23 +2380,23 @@ YYLTYPE yylloc = yyloc_default;
   }
   context->actto++;
 }
-#line 2379 "src/vendor/io/pajek-parser.c"
+#line 2384 "src/vendor/io/pajek-parser.c"
     break;
 
   case 109: /* integer: "number"  */
-#line 525 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 530 "src/vendor/cigraph/src/io/pajek-parser.y"
              {
-  igraph_integer_t val;
+  igraph_int_t val;
   IGRAPH_YY_CHECK(igraph_i_parse_integer(igraph_pajek_yyget_text(scanner),
                                          igraph_pajek_yyget_leng(scanner),
                                          &val));
   (yyval.intnum)=val;
 }
-#line 2391 "src/vendor/io/pajek-parser.c"
+#line 2396 "src/vendor/io/pajek-parser.c"
     break;
 
   case 110: /* number: "number"  */
-#line 533 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 538 "src/vendor/cigraph/src/io/pajek-parser.y"
              {
   igraph_real_t val;
   IGRAPH_YY_CHECK(igraph_i_parse_real(igraph_pajek_yyget_text(scanner),
@@ -2399,46 +2404,46 @@ YYLTYPE yylloc = yyloc_default;
                                       &val));
   (yyval.realnum)=val;
 }
-#line 2403 "src/vendor/io/pajek-parser.c"
+#line 2408 "src/vendor/io/pajek-parser.c"
     break;
 
   case 111: /* parname: word  */
-#line 541 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 546 "src/vendor/cigraph/src/io/pajek-parser.y"
               {
   IGRAPH_YY_CHECK(make_dynstr((yyvsp[0].string).str, (yyvsp[0].string).len, &(yyval.dynstr)));
 }
-#line 2411 "src/vendor/io/pajek-parser.c"
+#line 2416 "src/vendor/io/pajek-parser.c"
     break;
 
   case 112: /* parstrval: word  */
-#line 545 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 550 "src/vendor/cigraph/src/io/pajek-parser.y"
                 { (yyval.string)=(yyvsp[0].string); }
-#line 2417 "src/vendor/io/pajek-parser.c"
+#line 2422 "src/vendor/io/pajek-parser.c"
     break;
 
   case 113: /* word: "word"  */
-#line 547 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 552 "src/vendor/cigraph/src/io/pajek-parser.y"
             { (yyval.string).str=igraph_pajek_yyget_text(scanner);
               (yyval.string).len=igraph_pajek_yyget_leng(scanner); }
-#line 2424 "src/vendor/io/pajek-parser.c"
+#line 2429 "src/vendor/io/pajek-parser.c"
     break;
 
   case 114: /* word: "number"  */
-#line 549 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 554 "src/vendor/cigraph/src/io/pajek-parser.y"
             { (yyval.string).str=igraph_pajek_yyget_text(scanner);
               (yyval.string).len=igraph_pajek_yyget_leng(scanner); }
-#line 2431 "src/vendor/io/pajek-parser.c"
+#line 2436 "src/vendor/io/pajek-parser.c"
     break;
 
   case 115: /* word: "quoted string"  */
-#line 551 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 556 "src/vendor/cigraph/src/io/pajek-parser.y"
              { (yyval.string).str=igraph_pajek_yyget_text(scanner)+1;
                (yyval.string).len=igraph_pajek_yyget_leng(scanner)-2; }
-#line 2438 "src/vendor/io/pajek-parser.c"
+#line 2443 "src/vendor/io/pajek-parser.c"
     break;
 
 
-#line 2442 "src/vendor/io/pajek-parser.c"
+#line 2447 "src/vendor/io/pajek-parser.c"
 
       default: break;
     }
@@ -2667,7 +2672,7 @@ YYLTYPE yylloc = yyloc_default;
   return yyresult;
 }
 
-#line 554 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 559 "src/vendor/cigraph/src/io/pajek-parser.y"
 
 
 int igraph_pajek_yyerror(YYLTYPE* locp,
@@ -2682,49 +2687,38 @@ int igraph_pajek_yyerror(YYLTYPE* locp,
 /* TODO: NA's */
 
 static igraph_error_t add_numeric_attribute(igraph_trie_t *names,
-                                            igraph_vector_ptr_t *attrs,
-                                            igraph_integer_t count,
+                                            igraph_attribute_record_list_t *attrs,
+                                            igraph_int_t count,
                                             const char *attrname,
-                                            igraph_integer_t elem_id,
+                                            igraph_real_t default_value,
+                                            igraph_int_t elem_id,
                                             igraph_real_t number) {
-  igraph_integer_t attrsize = igraph_trie_size(names);
-  igraph_integer_t id;
+  igraph_int_t attrsize = igraph_trie_size(names);
+  igraph_int_t id;
   igraph_vector_t *na;
-  igraph_attribute_record_t *rec;
+  igraph_attribute_record_t *prec;
 
   IGRAPH_CHECK(igraph_trie_get(names, attrname, &id));
   if (id == attrsize) {
-    /* add a new attribute */
-    rec = IGRAPH_CALLOC(1, igraph_attribute_record_t);
-    CHECK_OOM_RP(rec);
-    IGRAPH_FINALLY(igraph_free, rec);
-
-    na = IGRAPH_CALLOC(1, igraph_vector_t);
-    CHECK_OOM_RP(na);
-    IGRAPH_FINALLY(igraph_free, na);
-    IGRAPH_VECTOR_INIT_FINALLY(na, count);
+    igraph_attribute_record_t rec;
 
-    rec->name = strdup(attrname);
-    CHECK_OOM_RP(rec->name);
-    IGRAPH_FINALLY(igraph_free, (void *) rec->name);
+    /* add a new attribute */
+    IGRAPH_CHECK(igraph_attribute_record_init(&rec, attrname, IGRAPH_ATTRIBUTE_NUMERIC));
+    IGRAPH_FINALLY(igraph_attribute_record_destroy, &rec);
 
-    rec->type = IGRAPH_ATTRIBUTE_NUMERIC;
-    rec->value = na;
+    IGRAPH_CHECK(igraph_attribute_record_set_default_numeric(&rec, default_value));
 
-    IGRAPH_CHECK(igraph_vector_ptr_push_back(attrs, rec));
-    IGRAPH_FINALLY_CLEAN(4); /* ownership of rec transferred to attrs */
+    IGRAPH_CHECK(igraph_attribute_record_resize(&rec, count));
+    IGRAPH_CHECK(igraph_attribute_record_list_push_back(attrs, &rec));
+    IGRAPH_FINALLY_CLEAN(1); /* ownership of rec transferred to attrs */
   }
 
-  rec = VECTOR(*attrs)[id];
-  na = (igraph_vector_t *) rec->value;
+  prec = igraph_attribute_record_list_get_ptr(attrs, id);
+  na = prec->value.as_vector;
   if (igraph_vector_size(na) == elem_id) {
     IGRAPH_CHECK(igraph_vector_push_back(na, number));
   } else if (igraph_vector_size(na) < elem_id) {
-    igraph_integer_t origsize=igraph_vector_size(na);
-    IGRAPH_CHECK(igraph_vector_resize(na, elem_id+1));
-    for (;origsizename = strdup(attrname);
-    CHECK_OOM_RP(rec->name);
-    IGRAPH_FINALLY(igraph_free, (char *) rec->name);
+    IGRAPH_CHECK(igraph_attribute_record_set_default_string(&rec, default_value));
 
-    rec->type = IGRAPH_ATTRIBUTE_STRING;
-    rec->value = na;
-
-    IGRAPH_CHECK(igraph_vector_ptr_push_back(attrs, rec));
-    IGRAPH_FINALLY_CLEAN(4); /* ownership of rec transferred to attrs */
+    IGRAPH_CHECK(igraph_attribute_record_resize(&rec, count));
+    IGRAPH_CHECK(igraph_attribute_record_list_push_back(attrs, &rec));
+    IGRAPH_FINALLY_CLEAN(1); /* ownership of rec transferred to attrs */
   }
 
-  rec = VECTOR(*attrs)[id];
-  na = (igraph_strvector_t *) rec->value;
+  prec = igraph_attribute_record_list_get_ptr(attrs, id);
+  na = prec->value.as_strvector;
   if (igraph_strvector_size(na) <= elem_id) {
     IGRAPH_CHECK(igraph_strvector_resize(na, elem_id+1));
   }
@@ -2809,7 +2792,9 @@ static igraph_error_t add_string_vertex_attribute(const char *name,
   return add_string_attribute(context->vertex_attribute_names,
                               context->vertex_attributes,
                               context->vcount,
-                              name, context->actvertex-1,
+                              name,
+                              get_default_value_for_string_vattr(name),
+                              context->actvertex-1,
                               value, len);
 }
 
@@ -2821,7 +2806,9 @@ static igraph_error_t add_string_edge_attribute(const char *name,
   return add_string_attribute(context->edge_attribute_names,
                               context->edge_attributes,
                               context->actedge,
-                              name, context->actedge-1,
+                              name,
+                              get_default_value_for_string_eattr(name),
+                              context->actedge-1,
                               value, len);
 }
 
@@ -2832,7 +2819,9 @@ static igraph_error_t add_numeric_vertex_attribute(const char *name,
   return add_numeric_attribute(context->vertex_attribute_names,
                                context->vertex_attributes,
                                context->vcount,
-                               name, context->actvertex-1,
+                               name,
+                               get_default_value_for_numeric_vattr(name),
+                               context->actvertex-1,
                                value);
 }
 
@@ -2843,7 +2832,9 @@ static igraph_error_t add_numeric_edge_attribute(const char *name,
   return add_numeric_attribute(context->edge_attribute_names,
                                context->edge_attributes,
                                context->actedge,
-                               name, context->actedge-1,
+                               name,
+                               get_default_value_for_numeric_eattr(name),
+                               context->actedge-1,
                                value);
 }
 
@@ -2851,10 +2842,10 @@ static igraph_error_t add_bipartite_type(igraph_i_pajek_parsedata_t *context) {
 
   const char *attrname="type";
   igraph_trie_t *names=context->vertex_attribute_names;
-  igraph_vector_ptr_t *attrs=context->vertex_attributes;
-  igraph_integer_t n=context->vcount, n1=context->vcount2;
-  igraph_integer_t attrid, attrsize = igraph_trie_size(names);
-  igraph_attribute_record_t *rec;
+  igraph_attribute_record_list_t *attrs=context->vertex_attributes;
+  igraph_int_t n=context->vcount, n1=context->vcount2;
+  igraph_int_t attrid, attrsize = igraph_trie_size(names);
+  igraph_attribute_record_t* rec;
   igraph_vector_bool_t *na;
 
   if (n1 > n) {
@@ -2869,29 +2860,13 @@ static igraph_error_t add_bipartite_type(igraph_i_pajek_parsedata_t *context) {
   IGRAPH_ASSERT(attrid == attrsize);
 
   /* add a new attribute */
-  rec = IGRAPH_CALLOC(1, igraph_attribute_record_t);
-  CHECK_OOM_RP(rec);
-  IGRAPH_FINALLY(igraph_free, rec);
-
-  na = IGRAPH_CALLOC(1, igraph_vector_bool_t);
-  CHECK_OOM_RP(na);
-  IGRAPH_FINALLY(igraph_free, na);
-  IGRAPH_VECTOR_BOOL_INIT_FINALLY(na, n);
+  IGRAPH_CHECK(igraph_attribute_record_list_push_back_new(attrs, &rec));
+  IGRAPH_CHECK(igraph_attribute_record_set_name(rec, attrname));
+  IGRAPH_CHECK(igraph_attribute_record_set_type(rec, IGRAPH_ATTRIBUTE_BOOLEAN));
+  IGRAPH_CHECK(igraph_attribute_record_resize(rec, n));
 
-  rec->name = strdup(attrname);
-  CHECK_OOM_RP(rec->name);
-  IGRAPH_FINALLY(igraph_free, (char *) rec->name);
-
-  rec->type = IGRAPH_ATTRIBUTE_BOOLEAN;
-  rec->value = na;
-
-  IGRAPH_CHECK(igraph_vector_ptr_push_back(attrs, rec));
-  IGRAPH_FINALLY_CLEAN(4); /* ownership of 'rec' transferred to 'attrs' */
-
-  for (igraph_integer_t i=0; ivalue.as_vector_bool;
+  for (igraph_int_t i = n1; i < n; i++) {
     VECTOR(*na)[i] = true;
   }
 
@@ -2900,12 +2875,12 @@ static igraph_error_t add_bipartite_type(igraph_i_pajek_parsedata_t *context) {
 
 static igraph_error_t check_bipartite(igraph_i_pajek_parsedata_t *context) {
   const igraph_vector_int_t *edges=context->vector;
-  igraph_integer_t n1=context->vcount2;
-  igraph_integer_t ne=igraph_vector_int_size(edges);
+  igraph_int_t n1=context->vcount2;
+  igraph_int_t ne=igraph_vector_int_size(edges);
 
-  for (igraph_integer_t i=0; i n1 && v2 > n1) ) {
       IGRAPH_WARNING("Invalid edge in bipartite graph.");
     }
@@ -2931,7 +2906,7 @@ static igraph_bool_t is_standard_vattr(const char *attrname) {
     "font", "url", "color", "framecolor",
     "labelcolor"
   };
-  for (size_t i=0; i < sizeof(names) / sizeof(names[0]); i++) {
+  for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
     if (strcmp(attrname, names[i]) == 0) {
       return true;
     }
@@ -2973,3 +2948,108 @@ static igraph_error_t deconflict_attrname(char **attrname) {
   *attrname = tmp;
   return IGRAPH_SUCCESS;
 }
+
+typedef struct {
+  const char* name;
+  igraph_real_t default_value;
+} attribute_numeric_defaults_t;
+
+typedef struct {
+  const char* name;
+  const char* default_value;
+} attribute_string_defaults_t;
+
+/* The defaults listed below are Pajek's built-in defaults unless the user
+ * overrides them.
+ *
+ * See: https://nascol.discourse.group/t/pajek-file-format-default-values-for-attributes/38/2
+ */
+
+const attribute_numeric_defaults_t vattr_numeric_defaults[] = {
+  { "xfact", 1 },
+  { "yfact", 1 },
+  { "labeldist", 20 },
+  { "labeldegree2", 285 },
+  { "framewidth", 1 },
+  { "fontsize", 15 },
+  { "rotation", 0 },
+  { "radius", 0 },
+  { "diamondratio", 0.01 },
+  { "labeldegree", 0 },
+  { 0 }
+};
+
+const attribute_string_defaults_t vattr_string_defaults[] = {
+  { "color", "LightOrange" },
+  { "framecolor", "Brown" },
+  { "labelcolor", "Maroon" },
+  { 0 }
+};
+
+const attribute_numeric_defaults_t eattr_numeric_defaults[] = {
+  { "arrowsize", 1 },
+  { "edgewidth", 2 },
+  { "hook1", 0 },
+  { "hook2", 0 },
+  { "angle1", 0 },
+  { "angle2", 0 },
+  { "velocity1", 1 },
+  { "velocity2", 1 },
+  { "arrowpos", 0 },
+  { "labelpos", 0.5 },
+  { "labelangle", 10 },
+  { "labelangle2", 90 },
+  { "labeldegree", 0 },
+  { "fontsize", 15 },
+  { 0 }
+};
+
+const attribute_string_defaults_t eattr_string_defaults[] = {
+  { "color", "MidnightBlue" },
+  { "labelcolor", "Black" },
+  { 0 }
+};
+
+static igraph_real_t get_default_value_for_numeric_attr(
+  const char *attrname, const attribute_numeric_defaults_t* table
+) {
+  const attribute_numeric_defaults_t* ptr;
+
+  for (ptr = table; ptr->name != 0; ptr++) {
+    if (!strcmp(attrname, ptr->name)) {
+      return ptr->default_value;
+    }
+  }
+
+  return IGRAPH_NAN;
+}
+
+static const char* get_default_value_for_string_attr(
+  const char *attrname, const attribute_string_defaults_t* table
+) {
+  const attribute_string_defaults_t* ptr;
+
+  for (ptr = table; ptr->name != 0; ptr++) {
+    if (!strcmp(attrname, ptr->name)) {
+      return ptr->default_value;
+    }
+  }
+
+  return "";
+}
+
+static igraph_real_t get_default_value_for_numeric_vattr(const char *attrname) {
+  return get_default_value_for_numeric_attr(attrname, vattr_numeric_defaults);
+}
+
+static igraph_real_t get_default_value_for_numeric_eattr(const char *attrname) {
+  return get_default_value_for_numeric_attr(attrname, eattr_numeric_defaults);
+}
+
+static const char* get_default_value_for_string_vattr(const char *attrname) {
+  return get_default_value_for_string_attr(attrname, vattr_string_defaults);
+}
+
+static const char* get_default_value_for_string_eattr(const char *attrname) {
+  return get_default_value_for_string_attr(attrname, eattr_string_defaults);
+}
diff --git a/src/vendor/io/parsers/dl-parser.h b/src/vendor/io/parsers/dl-parser.h
index 46dac54e14b..95b943f5eac 100644
--- a/src/vendor/io/parsers/dl-parser.h
+++ b/src/vendor/io/parsers/dl-parser.h
@@ -78,7 +78,7 @@ union YYSTYPE
 {
 #line 78 "src/vendor/cigraph/src/io/dl-parser.y"
 
-  igraph_integer_t integer;
+  igraph_int_t integer;
   igraph_real_t real;
 
 #line 85 "src/vendor/io/dl-parser.h"
diff --git a/src/vendor/io/parsers/lgl-parser.h b/src/vendor/io/parsers/lgl-parser.h
index b391c8fac2b..e7929b4047f 100644
--- a/src/vendor/io/parsers/lgl-parser.h
+++ b/src/vendor/io/parsers/lgl-parser.h
@@ -68,7 +68,7 @@ union YYSTYPE
 {
 #line 76 "src/vendor/cigraph/src/io/lgl-parser.y"
 
-  igraph_integer_t edgenum;
+  igraph_int_t edgenum;
   igraph_real_t weightnum;
 
 #line 75 "src/vendor/io/lgl-parser.h"
diff --git a/src/vendor/io/parsers/ncol-parser.h b/src/vendor/io/parsers/ncol-parser.h
index 361262035fe..c00fbf67c61 100644
--- a/src/vendor/io/parsers/ncol-parser.h
+++ b/src/vendor/io/parsers/ncol-parser.h
@@ -67,7 +67,7 @@ union YYSTYPE
 {
 #line 77 "src/vendor/cigraph/src/io/ncol-parser.y"
 
-  igraph_integer_t edgenum;
+  igraph_int_t edgenum;
   igraph_real_t weightnum;
 
 #line 74 "src/vendor/io/ncol-parser.h"
diff --git a/src/vendor/io/parsers/pajek-parser.h b/src/vendor/io/parsers/pajek-parser.h
index 79385e2e367..1f9b313a94c 100644
--- a/src/vendor/io/parsers/pajek-parser.h
+++ b/src/vendor/io/parsers/pajek-parser.h
@@ -109,9 +109,9 @@ extern int igraph_pajek_yydebug;
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 union YYSTYPE
 {
-#line 116 "src/vendor/cigraph/src/io/pajek-parser.y"
+#line 122 "src/vendor/cigraph/src/io/pajek-parser.y"
 
-  igraph_integer_t intnum;
+  igraph_int_t intnum;
   igraph_real_t    realnum;
   struct {
     char *str;
diff --git a/tests/testthat/_snaps/aaa-auto.md b/tests/testthat/_snaps/aaa-auto.md
index 5314b0acf6d..9942e6eecc8 100644
--- a/tests/testthat/_snaps/aaa-auto.md
+++ b/tests/testthat/_snaps/aaa-auto.md
@@ -55,30 +55,6 @@
       Error in `ensure_igraph()`:
       ! Must provide a graph object (provided `NULL`).
 
-# delete_vertices_idx_impl basic
-
-    Code
-      delete_vertices_idx_impl(graph = g, vertices = 1)
-    Output
-      $graph
-      IGRAPH D--- 2 0 -- 
-      + edges:
-      
-      $idx
-      [1] 0 1 2
-      
-      $invidx
-      [1] 1 2
-      
-
-# delete_vertices_idx_impl errors
-
-    Code
-      delete_vertices_idx_impl(graph = NULL, vertices = 1)
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
 # vcount_impl basic
 
     Code
@@ -500,25 +476,6 @@
       Error in `kautz_impl()`:
       ! At vendor/cigraph/src/constructors/kautz.c:xx : `m' and `n' should be non-negative in a Kautz graph, Invalid value
 
-# lcf_vector_impl basic
-
-    Code
-      lcf_vector_impl(n = 10, shifts = c(3, -3, 4), repeats = 2)
-    Output
-      IGRAPH U--- 10 16 -- LCF graph
-      + attr: name (g/c)
-      + edges:
-       [1] 1-- 2 1-- 4 1--10 2-- 3 2-- 5 2-- 9 3-- 4 3-- 7 4-- 5 4-- 7 5-- 6 6-- 7
-      [13] 6--10 7-- 8 8-- 9 9--10
-
-# lcf_vector_impl errors
-
-    Code
-      lcf_vector_impl(n = -1, shifts = c(3, -3, 4), repeats = 2)
-    Condition
-      Error in `lcf_vector_impl()`:
-      ! At vendor/cigraph/src/graph/type_indexededgelist.c:xx : Number of vertices must not be negative. Invalid value
-
 # mycielski_graph_impl basic
 
     Code
@@ -654,7 +611,7 @@
       + attr: name (g/c), out_deg (g/n), in_deg (g/x), allowed_edge_types
       | (g/n), method (g/n)
       + edges:
-      [1] 2--3 1--3 1--2
+      [1] 1--3 2--3 1--2
 
 ---
 
@@ -808,7 +765,7 @@
       erdos_renyi_game_gnp_impl(n = -1, p = 0.5)
     Condition
       Error in `erdos_renyi_game_gnp_impl()`:
-      ! At vendor/cigraph/src/games/erdos_renyi.c:xx : Invalid number of vertices. Invalid value
+      ! At vendor/cigraph/src/games/erdos_renyi.c:xx : Invalid number of vertices for G(n,p) model. Invalid value
 
 # erdos_renyi_game_gnm_impl basic
 
@@ -834,7 +791,7 @@
       erdos_renyi_game_gnm_impl(n = -1, m = 3)
     Condition
       Error in `erdos_renyi_game_gnm_impl()`:
-      ! At vendor/cigraph/src/games/erdos_renyi.c:xx : Invalid number of vertices. Invalid value
+      ! At vendor/cigraph/src/games/erdos_renyi.c:xx : Invalid number of vertices for G(n,m) model. Invalid value
 
 # growing_random_game_impl basic
 
@@ -986,11 +943,11 @@
       simple_interconnected_islands_game_impl(islands_n = 2, islands_size = 3,
         islands_pin = 0.5, n_inter = 1)
     Output
-      IGRAPH U--- 6 5 -- Interconnected islands model
-      + attr: name (g/c), islands_n (g/n), islands_size (g/n), islands_pin
-      | (g/n), n_inter (g/n)
+      IGRAPH U--- 6 6 -- Interconnected islands model
+      + attr: name (g/c), islands.n (g/n), islands.size (g/n), islands.pin
+      | (g/n), n.inter (g/n)
       + edges:
-      [1] 1--2 1--3 2--3 3--6 5--6
+      [1] 1--2 1--3 2--3 2--6 4--5 4--6
 
 # simple_interconnected_islands_game_impl errors
 
@@ -1145,7 +1102,7 @@
       sbm_game_impl(n = -1, pref_matrix = matrix(0.5, 2, 2), block_sizes = c(2, 3))
     Condition
       Error in `sbm_game_impl()`:
-      ! At vendor/cigraph/src/games/sbm.c:xx : Sum of the block sizes (5) must equal the number of vertices (-1). Invalid value
+      ! unused argument (n = -1)
 
 # hsbm_game_impl basic
 
@@ -1249,7 +1206,7 @@
       correlated_pair_game_impl(n = -1, corr = 0.5, p = 0.5)
     Condition
       Error in `correlated_pair_game_impl()`:
-      ! At vendor/cigraph/src/games/erdos_renyi.c:xx : Invalid number of vertices. Invalid value
+      ! At vendor/cigraph/src/games/erdos_renyi.c:xx : Invalid number of vertices for G(n,p) model. Invalid value
 
 # dot_product_game_impl basic
 
@@ -1257,7 +1214,7 @@
       dot_product_game_impl(vecs = matrix(0.5, 5, 2))
     Condition
       Warning in `dot_product_game_impl()`:
-      At vendor/cigraph/src/games/dotproduct.c:90 : Greater than 1 connection probability in dot-product graph.
+      At vendor/cigraph/src/games/dotproduct.c:86 : Greater than 1 connection probability in dot-product graph.
     Output
       IGRAPH U--- 2 1 -- 
       + edge:
@@ -1269,7 +1226,7 @@
       dot_product_game_impl(vecs = matrix(0.5, 5, 2), directed = TRUE)
     Condition
       Warning in `dot_product_game_impl()`:
-      At vendor/cigraph/src/games/dotproduct.c:90 : Greater than 1 connection probability in dot-product graph.
+      At vendor/cigraph/src/games/dotproduct.c:86 : Greater than 1 connection probability in dot-product graph.
     Output
       IGRAPH D--- 2 2 -- 
       + edges:
@@ -1283,80 +1240,6 @@
       Error in `dot_product_game_impl()`:
       ! REAL() can only be applied to a 'numeric', not a 'NULL'
 
-# sample_sphere_surface_impl basic
-
-    Code
-      sample_sphere_surface_impl(dim = 3, n = 5)
-    Output
-                 [,1]      [,2]      [,3]      [,4]       [,5]
-      [1,] 0.87877523 0.8206548 0.1430028 0.6349227 0.99933629
-      [2,] 0.05165973 0.5261159 0.1145481 0.2979741 0.02649327
-      [3,] 0.47443162 0.2229974 0.9830712 0.7128005 0.02500179
-
----
-
-    Code
-      sample_sphere_surface_impl(dim = 3, n = 5, radius = 2, positive = FALSE)
-    Output
-                 [,1]       [,2]       [,3]        [,4]     [,5]
-      [1,] -0.4904253 -1.4825368 -0.5141332  1.95644246 0.369407
-      [2,] -1.6787252  1.1329528 -0.7872709 -0.41498660 1.953509
-      [3,] -0.9702395  0.7200713  1.7651832 -0.01090904 0.217584
-
-# sample_sphere_surface_impl errors
-
-    Code
-      sample_sphere_surface_impl(dim = -1, n = 5)
-    Condition
-      Error in `sample_sphere_surface_impl()`:
-      ! At vendor/cigraph/src/games/dotproduct.c:xx : Sphere must be at least two dimensional to sample from surface. Invalid value
-
-# sample_sphere_volume_impl basic
-
-    Code
-      sample_sphere_volume_impl(dim = 3, n = 5)
-    Output
-                 [,1]      [,2]       [,3]      [,4]       [,5]
-      [1,] 0.67165090 0.6105364 0.09806950 0.4132698 0.73325518
-      [2,] 0.03948371 0.3914105 0.07855561 0.1939507 0.01943923
-      [3,] 0.36260970 0.1659017 0.67417787 0.4639603 0.01834487
-
----
-
-    Code
-      sample_sphere_volume_impl(dim = 3, n = 5, radius = 2, positive = FALSE)
-    Output
-                   [,1]       [,2]       [,3]      [,4]       [,5]
-      [1,]  1.903629152 -1.3795904 -1.2061886 0.9035986 -1.1692436
-      [2,] -0.159619927  0.2402815 -0.1258477 0.1842403 -1.4940836
-      [3,]  0.003829883  1.2440192  0.6204597 1.5776103  0.4096058
-
-# sample_sphere_volume_impl errors
-
-    Code
-      sample_sphere_volume_impl(dim = -1, n = 5)
-    Condition
-      Error in `sample_sphere_volume_impl()`:
-      ! At vendor/cigraph/src/games/dotproduct.c:xx : Sphere must be at least two dimensional to sample from surface. Invalid value
-
-# sample_dirichlet_impl basic
-
-    Code
-      sample_dirichlet_impl(n = 5, alpha = c(1, 1, 1))
-    Output
-                [,1]      [,2]       [,3]      [,4]      [,5]
-      [1,] 0.6298008 0.4168413 0.29594281 0.2432340 0.1516815
-      [2,] 0.1093984 0.3461600 0.08924333 0.4251328 0.3561426
-      [3,] 0.2608008 0.2369988 0.61481386 0.3316331 0.4921759
-
-# sample_dirichlet_impl errors
-
-    Code
-      sample_dirichlet_impl(n = -1, alpha = c(1, 1, 1))
-    Condition
-      Error in `sample_dirichlet_impl()`:
-      ! At vendor/cigraph/src/games/dotproduct.c:xx : Number of samples should be non-negative, got -1. Invalid value
-
 # are_adjacent_impl basic
 
     Code
@@ -1824,7 +1707,7 @@
 ---
 
     Code
-      personalized_pagerank_impl(graph = g, algo = "arpack", damping = 0.9)
+      personalized_pagerank_impl(graph = g, damping = 0.9, algo = "arpack")
     Output
       $vector
       [1] 0.2543860 0.4912281 0.2543860
@@ -1913,7 +1796,7 @@
 ---
 
     Code
-      personalized_pagerank_vs_impl(graph = g, algo = "arpack", reset_vids = 1,
+      personalized_pagerank_vs_impl(graph = g, reset.vids = 1, algo = "arpack",
         details = TRUE)
     Output
       $vector
@@ -2174,7 +2057,7 @@
       transitivity_barrat_impl(graph = g)
     Condition
       Warning in `transitivity_barrat_impl()`:
-      At vendor/cigraph/src/properties/triangles.c:913 : No weights given for Barrat's transitivity, unweighted version is used.
+      At vendor/cigraph/src/properties/triangles.c:889 : No weights given for Barrat's transitivity, unweighted version is used.
     Output
       [1] NaN   0 NaN
 
@@ -2184,7 +2067,7 @@
       transitivity_barrat_impl(graph = g, mode = "zero")
     Condition
       Warning in `transitivity_barrat_impl()`:
-      At vendor/cigraph/src/properties/triangles.c:913 : No weights given for Barrat's transitivity, unweighted version is used.
+      At vendor/cigraph/src/properties/triangles.c:889 : No weights given for Barrat's transitivity, unweighted version is used.
     Output
       [1] 0 0 0
 
@@ -2250,7 +2133,7 @@
 ---
 
     Code
-      maxdegree_impl(graph = g, mode = "in", loops = FALSE)
+      maxdegree_impl(graph = g, mode = "in", loops = "twice")
     Output
       [1] 2
 
@@ -2570,10 +2453,10 @@
 ---
 
     Code
-      eigenvector_centrality_impl(graph = g, directed = TRUE, scale = FALSE)
+      eigenvector_centrality_impl(graph = g, mode = "out")
     Output
       $vector
-      [1] 0.5000000 0.7071068 0.5000000
+      [1] 0.7071068 1.0000000 0.7071068
       
       $value
       [1] 1.414214
@@ -2652,7 +2535,7 @@
 # hub_and_authority_scores_impl basic
 
     Code
-      hub_and_authority_scores_impl(graph = g)
+      suppressWarnings(hub_and_authority_scores_impl(graph = g))
     Output
       $hub
       [1] 1 1 1 1 1
@@ -2726,83 +2609,6 @@
       
       
 
----
-
-    Code
-      hub_and_authority_scores_impl(graph = g, scale = FALSE)
-    Output
-      $hub
-      [1] 0.4472136 0.4472136 0.4472136 0.4472136 0.4472136
-      
-      $authority
-      [1] 0.4472136 0.4472136 0.4472136 0.4472136 0.4472136
-      
-      $value
-      [1] 16
-      
-      $options
-      $options$bmat
-      [1] "I"
-      
-      $options$n
-      [1] 5
-      
-      $options$which
-      [1] "LA"
-      
-      $options$nev
-      [1] 1
-      
-      $options$tol
-      [1] 0
-      
-      $options$ncv
-      [1] 0
-      
-      $options$ldv
-      [1] 0
-      
-      $options$ishift
-      [1] 1
-      
-      $options$maxiter
-      [1] 3000
-      
-      $options$nb
-      [1] 1
-      
-      $options$mode
-      [1] 1
-      
-      $options$start
-      [1] 1
-      
-      $options$sigma
-      [1] 0
-      
-      $options$sigmai
-      [1] 0
-      
-      $options$info
-      [1] 0
-      
-      $options$iter
-      [1] 1
-      
-      $options$nconv
-      [1] 1
-      
-      $options$numop
-      [1] 4
-      
-      $options$numopb
-      [1] 0
-      
-      $options$numreo
-      [1] 4
-      
-      
-
 # hub_and_authority_scores_impl errors
 
     Code
@@ -3000,7 +2806,7 @@
 ---
 
     Code
-      strength_impl(graph = g, mode = "in", loops = FALSE)
+      strength_impl(graph = g, mode = "in", loops = "twice")
     Output
       [1] 1 2 1
 
@@ -3052,7 +2858,7 @@
 ---
 
     Code
-      centralization_degree_impl(graph = g, mode = "in", loops = FALSE, normalized = FALSE)
+      centralization_degree_impl(graph = g, mode = "in", loops = "twice", normalized = FALSE)
     Output
       $res
       [1] 1 2 1
@@ -3072,28 +2878,6 @@
       Error in `ensure_igraph()`:
       ! Must provide a graph object (provided `NULL`).
 
-# centralization_degree_tmax_impl basic
-
-    Code
-      centralization_degree_tmax_impl(nodes = 3, loops = TRUE)
-    Output
-      [1] 6
-
----
-
-    Code
-      centralization_degree_tmax_impl(nodes = 3, mode = "in", loops = FALSE)
-    Output
-      [1] 4
-
-# centralization_degree_tmax_impl errors
-
-    Code
-      centralization_degree_tmax_impl(nodes = -1, loops = TRUE)
-    Condition
-      Error in `centralization_degree_tmax_impl()`:
-      ! At vendor/cigraph/src/centrality/centralization.c:xx : Number of vertices must not be negative. Invalid value
-
 # centralization_betweenness_impl basic
 
     Code
@@ -3297,8 +3081,7 @@
 ---
 
     Code
-      centralization_eigenvector_centrality_impl(graph = g, directed = TRUE,
-        normalized = FALSE)
+      centralization_eigenvector_centrality_impl(graph = g, mode = "out", normalized = FALSE)
     Output
       $vector
       [1] 0.7071068 1.0000000 0.7071068
@@ -3388,12 +3171,12 @@
     Code
       centralization_eigenvector_centrality_tmax_impl(nodes = 3)
     Output
-      [1] 1
+      [1] 2
 
 ---
 
     Code
-      centralization_eigenvector_centrality_tmax_impl(nodes = 3, directed = TRUE)
+      centralization_eigenvector_centrality_tmax_impl(nodes = 3, mode = "out")
     Output
       [1] 2
 
@@ -3573,74 +3356,6 @@
       Error in `ensure_igraph()`:
       ! Must provide a graph object (provided `NULL`).
 
-# eccentricity_dijkstra_impl basic
-
-    Code
-      eccentricity_dijkstra_impl(graph = g)
-    Output
-      [1] 2 1 2
-
----
-
-    Code
-      eccentricity_dijkstra_impl(graph = g, mode = "in")
-    Output
-      [1] 2 1 2
-
-# eccentricity_dijkstra_impl errors
-
-    Code
-      eccentricity_dijkstra_impl(graph = NULL)
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
-# graph_center_dijkstra_impl basic
-
-    Code
-      graph_center_dijkstra_impl(graph = g)
-    Output
-      + 1/3 vertex:
-      [1] 2
-
----
-
-    Code
-      graph_center_dijkstra_impl(graph = g, mode = "in")
-    Output
-      + 1/3 vertex:
-      [1] 2
-
-# graph_center_dijkstra_impl errors
-
-    Code
-      graph_center_dijkstra_impl(graph = NULL)
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
-# radius_dijkstra_impl basic
-
-    Code
-      radius_dijkstra_impl(graph = g)
-    Output
-      [1] 1
-
----
-
-    Code
-      radius_dijkstra_impl(graph = g, mode = "in")
-    Output
-      [1] 1
-
-# radius_dijkstra_impl errors
-
-    Code
-      radius_dijkstra_impl(graph = NULL)
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
 # pseudo_diameter_impl basic
 
     Code
@@ -3679,45 +3394,6 @@
       Error in `ensure_igraph()`:
       ! Must provide a graph object (provided `NULL`).
 
-# pseudo_diameter_dijkstra_impl basic
-
-    Code
-      pseudo_diameter_dijkstra_impl(graph = g, start_vid = 1)
-    Output
-      $diameter
-      [1] 2
-      
-      $from
-      [1] 0
-      
-      $to
-      [1] 2
-      
-
----
-
-    Code
-      pseudo_diameter_dijkstra_impl(graph = g, start_vid = 1, directed = FALSE,
-        unconnected = FALSE)
-    Output
-      $diameter
-      [1] 2
-      
-      $from
-      [1] 0
-      
-      $to
-      [1] 2
-      
-
-# pseudo_diameter_dijkstra_impl errors
-
-    Code
-      pseudo_diameter_dijkstra_impl(graph = NULL, start_vid = 1)
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
 # diversity_impl basic
 
     Code
@@ -3835,23 +3511,6 @@
       Error in `ensure_igraph()`:
       ! Must provide a graph object (provided `NULL`).
 
-# transitive_closure_dag_impl basic
-
-    Code
-      transitive_closure_dag_impl(graph = g)
-    Output
-      IGRAPH D--- 3 3 -- 
-      + edges:
-      [1] 1->3 1->2 2->3
-
-# transitive_closure_dag_impl errors
-
-    Code
-      transitive_closure_dag_impl(graph = NULL)
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
 # transitive_closure_impl basic
 
     Code
@@ -3978,7 +3637,7 @@
 # biadjacency_impl basic
 
     Code
-      biadjacency_impl(incidence = m)
+      biadjacency_impl(biadjmatrix = m)
     Output
       $graph
       IGRAPH U--- 5 4 -- 
@@ -3992,7 +3651,7 @@
 ---
 
     Code
-      biadjacency_impl(incidence = m, directed = TRUE, mode = "in", multiple = TRUE)
+      biadjacency_impl(biadjmatrix = m, directed = TRUE, mode = "in", multiple = TRUE)
     Output
       $graph
       IGRAPH D--- 5 4 -- 
@@ -4091,7 +3750,7 @@
       bipartite_game_gnp_impl(n1 = -1, n2 = 2, p = 0.5)
     Condition
       Error in `bipartite_game_gnp_impl()`:
-      ! At vendor/cigraph/src/misc/bipartite.c:xx : Invalid number of vertices for bipartite graph. Invalid value
+      ! At vendor/cigraph/src/misc/bipartite.c:xx : Invalid number of vertices for bipartite G(n,p) model. Invalid value
 
 # bipartite_game_gnm_impl basic
 
@@ -4127,7 +3786,7 @@
       bipartite_game_gnm_impl(n1 = -1, n2 = 2, m = 1)
     Condition
       Error in `bipartite_game_gnm_impl()`:
-      ! At vendor/cigraph/src/misc/bipartite.c:xx : Invalid number of vertices for bipartite graph. Invalid value
+      ! At vendor/cigraph/src/misc/bipartite.c:xx : Invalid number of vertices for bipartite G(n,m) model. Invalid value
 
 # get_laplacian_impl basic
 
@@ -5162,7 +4821,7 @@
 ---
 
     Code
-      similarity_dice_impl(graph = g, vids = 1:2, mode = "in", loops = TRUE)
+      similarity_dice_impl(g, vit.from = 1:2, mode = "in", loops = TRUE)
     Output
            [,1] [,2]
       [1,]  1.0  0.8
@@ -5261,7 +4920,7 @@
 ---
 
     Code
-      similarity_jaccard_impl(graph = g, vids = 1:2, mode = "in", loops = TRUE)
+      similarity_jaccard_impl(g, vit.from = 1:2, mode = "in", loops = TRUE)
     Output
                 [,1]      [,2]
       [1,] 1.0000000 0.6666667
@@ -5413,6 +5072,13 @@
 
 # community_label_propagation_impl basic
 
+    Code
+      community_label_propagation_impl(graph = g, lpa.variant = "dominance")
+    Output
+      [1] 0 0 0
+
+---
+
     Code
       community_label_propagation_impl(graph = g)
     Output
@@ -5422,7 +5088,7 @@
 
     Code
       community_label_propagation_impl(graph = g, mode = "in", weights = c(1, 2),
-      initial = 1:3, fixed = c(TRUE, FALSE, TRUE))
+      initial = 1:3, fixed = c(TRUE, FALSE, TRUE), lpa.variant = "retention")
     Output
       [1] 0 1 1
 
@@ -5509,8 +5175,9 @@
 # community_leiden_impl basic
 
     Code
-      community_leiden_impl(graph = g, weights = c(1, 2), vertex_weights = c(1, 2, 3),
-      resolution = 0.5, beta = 0.1, start = TRUE, n_iterations = 1, membership = 1:3)
+      community_leiden_impl(graph = g, weights = c(1, 2), vertex.out.weights = c(1, 2,
+        3), resolution = 0.5, beta = 0.1, start = TRUE, n.iterations = 1, membership = 1:
+        3)
     Output
       $membership
       [1] 0 1 2
@@ -5567,8 +5234,8 @@
 ---
 
     Code
-      community_infomap_impl(graph = g, e_weights = c(1, 2), v_weights = c(1, 2, 3),
-      nb_trials = 2)
+      community_infomap_impl(graph = g, edge.weights = c(1, 2), vertex.weights = c(1, 2, 3),
+      nb.trials = 2)
     Output
       $membership
       [1] 0 0 0
@@ -6118,7 +5785,7 @@
       triad_census_impl(graph = g)
     Condition
       Warning in `triad_census_impl()`:
-      At vendor/cigraph/src/misc/motifs.c:1157 : Triad census called on an undirected graph. All connections will be treated as mutual.
+      At vendor/cigraph/src/misc/motifs.c:1170 : Triad census called on an undirected graph. All connections will be treated as mutual.
     Output
        [1] 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
 
@@ -6303,8 +5970,8 @@
 # local_scan_neighborhood_ecount_impl basic
 
     Code
-      local_scan_neighborhood_ecount_impl(graph = g, neighborhoods = list(1:2, 2:3, 2:
-        4, 2))
+      local_scan_neighborhood_ecount_impl(graph = g, neighborhoods = list(1:2 - 1, 2:
+      3 - 1, 2:4 - 1, 2 - 1))
     Output
       [1] 1 1 2 0
 
@@ -6312,7 +5979,7 @@
 
     Code
       local_scan_neighborhood_ecount_impl(graph = g, weights = c(1, 2, 3),
-      neighborhoods = list(1:2, 1:3, 2:4, 1))
+      neighborhoods = list(1:2 - 1, 1:3 - 1, 2:4 - 1, 1 - 1))
     Output
       [1] 1 3 5 0
 
@@ -6337,15 +6004,15 @@
       local_scan_subset_ecount_impl(graph = g, weights = c(1, 2, 3), subsets = list(c(
         1, 2), c(2, 3)))
     Output
-      [1] 1 2
+      [1] 2 3
 
 # local_scan_subset_ecount_impl errors
 
     Code
       local_scan_subset_ecount_impl(graph = g, subsets = list(1:2, letters[2:3]))
     Condition
-      Error in `.x - 1`:
-      ! non-numeric argument to binary operator
+      Error in `local_scan_subset_ecount_impl()`:
+      ! REAL() can only be applied to a 'numeric', not a 'integer'
 
 # list_triangles_impl basic
 
@@ -7233,7 +6900,7 @@
 ---
 
     Code
-      canonical_permutation_impl(graph = g, colors = c(1, 2, 3), sh = "fl")
+      canonical_permutation_impl(graph = g, colors = c(1, 2, 3))
     Output
       $labeling
       [1] 1 2 3
@@ -7430,7 +7097,7 @@
 ---
 
     Code
-      count_automorphisms_impl(graph = g, colors = c(1, 2, 3), sh = "fl")
+      count_automorphisms_impl(graph = g, colors = c(1, 2, 3))
     Output
       $nof_nodes
       [1] 1
@@ -7462,7 +7129,7 @@
 # automorphism_group_impl basic
 
     Code
-      automorphism_group_impl(graph = g)
+      automorphism_group_impl(graph = g, colors = c(1, 2, 3))
     Output
       [[1]]
       + 3/3 vertices:
@@ -7472,7 +7139,7 @@
 ---
 
     Code
-      automorphism_group_impl(graph = g, colors = c(1, 2, 3), sh = "fl", details = TRUE)
+      automorphism_group_impl(g, colors = c(1, 2, 3))
     Output
       $generators
       list()
@@ -9500,30 +9167,6 @@
       Error in `ensure_igraph()`:
       ! Must provide a graph object (provided `NULL`).
 
-# convex_hull_2d_impl basic
-
-    Code
-      convex_hull_2d_impl(data = matrix(1:6, ncol = 2))
-    Output
-      $resverts
-      [1] 1 3
-      
-      $rescoords
-           [,1] [,2]
-      [1,]    1    4
-      [2,]    3    6
-      
-
-# convex_hull_2d_impl errors
-
-    Code
-      convex_hull_2d_impl(data = "a")
-    Condition
-      Warning in `convex_hull_2d_impl()`:
-      NAs introduced by coercion
-      Error in `convex_hull_2d_impl()`:
-      ! REAL() can only be applied to a 'numeric', not a 'character'
-
 # dim_select_impl basic
 
     Code
@@ -9990,103 +9633,6 @@
       Error in `ensure_igraph()`:
       ! Must provide a graph object (provided `NULL`).
 
-# deterministic_optimal_imitation_impl basic
-
-    Code
-      deterministic_optimal_imitation_impl(graph = g, vid = 1, quantities = c(1, 2, 3),
-      strategies = c(1, 2, 3))
-    Output
-      [1] 2 2 3
-
----
-
-    Code
-      deterministic_optimal_imitation_impl(graph = g, vid = 1, optimality = "minimum",
-        quantities = c(1, 2, 3), strategies = c(1, 2, 3), mode = "in")
-    Output
-      [1] 1 2 3
-
-# deterministic_optimal_imitation_impl errors
-
-    Code
-      deterministic_optimal_imitation_impl(graph = NULL, vid = 1, quantities = c(1, 2,
-        3), strategies = c(1, 2, 3))
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
-# moran_process_impl basic
-
-    Code
-      moran_process_impl(graph = g, weights = c(1, 1), quantities = c(1, 2, 3),
-      strategies = c(1, 2, 3), mode = "in")
-    Output
-      $quantities
-      [1] 1 3 3
-      
-      $strategies
-      [1] 1 3 3
-      
-
-# moran_process_impl errors
-
-    Code
-      moran_process_impl(graph = NULL, quantities = c(1, 2, 3), strategies = c(1, 2,
-        3))
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
-# roulette_wheel_imitation_impl basic
-
-    Code
-      roulette_wheel_imitation_impl(graph = g, vid = 1, is_local = TRUE, quantities = c(
-        1, 2, 3), strategies = c(1, 2, 3))
-    Output
-      [1] 1 2 3
-
----
-
-    Code
-      roulette_wheel_imitation_impl(graph = g, vid = 1, is_local = FALSE, quantities = c(
-        1, 2, 3), strategies = c(1, 2, 3), mode = "in")
-    Output
-      [1] 3 2 3
-
-# roulette_wheel_imitation_impl errors
-
-    Code
-      roulette_wheel_imitation_impl(graph = NULL, vid = 1, is_local = TRUE,
-        quantities = c(1, 2, 3), strategies = c(1, 2, 3))
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
-# stochastic_imitation_impl basic
-
-    Code
-      stochastic_imitation_impl(graph = g, vid = 1, algo = 1, quantities = c(1, 2, 3),
-      strategies = c(1, 2, 3))
-    Output
-      [1] 1 2 3
-
----
-
-    Code
-      stochastic_imitation_impl(graph = g, vid = 1, algo = 2, quantities = c(1, 2, 3),
-      strategies = c(1, 2, 3), mode = "in")
-    Output
-      [1] 1 2 3
-
-# stochastic_imitation_impl errors
-
-    Code
-      stochastic_imitation_impl(graph = NULL, vid = 1, algo = 1, quantities = c(1, 2,
-        3), strategies = c(1, 2, 3))
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
 # invalidate_cache_impl basic
 
     Code
@@ -10104,36 +9650,12 @@
       Error in `ensure_igraph()`:
       ! Must provide a graph object (provided `NULL`).
 
-# vertex_path_from_edge_path_impl basic
-
-    Code
-      vertex_path_from_edge_path_impl(graph = g, start = 1, edge_path = c(1, 2))
-    Output
-      + 3/3 vertices:
-      [1] 1 2 3
-
----
-
-    Code
-      vertex_path_from_edge_path_impl(graph = g, start = 1, edge_path = c(1), mode = "in")
-    Output
-      + 2/3 vertices:
-      [1] 1 2
-
-# vertex_path_from_edge_path_impl errors
-
-    Code
-      vertex_path_from_edge_path_impl(graph = NULL, start = 1, edge_path = c(1, 2))
-    Condition
-      Error in `ensure_igraph()`:
-      ! Must provide a graph object (provided `NULL`).
-
 # version_impl basic
 
     Code
       version_impl_clean()
     Output
-      [1] "0.10.17"
+      [1] "1.0.0"
 
 # version_impl errors
 
diff --git a/tests/testthat/_snaps/centrality.md b/tests/testthat/_snaps/centrality.md
index 62a6c46264f..febfd202987 100644
--- a/tests/testthat/_snaps/centrality.md
+++ b/tests/testthat/_snaps/centrality.md
@@ -10,6 +10,9 @@
       arpack_defaults was deprecated in igraph 1.6.0.
       i Please use `arpack_defaults()` instead.
       i So the function arpack_defaults(), not an object called arpack_defaults.
+      Warning:
+      The `scale` argument of `hits_scores()` is deprecated as of igraph 2.1.5.
+      i The function always behaves as if `scale = TRUE`. The argument will be removed in the future.
 
 # `hub_score()` works
 
@@ -23,6 +26,9 @@
       arpack_defaults was deprecated in igraph 1.6.0.
       i Please use `arpack_defaults()` instead.
       i So the function arpack_defaults(), not an object called arpack_defaults.
+      Warning:
+      The `scale` argument of `hits_scores()` is deprecated as of igraph 2.1.5.
+      i The function always behaves as if `scale = TRUE`. The argument will be removed in the future.
 
 # eigen_centrality() deprecated scale argument
 
@@ -48,7 +54,7 @@
       arpack(f, options = list(nev = 2, ncv = 4), sym = TRUE)
     Condition
       Error in `arpack()`:
-      ! At vendor/cigraph/src/linalg/arpack.c:1102 : ARPACK error, N must be positive
+      ! At vendor/cigraph/src/linalg/arpack.c:1025 : N must be positive, ARPACK error
 
 ---
 
diff --git a/tests/testthat/_snaps/incidence.md b/tests/testthat/_snaps/incidence.md
index dbb1ba9a91e..541b8034a6d 100644
--- a/tests/testthat/_snaps/incidence.md
+++ b/tests/testthat/_snaps/incidence.md
@@ -6,7 +6,7 @@
       IGRAPH UN-B 8 7 -- 
       + attr: type (v/l), name (v/c)
       + edges (vertex names):
-      [1] A--c A--d B--b B--c B--e C--b C--d
+      [1] B--b C--b A--c B--c A--d C--d B--e
 
 ---
 
@@ -26,7 +26,7 @@
       IGRAPH UN-B 8 10 -- 
       + attr: type (v/l), name (v/c)
       + edges (vertex names):
-       [1] A--c A--d A--d A--e B--b B--e C--b C--c C--c C--e
+       [1] B--b C--b A--c C--c C--c A--d A--d A--e B--e C--e
 
 # graph_from_biadjacency_matrix() works -- sparse
 
diff --git a/tests/testthat/_snaps/interface.md b/tests/testthat/_snaps/interface.md
index d394032f7a6..1c13eac2c5e 100644
--- a/tests/testthat/_snaps/interface.md
+++ b/tests/testthat/_snaps/interface.md
@@ -33,3 +33,21 @@
       Error in `el_to_vec()`:
       ! The columns of the data.frame are of different type (character and double)
 
+# incident() works
+
+    Code
+      incident(g, 1)
+    Output
+      + 16/78 edges:
+       [1] 1-- 2 1-- 3 1-- 4 1-- 5 1-- 6 1-- 7 1-- 8 1-- 9 1--11 1--12 1--13 1--14
+      [13] 1--18 1--20 1--22 1--32
+
+---
+
+    Code
+      incident(g, 34)
+    Output
+      + 17/78 edges:
+       [1]  9--34 10--34 14--34 15--34 16--34 19--34 20--34 21--34 23--34 24--34
+      [11] 27--34 28--34 29--34 30--34 31--34 32--34 33--34
+
diff --git a/tests/testthat/_snaps/minimum.spanning.tree.md b/tests/testthat/_snaps/minimum.spanning.tree.md
index 9cdfaeb90d6..d14e5554966 100644
--- a/tests/testthat/_snaps/minimum.spanning.tree.md
+++ b/tests/testthat/_snaps/minimum.spanning.tree.md
@@ -4,5 +4,6 @@
       mst(g, algorithm = "undefined")
     Condition
       Error in `mst()`:
-      ! Invalid `algorithm`.
+      ! `algorithm` must be one of "automatic", "unweighted", "prim", or "kruskal", not "undefined".
+      i Did you mean "unweighted"?
 
diff --git a/tests/testthat/test-aaa-auto.R b/tests/testthat/test-aaa-auto.R
index 1b59cb88838..2991f0049f2 100644
--- a/tests/testthat/test-aaa-auto.R
+++ b/tests/testthat/test-aaa-auto.R
@@ -110,40 +110,6 @@ test_that("copy_impl errors", {
   ))
 })
 
-# 4. delete_vertices_idx_impl
-
-test_that("delete_vertices_idx_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  g <- empty_impl(
-    n = 3
-  )
-
-  expect_snapshot(delete_vertices_idx_impl(
-    graph = g,
-    vertices = 1
-  ))
-
-  # Structured tests
-  result <- delete_vertices_idx_impl(
-    graph = g,
-    vertices = 1
-  )
-  expect_type(result, "list")
-  expect_named(result, c("graph", "idx", "invidx"))
-  expect_s3_class(result$graph, "igraph")
-  expect_equal(vcount(result$graph), 2)
-})
-
-test_that("delete_vertices_idx_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(delete_vertices_idx_impl(
-    graph = NULL,
-    vertices = 1
-  ))
-})
-
 # 5. vcount_impl
 
 test_that("vcount_impl basic", {
@@ -675,34 +641,6 @@ test_that("kautz_impl errors", {
   ))
 })
 
-# 23. lcf_vector_impl
-test_that("lcf_vector_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot(lcf_vector_impl(
-    n = 10,
-    shifts = c(3, -3, 4),
-    repeats = 2
-  ))
-
-  # Structured tests
-  result <- lcf_vector_impl(
-    n = 10,
-    shifts = c(3, -3, 4),
-    repeats = 2
-  )
-  expect_s3_class(result, "igraph")
-})
-test_that("lcf_vector_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(lcf_vector_impl(
-    n = -1,
-    shifts = c(3, -3, 4),
-    repeats = 2
-  ))
-})
-
 # 24. mycielski_graph_impl
 test_that("mycielski_graph_impl basic", {
   withr::local_seed(20250909)
@@ -1592,99 +1530,6 @@ test_that("dot_product_game_impl errors", {
   ))
 })
 
-# 52. sample_sphere_surface_impl
-
-test_that("sample_sphere_surface_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot(sample_sphere_surface_impl(
-    dim = 3,
-    n = 5
-  ))
-  expect_snapshot(sample_sphere_surface_impl(
-    dim = 3,
-    n = 5,
-    radius = 2,
-    positive = FALSE
-  ))
-
-  # Structured tests
-  result <- sample_sphere_surface_impl(
-    dim = 3,
-    n = 5
-  )
-  expect_true(is.numeric(result) || is.logical(result))
-})
-
-test_that("sample_sphere_surface_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(sample_sphere_surface_impl(
-    dim = -1,
-    n = 5
-  ))
-})
-
-# 53. sample_sphere_volume_impl
-
-test_that("sample_sphere_volume_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot(sample_sphere_volume_impl(
-    dim = 3,
-    n = 5
-  ))
-  expect_snapshot(sample_sphere_volume_impl(
-    dim = 3,
-    n = 5,
-    radius = 2,
-    positive = FALSE
-  ))
-
-  # Structured tests
-  result <- sample_sphere_volume_impl(
-    dim = 3,
-    n = 5
-  )
-  expect_true(is.numeric(result) || is.logical(result))
-})
-
-test_that("sample_sphere_volume_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(sample_sphere_volume_impl(
-    dim = -1,
-    n = 5
-  ))
-})
-
-# 54. sample_dirichlet_impl
-
-test_that("sample_dirichlet_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot(sample_dirichlet_impl(
-    n = 5,
-    alpha = c(1, 1, 1)
-  ))
-
-  # Structured tests
-  result <- sample_dirichlet_impl(
-    n = 5,
-    alpha = c(1, 1, 1)
-  )
-  expect_true(is.numeric(result) || is.logical(result))
-})
-
-test_that("sample_dirichlet_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(sample_dirichlet_impl(
-    n = -1,
-    alpha = c(1, 1, 1)
-  ))
-})
-
 # 55. are_adjacent_impl
 
 test_that("are_adjacent_impl basic", {
@@ -2364,8 +2209,8 @@ test_that("personalized_pagerank_impl basic", {
   ))
   expect_snapshot(personalized_pagerank_impl(
     graph = g,
-    algo = "arpack",
-    damping = 0.9
+    damping = 0.9,
+    algo = "arpack"
   ))
 
   # Structured tests
@@ -2398,8 +2243,8 @@ test_that("personalized_pagerank_vs_impl basic", {
   ))
   expect_snapshot(personalized_pagerank_vs_impl(
     graph = g,
+    reset.vids = 1,
     algo = "arpack",
-    reset_vids = 1,
     details = TRUE
   ))
 
@@ -2793,7 +2638,7 @@ test_that("maxdegree_impl basic", {
   expect_snapshot(maxdegree_impl(
     graph = g,
     mode = "in",
-    loops = FALSE
+    loops = "twice"
   ))
 
   # Structured tests
@@ -3229,8 +3074,7 @@ test_that("eigenvector_centrality_impl basic", {
   ))
   expect_snapshot(eigenvector_centrality_impl(
     graph = g,
-    directed = TRUE,
-    scale = FALSE
+    mode = "out"
   ))
 
   # Structured tests
@@ -3254,19 +3098,9 @@ test_that("hub_and_authority_scores_impl basic", {
   withr::local_seed(20250909)
   local_igraph_options(print.id = FALSE)
   g <- make_full_graph(5)
-  expect_snapshot(hub_and_authority_scores_impl(
+  expect_snapshot(suppressWarnings(hub_and_authority_scores_impl(
     graph = g
-  ))
-  expect_snapshot(hub_and_authority_scores_impl(
-    graph = g,
-    scale = FALSE
-  ))
-
-  # Structured tests
-  result <- hub_and_authority_scores_impl(
-    graph = g
-  )
-  expect_type(result, "list")
+  )))
 })
 
 test_that("hub_and_authority_scores_impl errors", {
@@ -3527,7 +3361,7 @@ test_that("strength_impl basic", {
   expect_snapshot(strength_impl(
     graph = g,
     mode = "in",
-    loops = FALSE
+    loops = "twice"
   ))
 
   # Structured tests
@@ -3589,7 +3423,7 @@ test_that("centralization_degree_impl basic", {
   expect_snapshot(centralization_degree_impl(
     graph = g,
     mode = "in",
-    loops = FALSE,
+    loops = "twice",
     normalized = FALSE
   ))
 
@@ -3608,40 +3442,6 @@ test_that("centralization_degree_impl errors", {
   ))
 })
 
-# 136. centralization_degree_tmax_impl
-
-test_that("centralization_degree_tmax_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot(centralization_degree_tmax_impl(
-    nodes = 3,
-    loops = TRUE
-  ))
-  expect_snapshot(centralization_degree_tmax_impl(
-    nodes = 3,
-    mode = "in",
-    loops = FALSE
-  ))
-
-  # Structured tests
-  result <- centralization_degree_tmax_impl(
-    nodes = 3,
-    loops = TRUE
-  )
-  expect_true(is.numeric(result))
-})
-
-test_that("centralization_degree_tmax_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(
-    centralization_degree_tmax_impl(
-      nodes = -1,
-      loops = TRUE
-    )
-  )
-})
-
 # 137. centralization_betweenness_impl
 
 test_that("centralization_betweenness_impl basic", {
@@ -3778,12 +3578,9 @@ test_that("centralization_eigenvector_centrality_impl basic", {
     n = 3
   )
 
-  expect_snapshot(centralization_eigenvector_centrality_impl(
-    graph = g
-  ))
   expect_snapshot(centralization_eigenvector_centrality_impl(
     graph = g,
-    directed = TRUE,
+    mode = "out",
     normalized = FALSE
   ))
 
@@ -3814,7 +3611,7 @@ test_that("centralization_eigenvector_centrality_tmax_impl basic", {
   ))
   expect_snapshot(centralization_eigenvector_centrality_tmax_impl(
     nodes = 3,
-    directed = TRUE
+    mode = "out"
   ))
 
   # Structured tests
@@ -4081,102 +3878,6 @@ test_that("contract_vertices_impl errors", {
   ))
 })
 
-# 150. eccentricity_dijkstra_impl
-
-test_that("eccentricity_dijkstra_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  g <- path_graph_impl(
-    n = 3
-  )
-
-  expect_snapshot(eccentricity_dijkstra_impl(
-    graph = g
-  ))
-  expect_snapshot(eccentricity_dijkstra_impl(
-    graph = g,
-    mode = "in"
-  ))
-
-  # Structured tests
-  result <- eccentricity_dijkstra_impl(
-    graph = g
-  )
-  expect_true(is.numeric(result))
-})
-
-test_that("eccentricity_dijkstra_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(eccentricity_dijkstra_impl(
-    graph = NULL
-  ))
-})
-
-# 151. graph_center_dijkstra_impl
-
-test_that("graph_center_dijkstra_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  g <- path_graph_impl(
-    n = 3
-  )
-
-  expect_snapshot(graph_center_dijkstra_impl(
-    graph = g
-  ))
-  expect_snapshot(graph_center_dijkstra_impl(
-    graph = g,
-    mode = "in"
-  ))
-
-  # Structured tests
-  result <- graph_center_dijkstra_impl(
-    graph = g
-  )
-  expect_s3_class(result, "igraph.vs")
-})
-
-test_that("graph_center_dijkstra_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(graph_center_dijkstra_impl(
-    graph = NULL
-  ))
-})
-
-# 152. radius_dijkstra_impl
-
-test_that("radius_dijkstra_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  g <- path_graph_impl(
-    n = 3
-  )
-
-  expect_snapshot(radius_dijkstra_impl(
-    graph = g
-  ))
-  expect_snapshot(radius_dijkstra_impl(
-    graph = g,
-    mode = "in"
-  ))
-
-  # Structured tests
-  result <- radius_dijkstra_impl(
-    graph = g
-  )
-  expect_true(is.numeric(result))
-})
-
-test_that("radius_dijkstra_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(radius_dijkstra_impl(
-    graph = NULL
-  ))
-})
-
 # 153. pseudo_diameter_impl
 
 test_that("pseudo_diameter_impl basic", {
@@ -4214,45 +3915,6 @@ test_that("pseudo_diameter_impl errors", {
   ))
 })
 
-# 154. pseudo_diameter_dijkstra_impl
-
-test_that("pseudo_diameter_dijkstra_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  g <- path_graph_impl(
-    n = 3
-  )
-
-  expect_snapshot(pseudo_diameter_dijkstra_impl(
-    graph = g,
-    start_vid = 1
-  ))
-  expect_snapshot(pseudo_diameter_dijkstra_impl(
-    graph = g,
-    start_vid = 1,
-    directed = FALSE,
-    unconnected = FALSE
-  ))
-
-  # Structured tests
-  result <- pseudo_diameter_dijkstra_impl(
-    graph = g,
-    start_vid = 1
-  )
-  expect_type(result, "list")
-})
-
-test_that("pseudo_diameter_dijkstra_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(
-    pseudo_diameter_dijkstra_impl(
-      graph = NULL,
-      start_vid = 1
-    )
-  )
-})
-
 # 155. diversity_impl
 
 test_that("diversity_impl basic", {
@@ -4421,35 +4083,6 @@ test_that("average_local_efficiency_impl errors", {
   ))
 })
 
-# 160. transitive_closure_dag_impl
-
-test_that("transitive_closure_dag_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  g <- path_graph_impl(
-    n = 3,
-    directed = TRUE
-  )
-
-  expect_snapshot(transitive_closure_dag_impl(
-    graph = g
-  ))
-
-  # Structured tests
-  result <- transitive_closure_dag_impl(
-    graph = g
-  )
-  expect_s3_class(result, "igraph")
-})
-
-test_that("transitive_closure_dag_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(transitive_closure_dag_impl(
-    graph = NULL
-  ))
-})
-
 # 161. transitive_closure_impl
 
 test_that("transitive_closure_impl basic", {
@@ -4607,10 +4240,10 @@ test_that("biadjacency_impl basic", {
   local_igraph_options(print.id = FALSE)
   m <- matrix(c(1, 0, 1, 0, 1, 1), nrow = 2)
   expect_snapshot(biadjacency_impl(
-    incidence = m
+    biadjmatrix = m
   ))
   expect_snapshot(biadjacency_impl(
-    incidence = m,
+    biadjmatrix = m,
     directed = TRUE,
     mode = "in",
     multiple = TRUE
@@ -4627,7 +4260,7 @@ test_that("biadjacency_impl errors", {
   withr::local_seed(20250909)
   local_igraph_options(print.id = FALSE)
   expect_snapshot_igraph_error(biadjacency_impl(
-    incidence = "a"
+    biadjmatrix = "a"
   ))
 })
 
@@ -5331,10 +4964,10 @@ test_that("weighted_cliques_impl basic", {
   ))
   expect_snapshot(weighted_cliques_impl(
     graph = g,
-    vertex_weights = c(1, 2, 3),
-    min_weight = 1,
-    max_weight = 3,
-    maximal = TRUE
+    vertex.weights = c(1, 2, 3),
+    maximal = TRUE,
+    min.weight = 1,
+    max.weight = 3
   ))
 
   # Structured tests
@@ -6070,11 +5703,8 @@ test_that("similarity_dice_impl basic", {
   )
 
   expect_snapshot(similarity_dice_impl(
-    graph = g
-  ))
-  expect_snapshot(similarity_dice_impl(
-    graph = g,
-    vids = 1:2,
+    g,
+    vit.from = 1:2,
     mode = "in",
     loops = TRUE
   ))
@@ -6210,11 +5840,8 @@ test_that("similarity_jaccard_impl basic", {
   )
 
   expect_snapshot(similarity_jaccard_impl(
-    graph = g
-  ))
-  expect_snapshot(similarity_jaccard_impl(
-    graph = g,
-    vids = 1:2,
+    g,
+    vit.from = 1:2,
     mode = "in",
     loops = TRUE
   ))
@@ -6453,6 +6080,10 @@ test_that("community_label_propagation_impl basic", {
     n = 3
   )
 
+  expect_snapshot(community_label_propagation_impl(
+    graph = g,
+    lpa.variant = "dominance"
+  ))
   expect_snapshot(community_label_propagation_impl(
     graph = g
   ))
@@ -6461,7 +6092,8 @@ test_that("community_label_propagation_impl basic", {
     mode = "in",
     weights = c(1, 2),
     initial = 1:3,
-    fixed = c(TRUE, FALSE, TRUE)
+    fixed = c(TRUE, FALSE, TRUE),
+    lpa.variant = "retention"
   ))
 
   # Structured tests
@@ -6556,7 +6188,7 @@ test_that("community_leiden_impl basic", {
   expect_snapshot(community_leiden_impl(
     graph = g,
     weights = c(1, 2),
-    vertex_weights = c(1, 2, 3),
+    vertex.out.weights = c(1, 2, 3),
     resolution = 0.5,
     beta = 0.1,
     start = TRUE,
@@ -6623,14 +6255,11 @@ test_that("community_infomap_impl basic", {
     n = 3
   )
 
-  expect_snapshot(community_infomap_impl(
-    graph = g
-  ))
   expect_snapshot(community_infomap_impl(
     graph = g,
-    e_weights = c(1, 2),
-    v_weights = c(1, 2, 3),
-    nb_trials = 2
+    edge.weights = c(1, 2),
+    vertex.weights = c(1, 2, 3),
+    nb.trials = 2
   ))
 
   # Structured tests
@@ -7605,12 +7234,22 @@ test_that("local_scan_neighborhood_ecount_impl basic", {
 
   expect_snapshot(local_scan_neighborhood_ecount_impl(
     graph = g,
-    neighborhoods = list(1:2, 2:3, 2:4, 2)
+    neighborhoods = list(
+      1:2 - 1,
+      2:3 - 1,
+      2:4 - 1,
+      2 - 1
+    )
   ))
   expect_snapshot(local_scan_neighborhood_ecount_impl(
     graph = g,
     weights = c(1, 2, 3),
-    neighborhoods = list(1:2, 1:3, 2:4, 1)
+    neighborhoods = list(
+      1:2 - 1,
+      1:3 - 1,
+      2:4 - 1,
+      1 - 1
+    )
   ))
 
   # Structured tests
@@ -8814,8 +8453,7 @@ test_that("canonical_permutation_impl basic", {
   ))
   expect_snapshot(canonical_permutation_impl(
     graph = g,
-    colors = c(1, 2, 3),
-    sh = "fl"
+    colors = c(1, 2, 3)
   ))
 
   # Structured tests
@@ -8923,8 +8561,7 @@ test_that("count_automorphisms_impl basic", {
   ))
   expect_snapshot(count_automorphisms_impl(
     graph = g,
-    colors = c(1, 2, 3),
-    sh = "fl"
+    colors = c(1, 2, 3)
   ))
 
   # Structured tests
@@ -8951,14 +8588,9 @@ test_that("automorphism_group_impl basic", {
     n = 3
   )
 
-  expect_snapshot(automorphism_group_impl(
-    graph = g
-  ))
   expect_snapshot(automorphism_group_impl(
     graph = g,
-    colors = c(1, 2, 3),
-    sh = "fl",
-    details = TRUE
+    colors = c(1, 2, 3)
   ))
 
   # Structured tests
@@ -9319,30 +8951,6 @@ test_that("sir_impl errors", {
   ))
 })
 
-# 304. convex_hull_2d_impl
-
-test_that("convex_hull_2d_impl basic", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot(convex_hull_2d_impl(
-    data = matrix(1:6, ncol = 2)
-  ))
-
-  # Structured tests
-  result <- convex_hull_2d_impl(
-    data = matrix(1:6, ncol = 2)
-  )
-  expect_type(result, "list")
-})
-
-test_that("convex_hull_2d_impl errors", {
-  withr::local_seed(20250909)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(convex_hull_2d_impl(
-    data = "a"
-  ))
-})
-
 # 305. dim_select_impl
 
 test_that("dim_select_impl basic", {
@@ -9566,9 +9174,9 @@ test_that("fundamental_cycles_impl basic", {
   ))
   expect_snapshot(fundamental_cycles_impl(
     graph = g,
+    weights = c(1, 2),
     start = 1,
-    bfs_cutoff = 2,
-    weights = c(1, 2)
+    bfs.cutoff = 2
   ))
 
   # Structured tests
@@ -9602,10 +9210,10 @@ test_that("minimum_cycle_basis_impl basic", {
   ))
   expect_snapshot(minimum_cycle_basis_impl(
     graph = g,
-    bfs_cutoff = 2,
+    weights = c(1, 2),
+    bfs.cutoff = 2,
     complete = FALSE,
-    use_cycle_order = FALSE,
-    weights = c(1, 2)
+    use.cycle.order = FALSE
   ))
 
   # Structured tests
@@ -10000,193 +9608,6 @@ test_that("is_edge_coloring_impl errors", {
   ))
 })
 
-# 327. deterministic_optimal_imitation_impl
-
-test_that("deterministic_optimal_imitation_impl basic", {
-  withr::local_seed(12345)
-  local_igraph_options(print.id = FALSE)
-  g <- path_graph_impl(
-    n = 3
-  )
-
-  expect_snapshot(deterministic_optimal_imitation_impl(
-    graph = g,
-    vid = 1,
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3)
-  ))
-  expect_snapshot(deterministic_optimal_imitation_impl(
-    graph = g,
-    vid = 1,
-    optimality = "minimum",
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3),
-    mode = "in"
-  ))
-
-  # Structured tests
-  result <- deterministic_optimal_imitation_impl(
-    graph = g,
-    vid = 1,
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3)
-  )
-  expect_true(is.numeric(result) || is.logical(result))
-})
-
-test_that("deterministic_optimal_imitation_impl errors", {
-  withr::local_seed(12345)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(
-    deterministic_optimal_imitation_impl(
-      graph = NULL,
-      vid = 1,
-      quantities = c(1, 2, 3),
-      strategies = c(1, 2, 3)
-    )
-  )
-})
-
-# 328. moran_process_impl
-
-test_that("moran_process_impl basic", {
-  withr::local_seed(12345)
-  local_igraph_options(print.id = FALSE)
-  g <- path_graph_impl(
-    n = 3
-  )
-
-  expect_snapshot(moran_process_impl(
-    graph = g,
-    weights = c(1, 1),
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3),
-    mode = "in"
-  ))
-
-  # Structured tests
-  result <- moran_process_impl(
-    graph = g,
-    weights = c(1, 1),
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3),
-    mode = "in"
-  )
-  expect_type(result, "list")
-})
-
-test_that("moran_process_impl errors", {
-  withr::local_seed(12345)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(
-    moran_process_impl(
-      graph = NULL,
-      quantities = c(1, 2, 3),
-      strategies = c(1, 2, 3)
-    )
-  )
-})
-
-# 329. roulette_wheel_imitation_impl
-
-test_that("roulette_wheel_imitation_impl basic", {
-  withr::local_seed(12345)
-  local_igraph_options(print.id = FALSE)
-  g <- path_graph_impl(
-    n = 3
-  )
-
-  expect_snapshot(roulette_wheel_imitation_impl(
-    graph = g,
-    vid = 1,
-    is_local = TRUE,
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3)
-  ))
-  expect_snapshot(roulette_wheel_imitation_impl(
-    graph = g,
-    vid = 1,
-    is_local = FALSE,
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3),
-    mode = "in"
-  ))
-
-  # Structured tests
-  result <- roulette_wheel_imitation_impl(
-    graph = g,
-    vid = 1,
-    is_local = TRUE,
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3)
-  )
-  expect_true(is.numeric(result) || is.logical(result))
-})
-
-test_that("roulette_wheel_imitation_impl errors", {
-  withr::local_seed(12345)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(
-    roulette_wheel_imitation_impl(
-      graph = NULL,
-      vid = 1,
-      is_local = TRUE,
-      quantities = c(1, 2, 3),
-      strategies = c(1, 2, 3)
-    )
-  )
-})
-
-# 330. stochastic_imitation_impl
-
-test_that("stochastic_imitation_impl basic", {
-  withr::local_seed(12345)
-  local_igraph_options(print.id = FALSE)
-  g <- path_graph_impl(
-    n = 3
-  )
-
-  expect_snapshot(stochastic_imitation_impl(
-    graph = g,
-    vid = 1,
-    algo = 1,
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3)
-  ))
-  expect_snapshot(stochastic_imitation_impl(
-    graph = g,
-    vid = 1,
-    algo = 2,
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3),
-    mode = "in"
-  ))
-
-  # Structured tests
-  result <- stochastic_imitation_impl(
-    graph = g,
-    vid = 1,
-    algo = 1,
-    quantities = c(1, 2, 3),
-    strategies = c(1, 2, 3)
-  )
-  expect_true(is.numeric(result) || is.logical(result))
-})
-
-test_that("stochastic_imitation_impl errors", {
-  withr::local_seed(12345)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(
-    stochastic_imitation_impl(
-      graph = NULL,
-      vid = 1,
-      algo = 1,
-      quantities = c(1, 2, 3),
-      strategies = c(1, 2, 3)
-    )
-  )
-})
-
 # 331. invalidate_cache_impl
 
 test_that("invalidate_cache_impl basic", {
@@ -10215,48 +9636,6 @@ test_that("invalidate_cache_impl errors", {
   ))
 })
 
-# 332. vertex_path_from_edge_path_impl
-
-test_that("vertex_path_from_edge_path_impl basic", {
-  withr::local_seed(12345)
-  local_igraph_options(print.id = FALSE)
-  g <- path_graph_impl(
-    n = 3
-  )
-
-  expect_snapshot(vertex_path_from_edge_path_impl(
-    graph = g,
-    start = 1,
-    edge_path = c(1, 2)
-  ))
-  expect_snapshot(vertex_path_from_edge_path_impl(
-    graph = g,
-    start = 1,
-    edge_path = c(1),
-    mode = "in"
-  ))
-
-  # Structured tests
-  result <- vertex_path_from_edge_path_impl(
-    graph = g,
-    start = 1,
-    edge_path = c(1, 2)
-  )
-  expect_s3_class(result, "igraph.vs")
-})
-
-test_that("vertex_path_from_edge_path_impl errors", {
-  withr::local_seed(12345)
-  local_igraph_options(print.id = FALSE)
-  expect_snapshot_igraph_error(
-    vertex_path_from_edge_path_impl(
-      graph = NULL,
-      start = 1,
-      edge_path = c(1, 2)
-    )
-  )
-})
-
 # 333. version_impl
 
 test_that("version_impl basic", {
diff --git a/tests/testthat/test-centrality.R b/tests/testthat/test-centrality.R
index 41653455073..ed51e90220d 100644
--- a/tests/testthat/test-centrality.R
+++ b/tests/testthat/test-centrality.R
@@ -590,7 +590,8 @@ test_that("eigen_centrality() works", {
 
   for (i in 1:1000) {
     G <- sample_gnm(10, sample(1:20, 1))
-    ev <- eigen_centrality(G)
+    # FIXME: Find a way to avoid warnings
+    suppressWarnings(ev <- eigen_centrality(G))
     expect_good(
       as_adjacency_matrix(G, sparse = FALSE),
       ev$vector,
diff --git a/tests/testthat/test-interface.R b/tests/testthat/test-interface.R
index 0d331bda8fc..7e4569d4dce 100644
--- a/tests/testthat/test-interface.R
+++ b/tests/testthat/test-interface.R
@@ -223,6 +223,13 @@ test_that("get_edge_id() errors correctly for wrong matrices", {
   lifecycle::expect_deprecated(get_edge_ids(g, mat))
 })
 
+test_that("incident() works", {
+  local_igraph_options(print.id = FALSE)
+  g <- make_graph("Zachary")
+  expect_snapshot(incident(g, 1))
+  expect_snapshot(incident(g, 34))
+})
+
 test_that("invalidate_cache works", {
   g <- make_ring(10)
 
diff --git a/tests/testthat/test-simple.R b/tests/testthat/test-simple.R
new file mode 100644
index 00000000000..aff0bea5c1e
--- /dev/null
+++ b/tests/testthat/test-simple.R
@@ -0,0 +1,5 @@
+test_that("is_simple() works", {
+  g <- graph_from_literal(1 +-+ 2 -+ 3)
+  expect_true(is_simple(g))
+  expect_false(is_simple(g, directed = FALSE))
+})
diff --git a/tests/testthat/test-structural-properties.R b/tests/testthat/test-structural-properties.R
index 422e615f969..a8ab24fd22b 100644
--- a/tests/testthat/test-structural-properties.R
+++ b/tests/testthat/test-structural-properties.R
@@ -65,9 +65,9 @@ test_that("max_degree() works", {
   g <- make_graph(c(1, 2, 2, 2, 2, 3), directed = TRUE)
   expect_equal(max_degree(g), 4)
   expect_equal(max_degree(g, mode = "out"), 2)
-  expect_equal(max_degree(g, loops = FALSE), 2)
-  expect_equal(max_degree(g, mode = "out", loops = FALSE), 1)
-  expect_equal(max_degree(g, mode = "in", loops = FALSE), 1)
+  expect_equal(max_degree(g, loops = "none"), 2)
+  expect_equal(max_degree(g, mode = "out", loops = "none"), 1)
+  expect_equal(max_degree(g, mode = "in", loops = "none"), 1)
   expect_equal(max_degree(g, v = c()), 0)
   expect_equal(max_degree(make_empty_graph()), 0)
 })
@@ -1002,7 +1002,7 @@ test_that("edge_density works", {
   expect_equal(gd, gd2)
 })
 
-test_that("knn works", {
+test_that("knn works -- trivial examples", {
   withr::local_seed(42)
 
   ## Some trivial ones
@@ -1014,23 +1014,28 @@ test_that("knn works", {
     knn(g2),
     list(knn = c(1, rep(9, 9)), knnk = c(9, rep(NaN, 7), 1))
   )
+})
 
-  ## A scale-free one, try to plot 'knnk'
+test_that("knn works -- scale-free one", {
+  withr::local_seed(42)
   g3 <- simplify(sample_pa(1000, m = 5))
   r3 <- knn(g3)
   expect_equal(r3$knn[43], 46)
   expect_equal(r3$knn[1000], 192.4)
   expect_equal(r3$knnk[100], 18.78)
   expect_equal(length(r3$knnk), 359)
+})
 
-  ## A random graph
+test_that("knn works -- random graph", {
+  withr::local_seed(42)
   g4 <- sample_gnp(1000, p = 5 / 1000)
   r4 <- knn(g4)
-  expect_equal(r4$knn[1000], 20 / 3)
+  expect_equal(r4$knn[1000], 5)
   expect_equal(length(r4$knnk), 15)
-  expect_equal(r4$knnk[12], 19 / 3)
+  expect_equal(r4$knnk[12], 5.6389, tolerance = 1e-5)
+})
 
-  ## A weighted graph
+test_that("knn works -- weighted graph", {
   g5 <- make_star(10)
   E(g5)$weight <- seq(ecount(g5))
   r5 <- knn(g5)
diff --git a/tools/py-stimulus/.gitrepo b/tools/py-stimulus/.gitrepo
index 05d5fc4eeff..f99282820ff 100644
--- a/tools/py-stimulus/.gitrepo
+++ b/tools/py-stimulus/.gitrepo
@@ -5,8 +5,8 @@
 ;
 [subrepo]
 	remote = git@github.com:igraph/stimulus
-	branch = 0.21.5
-	commit = f62f215a6d325545b44b59e114c963cf04abb4ce
-	parent = 63943053a43a247f1bf7628bbf481d400ce3e315
+	branch = main
+	commit = 9652bc7b3037b235f5e88b3f6e325ec9f5fda7b9
+	parent = 9fbd9772fd942be5a2516c496c59a4166438f6d2
 	method = merge
 	cmdver = 0.4.9
diff --git a/tools/py-stimulus/.pre-commit-config.yaml b/tools/py-stimulus/.pre-commit-config.yaml
index 04afe0c00e0..2b88275d5e3 100644
--- a/tools/py-stimulus/.pre-commit-config.yaml
+++ b/tools/py-stimulus/.pre-commit-config.yaml
@@ -1,20 +1,14 @@
 fail_fast: true
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.0.1
+    rev: v4.6.0
     hooks:
-      - id: check-ast
       - id: end-of-file-fixer
       - id: trailing-whitespace
 
   - repo: https://github.com/charliermarsh/ruff-pre-commit
-    rev: v0.0.275
+    rev: v0.3.5
     hooks:
       - id: ruff
         args: [--fix, --exit-non-zero-on-fix]
-
-  - repo: https://github.com/psf/black
-    rev: 22.3.0
-    hooks:
-      - id: black
-        language_version: python3
+      - id: ruff-format
diff --git a/tools/py-stimulus/README.md b/tools/py-stimulus/README.md
index 3ae92f0046d..705a2da46e6 100644
--- a/tools/py-stimulus/README.md
+++ b/tools/py-stimulus/README.md
@@ -8,3 +8,13 @@ of the R interface of igraph. The aim of this repository is to refactor it in a
 way that makes it easier to potentially use `stimulus` for other high-level
 interfaces (e.g., the Python interface, which still relies on hand-written code
 for the Python bindings).
+
+## Installation
+
+Install [`uv`](https://astral.sh/uv) and then run `uv sync` to create a virtual
+environment with all required dependencies. Then run `uv run stimulus --help` to
+get help about the command line options.
+
+## Documentation
+
+See `docs/index.mdx` for generic usage instructions.
diff --git a/tools/py-stimulus/poetry.lock b/tools/py-stimulus/poetry.lock
deleted file mode 100644
index 990ff8992f5..00000000000
--- a/tools/py-stimulus/poetry.lock
+++ /dev/null
@@ -1,156 +0,0 @@
-# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
-
-[[package]]
-name = "deepmerge"
-version = "0.3.0"
-description = "a toolset to deeply merge python dictionaries."
-optional = false
-python-versions = ">=3"
-groups = ["main"]
-files = [
-    {file = "deepmerge-0.3.0-py2.py3-none-any.whl", hash = "sha256:87166dbe9ba1a3348a45c9d4ada6778f518d41afc0b85aa017ea3041facc3f9c"},
-    {file = "deepmerge-0.3.0.tar.gz", hash = "sha256:f6fd7f1293c535fb599e197e750dbe8674503c5d2a89759b3c72a3c46746d4fd"},
-]
-
-[[package]]
-name = "jinja2"
-version = "3.1.6"
-description = "A very fast and expressive template engine."
-optional = false
-python-versions = ">=3.7"
-groups = ["main"]
-files = [
-    {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"},
-    {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"},
-]
-
-[package.dependencies]
-MarkupSafe = ">=2.0"
-
-[package.extras]
-i18n = ["Babel (>=2.7)"]
-
-[[package]]
-name = "markupsafe"
-version = "2.1.3"
-description = "Safely add untrusted strings to HTML/XML markup."
-optional = false
-python-versions = ">=3.7"
-groups = ["main"]
-files = [
-    {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"},
-    {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"},
-    {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"},
-    {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"},
-    {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"},
-    {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"},
-    {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"},
-    {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"},
-    {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"},
-    {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"},
-    {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"},
-    {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"},
-    {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"},
-    {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"},
-    {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"},
-    {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"},
-    {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"},
-    {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
-    {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
-    {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
-    {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
-    {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
-    {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
-    {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"},
-    {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"},
-    {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"},
-    {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"},
-    {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"},
-    {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"},
-    {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"},
-    {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"},
-    {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"},
-    {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"},
-    {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"},
-    {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"},
-    {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"},
-    {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"},
-    {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"},
-    {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"},
-    {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"},
-    {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"},
-    {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"},
-    {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"},
-    {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"},
-    {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"},
-    {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"},
-    {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"},
-    {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"},
-    {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"},
-    {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
-]
-
-[[package]]
-name = "pyyaml"
-version = "6.0"
-description = "YAML parser and emitter for Python"
-optional = false
-python-versions = ">=3.6"
-groups = ["main"]
-files = [
-    {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
-    {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
-    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
-    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
-    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
-    {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
-    {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
-    {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
-    {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
-    {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
-    {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
-    {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
-    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
-    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
-    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
-    {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
-    {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
-    {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
-    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
-    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
-    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
-    {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
-    {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
-    {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
-    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
-    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
-    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
-    {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
-    {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
-    {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
-    {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
-    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
-    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
-    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
-    {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
-    {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
-    {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
-]
-
-[metadata]
-lock-version = "2.1"
-python-versions = "^3.7"
-content-hash = "cb05f0d7047d2ec7665baeb0beadf88b18664520fbde04079198c652410a04b7"
diff --git a/tools/py-stimulus/poetry.toml b/tools/py-stimulus/poetry.toml
deleted file mode 100644
index d697ca4701e..00000000000
--- a/tools/py-stimulus/poetry.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[virtualenvs]
-in-project=true
diff --git a/tools/py-stimulus/pyproject.toml b/tools/py-stimulus/pyproject.toml
index b4b6f19aab2..c05bd3eba27 100644
--- a/tools/py-stimulus/pyproject.toml
+++ b/tools/py-stimulus/pyproject.toml
@@ -1,30 +1,22 @@
-[tool.poetry]
+[project]
 name = "stimulus"
-version = "0.21.5"
+version = "0.23.0"
 description = "Experimental code generator for high-level interfaces of igraph"
 authors = [
-    "Gabor Csardi ",
-    "Tamas Nepusz ",
+  { name = "Gabor Csardi", email = "csardi.gabor@gmail.com" },
+  { name = "Tamas Nepusz", email = "ntamas@gmail.com" },
 ]
-packages = [{ include = "stimulus", from = "src" }]
 license = "GPL-2.0-or-later"
+requires-python = ">=3.8"
+dependencies = ["PyYAML>=6.0", "deepmerge>=0.3.0", "jinja2>=3.1.2"]
 
-[tool.poetry.dependencies]
-python = "^3.8"
-PyYAML = "^6.0"
-deepmerge = "^0.3.0"
-jinja2 = "^3.1.6"
-
-[tool.poetry.dev-dependencies]
-
-[tool.poetry.scripts]
+[project.scripts]
 stimulus = 'stimulus.__main__:main'
 
 [tool.ruff]
-ignore = ["B905", "C901", "E402", "E501"]
-line-length = 80
-select = ["B", "C", "E", "F", "W"]
+lint.ignore = ["B905", "C901", "E402", "E501"]
+lint.select = ["B", "C", "E", "F", "W"]
 
 [build-system]
-requires = ["poetry-core>=1.0.0"]
-build-backend = "poetry.core.masonry.api"
+requires = ["uv_build>=0.7.18"]
+build-backend = "uv_build"
diff --git a/tools/py-stimulus/src/stimulus/generators/debug.py b/tools/py-stimulus/src/stimulus/generators/debug.py
index bae75fef9e2..198e69cff80 100644
--- a/tools/py-stimulus/src/stimulus/generators/debug.py
+++ b/tools/py-stimulus/src/stimulus/generators/debug.py
@@ -160,7 +160,7 @@ def generate_epilogue(self, inputs: Sequence[str], output: IO[str]) -> None:
         write("#endif")
 
         write()
-        write('    printf("Everything OK!\n");')
+        write('    printf("Everything OK!\\n");')
         write("    return 0;")
         write("}")
 
diff --git a/tools/py-stimulus/src/stimulus/generators/r.py b/tools/py-stimulus/src/stimulus/generators/r.py
index c8d0cde0d2d..3ff75084920 100644
--- a/tools/py-stimulus/src/stimulus/generators/r.py
+++ b/tools/py-stimulus/src/stimulus/generators/r.py
@@ -432,7 +432,7 @@ def handle_output_argument(
 
         ## See if there is a postprocessor
         if "PP" in r_spec:
-            out.write(f'  res <- {r_spec["PP"]}(res)\n')
+            out.write(f"  res <- {r_spec['PP']}(res)\n")
 
         out.write("  res\n}\n\n")
 
@@ -606,7 +606,7 @@ def chunk_call(self, desc: FunctionDescriptor) -> str:
                     and not param.is_output
                     and call != "0"
                 ):
-                    call = f"(Rf_isNull(%I%) ? 0 : {call})"
+                    call = f"(Rf_isNull(%I%) ? {param.get_default_value(t) or "NULL"} : {call})"
                 call = call.replace("%C%", f"c_{param.name}").replace("%I%", param.name)
                 calls.append(call)
 
@@ -624,6 +624,9 @@ def chunk_call(self, desc: FunctionDescriptor) -> str:
             else:
                 res = f"  c_result={desc.name}({calls});\n"
 
+        if desc.uses_rng:
+            res = "".join(["  GetRNGstate();\n", res, "  PutRNGstate();\n"])
+
         return res
 
     def chunk_outconv(self, desc: FunctionDescriptor) -> str:
diff --git a/tools/py-stimulus/src/stimulus/model/functions.py b/tools/py-stimulus/src/stimulus/model/functions.py
index ff72bbcfc73..1bd7956572f 100644
--- a/tools/py-stimulus/src/stimulus/model/functions.py
+++ b/tools/py-stimulus/src/stimulus/model/functions.py
@@ -70,6 +70,11 @@ def is_internal(self) -> bool:
         """
         return self.has_flag("internal")
 
+    @property
+    def uses_rng(self) -> bool:
+        """Returns whether the function uses a random number generator."""
+        return not self.has_flag("no_rng")
+
     @property
     def parameters(self) -> OrderedDict[str, ParamSpec]:
         if self._parameters is None:
diff --git a/tools/py-stimulus/src/stimulus/version.py b/tools/py-stimulus/src/stimulus/version.py
index ac83366729e..827137eafc6 100644
--- a/tools/py-stimulus/src/stimulus/version.py
+++ b/tools/py-stimulus/src/stimulus/version.py
@@ -1,2 +1,2 @@
-__version_info__ = (0, 21, 5)
+__version_info__ = (0, 23, 0)
 __version__ = ".".join("{0}".format(x) for x in __version_info__)
diff --git a/tools/py-stimulus/tbump.toml b/tools/py-stimulus/tbump.toml
index e6602e24f82..294e1661def 100644
--- a/tools/py-stimulus/tbump.toml
+++ b/tools/py-stimulus/tbump.toml
@@ -1,5 +1,5 @@
 [version]
-current = "0.21.5"
+current = "0.23.0"
 regex = '''
   (?P\d+)
   \.
diff --git a/tools/py-stimulus/uv.lock b/tools/py-stimulus/uv.lock
new file mode 100644
index 00000000000..08cde9e06b6
--- /dev/null
+++ b/tools/py-stimulus/uv.lock
@@ -0,0 +1,250 @@
+version = 1
+revision = 3
+requires-python = ">=3.8"
+resolution-markers = [
+    "python_full_version >= '3.9'",
+    "python_full_version < '3.9'",
+]
+
+[[package]]
+name = "deepmerge"
+version = "2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "typing-extensions", marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a8/3a/b0ba594708f1ad0bc735884b3ad854d3ca3bdc1d741e56e40bbda6263499/deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20", size = 19890, upload-time = "2024-08-30T05:31:50.308Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/2d/82/e5d2c1c67d19841e9edc74954c827444ae826978499bde3dfc1d007c8c11/deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00", size = 13475, upload-time = "2024-08-30T05:31:48.659Z" },
+]
+
+[[package]]
+name = "jinja2"
+version = "3.1.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "markupsafe", version = "2.1.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
+    { name = "markupsafe", version = "3.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
+]
+
+[[package]]
+name = "markupsafe"
+version = "2.1.5"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+    "python_full_version < '3.9'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", size = 19384, upload-time = "2024-02-02T16:31:22.863Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/e4/54/ad5eb37bf9d51800010a74e4665425831a9db4e7c4e0fde4352e391e808e/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", size = 18206, upload-time = "2024-02-02T16:30:04.105Z" },
+    { url = "https://files.pythonhosted.org/packages/6a/4a/a4d49415e600bacae038c67f9fecc1d5433b9d3c71a4de6f33537b89654c/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", size = 14079, upload-time = "2024-02-02T16:30:06.5Z" },
+    { url = "https://files.pythonhosted.org/packages/0a/7b/85681ae3c33c385b10ac0f8dd025c30af83c78cec1c37a6aa3b55e67f5ec/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", size = 26620, upload-time = "2024-02-02T16:30:08.31Z" },
+    { url = "https://files.pythonhosted.org/packages/7c/52/2b1b570f6b8b803cef5ac28fdf78c0da318916c7d2fe9402a84d591b394c/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", size = 25818, upload-time = "2024-02-02T16:30:09.577Z" },
+    { url = "https://files.pythonhosted.org/packages/29/fe/a36ba8c7ca55621620b2d7c585313efd10729e63ef81e4e61f52330da781/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", size = 25493, upload-time = "2024-02-02T16:30:11.488Z" },
+    { url = "https://files.pythonhosted.org/packages/60/ae/9c60231cdfda003434e8bd27282b1f4e197ad5a710c14bee8bea8a9ca4f0/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", size = 30630, upload-time = "2024-02-02T16:30:13.144Z" },
+    { url = "https://files.pythonhosted.org/packages/65/dc/1510be4d179869f5dafe071aecb3f1f41b45d37c02329dfba01ff59e5ac5/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", size = 29745, upload-time = "2024-02-02T16:30:14.222Z" },
+    { url = "https://files.pythonhosted.org/packages/30/39/8d845dd7d0b0613d86e0ef89549bfb5f61ed781f59af45fc96496e897f3a/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", size = 30021, upload-time = "2024-02-02T16:30:16.032Z" },
+    { url = "https://files.pythonhosted.org/packages/c7/5c/356a6f62e4f3c5fbf2602b4771376af22a3b16efa74eb8716fb4e328e01e/MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", size = 16659, upload-time = "2024-02-02T16:30:17.079Z" },
+    { url = "https://files.pythonhosted.org/packages/69/48/acbf292615c65f0604a0c6fc402ce6d8c991276e16c80c46a8f758fbd30c/MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", size = 17213, upload-time = "2024-02-02T16:30:18.251Z" },
+    { url = "https://files.pythonhosted.org/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", size = 18219, upload-time = "2024-02-02T16:30:19.988Z" },
+    { url = "https://files.pythonhosted.org/packages/6b/cb/aed7a284c00dfa7c0682d14df85ad4955a350a21d2e3b06d8240497359bf/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", size = 14098, upload-time = "2024-02-02T16:30:21.063Z" },
+    { url = "https://files.pythonhosted.org/packages/1c/cf/35fe557e53709e93feb65575c93927942087e9b97213eabc3fe9d5b25a55/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", size = 29014, upload-time = "2024-02-02T16:30:22.926Z" },
+    { url = "https://files.pythonhosted.org/packages/97/18/c30da5e7a0e7f4603abfc6780574131221d9148f323752c2755d48abad30/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", size = 28220, upload-time = "2024-02-02T16:30:24.76Z" },
+    { url = "https://files.pythonhosted.org/packages/0c/40/2e73e7d532d030b1e41180807a80d564eda53babaf04d65e15c1cf897e40/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", size = 27756, upload-time = "2024-02-02T16:30:25.877Z" },
+    { url = "https://files.pythonhosted.org/packages/18/46/5dca760547e8c59c5311b332f70605d24c99d1303dd9a6e1fc3ed0d73561/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", size = 33988, upload-time = "2024-02-02T16:30:26.935Z" },
+    { url = "https://files.pythonhosted.org/packages/6d/c5/27febe918ac36397919cd4a67d5579cbbfa8da027fa1238af6285bb368ea/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", size = 32718, upload-time = "2024-02-02T16:30:28.111Z" },
+    { url = "https://files.pythonhosted.org/packages/f8/81/56e567126a2c2bc2684d6391332e357589a96a76cb9f8e5052d85cb0ead8/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", size = 33317, upload-time = "2024-02-02T16:30:29.214Z" },
+    { url = "https://files.pythonhosted.org/packages/00/0b/23f4b2470accb53285c613a3ab9ec19dc944eaf53592cb6d9e2af8aa24cc/MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", size = 16670, upload-time = "2024-02-02T16:30:30.915Z" },
+    { url = "https://files.pythonhosted.org/packages/b7/a2/c78a06a9ec6d04b3445a949615c4c7ed86a0b2eb68e44e7541b9d57067cc/MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", size = 17224, upload-time = "2024-02-02T16:30:32.09Z" },
+    { url = "https://files.pythonhosted.org/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", size = 18215, upload-time = "2024-02-02T16:30:33.081Z" },
+    { url = "https://files.pythonhosted.org/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", size = 14069, upload-time = "2024-02-02T16:30:34.148Z" },
+    { url = "https://files.pythonhosted.org/packages/51/b5/5d8ec796e2a08fc814a2c7d2584b55f889a55cf17dd1a90f2beb70744e5c/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", size = 29452, upload-time = "2024-02-02T16:30:35.149Z" },
+    { url = "https://files.pythonhosted.org/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", size = 28462, upload-time = "2024-02-02T16:30:36.166Z" },
+    { url = "https://files.pythonhosted.org/packages/2d/75/fd6cb2e68780f72d47e6671840ca517bda5ef663d30ada7616b0462ad1e3/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", size = 27869, upload-time = "2024-02-02T16:30:37.834Z" },
+    { url = "https://files.pythonhosted.org/packages/b0/81/147c477391c2750e8fc7705829f7351cf1cd3be64406edcf900dc633feb2/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", size = 33906, upload-time = "2024-02-02T16:30:39.366Z" },
+    { url = "https://files.pythonhosted.org/packages/8b/ff/9a52b71839d7a256b563e85d11050e307121000dcebc97df120176b3ad93/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", size = 32296, upload-time = "2024-02-02T16:30:40.413Z" },
+    { url = "https://files.pythonhosted.org/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", size = 33038, upload-time = "2024-02-02T16:30:42.243Z" },
+    { url = "https://files.pythonhosted.org/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", size = 16572, upload-time = "2024-02-02T16:30:43.326Z" },
+    { url = "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127, upload-time = "2024-02-02T16:30:44.418Z" },
+    { url = "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", size = 18192, upload-time = "2024-02-02T16:30:57.715Z" },
+    { url = "https://files.pythonhosted.org/packages/4f/14/6f294b9c4f969d0c801a4615e221c1e084722ea6114ab2114189c5b8cbe0/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", size = 14072, upload-time = "2024-02-02T16:30:58.844Z" },
+    { url = "https://files.pythonhosted.org/packages/81/d4/fd74714ed30a1dedd0b82427c02fa4deec64f173831ec716da11c51a50aa/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", size = 26928, upload-time = "2024-02-02T16:30:59.922Z" },
+    { url = "https://files.pythonhosted.org/packages/c7/bd/50319665ce81bb10e90d1cf76f9e1aa269ea6f7fa30ab4521f14d122a3df/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", size = 26106, upload-time = "2024-02-02T16:31:01.582Z" },
+    { url = "https://files.pythonhosted.org/packages/4c/6f/f2b0f675635b05f6afd5ea03c094557bdb8622fa8e673387444fe8d8e787/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68", size = 25781, upload-time = "2024-02-02T16:31:02.71Z" },
+    { url = "https://files.pythonhosted.org/packages/51/e0/393467cf899b34a9d3678e78961c2c8cdf49fb902a959ba54ece01273fb1/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", size = 30518, upload-time = "2024-02-02T16:31:04.392Z" },
+    { url = "https://files.pythonhosted.org/packages/f6/02/5437e2ad33047290dafced9df741d9efc3e716b75583bbd73a9984f1b6f7/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", size = 29669, upload-time = "2024-02-02T16:31:05.53Z" },
+    { url = "https://files.pythonhosted.org/packages/0e/7d/968284145ffd9d726183ed6237c77938c021abacde4e073020f920e060b2/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", size = 29933, upload-time = "2024-02-02T16:31:06.636Z" },
+    { url = "https://files.pythonhosted.org/packages/bf/f3/ecb00fc8ab02b7beae8699f34db9357ae49d9f21d4d3de6f305f34fa949e/MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", size = 16656, upload-time = "2024-02-02T16:31:07.767Z" },
+    { url = "https://files.pythonhosted.org/packages/92/21/357205f03514a49b293e214ac39de01fadd0970a6e05e4bf1ddd0ffd0881/MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", size = 17206, upload-time = "2024-02-02T16:31:08.843Z" },
+    { url = "https://files.pythonhosted.org/packages/0f/31/780bb297db036ba7b7bbede5e1d7f1e14d704ad4beb3ce53fb495d22bc62/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", size = 18193, upload-time = "2024-02-02T16:31:10.155Z" },
+    { url = "https://files.pythonhosted.org/packages/6c/77/d77701bbef72892affe060cdacb7a2ed7fd68dae3b477a8642f15ad3b132/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", size = 14073, upload-time = "2024-02-02T16:31:11.442Z" },
+    { url = "https://files.pythonhosted.org/packages/d9/a7/1e558b4f78454c8a3a0199292d96159eb4d091f983bc35ef258314fe7269/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", size = 26486, upload-time = "2024-02-02T16:31:12.488Z" },
+    { url = "https://files.pythonhosted.org/packages/5f/5a/360da85076688755ea0cceb92472923086993e86b5613bbae9fbc14136b0/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", size = 25685, upload-time = "2024-02-02T16:31:13.726Z" },
+    { url = "https://files.pythonhosted.org/packages/6a/18/ae5a258e3401f9b8312f92b028c54d7026a97ec3ab20bfaddbdfa7d8cce8/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", size = 25338, upload-time = "2024-02-02T16:31:14.812Z" },
+    { url = "https://files.pythonhosted.org/packages/0b/cc/48206bd61c5b9d0129f4d75243b156929b04c94c09041321456fd06a876d/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", size = 30439, upload-time = "2024-02-02T16:31:15.946Z" },
+    { url = "https://files.pythonhosted.org/packages/d1/06/a41c112ab9ffdeeb5f77bc3e331fdadf97fa65e52e44ba31880f4e7f983c/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", size = 29531, upload-time = "2024-02-02T16:31:17.13Z" },
+    { url = "https://files.pythonhosted.org/packages/02/8c/ab9a463301a50dab04d5472e998acbd4080597abc048166ded5c7aa768c8/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", size = 29823, upload-time = "2024-02-02T16:31:18.247Z" },
+    { url = "https://files.pythonhosted.org/packages/bc/29/9bc18da763496b055d8e98ce476c8e718dcfd78157e17f555ce6dd7d0895/MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", size = 16658, upload-time = "2024-02-02T16:31:19.583Z" },
+    { url = "https://files.pythonhosted.org/packages/f6/f8/4da07de16f10551ca1f640c92b5f316f9394088b183c6a57183df6de5ae4/MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", size = 17211, upload-time = "2024-02-02T16:31:20.96Z" },
+]
+
+[[package]]
+name = "markupsafe"
+version = "3.0.2"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+    "python_full_version >= '3.9'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" },
+    { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" },
+    { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" },
+    { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" },
+    { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" },
+    { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" },
+    { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" },
+    { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" },
+    { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" },
+    { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" },
+    { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" },
+    { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" },
+    { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" },
+    { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" },
+    { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" },
+    { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" },
+    { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" },
+    { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" },
+    { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" },
+    { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" },
+    { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" },
+    { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" },
+    { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" },
+    { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" },
+    { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" },
+    { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" },
+    { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" },
+    { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" },
+    { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" },
+    { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" },
+    { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" },
+    { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" },
+    { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" },
+    { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" },
+    { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" },
+    { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" },
+    { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" },
+    { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" },
+    { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" },
+    { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" },
+    { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" },
+    { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" },
+    { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" },
+    { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" },
+    { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" },
+    { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" },
+    { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" },
+    { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" },
+    { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" },
+    { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" },
+    { url = "https://files.pythonhosted.org/packages/a7/ea/9b1530c3fdeeca613faeb0fb5cbcf2389d816072fab72a71b45749ef6062/MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", size = 14344, upload-time = "2024-10-18T15:21:43.721Z" },
+    { url = "https://files.pythonhosted.org/packages/4b/c2/fbdbfe48848e7112ab05e627e718e854d20192b674952d9042ebd8c9e5de/MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", size = 12389, upload-time = "2024-10-18T15:21:44.666Z" },
+    { url = "https://files.pythonhosted.org/packages/f0/25/7a7c6e4dbd4f867d95d94ca15449e91e52856f6ed1905d58ef1de5e211d0/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", size = 21607, upload-time = "2024-10-18T15:21:45.452Z" },
+    { url = "https://files.pythonhosted.org/packages/53/8f/f339c98a178f3c1e545622206b40986a4c3307fe39f70ccd3d9df9a9e425/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", size = 20728, upload-time = "2024-10-18T15:21:46.295Z" },
+    { url = "https://files.pythonhosted.org/packages/1a/03/8496a1a78308456dbd50b23a385c69b41f2e9661c67ea1329849a598a8f9/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", size = 20826, upload-time = "2024-10-18T15:21:47.134Z" },
+    { url = "https://files.pythonhosted.org/packages/e6/cf/0a490a4bd363048c3022f2f475c8c05582179bb179defcee4766fb3dcc18/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", size = 21843, upload-time = "2024-10-18T15:21:48.334Z" },
+    { url = "https://files.pythonhosted.org/packages/19/a3/34187a78613920dfd3cdf68ef6ce5e99c4f3417f035694074beb8848cd77/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", size = 21219, upload-time = "2024-10-18T15:21:49.587Z" },
+    { url = "https://files.pythonhosted.org/packages/17/d8/5811082f85bb88410ad7e452263af048d685669bbbfb7b595e8689152498/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", size = 20946, upload-time = "2024-10-18T15:21:50.441Z" },
+    { url = "https://files.pythonhosted.org/packages/7c/31/bd635fb5989440d9365c5e3c47556cfea121c7803f5034ac843e8f37c2f2/MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", size = 15063, upload-time = "2024-10-18T15:21:51.385Z" },
+    { url = "https://files.pythonhosted.org/packages/b3/73/085399401383ce949f727afec55ec3abd76648d04b9f22e1c0e99cb4bec3/MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", size = 15506, upload-time = "2024-10-18T15:21:52.974Z" },
+]
+
+[[package]]
+name = "pyyaml"
+version = "6.0.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" },
+    { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" },
+    { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" },
+    { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" },
+    { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" },
+    { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" },
+    { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" },
+    { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" },
+    { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" },
+    { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" },
+    { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" },
+    { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" },
+    { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" },
+    { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" },
+    { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" },
+    { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" },
+    { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" },
+    { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" },
+    { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" },
+    { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" },
+    { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" },
+    { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" },
+    { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" },
+    { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" },
+    { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" },
+    { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" },
+    { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" },
+    { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" },
+    { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" },
+    { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" },
+    { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" },
+    { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" },
+    { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" },
+    { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" },
+    { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" },
+    { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" },
+    { url = "https://files.pythonhosted.org/packages/74/d9/323a59d506f12f498c2097488d80d16f4cf965cee1791eab58b56b19f47a/PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", size = 183218, upload-time = "2024-08-06T20:33:06.411Z" },
+    { url = "https://files.pythonhosted.org/packages/74/cc/20c34d00f04d785f2028737e2e2a8254e1425102e730fee1d6396f832577/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", size = 728067, upload-time = "2024-08-06T20:33:07.879Z" },
+    { url = "https://files.pythonhosted.org/packages/20/52/551c69ca1501d21c0de51ddafa8c23a0191ef296ff098e98358f69080577/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", size = 757812, upload-time = "2024-08-06T20:33:12.542Z" },
+    { url = "https://files.pythonhosted.org/packages/fd/7f/2c3697bba5d4aa5cc2afe81826d73dfae5f049458e44732c7a0938baa673/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", size = 746531, upload-time = "2024-08-06T20:33:14.391Z" },
+    { url = "https://files.pythonhosted.org/packages/8c/ab/6226d3df99900e580091bb44258fde77a8433511a86883bd4681ea19a858/PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", size = 800820, upload-time = "2024-08-06T20:33:16.586Z" },
+    { url = "https://files.pythonhosted.org/packages/a0/99/a9eb0f3e710c06c5d922026f6736e920d431812ace24aae38228d0d64b04/PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", size = 145514, upload-time = "2024-08-06T20:33:22.414Z" },
+    { url = "https://files.pythonhosted.org/packages/75/8a/ee831ad5fafa4431099aa4e078d4c8efd43cd5e48fbc774641d233b683a9/PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", size = 162702, upload-time = "2024-08-06T20:33:23.813Z" },
+    { url = "https://files.pythonhosted.org/packages/65/d8/b7a1db13636d7fb7d4ff431593c510c8b8fca920ade06ca8ef20015493c5/PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", size = 184777, upload-time = "2024-08-06T20:33:25.896Z" },
+    { url = "https://files.pythonhosted.org/packages/0a/02/6ec546cd45143fdf9840b2c6be8d875116a64076218b61d68e12548e5839/PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", size = 172318, upload-time = "2024-08-06T20:33:27.212Z" },
+    { url = "https://files.pythonhosted.org/packages/0e/9a/8cc68be846c972bda34f6c2a93abb644fb2476f4dcc924d52175786932c9/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", size = 720891, upload-time = "2024-08-06T20:33:28.974Z" },
+    { url = "https://files.pythonhosted.org/packages/e9/6c/6e1b7f40181bc4805e2e07f4abc10a88ce4648e7e95ff1abe4ae4014a9b2/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", size = 722614, upload-time = "2024-08-06T20:33:34.157Z" },
+    { url = "https://files.pythonhosted.org/packages/3d/32/e7bd8535d22ea2874cef6a81021ba019474ace0d13a4819c2a4bce79bd6a/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", size = 737360, upload-time = "2024-08-06T20:33:35.84Z" },
+    { url = "https://files.pythonhosted.org/packages/d7/12/7322c1e30b9be969670b672573d45479edef72c9a0deac3bb2868f5d7469/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", size = 699006, upload-time = "2024-08-06T20:33:37.501Z" },
+    { url = "https://files.pythonhosted.org/packages/82/72/04fcad41ca56491995076630c3ec1e834be241664c0c09a64c9a2589b507/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", size = 723577, upload-time = "2024-08-06T20:33:39.389Z" },
+    { url = "https://files.pythonhosted.org/packages/ed/5e/46168b1f2757f1fcd442bc3029cd8767d88a98c9c05770d8b420948743bb/PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", size = 144593, upload-time = "2024-08-06T20:33:46.63Z" },
+    { url = "https://files.pythonhosted.org/packages/19/87/5124b1c1f2412bb95c59ec481eaf936cd32f0fe2a7b16b97b81c4c017a6a/PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", size = 162312, upload-time = "2024-08-06T20:33:49.073Z" },
+]
+
+[[package]]
+name = "stimulus"
+version = "0.22.0"
+source = { editable = "." }
+dependencies = [
+    { name = "deepmerge" },
+    { name = "jinja2" },
+    { name = "pyyaml" },
+]
+
+[package.metadata]
+requires-dist = [
+    { name = "deepmerge", specifier = ">=0.3.0" },
+    { name = "jinja2", specifier = ">=3.1.2" },
+    { name = "pyyaml", specifier = ">=6.0" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.13.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload-time = "2025-04-10T14:19:05.416Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload-time = "2025-04-10T14:19:03.967Z" },
+]
diff --git a/tools/stimulus/functions-R.yaml b/tools/stimulus/functions-R.yaml
index 7470eaf8f5d..b6f3850b2a4 100644
--- a/tools/stimulus/functions-R.yaml
+++ b/tools/stimulus/functions-R.yaml
@@ -20,12 +20,12 @@ igraph_delete_edges:
 
 igraph_delete_vertices:
 
+igraph_vcount:
+
 igraph_ecount:
 
 igraph_is_directed:
 
-igraph_degree:
-
 igraph_edge:
     IGNORE: RR, RC, RInit
 
@@ -44,8 +44,6 @@ igraph_get_all_eids_between:
     # in the argument list.
     DEPS: from ON graph, to ON graph, eids ON graph
 
-igraph_incident:
-
 igraph_is_same_graph:
     IGNORE: RR, RC, RInit
     # Not needed in R; we can simply compare things in the R layer without
@@ -91,16 +89,7 @@ igraph_connect_neighborhood:
 
 igraph_famous:
 
-igraph_circulant:
-    R:
-      GATTR:
-        name: Circulant graph
-      GATTR-PARAM: shifts
-
-igraph_lcf_vector:
-    R:
-      GATTR:
-        name: LCF graph
+igraph_adjlist:
 
 igraph_realize_degree_sequence:
     PARAMS: |-
@@ -206,7 +195,7 @@ igraph_static_power_law_game:
     R:
         GATTR:
           name: Static power law model
-        GATTR-PARAM: exponent_out, exponent_in, loops, multiple, finite_size_correction
+        GATTR-PARAM: exponent_out, exponent_in, finite_size_correction
 
 igraph_k_regular_game:
     R:
@@ -240,6 +229,25 @@ igraph_correlated_game:
           name: Correlated random graph
         GATTR-PARAM: corr, p
 
+igraph_correlated_pair_game:
+
+igraph_dot_product_game:
+
+# HACK
+igraph_sample_sphere_surface:
+    PARAMS: |-
+        INTEGER dim, INTEGER n=1, REAL radius=1,
+        BOOLEAN positive=True, OUT MATRIX res
+
+igraph_sample_sphere_volume:
+    PARAMS: |-
+        INTEGER dim, INTEGER n=1, REAL radius=1,
+        BOOLEAN positive=True, OUT MATRIX res
+
+igraph_sample_dirichlet:
+    PARAMS: INTEGER n, VECTOR alpha, OUT MATRIX res
+
+
 #######################################
 # Basic query functions
 #######################################
@@ -252,12 +260,6 @@ igraph_are_connected:
 # Structural properties
 #######################################
 
-igraph_diameter:
-    IGNORE: RR, RC, RInit
-
-igraph_diameter_dijkstra:
-    IGNORE: RR, RC, RInit
-
 igraph_distances:
     IGNORE: RR, RC
 
@@ -310,37 +312,6 @@ igraph_get_k_shortest_paths:
         vertex_paths: vpaths
         edge_paths: epaths
 
-igraph_get_widest_path:
-    PARAMS: |-
-        GRAPH graph,
-        OPTIONAL OUT VERTEX_INDICES vertices, OPTIONAL OUT EDGE_INDICES edges,
-        VERTEX from, VERTEX to, EDGEWEIGHTS weights=NULL, NEIMODE mode=OUT
-    DEPS: |-
-        from ON graph, to ON graph, weights ON graph, vertices ON graph, edges ON graph
-
-igraph_get_widest_paths:
-    PARAMS: |-
-        GRAPH graph,
-        OPTIONAL OUT VERTEXSET_LIST vertices, OPTIONAL OUT EDGESET_LIST edges,
-        VERTEX from, VERTEX_SELECTOR to=ALL, EDGEWEIGHTS weights=NULL,
-        NEIMODE mode=OUT, OPTIONAL OUT VECTOR_INT parents,
-        OPTIONAL OUT VECTOR_INT inbound_edges
-    DEPS: |-
-        from ON graph, to ON graph, weights ON graph, vertices ON graph,
-        edges ON graph
-
-igraph_widest_path_widths_dijkstra:
-    PARAMS: |-
-        GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL,
-        VERTEX_SELECTOR to=ALL, EDGEWEIGHTS weights=NULL, NEIMODE mode=OUT
-    DEPS: from ON graph, to ON graph, weights ON graph
-
-igraph_widest_path_widths_floyd_warshall:
-    PARAMS: |-
-        GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL,
-        VERTEX_SELECTOR to=ALL, EDGEWEIGHTS weights=NULL, NEIMODE mode=OUT
-    DEPS: from ON graph, to ON graph, weights ON graph
-
 igraph_spanner:
     DEPS: weights ON graph, spanner ON graph
 
@@ -370,15 +341,17 @@ igraph_rewire:
         DEFAULTS:
             mode: 0L
 
-igraph_average_path_length:
-    IGNORE: RR, RC, RInit
-    # No need for it, igraph_average_path_length_dijkstra takes care of the
-    # unweighted case as well
+igraph_subgraph_from_edges:
 
-igraph_average_path_length_dijkstra:
-    PARAM_NAMES:
-        unconn_pairs: unconnected
-        unconn: unconnected
+igraph_reverse_edges:
+
+igraph_path_length_hist:
+
+igraph_simplify:
+
+igraph_ecc:
+
+igraph_reciprocity:
 
 igraph_constraint:
 
@@ -437,16 +410,6 @@ igraph_hub_score:
 igraph_authority_score:
     IGNORE: RR, RC
 
-igraph_hub_and_authority_scores:
-    # This is a temporary hack; we need to find a way to handle default values
-    # for dependencies. The problem is that the VERTEXINDEX type needs two
-    # dependencies: the graph and the vertex set, but we only have the graph
-    # in the argument list.
-    DEPS: weights ON graph, hub ON graph V(graph), authority ON graph V(graph)
-    PARAMS: GRAPH graph, OUT VERTEX_QTY hub, OUT VERTEX_QTY authority,
-        OUT REAL value, BOOLEAN scale=True, OPTIONAL EDGEWEIGHTS weights,
-        INOUT ARPACKOPT options=ARPACK_DEFAULTS
-
 igraph_is_mutual:
     PARAM_NAMES:
         es: eids
@@ -454,39 +417,62 @@ igraph_is_mutual:
 igraph_is_chordal:
     IGNORE: RR, RC, RInit
 
-# We use igraph_eccentricity_dijkstra instead
-igraph_eccentricity:
-    IGNORE: RR, RC
+igraph_avg_nearest_neighbor_degree:
 
-igraph_eccentricity_dijkstra:
-    PARAM_ORDER: graph, vids, *, weights, ...
+igraph_degree_correlation_vector:
 
-# We use igraph_graph_center_dijkstra instead
-igraph_graph_center:
-    IGNORE: RR, RC
+igraph_strength:
 
-igraph_graph_center_dijkstra:
-    FIRST_KW_PARAM: weights
+igraph_centralization:
 
-# We use igraph_radius_dijkstra instead
-igraph_radius:
-    IGNORE: RR, RC
+igraph_centralization_degree:
 
-igraph_radius_dijkstra:
-    FIRST_KW_PARAM: weights
+igraph_centralization_betweenness:
 
-igraph_pseudo_diameter:
-    DEPS: start_vid ON graph
+igraph_centralization_betweenness_tmax:
+
+igraph_centralization_closeness:
+
+igraph_centralization_closeness_tmax:
+
+igraph_centralization_eigenvector_centrality:
+
+igraph_centralization_eigenvector_centrality_tmax:
+
+igraph_assortativity_nominal:
 
-igraph_pseudo_diameter_dijkstra:
+igraph_assortativity:
+
+igraph_assortativity_degree:
+
+igraph_joint_degree_matrix:
+
+igraph_joint_degree_distribution:
+
+igraph_joint_type_distribution:
+
+igraph_contract_vertices:
+
+
+igraph_pseudo_diameter:
     DEPS: start_vid ON graph, weights ON graph
 
+igraph_diversity:
+
 igraph_random_walk:
     PARAM_ORDER: graph, start, steps, ...
 
 igraph_random_edge_walk:
     IGNORE: RR, RC
 
+igraph_global_efficiency:
+
+igraph_local_efficiency:
+
+igraph_average_local_efficiency:
+
+igraph_trussness:
+
 #######################################
 # Degree sequences
 #######################################
@@ -528,9 +514,6 @@ igraph_bipartite_projection_size:
 igraph_bipartite_projection:
     IGNORE: RR, RC, RInit
 
-igraph_create_bipartite:
-    IGNORE: RR
-
 igraph_biadjacency:
     DEPS: types ON res$graph V(res$graph)
 
@@ -540,22 +523,26 @@ igraph_is_bipartite:
     DEPS: type ON graph V(graph)
 
 igraph_bipartite_game_gnp:
-    PARAMS: |-
-        OUT GRAPH graph, OPTIONAL OUT BIPARTITE_TYPES_UNNAMED types,
-        INTEGER n1, INTEGER n2, REAL p, BOOLEAN directed=False,
-        NEIMODE mode=ALL
-
-igraph_bipartite_game_gnm:
-    PARAMS: |-
-        OUT GRAPH graph, OPTIONAL OUT BIPARTITE_TYPES_UNNAMED types,
-        INTEGER n1, INTEGER n2, INTEGER m, BOOLEAN directed=False,
-        NEIMODE mode=ALL
+    DEPS: types ON res$graph V(res$graph)
 
 igraph_bipartite_game:
     IGNORE: RR, RC
 
+igraph_bipartite_game_gnm:
+    DEPS: types ON res$graph V(res$graph)
+
+igraph_bipartite_iea_game:
+    DEPS: types ON res$graph V(res$graph)
+
+igraph_create_bipartite:
+    DEPS: types ON graph
+
+igraph_weighted_biadjacency:
+    DEPS: |-
+        weights ON res$graph E(res$graph), types ON res$graph V(res$graph)
+
 igraph_full_bipartite:
-    DEPS: types ON res$graph
+    DEPS: types ON res$graph V(res$graph)
 
 
 #######################################
@@ -647,12 +634,6 @@ igraph_layout_kamada_kawai_3d:
 igraph_layout_graphopt:
     IGNORE: RR, RC, RInit
 
-igraph_layout_drl:
-    IGNORE: RR
-
-igraph_layout_drl_3d:
-    IGNORE: RR
-
 igraph_layout_merge_dla:
     IGNORE: RR, RC
 
@@ -879,6 +860,16 @@ igraph_coreness:
 igraph_get_subisomorphisms_vf2_callback:
     IGNORE: RR, RC
 
+igraph_count_subisomorphisms_vf2:
+
+igraph_canonical_permutation:
+
+igraph_permute_vertices:
+
+igraph_isomorphic_bliss:
+
+igraph_count_automorphisms:
+
 igraph_subisomorphic_lad:
     IGNORE: RR, RC, RInit
     # R function is hand-rolled
@@ -970,6 +961,8 @@ igraph_eulerian_cycle:
 # Cycle bases
 #######################################
 
+igraph_minimum_cycle_basis:
+
 #######################################
 # Trees
 #######################################
@@ -984,31 +977,17 @@ igraph_from_prufer:
           name: Tree from Prufer sequence
         GATTR-PARAM: prufer
 
-igraph_minimum_spanning_tree:
-    IGNORE: RR, RC, RInit
-
-igraph_minimum_spanning_tree_unweighted:
-
-igraph_minimum_spanning_tree_prim:
-
-igraph_random_spanning_tree:
-    PARAMS: GRAPH graph, OUT EDGE_INDICES res, OPTIONAL VERTEX vid=0
 
 #######################################
 # Coloring
 #######################################
 
+igraph_vertex_coloring_greedy:
+
 igraph_is_bipartite_coloring:
     PARAMS: GRAPH graph, BIPARTITE_TYPES types, OUT BOOLEAN res, OPTIONAL OUT NULL mode
     DEPS: types ON graph
 
-#######################################
-# Microscopic update
-#######################################
-
-igraph_moran_process:
-    DEPS: weights ON graph, quantities ON graph V(graph), strategies ON graph
-
 #######################################
 # Other, (yet) undocumented functions
 #######################################
@@ -1037,14 +1016,16 @@ igraph_strerror:
 # Other functions, documented, graph related
 #######################################
 
+# A very special case
 igraph_expand_path_to_pairs:
     IGNORE: RR
 
 igraph_invalidate_cache:
     PARAMS: INOUT GRAPH graph
 
+# FIXME: Optional IN vertex not easily supported
 igraph_vertex_path_from_edge_path:
-    DEPS: start ON graph, vertex_path ON graph, edge_path ON graph
+    IGNORE: RC, RR
 
 #######################################
 # Meta info
diff --git a/tools/stimulus/types-RC.yaml b/tools/stimulus/types-RC.yaml
index 29f55765538..38044fa5a14 100644
--- a/tools/stimulus/types-RC.yaml
+++ b/tools/stimulus/types-RC.yaml
@@ -294,7 +294,7 @@ ADJLIST:
     OUTCONV:
         IN: igraph_adjlist_destroy(&%C%);
 
-EDGEWEIGHTS:
+EDGE_WEIGHTS:
     CALL: '&%C%'
     CTYPE: igraph_vector_t
     INCONV:
@@ -309,7 +309,7 @@ EDGEWEIGHTS:
             igraph_vector_destroy(&%C%);
             IGRAPH_FINALLY_CLEAN(1);
 
-VERTEXWEIGHTS:
+EDGE_LENGTHS:
     CALL: '&%C%'
     CTYPE: igraph_vector_t
     INCONV:
@@ -324,7 +324,22 @@ VERTEXWEIGHTS:
             igraph_vector_destroy(&%C%);
             IGRAPH_FINALLY_CLEAN(1);
 
-EDGE_CAPACITY:
+VERTEX_WEIGHTS:
+    CALL: '&%C%'
+    CTYPE: igraph_vector_t
+    INCONV:
+        IN: R_SEXP_to_vector(%I%, &%C%);
+        OUT: |-
+            IGRAPH_R_CHECK(igraph_vector_init(&%C%, 0));
+            IGRAPH_FINALLY(igraph_vector_destroy, &%C%);
+            %I%=R_GlobalEnv; /* hack to have a non-NULL value */
+    OUTCONV:
+        OUT: |-
+            PROTECT(%I%=R_igraph_0orvector_to_SEXP(&%C%));
+            igraph_vector_destroy(&%C%);
+            IGRAPH_FINALLY_CLEAN(1);
+
+EDGE_CAPACITIES:
     CALL: '&%C%'
     CTYPE: igraph_vector_t
     INCONV:
@@ -511,6 +526,27 @@ VERTEX_INDICES_PV:
             igraph_vector_int_destroy(&%C%);
             IGRAPH_FINALLY_CLEAN(1);
 
+VERTEX_INDICES_LIST:
+    CALL: '&%C%'
+    CTYPE: igraph_vector_int_list_t
+    INCONV:
+        IN: |-
+            R_igraph_SEXP_to_vector_int_list(%I%, &%C%);
+            IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &%C%);
+        OUT: |-
+            if (0 != igraph_vector_int_list_init(&%C%, 0)) {
+              igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM);
+            }
+            IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &%C%);
+    OUTCONV:
+        IN: |-
+            igraph_vector_int_list_destroy(&%C%);
+            IGRAPH_FINALLY_CLEAN(1);
+        OUT: |-
+            PROTECT(%I%=R_igraph_vector_int_list_to_SEXPp1(&%C%));
+            igraph_vector_int_list_destroy(&%C%);
+            IGRAPH_FINALLY_CLEAN(1);
+
 VERTEX_INDEX_PAIRS:
     CALL: '&%C%'
     CTYPE: igraph_vector_int_t
@@ -549,6 +585,27 @@ EDGE_INDICES:
             igraph_vector_int_destroy(&%C%);
             IGRAPH_FINALLY_CLEAN(1);
 
+EDGE_INDICES_LIST:
+    CALL: '&%C%'
+    CTYPE: igraph_vector_int_list_t
+    INCONV:
+        IN: |-
+            R_igraph_SEXP_to_vector_int_list(%I%, &%C%);
+            IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &%C%);
+        OUT: |-
+            if (0 != igraph_vector_int_list_init(&%C%, 0)) {
+              igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM);
+            }
+            IGRAPH_FINALLY_PV(igraph_vector_int_list_destroy, &%C%);
+    OUTCONV:
+        IN: |-
+            igraph_vector_int_list_destroy(&%C%);
+            IGRAPH_FINALLY_CLEAN(1);
+        OUT: |-
+            PROTECT(%I%=R_igraph_vector_int_list_to_SEXPp1(&%C%));
+            igraph_vector_int_list_destroy(&%C%);
+            IGRAPH_FINALLY_CLEAN(1);
+
 'NULL':
     CALL: '0'
     CTYPE: ~
@@ -579,14 +636,14 @@ ATTRIBUTES:
     CTYPE: ~
     HEADER: {}
 
-ARPACKOPT:
+ARPACK_OPTIONS:
     CALL: '&%C%'
     INCONV:
         INOUT: R_SEXP_to_igraph_arpack_options(%I%, &%C%);
     OUTCONV:
         INOUT: PROTECT(%I%=Rx_igraph_arpack_options_to_SEXP(&%C%));
 
-ARPACKSTORAGE:
+ARPACK_STORAGE:
     CALL: '0'
     CTYPE: ~
     HEADER: {}
@@ -668,7 +725,7 @@ BIPARTITE_TYPES_UNNAMED:
             igraph_vector_bool_destroy(&%C%);
             IGRAPH_FINALLY_CLEAN(1);
 
-VERTEX_COLOR:
+VERTEX_COLORS:
     CALL:
         IN: '&%C%'
         OUT: '&%C%'
@@ -693,7 +750,7 @@ VERTEX_COLOR:
             igraph_vector_int_destroy(&%C%);
             IGRAPH_FINALLY_CLEAN(1);
 
-EDGE_COLOR:
+EDGE_COLORS:
     CALL:
         IN: '&%C%'
         OUT: '&%C%'
@@ -858,6 +915,10 @@ PLFIT:
     OUTCONV:
         OUT: PROTECT(%I%=R_igraph_plfit_result_to_SEXP(&%C%));
 
+
+REWIRING_STATS:
+    CALL: '&%C%'
+
 MAXFLOW_STATS:
     CALL: '&%C%'
     HEADER: {}
diff --git a/tools/stimulus/types-RR.yaml b/tools/stimulus/types-RR.yaml
index 7e415b49a16..bf96cd2b913 100644
--- a/tools/stimulus/types-RR.yaml
+++ b/tools/stimulus/types-RR.yaml
@@ -47,7 +47,7 @@ ALL_VERTEX_QTY:
     OUTCONV:
         OUT: |-
             if (igraph_opt("add.vertex.names") && is_named(%I1%)) {
-              names(%I%) <- vertex_attr(%I1%, "name", %I2%)
+              names(%I%) <- vertex_attr(%I1%, "name")
             }
 
 VECTOR_INT:
@@ -191,34 +191,12 @@ EDGE_SELECTOR:
               %I% <- create_es(%I1%, %I%)
             }
 
-EDGEWEIGHTS:
-    INCONV: |-
-        if (is.null(%I%) && "weight" %in% edge_attr_names(%I1%)) {
-          %I% <- E(%I1%)$weight
-        }
-        if (!is.null(%I%) && !all(is.na(%I%))) {
-          %I% <- as.numeric(%I%)
-        } else {
-          %I% <- NULL
-        }
-
-VERTEXWEIGHTS:
-    INCONV: |-
-        if (is.null(%I%) && "weight" %in% vertex_attr_names(%I1%)) {
-          %I% <- V(%I1%)$weight
-        }
-        if (!is.null(%I%) && !all(is.na(%I%))) {
-          %I% <- as.numeric(%I%)
-        } else {
-          %I% <- NULL
-        }
-
-EDGE_CAPACITY:
+EDGE_CAPACITIES:
     INCONV: |-
         if (is.null(%I%) && "capacity" %in% edge_attr_names(%I1%)) {
           %I% <- E(%I1%)$capacity
         }
-        if (!is.null(%I%) && !all(is.na(%I%))) {
+        if (!is.null(%I%) && any(!is.na(%I%))) {
           %I% <- as.numeric(%I%)
         } else {
           %I% <- NULL
@@ -244,7 +222,7 @@ ALL_BIPARTITE_TYPES:
 
 BIPARTITE_TYPES_UNNAMED:
 
-VERTEX_COLOR:
+VERTEX_COLORS:
     INCONV: |-
         if (is_missing(%I%)) {
           if ("color" %in% vertex_attr_names(%I1%)) {
@@ -263,7 +241,7 @@ VERTEX_COLOR:
               names(%I%) <- vertex_attr(%I1%, "name")
             }
 
-EDGE_COLOR:
+EDGE_COLORS:
     INCONV: |-
         if (is_missing(%I%)) {
           if ("color" %in% edge_attr_names(%I1%)) {
@@ -311,11 +289,11 @@ EDGESET_LIST:
               %I% <- lapply(%I%, unsafe_create_es, graph = %I1%, es = E(%I1%))
             }
 
-'ARPACKSTORAGE':
+ARPACK_STORAGE:
     CALL: {}
     HEADER: ~
 
-ARPACKOPT:
+ARPACK_OPTIONS:
     DEFAULT:
         ARPACK_DEFAULTS: arpack_defaults()
     INCONV:
@@ -434,6 +412,7 @@ LAPLACIAN_NORMALIZATION:
 LOOPS:
     DEFAULT:
         ONCE: c("once", "none", "twice")
+        TWICE: c("twice", "none", "once")
     INCONV: '%I% <- switch_igraph_arg(%I%, "none" = 0L, "twice" = 1L, "once" = 2L)'
 
 SIRLIST: {}
@@ -475,6 +454,15 @@ RWSTUCK:
         RETURN: c("return", "error")
     INCONV: '%I% <- switch_igraph_arg(%I%, "error" = 0L, "return" = 1L)'
 
+LPA_VARIANT:
+    DEFAULT:
+        DOMINANCE: c("dominance", "retention", "fast")
+        RETENTION: c("retention", "dominance", "fast")
+        FAST: c("fast", "dominance", "retention")
+    INCONV: |-
+        %I% <- switch_igraph_arg(%I%,
+          "dominance" = 0L, "retention" = 1L, "fast" = 2L)
+
 EDGE_TYPE_SW:
     DEFAULT:
         SIMPLE: c("simple", "loops", "multi", "all")
@@ -565,3 +553,30 @@ CHUNG_LU_VARIANT:
     DEFAULT:
         ORIGINAL: c("original", "maxent", "nr")
     INCONV: '%I% <- switch_igraph_arg(%I%, "original" = 0L, "maxent" = 1L, "nr" = 2L)'
+
+EDGE_WEIGHTS:
+    INCONV: |-
+        if (is.null(%I%) && "weight" %in% edge_attr_names(%I1%)) {
+          %I% <- E(%I1%)$weight
+        }
+        if (!is.null(%I%) && !all(is.na(%I%))) {
+          %I% <- as.numeric(%I%)
+        } else {
+          %I% <- NULL
+        }
+
+VERTEX_WEIGHTS:
+    INCONV: |-
+        if (is.null(%I%) && "weight" %in% vertex_attr_names(%I1%)) {
+          %I% <- V(%I1%)$weight
+        }
+        if (!is.null(%I%) && !all(is.na(%I%))) {
+          %I% <- as.numeric(%I%)
+        } else {
+          %I% <- NULL
+        }
+
+MSTALGORITHM:
+    DEFAULT:
+        AUTOMATIC: c("automatic", "unweighted", "prim", "kruskal")
+    INCONV: '%I% <- switch_igraph_arg(%I%, "automatic" = 0L, "unweighted" = 1L, "prim" = 2L, "kruskal" = 3L)'