From 143b448e9902d31c82fca7eaa65d0a1792d6b92c Mon Sep 17 00:00:00 2001 From: suppo01 Date: Sun, 20 Apr 2025 18:36:19 -0400 Subject: [PATCH 01/21] add article for module three --- allhands/module_three/index.qmd | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 allhands/module_three/index.qmd diff --git a/allhands/module_three/index.qmd b/allhands/module_three/index.qmd new file mode 100644 index 00000000..e69de29b From 1ce5e004ac344a14b8e391a295d160271f753712 Mon Sep 17 00:00:00 2001 From: Kris Hatcher Date: Sun, 20 Apr 2025 22:34:55 -0400 Subject: [PATCH 02/21] chore: move file into expected location --- .../{module_three => spring2025/weekfifteen/teamone}/index.qmd | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename allhands/{module_three => spring2025/weekfifteen/teamone}/index.qmd (100%) diff --git a/allhands/module_three/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd similarity index 100% rename from allhands/module_three/index.qmd rename to allhands/spring2025/weekfifteen/teamone/index.qmd From 1cdd86eb421a27d1e5d3294372d643e585c21609 Mon Sep 17 00:00:00 2001 From: Kris Hatcher Date: Sun, 20 Apr 2025 22:46:15 -0400 Subject: [PATCH 03/21] feat: adding outline and resources --- .../spring2025/weekfifteen/teamone/index.qmd | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index e69de29b..23d10873 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -0,0 +1,78 @@ +--- +author: [Anoop Guragain,Kris Hatcher,Anton Hedlund,Rosa Ruiz,Molly Suppo] +title: How does implementing a tree with Python's set and list structures impact performance in terms of insertion, deletion, and lookup speed? +page-layout: full +categories: [post, fibonacci, recursive, memoization, iterative] +date: "2025-04-24" +date-format: long +toc: true +--- + +# Introduction + +TODO: content here + +## Motivation + +TODO: content here + +## Approach + +### Generate Trees for Analysis + +TODO: Molly to describe her code here + +### Process Tree Created Using `Set` Container + +TODO: Rosa to describe her code here + +### Process Tree Created Using `List` Container + +TODO: Anton to describe his code here + +### Run a Benchmark + +TODO: Anoop to describe his code here + +## Raw Data + +TODO: Kris to convert Google Sheet into Markdown Table + +# Charts + +TODO: Kris to create charts to demonstrate data + +# Results + +TODO: write up findings + +# Next Steps + +TODO: write up recommended next steps + +# References + +1. Documentation + - [Python Lists](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists) + - [pytest Documentation](https://docs.pytest.org/en/stable/) + - [geeksforgeeks](https://www.geeksforgeeks.org/python-dictionary-update-method/) + - [Tree Data Structures](https://en.wikipedia.org/wiki/Tree_(data_structure)) + - [Rich Library for Tables](https://rich.readthedocs.io/en/stable/tables.html) + - [Graph vs Tree Data Structures](https://www.geeksforgeeks.org/difference-between-graph-and-tree/) +2. Course Slides + - [Hierarchical Data Structures Course Slides](https://algorithmology.org/slides/weekthirteen/) + +## AI Usage in this Project + +AI was used in this project for: + +- Tree generation algorithms (adapted from Microsoft Copilot) +- Code optimization and refactoring suggestions +- Test case generation and documentation templates +- Error handling and debugging support +- Generating sample data for testing +- Bug correction +- Writing documentation +- Autocompletion of repetitive code snippets + +All AI-generated content was reviewed and validated by team members. From 900b5a69d6064dde805b206d3fb40c9e87b71803 Mon Sep 17 00:00:00 2001 From: Kris Hatcher Date: Sun, 20 Apr 2025 22:47:59 -0400 Subject: [PATCH 04/21] fix: correcting categories list --- allhands/spring2025/weekfifteen/teamone/index.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index 23d10873..be1740b0 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -2,7 +2,7 @@ author: [Anoop Guragain,Kris Hatcher,Anton Hedlund,Rosa Ruiz,Molly Suppo] title: How does implementing a tree with Python's set and list structures impact performance in terms of insertion, deletion, and lookup speed? page-layout: full -categories: [post, fibonacci, recursive, memoization, iterative] +categories: [post, tree, set, list, speed, performance] date: "2025-04-24" date-format: long toc: true From c2608011c6c2cd4d464cce9e16ef1a073be17642 Mon Sep 17 00:00:00 2001 From: Kris Hatcher Date: Mon, 21 Apr 2025 15:03:20 -0400 Subject: [PATCH 05/21] feat: adding raw data table --- .../spring2025/weekfifteen/teamone/index.qmd | 203 +++++++++++++++++- 1 file changed, 202 insertions(+), 1 deletion(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index be1740b0..498a7966 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -36,7 +36,208 @@ TODO: Anoop to describe his code here ## Raw Data -TODO: Kris to convert Google Sheet into Markdown Table +| Team Member | Test ID | Implementation | Operation | Repetitions | Total Time (sec) | Average Time (sec) | +| -------------- | ------: | -------------- | --------------- | ----------: | ---------------: | -----------------: | +| Anoop Guragain | 1 | Set | Insert | 1249 | `0.0007219315` | `0.0000005780` | +| Anoop Guragain | 1 | Set | Lookup | 1249 | `0.0004174709` | `0.0000003342` | +| Anoop Guragain | 1 | Set | Delete | 624 | `0.0002694130` | `0.0000004318` | +| Anoop Guragain | 1 | Set | Verify Deletion | 624 | `0.0002048016` | `0.0000003282` | +| Anoop Guragain | 1 | List | Insert | 1249 | `0.0002067089` | `0.0000001655` | +| Anoop Guragain | 1 | List | Lookup | 1249 | `0.0114858150` | `0.0000091960` | +| Anoop Guragain | 1 | List | Delete | 624 | `0.0001938343` | `0.0000003106` | +| Anoop Guragain | 1 | List | Verify Deletion | 624 | `0.0059139729` | `0.0000094775` | +| Anoop Guragain | 2 | Set | Insert | 2499 | `0.0018906593` | `0.0000007566` | +| Anoop Guragain | 2 | Set | Lookup | 2499 | `0.0012483597` | `0.0000004995` | +| Anoop Guragain | 2 | Set | Delete | 1249 | `0.0006318092` | `0.0000005059` | +| Anoop Guragain | 2 | Set | Verify Deletion | 1249 | `0.0007519722` | `0.0000006021` | +| Anoop Guragain | 2 | List | Insert | 2499 | `0.0004298687` | `0.0000001720` | +| Anoop Guragain | 2 | List | Lookup | 2499 | `0.0469496250` | `0.0000187874` | +| Anoop Guragain | 2 | List | Delete | 1249 | `0.0005016327` | `0.0000004016` | +| Anoop Guragain | 2 | List | Verify Deletion | 1249 | `0.0245757103` | `0.0000196763` | +| Anoop Guragain | 3 | Set | Insert | 4999 | `0.0027675629` | `0.0000005536` | +| Anoop Guragain | 3 | Set | Lookup | 4999 | `0.0032362938` | `0.0000006474` | +| Anoop Guragain | 3 | Set | Delete | 2499 | `0.0018022060` | `0.0000007212` | +| Anoop Guragain | 3 | Set | Verify Deletion | 2499 | `0.0017445087` | `0.0000006981` | +| Anoop Guragain | 3 | List | Insert | 4999 | `0.0007727146` | `0.0000001546` | +| Anoop Guragain | 3 | List | Lookup | 4999 | `0.1906578541` | `0.0000381392` | +| Anoop Guragain | 3 | List | Delete | 2499 | `0.0015168190` | `0.0000006070` | +| Anoop Guragain | 3 | List | Verify Deletion | 2499 | `0.0985131264` | `0.0000394210` | +| Anoop Guragain | 4 | Set | Insert | 9999 | `0.0058395863` | `0.0000005840` | +| Anoop Guragain | 4 | Set | Lookup | 9999 | `0.0081734657` | `0.0000008174` | +| Anoop Guragain | 4 | Set | Delete | 4999 | `0.0044069290` | `0.0000008816` | +| Anoop Guragain | 4 | Set | Verify Deletion | 4999 | `0.0050458908` | `0.0000010094` | +| Anoop Guragain | 4 | List | Insert | 9999 | `0.0016064644` | `0.0000001607` | +| Anoop Guragain | 4 | List | Lookup | 9999 | `0.7679641247` | `0.0000768041` | +| Anoop Guragain | 4 | List | Delete | 4999 | `0.0058078766` | `0.0000011618` | +| Anoop Guragain | 4 | List | Verify Deletion | 4999 | `0.3994753361` | `0.0000799110` | +| Anoop Guragain | 5 | Set | Insert | 19999 | `0.0090425014` | `0.0000004521` | +| Anoop Guragain | 5 | Set | Lookup | 19999 | `0.0132143497` | `0.0000006608` | +| Anoop Guragain | 5 | Set | Delete | 9999 | `0.0083487034` | `0.0000008350` | +| Anoop Guragain | 5 | Set | Verify Deletion | 9999 | `0.0070867538` | `0.0000007087` | +| Anoop Guragain | 5 | List | Insert | 19999 | `0.0031774044` | `0.0000001589` | +| Anoop Guragain | 5 | List | Lookup | 19999 | `3.1757445335` | `0.0001587952` | +| Anoop Guragain | 5 | List | Delete | 9999 | `0.0226500034` | `0.0000022652` | +| Anoop Guragain | 5 | List | Verify Deletion | 9999 | `1.6271212101` | `0.0001627284` | +| Kris Hatcher | 1 | Set | Insert | 1249 | `0.0006544590` | `0.0000005240` | +| Kris Hatcher | 1 | Set | Lookup | 1249 | `0.0004522800` | `0.0000003621` | +| Kris Hatcher | 1 | Set | Delete | 624 | `0.0002281666` | `0.0000003657` | +| Kris Hatcher | 1 | Set | Verify Deletion | 624 | `0.0001893044` | `0.0000003034` | +| Kris Hatcher | 1 | List | Insert | 1249 | `0.0002603531` | `0.0000002084` | +| Kris Hatcher | 1 | List | Lookup | 1249 | `0.0140104294` | `0.0000112173` | +| Kris Hatcher | 1 | List | Delete | 624 | `0.0001783371` | `0.0000002858` | +| Kris Hatcher | 1 | List | Verify Deletion | 624 | `0.0066938400` | `0.0000107273` | +| Kris Hatcher | 2 | Set | Insert | 2499 | `0.0013871193` | `0.0000005551` | +| Kris Hatcher | 2 | Set | Lookup | 2499 | `0.0009014606` | `0.0000003607` | +| Kris Hatcher | 2 | Set | Delete | 1249 | `0.0005352497` | `0.0000004285` | +| Kris Hatcher | 2 | Set | Verify Deletion | 1249 | `0.0006377697` | `0.0000005106` | +| Kris Hatcher | 2 | List | Insert | 2499 | `0.0004427433` | `0.0000001772` | +| Kris Hatcher | 2 | List | Lookup | 2499 | `0.0568816662` | `0.0000227618` | +| Kris Hatcher | 2 | List | Delete | 1249 | `0.0005249977` | `0.0000004203` | +| Kris Hatcher | 2 | List | Verify Deletion | 1249 | `0.0305998325` | `0.0000244995` | +| Kris Hatcher | 3 | Set | Insert | 4999 | `0.0026187897` | `0.0000005239` | +| Kris Hatcher | 3 | Set | Lookup | 4999 | `0.0020656586` | `0.0000004132` | +| Kris Hatcher | 3 | Set | Delete | 2499 | `0.0011301041` | `0.0000004522` | +| Kris Hatcher | 3 | Set | Verify Deletion | 2499 | `0.0010702610` | `0.0000004283` | +| Kris Hatcher | 3 | List | Insert | 4999 | `0.0008723736` | `0.0000001745` | +| Kris Hatcher | 3 | List | Lookup | 4999 | `0.2281482220` | `0.0000456388` | +| Kris Hatcher | 3 | List | Delete | 2499 | `0.0015757084` | `0.0000006305` | +| Kris Hatcher | 3 | List | Verify Deletion | 2499 | `0.1140768528` | `0.0000456490` | +| Kris Hatcher | 4 | Set | Insert | 9999 | `0.0051593781` | `0.0000005160` | +| Kris Hatcher | 4 | Set | Lookup | 9999 | `0.0051286221` | `0.0000005129` | +| Kris Hatcher | 4 | Set | Delete | 4999 | `0.0029599667` | `0.0000005921` | +| Kris Hatcher | 4 | Set | Verify Deletion | 4999 | `0.0027363300` | `0.0000005474` | +| Kris Hatcher | 4 | List | Insert | 9999 | `0.0014669895` | `0.0000001467` | +| Kris Hatcher | 4 | List | Lookup | 9999 | `0.9439439774` | `0.0000944038` | +| Kris Hatcher | 4 | List | Delete | 4999 | `0.0077755451` | `0.0000015554` | +| Kris Hatcher | 4 | List | Verify Deletion | 4999 | `0.4784438610` | `0.0000957079` | +| Kris Hatcher | 5 | Set | Insert | 19999 | `0.0102605820` | `0.0000005131` | +| Kris Hatcher | 5 | Set | Lookup | 19999 | `0.0194635391` | `0.0000009732` | +| Kris Hatcher | 5 | Set | Delete | 9999 | `0.0068020821` | `0.0000006803` | +| Kris Hatcher | 5 | Set | Verify Deletion | 9999 | `0.0078239441` | `0.0000007825` | +| Kris Hatcher | 5 | List | Insert | 19999 | `0.0038275719` | `0.0000001914` | +| Kris Hatcher | 5 | List | Lookup | 19999 | `5.4431343079` | `0.0002721703` | +| Kris Hatcher | 5 | List | Delete | 9999 | `0.0259702206` | `0.0000025973` | +| Kris Hatcher | 5 | List | Verify Deletion | 9999 | `2.1690285206` | `0.0002169245` | +| Anton Hedlund | 1 | Set | Insert | 1249 | `0.0002536774` | `0.0000002031` | +| Anton Hedlund | 1 | Set | Lookup | 1249 | `0.0001590252` | `0.0000001273` | +| Anton Hedlund | 1 | Set | Delete | 624 | `0.0001053810` | `0.0000001689` | +| Anton Hedlund | 1 | Set | Verify Deletion | 624 | `0.0001015663` | `0.0000001628` | +| Anton Hedlund | 1 | List | Insert | 1249 | `0.0000927448` | `0.0000000743` | +| Anton Hedlund | 1 | List | Lookup | 1249 | `0.0081560612` | `0.0000065301` | +| Anton Hedlund | 1 | List | Delete | 624 | `0.0001132480` | `0.0000001815` | +| Anton Hedlund | 1 | List | Verify Deletion | 624 | `0.0040009022` | `0.0000064117` | +| Anton Hedlund | 2 | Set | Insert | 2499 | `0.0004878044` | `0.0000001952` | +| Anton Hedlund | 2 | Set | Lookup | 2499 | `0.0003283024` | `0.0000001314` | +| Anton Hedlund | 2 | Set | Delete | 1249 | `0.0001740456` | `0.0000001393` | +| Anton Hedlund | 2 | Set | Verify Deletion | 1249 | `0.0001869202` | `0.0000001497` | +| Anton Hedlund | 2 | List | Insert | 2499 | `0.0001413822` | `0.0000000566` | +| Anton Hedlund | 2 | List | Lookup | 2499 | `0.0313482285` | `0.0000125443` | +| Anton Hedlund | 2 | List | Delete | 1249 | `0.0003473759` | `0.0000002781` | +| Anton Hedlund | 2 | List | Verify Deletion | 1249 | `0.0157310963` | `0.0000125950` | +| Anton Hedlund | 3 | Set | Insert | 4999 | `0.0009343624` | `0.0000001869` | +| Anton Hedlund | 3 | Set | Lookup | 4999 | `0.0009300709` | `0.0000001861` | +| Anton Hedlund | 3 | Set | Delete | 2499 | `0.0004298687` | `0.0000001720` | +| Anton Hedlund | 3 | Set | Verify Deletion | 2499 | `0.0003609657` | `0.0000001444` | +| Anton Hedlund | 3 | List | Insert | 4999 | `0.0003294945` | `0.0000000659` | +| Anton Hedlund | 3 | List | Lookup | 4999 | `0.1207776070` | `0.0000241604` | +| Anton Hedlund | 3 | List | Delete | 2499 | `0.0010612011` | `0.0000004247` | +| Anton Hedlund | 3 | List | Verify Deletion | 2499 | `0.0603499413` | `0.0000241496` | +| Anton Hedlund | 4 | Set | Insert | 9999 | `0.0020077229` | `0.0000002008` | +| Anton Hedlund | 4 | Set | Lookup | 9999 | `0.0029425621` | `0.0000002943` | +| Anton Hedlund | 4 | Set | Delete | 4999 | `0.0012745857` | `0.0000002550` | +| Anton Hedlund | 4 | Set | Verify Deletion | 4999 | `0.0013880730` | `0.0000002777` | +| Anton Hedlund | 4 | List | Insert | 9999 | `0.0007171631` | `0.0000000717` | +| Anton Hedlund | 4 | List | Lookup | 9999 | `0.5085749626` | `0.0000508626` | +| Anton Hedlund | 4 | List | Delete | 4999 | `0.0041770935` | `0.0000008356` | +| Anton Hedlund | 4 | List | Verify Deletion | 4999 | `0.2452845573` | `0.0000490667` | +| Anton Hedlund | 5 | Set | Insert | 19999 | `0.0035853386` | `0.0000001793` | +| Anton Hedlund | 5 | Set | Lookup | 19999 | `0.0066003799` | `0.0000003300` | +| Anton Hedlund | 5 | Set | Delete | 9999 | `0.0029261112` | `0.0000002926` | +| Anton Hedlund | 5 | Set | Verify Deletion | 9999 | `0.0026454926` | `0.0000002646` | +| Anton Hedlund | 5 | List | Insert | 19999 | `0.0012934208` | `0.0000000647` | +| Anton Hedlund | 5 | List | Lookup | 19999 | `2.0283503532` | `0.0001014226` | +| Anton Hedlund | 5 | List | Delete | 9999 | `0.0191664696` | `0.0000019168` | +| Anton Hedlund | 5 | List | Verify Deletion | 9999 | `0.9842171669` | `0.0000984316` | +| Rosa Ruiz | 1 | Set | Insert | 1249 | `0.0002901554` | `0.0000002323` | +| Rosa Ruiz | 1 | Set | Lookup | 1249 | `0.0001721382` | `0.0000001378` | +| Rosa Ruiz | 1 | Set | Delete | 624 | `0.0001032352` | `0.0000001654` | +| Rosa Ruiz | 1 | Set | Verify Deletion | 624 | `0.0000953674` | `0.0000001528` | +| Rosa Ruiz | 1 | List | Insert | 1249 | `0.0000820160` | `0.0000000657` | +| Rosa Ruiz | 1 | List | Lookup | 1249 | `0.0073747635` | `0.0000059045` | +| Rosa Ruiz | 1 | List | Delete | 624 | `0.0001182556` | `0.0000001895` | +| Rosa Ruiz | 1 | List | Verify Deletion | 624 | `0.0038998127` | `0.0000062497` | +| Rosa Ruiz | 2 | Set | Insert | 2499 | `0.0005664825` | `0.0000002267` | +| Rosa Ruiz | 2 | Set | Lookup | 2499 | `0.0003759861` | `0.0000001505` | +| Rosa Ruiz | 2 | Set | Delete | 1249 | `0.0003008842` | `0.0000002409` | +| Rosa Ruiz | 2 | Set | Verify Deletion | 1249 | `0.0002179146` | `0.0000001745` | +| Rosa Ruiz | 2 | List | Insert | 2499 | `0.0001616478` | `0.0000000647` | +| Rosa Ruiz | 2 | List | Lookup | 2499 | `0.0299577713` | `0.0000119879` | +| Rosa Ruiz | 2 | List | Delete | 1249 | `0.0003404617` | `0.0000002726` | +| Rosa Ruiz | 2 | List | Verify Deletion | 1249 | `0.0156574249` | `0.0000125360` | +| Rosa Ruiz | 3 | Set | Insert | 4999 | `0.0012614727` | `0.0000002523` | +| Rosa Ruiz | 3 | Set | Lookup | 4999 | `0.0010662079` | `0.0000002133` | +| Rosa Ruiz | 3 | Set | Delete | 2499 | `0.0005378723` | `0.0000002152` | +| Rosa Ruiz | 3 | Set | Verify Deletion | 2499 | `0.0004682541` | `0.0000001874` | +| Rosa Ruiz | 3 | List | Insert | 4999 | `0.0003514290` | `0.0000000703` | +| Rosa Ruiz | 3 | List | Lookup | 4999 | `0.1198709011` | `0.0000239790` | +| Rosa Ruiz | 3 | List | Delete | 2499 | `0.0012116432` | `0.0000004849` | +| Rosa Ruiz | 3 | List | Verify Deletion | 2499 | `0.0594894886` | `0.0000238053` | +| Rosa Ruiz | 4 | Set | Insert | 9999 | `0.0022077560` | `0.0000002208` | +| Rosa Ruiz | 4 | Set | Lookup | 9999 | `0.0024387836` | `0.0000002439` | +| Rosa Ruiz | 4 | Set | Delete | 4999 | `0.0014414787` | `0.0000002884` | +| Rosa Ruiz | 4 | Set | Verify Deletion | 4999 | `0.0011606216` | `0.0000002322` | +| Rosa Ruiz | 4 | List | Insert | 9999 | `0.0006437302` | `0.0000000644` | +| Rosa Ruiz | 4 | List | Lookup | 9999 | `0.4762122631` | `0.0000476260` | +| Rosa Ruiz | 4 | List | Delete | 4999 | `0.0045065880` | `0.0000009015` | +| Rosa Ruiz | 4 | List | Verify Deletion | 4999 | `0.2361598015` | `0.0000472414` | +| Rosa Ruiz | 5 | Set | Insert | 19999 | `0.0044944286` | `0.0000002247` | +| Rosa Ruiz | 5 | Set | Lookup | 19999 | `0.0059998035` | `0.0000003000` | +| Rosa Ruiz | 5 | Set | Delete | 9999 | `0.0030324459` | `0.0000003033` | +| Rosa Ruiz | 5 | Set | Verify Deletion | 9999 | `0.0035686493` | `0.0000003569` | +| Rosa Ruiz | 5 | List | Insert | 19999 | `0.0013079643` | `0.0000000654` | +| Rosa Ruiz | 5 | List | Lookup | 19999 | `1.8983876705` | `0.0000949241` | +| Rosa Ruiz | 5 | List | Delete | 9999 | `0.0216803551` | `0.0000021683` | +| Rosa Ruiz | 5 | List | Verify Deletion | 9999 | `0.9522755146` | `0.0000952371` | +| Molly Suppo | 1 | Set | Insert | 1249 | `0.0010011196` | `0.0000008015` | +| Molly Suppo | 1 | Set | Lookup | 1249 | `0.0000000000` | `0.0000000000` | +| Molly Suppo | 1 | Set | Delete | 624 | `0.0009982586` | `0.0000015998` | +| Molly Suppo | 1 | Set | Verify Deletion | 624 | `0.0000000000` | `0.0000000000` | +| Molly Suppo | 1 | List | Insert | 1249 | `0.0000000000` | `0.0000000000` | +| Molly Suppo | 1 | List | Lookup | 1249 | `0.0110130310` | `0.0000088175` | +| Molly Suppo | 1 | List | Delete | 624 | `0.0000000000` | `0.0000000000` | +| Molly Suppo | 1 | List | Verify Deletion | 624 | `0.0063445568` | `0.0000101676` | +| Molly Suppo | 2 | Set | Insert | 2499 | `0.0000000000` | `0.0000000000` | +| Molly Suppo | 2 | Set | Lookup | 2499 | `0.0000000000` | `0.0000000000` | +| Molly Suppo | 2 | Set | Delete | 1249 | `0.0009999275` | `0.0000008006` | +| Molly Suppo | 2 | Set | Verify Deletion | 1249 | `0.0000000000` | `0.0000000000` | +| Molly Suppo | 2 | List | Insert | 2499 | `0.0000000000` | `0.0000000000` | +| Molly Suppo | 2 | List | Lookup | 2499 | `0.0470225811` | `0.0000188166` | +| Molly Suppo | 2 | List | Delete | 1249 | `0.0107953548` | `0.0000086432` | +| Molly Suppo | 2 | List | Verify Deletion | 1249 | `0.0270738602` | `0.0000216764` | +| Molly Suppo | 3 | Set | Insert | 4999 | `0.0009989738` | `0.0000001998` | +| Molly Suppo | 3 | Set | Lookup | 4999 | `0.0029928684` | `0.0000005987` | +| Molly Suppo | 3 | Set | Delete | 2499 | `0.0019989014` | `0.0000007999` | +| Molly Suppo | 3 | Set | Verify Deletion | 2499 | `0.0009071827` | `0.0000003630` | +| Molly Suppo | 3 | List | Insert | 4999 | `0.0010023117` | `0.0000002005` | +| Molly Suppo | 3 | List | Lookup | 4999 | `0.2084989548` | `0.0000417081` | +| Molly Suppo | 3 | List | Delete | 2499 | `0.0387632847` | `0.0000155115` | +| Molly Suppo | 3 | List | Verify Deletion | 2499 | `0.1109116077` | `0.0000443824` | +| Molly Suppo | 4 | Set | Insert | 9999 | `0.0070450306` | `0.0000007046` | +| Molly Suppo | 4 | Set | Lookup | 9999 | `0.0085387230` | `0.0000008540` | +| Molly Suppo | 4 | Set | Delete | 4999 | `0.0010113716` | `0.0000002023` | +| Molly Suppo | 4 | Set | Verify Deletion | 4999 | `0.0035007000` | `0.0000007003` | +| Molly Suppo | 4 | List | Insert | 9999 | `0.0000000000` | `0.0000000000` | +| Molly Suppo | 4 | List | Lookup | 9999 | `0.8312807083` | `0.0000831364` | +| Molly Suppo | 4 | List | Delete | 4999 | `0.1535332203` | `0.0000307128` | +| Molly Suppo | 4 | List | Verify Deletion | 4999 | `0.4479711056` | `0.0000896121` | +| Molly Suppo | 5 | Set | Insert | 19999 | `0.0154285431` | `0.0000007715` | +| Molly Suppo | 5 | Set | Lookup | 19999 | `0.0165197849` | `0.0000008260` | +| Molly Suppo | 5 | Set | Delete | 9999 | `0.0070683956` | `0.0000007069` | +| Molly Suppo | 5 | Set | Verify Deletion | 9999 | `0.0080151558` | `0.0000008016` | +| Molly Suppo | 5 | List | Insert | 19999 | `0.0039968491` | `0.0000001999` | +| Molly Suppo | 5 | List | Lookup | 19999 | `3.5107905865` | `0.0001755483` | +| Molly Suppo | 5 | List | Delete | 9999 | `0.6115274429` | `0.0000611589` | +| Molly Suppo | 5 | List | Verify Deletion | 9999 | `1.7308022976` | `0.0001730975` | # Charts From 095fb4975eecd15df91536e9a61ba1a24ab58be2 Mon Sep 17 00:00:00 2001 From: suppo01 Date: Mon, 21 Apr 2025 15:18:33 -0400 Subject: [PATCH 06/21] add generation part of the article --- .../spring2025/weekfifteen/teamone/index.qmd | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index be1740b0..1dc1d143 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -20,7 +20,23 @@ TODO: content here ### Generate Trees for Analysis -TODO: Molly to describe her code here +I have two separate generation algorithms to handle the different data types used for this experiment, lists and sets. +Regardless, both generate unordered integer pairs within the container specified in the function name. Both functions also +handle the case where there is not enough nodes present to make a tree. To generate a tree, there needs to be at least two +nodes, a parent or root node, and a child node. If there are not enough nodes, an error is raised explaining why a tree will +not be generated. + +The node pairs are generated using the random library and it's function, `randint`. The values generated are random integers +between `0` and `1000`. Nodes are generated until the number of nodes generated is the equal to the value of the parameter +`num_nodes`. The root or parent node is then assigned as the first node inside the container with the utilization of the `pop` +function and the value `0` or the first index in the list specified. The available parents list is started with the root node +as the first entry. + +For each value in the randomly generated list of values for the nodes, the parents are randomly selected and a pair consisting +of the parent value and the child's value are added to the tree. For sets, the `add` function is used and for lists, the +`append` function is used. Then the available parent list is updated with the value of the child node. + +At the end of both functions, the tree is returned either as a set or a list that contains pairs of unordered integers. ### Process Tree Created Using `Set` Container From f5ee279d3d0dd86ccb6148aa4290d2c0753b069d Mon Sep 17 00:00:00 2001 From: Kris Hatcher Date: Mon, 21 Apr 2025 16:58:18 -0400 Subject: [PATCH 07/21] feat: adding averages table --- .../spring2025/weekfifteen/teamone/index.qmd | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index c055178a..185b525d 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -255,6 +255,25 @@ TODO: Anoop to describe his code here | Molly Suppo | 5 | List | Delete | 9999 | `0.6115274429` | `0.0000611589` | | Molly Suppo | 5 | List | Verify Deletion | 9999 | `1.7308022976` | `0.0001730975` | +## Averages + +The following table averages out the data in the table above, grouping them by +the `Implementation` and `Operation` columns. The data was then pivoted so that +different vertex counts are displayed horizontally instead of vertically. + +| Implementation | Operation | 624 Vertices | 1249 Vertices | 2499 Vertices | 4999 Vertices | 9999 Vertices | 19999 Vertices | +| -------------- | -------------- | -------------: | -------------: | -------------: | -------------: | -------------: | -------------: | +| List | Delete | `0.0001207350` | `0.0025019646` | `0.0088257313` | `0.0351600647` | `0.1401988983` | - | +| List | Insert | - | `0.0001283646` | `0.0002351284` | `0.0006656647` | `0.0008868694` | `0.0027206421` | +| List | Lookup | - | `0.0104080200` | `0.0424319744` | `0.1735907078` | `0.7055952072` | `3.2112814903` | +| List | VerifyDeletion | `0.0053706169` | `0.0227275848` | `0.0886682034` | `0.3614669323` | `1.4926889420` | - | +| Set | Delete | `0.0003408909` | `0.0005283832` | `0.0011797905` | `0.0022188663` | `0.0056355476` | - | +| Set | Insert | - | `0.0005842686` | `0.0008664131` | `0.0017162323` | `0.0044518948` | `0.0085622787` | +| Set | Lookup | - | `0.0002401829` | `0.0005708218` | `0.0020582199` | `0.0054444313` | `0.0123595714` | +| Set | VerifyDeletion | `0.0001182079` | `0.0003589153` | `0.0009102344` | `0.0027663231` | `0.0058279991` | - | + +: Average execution time for all studied ways to access a tree. {.responsive} + # Charts TODO: Kris to create charts to demonstrate data From c295f8d190878492bf67d679cbc1185089ca2886 Mon Sep 17 00:00:00 2001 From: Kris Hatcher Date: Mon, 21 Apr 2025 17:00:10 -0400 Subject: [PATCH 08/21] feat: charts --- .../weekfifteen/teamone/images/linear.png | Bin 0 -> 31693 bytes .../weekfifteen/teamone/images/quadratic.png | Bin 0 -> 22342 bytes .../spring2025/weekfifteen/teamone/index.qmd | 14 +++++++++++++- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 allhands/spring2025/weekfifteen/teamone/images/linear.png create mode 100644 allhands/spring2025/weekfifteen/teamone/images/quadratic.png diff --git a/allhands/spring2025/weekfifteen/teamone/images/linear.png b/allhands/spring2025/weekfifteen/teamone/images/linear.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf7793cd5b50ba3b9c77235d9444a6ad0b04883 GIT binary patch literal 31693 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 B#_s?C literal 0 HcmV?d00001 diff --git a/allhands/spring2025/weekfifteen/teamone/images/quadratic.png b/allhands/spring2025/weekfifteen/teamone/images/quadratic.png new file mode 100644 index 0000000000000000000000000000000000000000..8f0f1f7595f8564e5618a895a0a186e1a1f7e0ec GIT binary patch literal 22342 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 Date: Mon, 21 Apr 2025 23:35:05 -0400 Subject: [PATCH 09/21] feat: added tree procces using list section --- .../spring2025/weekfifteen/teamone/index.qmd | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index b0a2e51b..0be576c4 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -6,6 +6,10 @@ categories: [post, tree, set, list, speed, performance] date: "2025-04-24" date-format: long toc: true +format: + html: + code-fold: true + code-tools: true --- # Introduction @@ -44,7 +48,76 @@ TODO: Rosa to describe her code here ### Process Tree Created Using `List` Container -TODO: Anton to describe his code here +The ListProcessor class implements a tree data structure using Python's list to store parent-child relationships. Each relationship is stored as a tuple pair (parent, child) within the list, allowing for efficient storage and traversal of the tree structure. +The class provides a set of operations to manage these relationships: + +- `insert_tree_pair(parent, child)`Creates a new parent-child relationship, returning True if successful or False if the relationship already exists +- `delete_tree_pair(parent, child)`Removes a specific relationship, returning True if successful or False if the relationship didn't exist +- `lookup_tree_pair(parent, child)` Checks if a specific relationship exists in the tree +- `get_tree_size()` Returns the total number of relationships in the tree +- `get_tree()` Returns a copy of all relationships in the tree +- `get_children(parent)` Retrieves all children connected to a specific parent +- `get_parents(child)` Retrieves all parents connected to a specific child + +```{python} +from typing import TypeVar, List, Tuple + +T = TypeVar('T') # Generic type for values + +class ListProcessor: + def __init__(self) -> None: + self.tree: List[Tuple[T, T]] = [] +#| class: scrollable + def insert_tree_pair(self, parent: T, child: T) -> bool: + """Insert a parent-child pair into the tree structure. + + Args: + parent: The parent node value + child: The child node value + + Returns: + bool: True if the pair was inserted, False if it already exists + """ + if (parent, child) in self.tree: + return False + self.tree.append((parent, child)) + return True + + def delete_tree_pair(self, parent: T, child: T) -> bool: + """Delete a parent-child pair from the tree structure. + + Args: + parent: The parent node value + child: The child node value + + Returns: + bool: True if the pair was deleted, False if it didn't exist + """ + try: + self.tree.remove((parent, child)) + return True + except ValueError: + return False + + def lookup_tree_pair(self, parent: T, child: T) -> bool: + """Check if a parent-child pair exists in the tree structure. + + Args: + parent: The parent node value + child: The child node value + + Returns: + bool: True if the pair exists, False otherwise + """ + return (parent, child) in self.tree +``` + +The implementation uses Python's built-in list operations: + +- `append()` for adding new relationships +- `remove()` for deleting relationships +- `in` operator for checking relationship existence +- `copy()` for returning safe copies of the tree data ### Run a Benchmark From b7c157988f31399880dfe7f04b4e0e315afaf970 Mon Sep 17 00:00:00 2001 From: Anton Hedlund Date: Tue, 22 Apr 2025 12:23:54 -0400 Subject: [PATCH 10/21] fix: added note for improved clarity in list section --- allhands/spring2025/weekfifteen/teamone/index.qmd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index 0be576c4..896eeb41 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -119,6 +119,8 @@ The implementation uses Python's built-in list operations: - `in` operator for checking relationship existence - `copy()` for returning safe copies of the tree data +Note: The Code arrow is interactive and will display relevant code snippets. + ### Run a Benchmark TODO: Anoop to describe his code here From f93c9e8220022578bbff9232fd0e686074c8e91e Mon Sep 17 00:00:00 2001 From: Anupraj Guragain <156822919+AN00P-G@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:20:29 -0400 Subject: [PATCH 11/21] Update index.qmd benchmarking --- .../spring2025/weekfifteen/teamone/index.qmd | 188 +++++++++++++++++- 1 file changed, 187 insertions(+), 1 deletion(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index 896eeb41..5cb6b132 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -123,7 +123,193 @@ Note: The Code arrow is interactive and will display relevant code snippets. ### Run a Benchmark -TODO: Anoop to describe his code here +The main.py implements a performance benchmarking system that compares two different tree data structure implementations which are a set-based (SetGraph) and a list-based (ListProcessor) implementation. It measures and visualizes execution times for common tree operations using the Rich library for formatted output. The operation are: + +- Insertion (adding parent-child relationships) +- Lookup (checking if relationships exist) +- Deletion (removing relationships) +- Verification (confirming deletions) + +```python + +def run_demo(num_vertices=20, quiet=False): + console = Console() + + # Generate tree data + try: + edges = generate_random_tree_with_random_values_list(num_vertices) + except ValueError: + edges = [(1, 2), (2, 3), (3, 4), (4, 5)] + + # Initialize implementations + set_tree = SetGraph() + list_tree = ListProcessor() + + set_insert_times = [] + list_insert_times = [] + set_lookup_times = [] + list_lookup_times = [] + set_delete_times = [] + list_delete_times = [] + set_verify_times = [] + list_verify_times = [] + + # Table for insertion + insertion_table = Table(title="Tree Node Insertion Operations") + insertion_table.add_column("Parent-Child Edge", style="cyan") + insertion_table.add_column("Set Implementation", style="green") + insertion_table.add_column("List Implementation", style="yellow") + + # Perform insertions + for v1, v2 in edges: + set_start_time = time.time() + set_tree.insert_edge(v1, v2) + set_end_time = time.time() + set_insert_times.append((set_end_time - set_start_time)) + + list_start_time = time.time() + list_tree.insert_tree_pair(v1, v2) + list_end_time = time.time() + list_insert_times.append((list_end_time - list_start_time)) + + insertion_table.add_row(f"({v1}, {v2})", "Success", "Success") + + # Table for lookup + lookup_table = Table(title="Tree Node Lookup Operations") + lookup_table.add_column("Parent-Child Edge", style="cyan") + lookup_table.add_column("Set Implementation", style="green") + lookup_table.add_column("List Implementation", style="yellow") + + # Perform lookups + for v1, v2 in edges: + set_start_time = time.time() + set_result = str(set_tree.lookup_edge(v1, v2)) + set_end_time = time.time() + set_lookup_times.append((set_end_time - set_start_time)) + + list_start_time = time.time() + list_result = str(list_tree.lookup_tree_pair(v1, v2)) + list_end_time = time.time() + list_lookup_times.append((list_end_time - list_start_time)) + + lookup_table.add_row(f"({v1}, {v2})", set_result, list_result) + + # Table for deletion + deletion_table = Table(title="Tree Node Deletion Operations") + deletion_table.add_column("Parent-Child Edge", style="cyan") + deletion_table.add_column("Set Implementation", style="green") + deletion_table.add_column("List Implementation", style="yellow") + + # Perform deletions + deletion_count = len(edges) // 2 + for v1, v2 in edges[:deletion_count]: + set_start_time = time.time() + set_tree.update_edge(v1, v2, False) + set_end_time = time.time() + set_delete_times.append((set_end_time - set_start_time)) + + list_start_time = time.time() + list_tree.delete_tree_pair(v1, v2) + list_end_time = time.time() + list_delete_times.append((list_end_time - list_start_time)) + + deletion_table.add_row(f"({v1}, {v2})", "Removed", "Removed") + + # Table for verification + verification_table = Table(title="Deletion Verification Operations") + verification_table.add_column("Parent-Child Edge", style="cyan") + verification_table.add_column("Set Implementation", style="green") + verification_table.add_column("List Implementation", style="yellow") + + # Verify deletions + for v1, v2 in edges[:deletion_count]: + set_start_time = time.time() + set_result = str(set_tree.lookup_edge(v1, v2)) + set_end_time = time.time() + set_verify_times.append((set_end_time - set_start_time)) + + list_start_time = time.time() + list_result = str(list_tree.lookup_tree_pair(v1, v2)) + list_end_time = time.time() + list_verify_times.append((list_end_time - list_start_time)) + + verification_table.add_row(f"({v1}, {v2})", set_result, list_result) + + results_table = Table(title="Experimental Results") + results_table.add_column("Implementation", style="green") + results_table.add_column("Operation", style="cyan") + results_table.add_column("Repetitions", style="yellow") + results_table.add_column("Total Time (sec)", style="white") + results_table.add_column("Average Time (sec)", style="magenta") + + results_table.add_row( + "Set", + "Insert", + str(len(set_insert_times)), + f"{sum(set_insert_times):.10f}", + f"{(sum(set_insert_times) / len(set_insert_times)):.10f}") + results_table.add_row( + "Set", + "Lookup", + str(len(set_lookup_times)), + f"{sum(set_lookup_times):.10f}", + f"{(sum(set_lookup_times) / len(set_lookup_times)):.10f}") + results_table.add_row( + "Set", + "Delete", + str(len(set_delete_times)), + f"{sum(set_delete_times):.10f}", + f"{(sum(set_delete_times) / len(set_delete_times)):.10f}") + results_table.add_row( + "Set", + "Verify Deletion", + str(len(set_verify_times)), + f"{sum(set_verify_times):.10f}", + f"{(sum(set_verify_times) / len(set_verify_times)):.10f}") + results_table.add_row( + "List", + "Insert", + str(len(list_insert_times)), + f"{sum(list_insert_times):.10f}", + f"{(sum(list_insert_times) / len(list_insert_times)):.10f}") + results_table.add_row( + "List", + "Lookup", + str(len(list_lookup_times)), + f"{sum(list_lookup_times):.10f}", + f"{(sum(list_lookup_times) / len(list_lookup_times)):.10f}") + results_table.add_row( + "List", + "Delete", + str(len(list_delete_times)), + f"{sum(list_delete_times):.10f}", + f"{(sum(list_delete_times) / len(list_delete_times)):.10f}") + results_table.add_row( + "List", + "Verify Deletion", + str(len(list_verify_times)), + f"{sum(list_verify_times):.10f}", + f"{(sum(list_verify_times) / len(list_verify_times)):.10f}") + + if quiet: + console.print("\n[bold blue]Tree Implementation Comparison Results Summary[/bold blue]\n") + console.print(results_table) + else: + console.print("\n[bold blue]Tree Implementation Comparison Results Detail[/bold blue]\n") + console.print(insertion_table) + console.print(lookup_table) + console.print(deletion_table) + console.print(verification_table) +``` + +The benchmarking process includes: + +- Tree generation with configurable size +- Parallel execution of operations on both implementations +- Precise time measurement for each operation +- Detailed operation logs showing successful insertions, lookups, and deletions +- Summary statistics comparing average execution times between implementations + ## Raw Data From f2eac969c04d88741f32bc37c5c999d0145d701d Mon Sep 17 00:00:00 2001 From: Anupraj Guragain <156822919+AN00P-G@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:55:30 -0400 Subject: [PATCH 12/21] Update index.qmd Result --- .../spring2025/weekfifteen/teamone/index.qmd | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index 5cb6b132..381ba566 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -553,7 +553,38 @@ which demonstrate a roughly quadratic time complexity. # Results -TODO: write up findings +The result of the worst case time complexities are as follow: + +| Implementation | Insert | Lookup | Delete | Verify Deletion | +| -------------- | -------- |--------: | -------: | ----------------: | +| List | 0(1)avg | 0(n) | 0(n) | 0(n) | +| Set | 0(1)avg | 0(1)avg | 0(1)avg | 0(1)av | + +## Insert +- Set remains at constant 0(1) +- List is also constant 0(1) as it is appending at the end +- Even though both are at 0(1), List is comparatively a lot faster than set at pure appending hence it is faster than set. + +## Lookup +- Set remains at constant 0(1) +- List provide worst case time complexity of 0(n) when doubling the list size +- Set is faster constantly for the both small and large data sizes compared to list as list + +## Delete +- Set remains at constant 0(1) +- List provide worst case time complexity of 0(n) +- For the smaller data both are almost similar for the deletion but as the data increases the list falls behind due to the shifting + +## Verify Deletion +- Set remains at constant 0(1) +- List provide worst case time complexity of 0(n) +- Set is faster constantly for the both small and large data sizes compared to list as list + +## Conclusion + +Set is alot faster than list because it uses hash table while list use dynamic array. Other than append(insert) which amortize 0(1) due to python geometrically growing capacity, List must look at every element or need to shift for other operations which results in 0(n). +- If you need fast, random insert, delete and lookup of vertices or edges use **Set**. +- If you truly just need to build up nodes or neighbors and then walk them sequentially use **List**. # Next Steps From 5904b31801404b11a74b86d870f6838470d9e00c Mon Sep 17 00:00:00 2001 From: Anupraj Guragain <156822919+AN00P-G@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:59:00 -0400 Subject: [PATCH 13/21] Update index.qmd result --- .../spring2025/weekfifteen/teamone/index.qmd | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index 381ba566..a8a5b1e4 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -558,31 +558,31 @@ The result of the worst case time complexities are as follow: | Implementation | Insert | Lookup | Delete | Verify Deletion | | -------------- | -------- |--------: | -------: | ----------------: | | List | 0(1)avg | 0(n) | 0(n) | 0(n) | -| Set | 0(1)avg | 0(1)avg | 0(1)avg | 0(1)av | +| Set | 0(1)avg | 0(1)avg | 0(1)avg | 0(1)avg | ## Insert -- Set remains at constant 0(1) -- List is also constant 0(1) as it is appending at the end +- Set remains at constant 0(1). +- List is also constant 0(1) as it is appending at the end. - Even though both are at 0(1), List is comparatively a lot faster than set at pure appending hence it is faster than set. ## Lookup - Set remains at constant 0(1) -- List provide worst case time complexity of 0(n) when doubling the list size -- Set is faster constantly for the both small and large data sizes compared to list as list +- List provide worst case time complexity of 0(n) when doubling the list size. +- Set is faster constantly for the both small and large data sizes compared to list. ## Delete -- Set remains at constant 0(1) -- List provide worst case time complexity of 0(n) -- For the smaller data both are almost similar for the deletion but as the data increases the list falls behind due to the shifting +- Set remains at constant 0(1). +- List provide worst case time complexity of 0(n). +- For the smaller data both are almost similar for the deletion but as the data increases the list falls behind due to the shifting. ## Verify Deletion -- Set remains at constant 0(1) -- List provide worst case time complexity of 0(n) -- Set is faster constantly for the both small and large data sizes compared to list as list +- Set remains at constant 0(1). +- List provide worst case time complexity of 0(n). +- Set is faster constantly for the both small and large data sizes compared to list. ## Conclusion -Set is alot faster than list because it uses hash table while list use dynamic array. Other than append(insert) which amortize 0(1) due to python geometrically growing capacity, List must look at every element or need to shift for other operations which results in 0(n). +Set is alot faster than list because it uses hash table while list use dynamic array.Other than append(insert) which amortize 0(1) due to python geometrically growing capacity, List must look at every element or need to shift for other operations which results in 0(n). - If you need fast, random insert, delete and lookup of vertices or edges use **Set**. - If you truly just need to build up nodes or neighbors and then walk them sequentially use **List**. From e5aa23970b3ad23675a1cf1761c277177cab12ea Mon Sep 17 00:00:00 2001 From: Anton Hedlund Date: Tue, 22 Apr 2025 15:56:56 -0400 Subject: [PATCH 14/21] feat: added intro and formating benchmark code --- allhands/spring2025/weekfifteen/teamone/index.qmd | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index a8a5b1e4..d3ab732d 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -14,7 +14,9 @@ format: # Introduction -TODO: content here +This investigation seeks to answer a fundamental question in data structure implementation: How does implementing a tree with Python's set and list structures impact performance in terms of insertion, deletion, and lookup speed? + +To evaluate the two different implmentations, we compare their performance across three operations: insertion, lookup and deletion. Using precise timing measurements and controlled experiments with varying tree sizes, we analyze how each data structure handles these operations. This comprehensive performance testing reveals differences in efficiency and scalability, enabling us to determine which implementation delivers optimal performance for different tree operation scenarios. ## Motivation @@ -130,7 +132,7 @@ The main.py implements a performance benchmarking system that compares two diffe - Deletion (removing relationships) - Verification (confirming deletions) -```python +```{python} def run_demo(num_vertices=20, quiet=False): console = Console() @@ -310,6 +312,7 @@ The benchmarking process includes: - Detailed operation logs showing successful insertions, lookups, and deletions - Summary statistics comparing average execution times between implementations +Note: The Code arrow is interactive and will display relevant code snippets. ## Raw Data From 1eec0ba3535459bc0d8f577ca912cc5877bcc936 Mon Sep 17 00:00:00 2001 From: Kris Hatcher Date: Tue, 22 Apr 2025 18:17:45 -0400 Subject: [PATCH 15/21] feat: adding responsive tags to tables --- allhands/spring2025/weekfifteen/teamone/index.qmd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index d3ab732d..3dfb1845 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -519,6 +519,8 @@ Note: The Code arrow is interactive and will display relevant code snippets. | Molly Suppo | 5 | List | Delete | 9999 | `0.6115274429` | `0.0000611589` | | Molly Suppo | 5 | List | Verify Deletion | 9999 | `1.7308022976` | `0.0001730975` | +: Raw data for all studied ways to access a tree. {.responsive} + ## Averages The following table averages out the data in the table above, grouping them by @@ -563,6 +565,8 @@ The result of the worst case time complexities are as follow: | List | 0(1)avg | 0(n) | 0(n) | 0(n) | | Set | 0(1)avg | 0(1)avg | 0(1)avg | 0(1)avg | +: Worst case time complexities for all operations and implementations studied in this experiment. {.responsive} + ## Insert - Set remains at constant 0(1). - List is also constant 0(1) as it is appending at the end. From 98201ffa020acd8db54211791d516b3eeee1d966 Mon Sep 17 00:00:00 2001 From: Kris Hatcher Date: Tue, 22 Apr 2025 18:20:19 -0400 Subject: [PATCH 16/21] chore: spelling and grammar fixes --- allhands/spring2025/weekfifteen/teamone/index.qmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index 3dfb1845..03b96b1e 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -16,7 +16,7 @@ format: This investigation seeks to answer a fundamental question in data structure implementation: How does implementing a tree with Python's set and list structures impact performance in terms of insertion, deletion, and lookup speed? -To evaluate the two different implmentations, we compare their performance across three operations: insertion, lookup and deletion. Using precise timing measurements and controlled experiments with varying tree sizes, we analyze how each data structure handles these operations. This comprehensive performance testing reveals differences in efficiency and scalability, enabling us to determine which implementation delivers optimal performance for different tree operation scenarios. +To evaluate the two different implementations, we compare their performance across three operations: insertion, lookup and deletion. Using precise timing measurements and controlled experiments with varying tree sizes, we analyze how each data structure handles these operations. This comprehensive performance testing reveals differences in efficiency and scalability, enabling us to determine which implementation delivers optimal performance for different tree operation scenarios. ## Motivation @@ -589,7 +589,7 @@ The result of the worst case time complexities are as follow: ## Conclusion -Set is alot faster than list because it uses hash table while list use dynamic array.Other than append(insert) which amortize 0(1) due to python geometrically growing capacity, List must look at every element or need to shift for other operations which results in 0(n). +Set is demonstrably faster than list because it uses a hash table while lists use dynamic arrays. Other than append(insert) which amortize 0(1) due to python geometrically growing capacity, List must look at every element or need to shift for other operations which results in 0(n). - If you need fast, random insert, delete and lookup of vertices or edges use **Set**. - If you truly just need to build up nodes or neighbors and then walk them sequentially use **List**. From 9a03ee69f56882080473c5af9e788706d66058d0 Mon Sep 17 00:00:00 2001 From: suppo01 Date: Tue, 22 Apr 2025 20:07:40 -0400 Subject: [PATCH 17/21] feat: add next step section --- .../spring2025/weekfifteen/teamone/index.qmd | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index 03b96b1e..99119b04 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -14,9 +14,13 @@ format: # Introduction -This investigation seeks to answer a fundamental question in data structure implementation: How does implementing a tree with Python's set and list structures impact performance in terms of insertion, deletion, and lookup speed? +This investigation seeks to answer a fundamental question in data structure implementation: How does implementing a tree with +Python's set and list structures impact performance in terms of insertion, deletion, and lookup speed? -To evaluate the two different implementations, we compare their performance across three operations: insertion, lookup and deletion. Using precise timing measurements and controlled experiments with varying tree sizes, we analyze how each data structure handles these operations. This comprehensive performance testing reveals differences in efficiency and scalability, enabling us to determine which implementation delivers optimal performance for different tree operation scenarios. +To evaluate the two different implementations, we compare their performance across three operations: insertion, lookup and +deletion. Using precise timing measurements and controlled experiments with varying tree sizes, we analyze how each data +structure handles these operations. This comprehensive performance testing reveals differences in efficiency and scalability, +enabling us to determine which implementation delivers optimal performance for different tree operation scenarios. ## Motivation @@ -50,7 +54,9 @@ TODO: Rosa to describe her code here ### Process Tree Created Using `List` Container -The ListProcessor class implements a tree data structure using Python's list to store parent-child relationships. Each relationship is stored as a tuple pair (parent, child) within the list, allowing for efficient storage and traversal of the tree structure. +The ListProcessor class implements a tree data structure using Python's list to store parent-child relationships. Each +relationship is stored as a tuple pair (parent, child) within the list, allowing for efficient storage and traversal of the +tree structure. The class provides a set of operations to manage these relationships: - `insert_tree_pair(parent, child)`Creates a new parent-child relationship, returning True if successful or False if the relationship already exists @@ -125,7 +131,9 @@ Note: The Code arrow is interactive and will display relevant code snippets. ### Run a Benchmark -The main.py implements a performance benchmarking system that compares two different tree data structure implementations which are a set-based (SetGraph) and a list-based (ListProcessor) implementation. It measures and visualizes execution times for common tree operations using the Rich library for formatted output. The operation are: +The main.py implements a performance benchmarking system that compares two different tree data structure implementations which +are a set-based (SetGraph) and a list-based (ListProcessor) implementation. It measures and visualizes execution times for +common tree operations using the Rich library for formatted output. The operation are: - Insertion (adding parent-child relationships) - Lookup (checking if relationships exist) @@ -589,13 +597,17 @@ The result of the worst case time complexities are as follow: ## Conclusion -Set is demonstrably faster than list because it uses a hash table while lists use dynamic arrays. Other than append(insert) which amortize 0(1) due to python geometrically growing capacity, List must look at every element or need to shift for other operations which results in 0(n). +Set is demonstrably faster than list because it uses a hash table while lists use dynamic arrays. Other than append(insert) +which amortize 0(1) due to python geometrically growing capacity, List must look at every element or need to shift for other +operations which results in 0(n). - If you need fast, random insert, delete and lookup of vertices or edges use **Set**. - If you truly just need to build up nodes or neighbors and then walk them sequentially use **List**. # Next Steps -TODO: write up recommended next steps +Potential next steps could be testing the limits of the set and list approaches, or seeing the largest number of verticies they +can handle. Also, considering that this experiment is implemented with a tree structure to avoid cycles, another next step +could be trying to implement the same thing with a graph structure and cycle detection. # References From a91d24ab46723c4b6b9d50d6f39b47c055844c85 Mon Sep 17 00:00:00 2001 From: Kris Hatcher Date: Tue, 22 Apr 2025 22:24:23 -0400 Subject: [PATCH 18/21] chore: remove unnecessary section --- allhands/spring2025/weekfifteen/teamone/index.qmd | 4 ---- 1 file changed, 4 deletions(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index 99119b04..cefc6c3c 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -22,10 +22,6 @@ deletion. Using precise timing measurements and controlled experiments with vary structure handles these operations. This comprehensive performance testing reveals differences in efficiency and scalability, enabling us to determine which implementation delivers optimal performance for different tree operation scenarios. -## Motivation - -TODO: content here - ## Approach ### Generate Trees for Analysis From bb07207c5e4ab91ee56e5683c4b8ed4f2992056c Mon Sep 17 00:00:00 2001 From: Rosa Ruiz Date: Tue, 22 Apr 2025 22:50:10 -0400 Subject: [PATCH 19/21] Finish set container part --- .../spring2025/weekfifteen/teamone/index.qmd | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index cefc6c3c..a211d60d 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -46,7 +46,77 @@ At the end of both functions, the tree is returned either as a set or a list tha ### Process Tree Created Using `Set` Container -TODO: Rosa to describe her code here +To create the process tree, I set up an undirected graph using a dictionary. Each key represents a node, and the value is a set of its connected neighbors. This design makes it easy to add, remove, and look up nodes quickly. + +The Graph class supports the following key features: + +Edge Insertion (insert_edge): Adds a two-way connection between nodes by updating each node’s neighbor set. +Node Deletion (delete_node): Removes a node and also cleans up any edges in which it participated by removing it from its neighbors' sets. +Edge Updating (update_edge): Allows dynamically adding or removing an edge between two existing nodes. +Node and Edge Lookup: Methods like lookup_node and lookup_edge check for node existence and whether two nodes are connected. +Neighbor Access and Graph Size: get_neighbors retrieves a node’s adjacent nodes, and get_graph_size returns the total number of nodes in the graph. +Graph Structure: get_graph_structure provides a full copy of the current graph, useful for visualization or further processing. + +This implementation avoids cycles and handles all connections through set operations, ensuring uniqueness and fast membership checks, which makes it well suited for managing tree like structures in process graphs. + +```python +from typing import Dict, Set + +class Graph: + def __init__(self) -> None: + """Initialize an empty graph using a dictionary of sets.""" + self.graph: Dict[int, Set[int]] = {} + + def insert_edge(self, node1: int, node2: int) -> None: + """Insert an edge between two nodes.""" + if node1 not in self.graph: + self.graph[node1] = set() + if node2 not in self.graph: + self.graph[node2] = set() + self.graph[node1].add(node2) + self.graph[node2].add(node1) + + def delete_node(self, node: int) -> bool: + """Delete a node and all its connections from the graph.""" + if node not in self.graph: + return False + for neighbor in list(self.graph[node]): + self.graph[neighbor].remove(node) + del self.graph[node] + return True + + def update_edge(self, node1: int, node2: int, add_edge: bool = True) -> None: + """Add or remove an edge between two nodes.""" + if node1 not in self.graph or node2 not in self.graph: + return + if add_edge: + self.graph[node1].add(node2) + self.graph[node2].add(node1) + else: + self.graph[node1].discard(node2) + self.graph[node2].discard(node1) + + def lookup_node(self, node: int) -> bool: + """Check if a node exists in the graph.""" + return node in self.graph + + def lookup_edge(self, node1: int, node2: int) -> bool: + """Check if an edge exists between two nodes.""" + return node1 in self.graph and node2 in self.graph[node1] + + def get_neighbors(self, node: int) -> Set[int]: + """Return all neighbors of a given node.""" + return self.graph.get(node, set()) + + def get_graph_size(self) -> int: + """Return the number of nodes in the graph.""" + return len(self.graph) + + def get_graph_structure(self) -> Dict[int, Set[int]]: + """Return the current graph structure.""" + return self.graph.copy() + +``` ### Process Tree Created Using `List` Container From 362f79d8ac4e99c56d4a30aaad43c840e075eb32 Mon Sep 17 00:00:00 2001 From: Kris Hatcher Date: Tue, 22 Apr 2025 22:53:28 -0400 Subject: [PATCH 20/21] chore: make code snippet match standard w/in post --- allhands/spring2025/weekfifteen/teamone/index.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index a211d60d..009204bd 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -59,7 +59,7 @@ Graph Structure: get_graph_structure provides a full copy of the current graph, This implementation avoids cycles and handles all connections through set operations, ensuring uniqueness and fast membership checks, which makes it well suited for managing tree like structures in process graphs. -```python +```{python} from typing import Dict, Set class Graph: From 42c02ab9792ad970eac0d7b0053e83181ba2dc2e Mon Sep 17 00:00:00 2001 From: Anupraj Guragain <156822919+AN00P-G@users.noreply.github.com> Date: Tue, 22 Apr 2025 23:28:25 -0400 Subject: [PATCH 21/21] Update index.qmd Results --- .../spring2025/weekfifteen/teamone/index.qmd | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/allhands/spring2025/weekfifteen/teamone/index.qmd b/allhands/spring2025/weekfifteen/teamone/index.qmd index 009204bd..5b714e93 100644 --- a/allhands/spring2025/weekfifteen/teamone/index.qmd +++ b/allhands/spring2025/weekfifteen/teamone/index.qmd @@ -636,36 +636,36 @@ The result of the worst case time complexities are as follow: | Implementation | Insert | Lookup | Delete | Verify Deletion | | -------------- | -------- |--------: | -------: | ----------------: | -| List | 0(1)avg | 0(n) | 0(n) | 0(n) | -| Set | 0(1)avg | 0(1)avg | 0(1)avg | 0(1)avg | +| List | 0(n) | 0(n^2) | 0(n^2) | 0(n^2) | +| Set | 0(n) | 0(n) | 0(n) | 0(n) | : Worst case time complexities for all operations and implementations studied in this experiment. {.responsive} ## Insert -- Set remains at constant 0(1). -- List is also constant 0(1) as it is appending at the end. -- Even though both are at 0(1), List is comparatively a lot faster than set at pure appending hence it is faster than set. +- Set remains at 0(n). +- List is also 0(n) as it is appending at the end. +- Even though both are at 0(n), List is comparatively a lot faster than set at pure appending hence it is faster than set. ## Lookup -- Set remains at constant 0(1) -- List provide worst case time complexity of 0(n) when doubling the list size. +- Set remains at 0(n) +- List provide time complexity of 0(n^2) when doubling the list size. - Set is faster constantly for the both small and large data sizes compared to list. ## Delete -- Set remains at constant 0(1). -- List provide worst case time complexity of 0(n). +- Set remains at 0(n). +- List provides time complexity of 0(n^2). - For the smaller data both are almost similar for the deletion but as the data increases the list falls behind due to the shifting. ## Verify Deletion -- Set remains at constant 0(1). -- List provide worst case time complexity of 0(n). +- Set remains at 0(n). +- List provide time complexity of 0(n^2). - Set is faster constantly for the both small and large data sizes compared to list. ## Conclusion Set is demonstrably faster than list because it uses a hash table while lists use dynamic arrays. Other than append(insert) -which amortize 0(1) due to python geometrically growing capacity, List must look at every element or need to shift for other -operations which results in 0(n). +which is 0(n) due to python geometrically growing capacity, List must look at every element or need to shift for other +operations which results in 0(n^2). - If you need fast, random insert, delete and lookup of vertices or edges use **Set**. - If you truly just need to build up nodes or neighbors and then walk them sequentially use **List**.