wiki-graph-core 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/data/editor/clue_reviewer.jinja +410 -0
- package/data/editor/clue_reviewer_generator.jinja +428 -0
- package/data/editor/revision_feedback.jinja +5 -0
- package/data/editor/text_compressor.jinja +127 -0
- package/data/guaranteed/response_intent_classifier.jinja +8 -0
- package/data/help/commands/archive/next.jinja +29 -0
- package/data/help/commands/gc.jinja +38 -0
- package/data/help/commands/legacy/migrate.jinja +20 -0
- package/data/help/commands/legacy.jinja +19 -0
- package/data/help/commands/maintenance/chapter/add.jinja +41 -0
- package/data/help/commands/maintenance/chapter/list.jinja +33 -0
- package/data/help/commands/maintenance/chapter/move.jinja +36 -0
- package/data/help/commands/maintenance/chapter/remove.jinja +26 -0
- package/data/help/commands/maintenance/chapter/reset.jinja +29 -0
- package/data/help/commands/maintenance/chapter/set-source.jinja +34 -0
- package/data/help/commands/maintenance/chapter/set-summary.jinja +31 -0
- package/data/help/commands/maintenance/chapter/set-title.jinja +29 -0
- package/data/help/commands/maintenance/chapter/tree.jinja +58 -0
- package/data/help/commands/maintenance/chapter.jinja +59 -0
- package/data/help/commands/maintenance/cover.jinja +28 -0
- package/data/help/commands/maintenance/meta.jinja +55 -0
- package/data/help/commands/predicate.jinja +460 -0
- package/data/help/commands/root.jinja +83 -0
- package/data/help/commands/transform.jinja +34 -0
- package/data/help/commands/uri.jinja +274 -0
- package/data/help/topics/config.jinja +88 -0
- package/data/help/topics/format.jinja +72 -0
- package/data/help/topics/readiness.jinja +99 -0
- package/data/help/topics/recipe.jinja +151 -0
- package/data/help/topics/runtime.jinja +62 -0
- package/data/help/topics/uri.jinja +178 -0
- package/data/output/epub/cover.xhtml.jinja +13 -0
- package/data/output/epub/nav.xhtml.jinja +12 -0
- package/data/output/epub/package.opf.xml.jinja +39 -0
- package/data/output/epub/section.xhtml.jinja +12 -0
- package/data/topologization/book_coherence_extraction.jinja +223 -0
- package/data/topologization/chunk_extraction.jinja +233 -0
- package/data/topologization/evidence_choice.jinja +38 -0
- package/data/topologization/translate_chunks.jinja +138 -0
- package/data/topologization/user_focused_extraction.jinja +378 -0
- package/dist/archive/query/archive-view.d.ts +26 -0
- package/dist/archive/query/archive-view.js +4540 -0
- package/dist/archive/query/archive-view.js.map +1 -0
- package/dist/archive/query/continuation-cursor.d.ts +61 -0
- package/dist/archive/query/continuation-cursor.js +363 -0
- package/dist/archive/query/continuation-cursor.js.map +1 -0
- package/dist/archive/query/index.d.ts +29 -0
- package/dist/archive/query/index.js +63 -0
- package/dist/archive/query/index.js.map +1 -0
- package/dist/archive/query/lexical-search.d.ts +22 -0
- package/dist/archive/query/lexical-search.js +137 -0
- package/dist/archive/query/lexical-search.js.map +1 -0
- package/dist/archive/query/search-cache.d.ts +192 -0
- package/dist/archive/query/search-cache.js +1248 -0
- package/dist/archive/query/search-cache.js.map +1 -0
- package/dist/archive/search-index/index.d.ts +26 -0
- package/dist/archive/search-index/index.js +29 -0
- package/dist/archive/search-index/index.js.map +1 -0
- package/dist/archive/search-index/search-index.d.ts +26 -0
- package/dist/archive/search-index/search-index.js +555 -0
- package/dist/archive/search-index/search-index.js.map +1 -0
- package/dist/archive/search-index/search-tokenizer.d.ts +16 -0
- package/dist/archive/search-index/search-tokenizer.js +225 -0
- package/dist/archive/search-index/search-tokenizer.js.map +1 -0
- package/dist/common/cli-command.d.ts +4 -0
- package/dist/common/cli-command.js +7 -0
- package/dist/common/cli-command.js.map +1 -0
- package/dist/common/data-dir.d.ts +3 -0
- package/dist/common/data-dir.js +48 -0
- package/dist/common/data-dir.js.map +1 -0
- package/dist/common/language.d.ts +55 -0
- package/dist/common/language.js +208 -0
- package/dist/common/language.js.map +1 -0
- package/dist/common/llm-scope.d.ts +19 -0
- package/dist/common/llm-scope.js +31 -0
- package/dist/common/llm-scope.js.map +1 -0
- package/dist/common/logging.d.ts +22 -0
- package/dist/common/logging.js +141 -0
- package/dist/common/logging.js.map +1 -0
- package/dist/common/template.d.ts +8 -0
- package/dist/common/template.js +54 -0
- package/dist/common/template.js.map +1 -0
- package/dist/common/tinyld-language.d.ts +6 -0
- package/dist/common/tinyld-language.js +34 -0
- package/dist/common/tinyld-language.js.map +1 -0
- package/dist/common/wiki-graph-dir.d.ts +10 -0
- package/dist/common/wiki-graph-dir.js +41 -0
- package/dist/common/wiki-graph-dir.js.map +1 -0
- package/dist/common/wiki-graph-temp.d.ts +6 -0
- package/dist/common/wiki-graph-temp.js +21 -0
- package/dist/common/wiki-graph-temp.js.map +1 -0
- package/dist/common/wiki-graph-uri.d.ts +28 -0
- package/dist/common/wiki-graph-uri.js +171 -0
- package/dist/common/wiki-graph-uri.js.map +1 -0
- package/dist/context/index.d.ts +1 -0
- package/dist/context/index.js +13 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/task-context.d.ts +41 -0
- package/dist/context/task-context.js +111 -0
- package/dist/context/task-context.js.map +1 -0
- package/dist/document/database.d.ts +30 -0
- package/dist/document/database.js +273 -0
- package/dist/document/database.js.map +1 -0
- package/dist/document/document.d.ts +153 -0
- package/dist/document/document.js +615 -0
- package/dist/document/document.js.map +1 -0
- package/dist/document/fragments.d.ts +63 -0
- package/dist/document/fragments.js +371 -0
- package/dist/document/fragments.js.map +1 -0
- package/dist/document/index.d.ts +13 -0
- package/dist/document/index.js +62 -0
- package/dist/document/index.js.map +1 -0
- package/dist/document/schema.d.ts +8 -0
- package/dist/document/schema.js +472 -0
- package/dist/document/schema.js.map +1 -0
- package/dist/document/shared-state-database.d.ts +9 -0
- package/dist/document/shared-state-database.js +193 -0
- package/dist/document/shared-state-database.js.map +1 -0
- package/dist/document/stores.d.ts +203 -0
- package/dist/document/stores.js +1678 -0
- package/dist/document/stores.js.map +1 -0
- package/dist/document/text-streams.d.ts +86 -0
- package/dist/document/text-streams.js +515 -0
- package/dist/document/text-streams.js.map +1 -0
- package/dist/document/types.d.ts +148 -0
- package/dist/document/types.js +69 -0
- package/dist/document/types.js.map +1 -0
- package/dist/editor/clue.d.ts +27 -0
- package/dist/editor/clue.js +158 -0
- package/dist/editor/clue.js.map +1 -0
- package/dist/editor/compressor.d.ts +18 -0
- package/dist/editor/compressor.js +68 -0
- package/dist/editor/compressor.js.map +1 -0
- package/dist/editor/editor.d.ts +39 -0
- package/dist/editor/editor.js +253 -0
- package/dist/editor/editor.js.map +1 -0
- package/dist/editor/feedback.d.ts +16 -0
- package/dist/editor/feedback.js +104 -0
- package/dist/editor/feedback.js.map +1 -0
- package/dist/editor/index.d.ts +17 -0
- package/dist/editor/index.js +5 -0
- package/dist/editor/index.js.map +1 -0
- package/dist/editor/language-review.d.ts +14 -0
- package/dist/editor/language-review.js +35 -0
- package/dist/editor/language-review.js.map +1 -0
- package/dist/editor/log.d.ts +37 -0
- package/dist/editor/log.js +202 -0
- package/dist/editor/log.js.map +1 -0
- package/dist/editor/markup.d.ts +20 -0
- package/dist/editor/markup.js +294 -0
- package/dist/editor/markup.js.map +1 -0
- package/dist/editor/prompt-templates.d.ts +6 -0
- package/dist/editor/prompt-templates.js +11 -0
- package/dist/editor/prompt-templates.js.map +1 -0
- package/dist/editor/response.d.ts +5 -0
- package/dist/editor/response.js +31 -0
- package/dist/editor/response.js.map +1 -0
- package/dist/editor/review.d.ts +34 -0
- package/dist/editor/review.js +189 -0
- package/dist/editor/review.js.map +1 -0
- package/dist/editor/types.d.ts +31 -0
- package/dist/editor/types.js +21 -0
- package/dist/editor/types.js.map +1 -0
- package/dist/evidence-selection/anchor-resolver.d.ts +43 -0
- package/dist/evidence-selection/anchor-resolver.js +783 -0
- package/dist/evidence-selection/anchor-resolver.js.map +1 -0
- package/dist/evidence-selection/anchor-types.d.ts +27 -0
- package/dist/evidence-selection/anchor-types.js +1 -0
- package/dist/evidence-selection/anchor-types.js.map +1 -0
- package/dist/evidence-selection/index.d.ts +8 -0
- package/dist/evidence-selection/index.js +32 -0
- package/dist/evidence-selection/index.js.map +1 -0
- package/dist/evidence-selection/prompt.d.ts +18 -0
- package/dist/evidence-selection/prompt.js +54 -0
- package/dist/evidence-selection/prompt.js.map +1 -0
- package/dist/evidence-selection/quote-score.d.ts +29 -0
- package/dist/evidence-selection/quote-score.js +331 -0
- package/dist/evidence-selection/quote-score.js.map +1 -0
- package/dist/evidence-selection/selection-resolver.d.ts +19 -0
- package/dist/evidence-selection/selection-resolver.js +303 -0
- package/dist/evidence-selection/selection-resolver.js.map +1 -0
- package/dist/evidence-selection/text.d.ts +4 -0
- package/dist/evidence-selection/text.js +66 -0
- package/dist/evidence-selection/text.js.map +1 -0
- package/dist/evidence-selection/types.d.ts +36 -0
- package/dist/evidence-selection/types.js +1 -0
- package/dist/evidence-selection/types.js.map +1 -0
- package/dist/facade/app.d.ts +75 -0
- package/dist/facade/app.js +141 -0
- package/dist/facade/app.js.map +1 -0
- package/dist/facade/build-queue.d.ts +181 -0
- package/dist/facade/build-queue.js +1442 -0
- package/dist/facade/build-queue.js.map +1 -0
- package/dist/facade/chapter-build.d.ts +60 -0
- package/dist/facade/chapter-build.js +1020 -0
- package/dist/facade/chapter-build.js.map +1 -0
- package/dist/facade/chapter.d.ts +168 -0
- package/dist/facade/chapter.js +944 -0
- package/dist/facade/chapter.js.map +1 -0
- package/dist/facade/digest.d.ts +55 -0
- package/dist/facade/digest.js +168 -0
- package/dist/facade/digest.js.map +1 -0
- package/dist/facade/graph.d.ts +60 -0
- package/dist/facade/graph.js +203 -0
- package/dist/facade/graph.js.map +1 -0
- package/dist/facade/import.d.ts +49 -0
- package/dist/facade/import.js +262 -0
- package/dist/facade/import.js.map +1 -0
- package/dist/facade/index.d.ts +39 -0
- package/dist/facade/index.js +171 -0
- package/dist/facade/index.js.map +1 -0
- package/dist/facade/knowledge-graph-build.d.ts +75 -0
- package/dist/facade/knowledge-graph-build.js +897 -0
- package/dist/facade/knowledge-graph-build.js.map +1 -0
- package/dist/facade/llm-sampling.d.ts +11 -0
- package/dist/facade/llm-sampling.js +58 -0
- package/dist/facade/llm-sampling.js.map +1 -0
- package/dist/facade/types.d.ts +8 -0
- package/dist/facade/types.js +1 -0
- package/dist/facade/types.js.map +1 -0
- package/dist/facade/wiki-graph-archive.d.ts +41 -0
- package/dist/facade/wiki-graph-archive.js +130 -0
- package/dist/facade/wiki-graph-archive.js.map +1 -0
- package/dist/gc/files.d.ts +15 -0
- package/dist/gc/files.js +141 -0
- package/dist/gc/files.js.map +1 -0
- package/dist/gc/index.d.ts +2 -0
- package/dist/gc/index.js +5 -0
- package/dist/gc/index.js.map +1 -0
- package/dist/gc/lock.d.ts +3 -0
- package/dist/gc/lock.js +137 -0
- package/dist/gc/lock.js.map +1 -0
- package/dist/gc/runner.d.ts +9 -0
- package/dist/gc/runner.js +129 -0
- package/dist/gc/runner.js.map +1 -0
- package/dist/gc/tmp-gc.d.ts +5 -0
- package/dist/gc/tmp-gc.js +57 -0
- package/dist/gc/tmp-gc.js.map +1 -0
- package/dist/gc/types.d.ts +24 -0
- package/dist/gc/types.js +1 -0
- package/dist/gc/types.js.map +1 -0
- package/dist/gc.cjs +10041 -0
- package/dist/gc.cjs.map +1 -0
- package/dist/gc.d.cts +10 -0
- package/dist/gc.d.ts +2 -0
- package/dist/gc.js +5 -0
- package/dist/gc.js.map +1 -0
- package/dist/guaranteed/classifier.d.ts +10 -0
- package/dist/guaranteed/classifier.js +88 -0
- package/dist/guaranteed/classifier.js.map +1 -0
- package/dist/guaranteed/errors.d.ts +38 -0
- package/dist/guaranteed/errors.js +73 -0
- package/dist/guaranteed/errors.js.map +1 -0
- package/dist/guaranteed/index.d.ts +7 -0
- package/dist/guaranteed/index.js +21 -0
- package/dist/guaranteed/index.js.map +1 -0
- package/dist/guaranteed/request.d.ts +8 -0
- package/dist/guaranteed/request.js +206 -0
- package/dist/guaranteed/request.js.map +1 -0
- package/dist/guaranteed/response.d.ts +12 -0
- package/dist/guaranteed/response.js +98 -0
- package/dist/guaranteed/response.js.map +1 -0
- package/dist/guaranteed/types.d.ts +20 -0
- package/dist/guaranteed/types.js +1 -0
- package/dist/guaranteed/types.js.map +1 -0
- package/dist/index-B8NNnQ8P.d.ts +424 -0
- package/dist/index.cjs +34774 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2462 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.js +168 -0
- package/dist/index.js.map +1 -0
- package/dist/legacy-sdpub/upgrade.d.ts +7 -0
- package/dist/legacy-sdpub/upgrade.js +795 -0
- package/dist/legacy-sdpub/upgrade.js.map +1 -0
- package/dist/llm/cache.d.ts +13 -0
- package/dist/llm/cache.js +35 -0
- package/dist/llm/cache.js.map +1 -0
- package/dist/llm/client.d.ts +26 -0
- package/dist/llm/client.js +572 -0
- package/dist/llm/client.js.map +1 -0
- package/dist/llm/context.d.ts +22 -0
- package/dist/llm/context.js +78 -0
- package/dist/llm/context.js.map +1 -0
- package/dist/llm/errors.d.ts +7 -0
- package/dist/llm/errors.js +12 -0
- package/dist/llm/errors.js.map +1 -0
- package/dist/llm/index.d.ts +7 -0
- package/dist/llm/index.js +17 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/request-log.d.ts +9 -0
- package/dist/llm/request-log.js +35 -0
- package/dist/llm/request-log.js.map +1 -0
- package/dist/llm/sampling.d.ts +11 -0
- package/dist/llm/sampling.js +67 -0
- package/dist/llm/sampling.js.map +1 -0
- package/dist/llm/types.d.ts +50 -0
- package/dist/llm/types.js +1 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/output/epub/archive.d.ts +9 -0
- package/dist/output/epub/archive.js +81 -0
- package/dist/output/epub/archive.js.map +1 -0
- package/dist/output/epub/book.d.ts +15 -0
- package/dist/output/epub/book.js +76 -0
- package/dist/output/epub/book.js.map +1 -0
- package/dist/output/epub/content.d.ts +9 -0
- package/dist/output/epub/content.js +35 -0
- package/dist/output/epub/content.js.map +1 -0
- package/dist/output/epub/index.d.ts +20 -0
- package/dist/output/epub/index.js +14 -0
- package/dist/output/epub/index.js.map +1 -0
- package/dist/output/epub/model.d.ts +24 -0
- package/dist/output/epub/model.js +1 -0
- package/dist/output/epub/model.js.map +1 -0
- package/dist/output/epub/navigation.d.ts +10 -0
- package/dist/output/epub/navigation.js +39 -0
- package/dist/output/epub/navigation.js.map +1 -0
- package/dist/output/epub/package.d.ts +17 -0
- package/dist/output/epub/package.js +29 -0
- package/dist/output/epub/package.js.map +1 -0
- package/dist/output/epub/shared.d.ts +4 -0
- package/dist/output/epub/shared.js +12 -0
- package/dist/output/epub/shared.js.map +1 -0
- package/dist/output/epub/templates.d.ts +35 -0
- package/dist/output/epub/templates.js +26 -0
- package/dist/output/epub/templates.js.map +1 -0
- package/dist/output/index.d.ts +14 -0
- package/dist/output/index.js +11 -0
- package/dist/output/index.js.map +1 -0
- package/dist/output/plain-text.d.ts +18 -0
- package/dist/output/plain-text.js +56 -0
- package/dist/output/plain-text.js.map +1 -0
- package/dist/progress/index.d.ts +3 -0
- package/dist/progress/index.js +14 -0
- package/dist/progress/index.js.map +1 -0
- package/dist/progress/reporter.d.ts +10 -0
- package/dist/progress/reporter.js +79 -0
- package/dist/progress/reporter.js.map +1 -0
- package/dist/progress/tracker.d.ts +37 -0
- package/dist/progress/tracker.js +119 -0
- package/dist/progress/tracker.js.map +1 -0
- package/dist/progress/types.d.ts +28 -0
- package/dist/progress/types.js +1 -0
- package/dist/progress/types.js.map +1 -0
- package/dist/reader/attention/attention.d.ts +39 -0
- package/dist/reader/attention/attention.js +123 -0
- package/dist/reader/attention/attention.js.map +1 -0
- package/dist/reader/attention/index.d.ts +9 -0
- package/dist/reader/attention/index.js +5 -0
- package/dist/reader/attention/index.js.map +1 -0
- package/dist/reader/attention/wave-reflection.d.ts +21 -0
- package/dist/reader/attention/wave-reflection.js +153 -0
- package/dist/reader/attention/wave-reflection.js.map +1 -0
- package/dist/reader/attention/working-memory.d.ts +28 -0
- package/dist/reader/attention/working-memory.js +62 -0
- package/dist/reader/attention/working-memory.js.map +1 -0
- package/dist/reader/chunk-batch/extract.d.ts +13 -0
- package/dist/reader/chunk-batch/extract.js +14 -0
- package/dist/reader/chunk-batch/extract.js.map +1 -0
- package/dist/reader/chunk-batch/extractor.d.ts +17 -0
- package/dist/reader/chunk-batch/extractor.js +337 -0
- package/dist/reader/chunk-batch/extractor.js.map +1 -0
- package/dist/reader/chunk-batch/fragment-projection.d.ts +34 -0
- package/dist/reader/chunk-batch/fragment-projection.js +94 -0
- package/dist/reader/chunk-batch/fragment-projection.js.map +1 -0
- package/dist/reader/chunk-batch/index.d.ts +12 -0
- package/dist/reader/chunk-batch/index.js +13 -0
- package/dist/reader/chunk-batch/index.js.map +1 -0
- package/dist/reader/chunk-batch/language.d.ts +9 -0
- package/dist/reader/chunk-batch/language.js +23 -0
- package/dist/reader/chunk-batch/language.js.map +1 -0
- package/dist/reader/chunk-batch/parser.d.ts +94 -0
- package/dist/reader/chunk-batch/parser.js +640 -0
- package/dist/reader/chunk-batch/parser.js.map +1 -0
- package/dist/reader/chunk-batch/prompt-templates.d.ts +6 -0
- package/dist/reader/chunk-batch/prompt-templates.js +11 -0
- package/dist/reader/chunk-batch/prompt-templates.js.map +1 -0
- package/dist/reader/chunk-batch/types.d.ts +85 -0
- package/dist/reader/chunk-batch/types.js +1 -0
- package/dist/reader/chunk-batch/types.js.map +1 -0
- package/dist/reader/index.d.ts +13 -0
- package/dist/reader/index.js +7 -0
- package/dist/reader/index.js.map +1 -0
- package/dist/reader/reader.d.ts +37 -0
- package/dist/reader/reader.js +82 -0
- package/dist/reader/reader.js.map +1 -0
- package/dist/reader/segment/index.d.ts +2 -0
- package/dist/reader/segment/index.js +5 -0
- package/dist/reader/segment/index.js.map +1 -0
- package/dist/reader/segment/intl-segmenter.d.ts +5 -0
- package/dist/reader/segment/intl-segmenter.js +102 -0
- package/dist/reader/segment/intl-segmenter.js.map +1 -0
- package/dist/reader/segment/segment.d.ts +5 -0
- package/dist/reader/segment/segment.js +9 -0
- package/dist/reader/segment/segment.js.map +1 -0
- package/dist/reader/segment/types.d.ts +14 -0
- package/dist/reader/segment/types.js +1 -0
- package/dist/reader/segment/types.js.map +1 -0
- package/dist/reader/types.d.ts +29 -0
- package/dist/reader/types.js +1 -0
- package/dist/reader/types.js.map +1 -0
- package/dist/serial.d.ts +89 -0
- package/dist/serial.js +476 -0
- package/dist/serial.js.map +1 -0
- package/dist/source/adapter.d.ts +15 -0
- package/dist/source/adapter.js +1 -0
- package/dist/source/adapter.js.map +1 -0
- package/dist/source/epub/archive.d.ts +27 -0
- package/dist/source/epub/archive.js +189 -0
- package/dist/source/epub/archive.js.map +1 -0
- package/dist/source/epub/content.d.ts +22 -0
- package/dist/source/epub/content.js +183 -0
- package/dist/source/epub/content.js.map +1 -0
- package/dist/source/epub/document.d.ts +55 -0
- package/dist/source/epub/document.js +179 -0
- package/dist/source/epub/document.js.map +1 -0
- package/dist/source/epub/index.d.ts +10 -0
- package/dist/source/epub/index.js +6 -0
- package/dist/source/epub/index.js.map +1 -0
- package/dist/source/epub/navigation.d.ts +16 -0
- package/dist/source/epub/navigation.js +215 -0
- package/dist/source/epub/navigation.js.map +1 -0
- package/dist/source/epub/package.d.ts +33 -0
- package/dist/source/epub/package.js +237 -0
- package/dist/source/epub/package.js.map +1 -0
- package/dist/source/epub/xml.d.ts +16 -0
- package/dist/source/epub/xml.js +111 -0
- package/dist/source/epub/xml.js.map +1 -0
- package/dist/source/index.d.ts +12 -0
- package/dist/source/index.js +32 -0
- package/dist/source/index.js.map +1 -0
- package/dist/source/meta.d.ts +30 -0
- package/dist/source/meta.js +22 -0
- package/dist/source/meta.js.map +1 -0
- package/dist/source/plain-text.d.ts +16 -0
- package/dist/source/plain-text.js +86 -0
- package/dist/source/plain-text.js.map +1 -0
- package/dist/source/toc.d.ts +16 -0
- package/dist/source/toc.js +17 -0
- package/dist/source/toc.js.map +1 -0
- package/dist/source/types.d.ts +16 -0
- package/dist/source/types.js +1 -0
- package/dist/source/types.js.map +1 -0
- package/dist/topology/grouping.d.ts +15 -0
- package/dist/topology/grouping.js +18 -0
- package/dist/topology/grouping.js.map +1 -0
- package/dist/topology/index.d.ts +21 -0
- package/dist/topology/index.js +5 -0
- package/dist/topology/index.js.map +1 -0
- package/dist/topology/resource-segmentation.d.ts +13 -0
- package/dist/topology/resource-segmentation.js +111 -0
- package/dist/topology/resource-segmentation.js.map +1 -0
- package/dist/topology/segment-incision.d.ts +18 -0
- package/dist/topology/segment-incision.js +197 -0
- package/dist/topology/segment-incision.js.map +1 -0
- package/dist/topology/snake-detector.d.ts +13 -0
- package/dist/topology/snake-detector.js +520 -0
- package/dist/topology/snake-detector.js.map +1 -0
- package/dist/topology/snake-graph-builder.d.ts +14 -0
- package/dist/topology/snake-graph-builder.js +76 -0
- package/dist/topology/snake-graph-builder.js.map +1 -0
- package/dist/topology/topology.d.ts +29 -0
- package/dist/topology/topology.js +348 -0
- package/dist/topology/topology.js.map +1 -0
- package/dist/topology/weights.d.ts +10 -0
- package/dist/topology/weights.js +84 -0
- package/dist/topology/weights.js.map +1 -0
- package/dist/types-FVIqiLC9.d.cts +24 -0
- package/dist/utils/async-semaphore.d.ts +7 -0
- package/dist/utils/async-semaphore.js +40 -0
- package/dist/utils/async-semaphore.js.map +1 -0
- package/dist/utils/enum.d.ts +5 -0
- package/dist/utils/enum.js +18 -0
- package/dist/utils/enum.js.map +1 -0
- package/dist/utils/hash.d.ts +3 -0
- package/dist/utils/hash.js +132 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/node-error.d.ts +4 -0
- package/dist/utils/node-error.js +59 -0
- package/dist/utils/node-error.js.map +1 -0
- package/dist/wikg/archive-uri.d.ts +1 -0
- package/dist/wikg/archive-uri.js +37 -0
- package/dist/wikg/archive-uri.js.map +1 -0
- package/dist/wikg/archive.d.ts +28 -0
- package/dist/wikg/archive.js +496 -0
- package/dist/wikg/archive.js.map +1 -0
- package/dist/wikg/index.d.ts +31 -0
- package/dist/wikg/index.js +60 -0
- package/dist/wikg/index.js.map +1 -0
- package/dist/wikg/wikg-coordinator.d.ts +45 -0
- package/dist/wikg/wikg-coordinator.js +1687 -0
- package/dist/wikg/wikg-coordinator.js.map +1 -0
- package/dist/wikg/wiki-graph-archive-file.d.ts +42 -0
- package/dist/wikg/wiki-graph-archive-file.js +78 -0
- package/dist/wikg/wiki-graph-archive-file.js.map +1 -0
- package/dist/wikilink/index.d.ts +10 -0
- package/dist/wikilink/index.js +7 -0
- package/dist/wikilink/index.js.map +1 -0
- package/dist/wikilink/relation-discovery.d.ts +31 -0
- package/dist/wikilink/relation-discovery.js +477 -0
- package/dist/wikilink/relation-discovery.js.map +1 -0
- package/dist/wikilink/types.d.ts +23 -0
- package/dist/wikilink/types.js +1 -0
- package/dist/wikilink/types.js.map +1 -0
- package/dist/wikilink/window.d.ts +7 -0
- package/dist/wikilink/window.js +53 -0
- package/dist/wikilink/window.js.map +1 -0
- package/dist/wikimatch/enrichment.d.ts +10 -0
- package/dist/wikimatch/enrichment.js +55 -0
- package/dist/wikimatch/enrichment.js.map +1 -0
- package/dist/wikimatch/index.d.ts +16 -0
- package/dist/wikimatch/index.js +66 -0
- package/dist/wikimatch/index.js.map +1 -0
- package/dist/wikimatch/option-narrowing.d.ts +17 -0
- package/dist/wikimatch/option-narrowing.js +208 -0
- package/dist/wikimatch/option-narrowing.js.map +1 -0
- package/dist/wikimatch/options.d.ts +14 -0
- package/dist/wikimatch/options.js +155 -0
- package/dist/wikimatch/options.js.map +1 -0
- package/dist/wikimatch/policy-judge.d.ts +17 -0
- package/dist/wikimatch/policy-judge.js +430 -0
- package/dist/wikimatch/policy-judge.js.map +1 -0
- package/dist/wikimatch/range-suppression.d.ts +9 -0
- package/dist/wikimatch/range-suppression.js +27 -0
- package/dist/wikimatch/range-suppression.js.map +1 -0
- package/dist/wikimatch/surface-screening.d.ts +16 -0
- package/dist/wikimatch/surface-screening.js +168 -0
- package/dist/wikimatch/surface-screening.js.map +1 -0
- package/dist/wikimatch/surface-window.d.ts +6 -0
- package/dist/wikimatch/surface-window.js +44 -0
- package/dist/wikimatch/surface-window.js.map +1 -0
- package/dist/wikimatch/types.d.ts +151 -0
- package/dist/wikimatch/types.js +1 -0
- package/dist/wikimatch/types.js.map +1 -0
- package/dist/wikimatch/wikispine.d.ts +43 -0
- package/dist/wikimatch/wikispine.js +399 -0
- package/dist/wikimatch/wikispine.js.map +1 -0
- package/dist/wikimatch/window.d.ts +6 -0
- package/dist/wikimatch/window.js +83 -0
- package/dist/wikimatch/window.js.map +1 -0
- package/dist/wikimatch/words.d.ts +16 -0
- package/dist/wikimatch/words.js +66 -0
- package/dist/wikimatch/words.js.map +1 -0
- package/dist/wikipage/cache.d.ts +18 -0
- package/dist/wikipage/cache.js +404 -0
- package/dist/wikipage/cache.js.map +1 -0
- package/dist/wikipage/fetch-log.d.ts +17 -0
- package/dist/wikipage/fetch-log.js +143 -0
- package/dist/wikipage/fetch-log.js.map +1 -0
- package/dist/wikipage/index.d.ts +14 -0
- package/dist/wikipage/index.js +17 -0
- package/dist/wikipage/index.js.map +1 -0
- package/dist/wikipage/normalizer.d.ts +14 -0
- package/dist/wikipage/normalizer.js +147 -0
- package/dist/wikipage/normalizer.js.map +1 -0
- package/dist/wikipage/rate-limiter.d.ts +13 -0
- package/dist/wikipage/rate-limiter.js +84 -0
- package/dist/wikipage/rate-limiter.js.map +1 -0
- package/dist/wikipage/resolver.d.ts +26 -0
- package/dist/wikipage/resolver.js +325 -0
- package/dist/wikipage/resolver.js.map +1 -0
- package/dist/wikipage/types.d.ts +96 -0
- package/dist/wikipage/types.js +1 -0
- package/dist/wikipage/types.js.map +1 -0
- package/dist/wikipage/wikimedia-client.d.ts +48 -0
- package/dist/wikipage/wikimedia-client.js +397 -0
- package/dist/wikipage/wikimedia-client.js.map +1 -0
- package/dist/worker-BgQ0Xl8T.d.cts +181 -0
- package/dist/worker.cjs +5259 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.cts +2 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.js +5 -0
- package/dist/worker.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
import { getReadingEdgeKey } from "./weights.js";
|
|
2
|
+
const ATTRIBUTE_BONUS_WEIGHT = 3;
|
|
3
|
+
const DEFAULT_LINK_STRENGTH_WEIGHT = 1;
|
|
4
|
+
const DEFAULT_SNAKE_WORDS_COUNT = 280;
|
|
5
|
+
const DECAY_FACTOR = 0.75;
|
|
6
|
+
const MIN_EDGE_WEIGHT = 0.1;
|
|
7
|
+
function splitConnectedComponents(input) {
|
|
8
|
+
const sortedChunkIds = [...input.chunkIds].sort(compareNumber);
|
|
9
|
+
const chunkIdRecord = createBooleanRecord();
|
|
10
|
+
const adjacentChunkIdsByChunkId = createNumberListRecord();
|
|
11
|
+
const visitedChunkIds = createBooleanRecord();
|
|
12
|
+
const components = [];
|
|
13
|
+
for (const chunkId of sortedChunkIds) {
|
|
14
|
+
chunkIdRecord[String(chunkId)] = true;
|
|
15
|
+
}
|
|
16
|
+
for (const edge of input.edges) {
|
|
17
|
+
if (chunkIdRecord[String(edge.fromId)] !== true || chunkIdRecord[String(edge.toId)] !== true) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
attachChunkAdjacency(adjacentChunkIdsByChunkId, edge.fromId, edge.toId);
|
|
21
|
+
attachChunkAdjacency(adjacentChunkIdsByChunkId, edge.toId, edge.fromId);
|
|
22
|
+
}
|
|
23
|
+
for (const chunkId of sortedChunkIds) {
|
|
24
|
+
if (visitedChunkIds[String(chunkId)] === true) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const stack = [chunkId];
|
|
28
|
+
const component = [];
|
|
29
|
+
visitedChunkIds[String(chunkId)] = true;
|
|
30
|
+
while (stack.length > 0) {
|
|
31
|
+
const currentChunkId = stack.pop();
|
|
32
|
+
if (currentChunkId === void 0) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
component.push(currentChunkId);
|
|
36
|
+
for (const nextChunkId of adjacentChunkIdsByChunkId[String(currentChunkId)] ?? []) {
|
|
37
|
+
if (visitedChunkIds[String(nextChunkId)] === true) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
visitedChunkIds[String(nextChunkId)] = true;
|
|
41
|
+
stack.push(nextChunkId);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
component.sort(compareNumber);
|
|
45
|
+
components.push(component);
|
|
46
|
+
}
|
|
47
|
+
components.sort((left, right) => {
|
|
48
|
+
const leftMinChunkId = left[0] ?? Number.POSITIVE_INFINITY;
|
|
49
|
+
const rightMinChunkId = right[0] ?? Number.POSITIVE_INFINITY;
|
|
50
|
+
return leftMinChunkId - rightMinChunkId;
|
|
51
|
+
});
|
|
52
|
+
return components;
|
|
53
|
+
}
|
|
54
|
+
function detectSnakesInComponent(input) {
|
|
55
|
+
if (input.chunks.length === 0) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
const graph = createDetectorGraph(input.chunks, input.edges);
|
|
59
|
+
if (!isWeaklyConnected(graph)) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
"Snake detector requires a weakly connected component input"
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
const snakeWordsCount = input.snakeWordsCount ?? DEFAULT_SNAKE_WORDS_COUNT;
|
|
65
|
+
const totalWordsCount = input.chunks.reduce((sum, chunk) => {
|
|
66
|
+
return sum + chunk.wordsCount;
|
|
67
|
+
}, 0);
|
|
68
|
+
if (totalWordsCount <= snakeWordsCount) {
|
|
69
|
+
return [
|
|
70
|
+
[...input.chunks].sort(compareChunkBySentence).map((chunk) => chunk.id)
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
const fingerprints = computeAllFingerprints(graph);
|
|
74
|
+
validateFingerprints(fingerprints);
|
|
75
|
+
const phaseOneClusters = greedyMerge(
|
|
76
|
+
graph,
|
|
77
|
+
fingerprints,
|
|
78
|
+
{
|
|
79
|
+
enableBonus: true,
|
|
80
|
+
snakeWordsCount
|
|
81
|
+
},
|
|
82
|
+
void 0
|
|
83
|
+
);
|
|
84
|
+
const phaseTwoClusters = greedyMerge(
|
|
85
|
+
graph,
|
|
86
|
+
fingerprints,
|
|
87
|
+
{
|
|
88
|
+
enableBonus: false,
|
|
89
|
+
snakeWordsCount
|
|
90
|
+
},
|
|
91
|
+
phaseOneClusters
|
|
92
|
+
);
|
|
93
|
+
return [...phaseTwoClusters.values()].map(
|
|
94
|
+
(cluster) => [...cluster].sort((leftId, rightId) => {
|
|
95
|
+
const leftChunk = graph.chunksById[String(leftId)];
|
|
96
|
+
const rightChunk = graph.chunksById[String(rightId)];
|
|
97
|
+
if (leftChunk === void 0 || rightChunk === void 0) {
|
|
98
|
+
return leftId - rightId;
|
|
99
|
+
}
|
|
100
|
+
return compareChunkBySentence(leftChunk, rightChunk);
|
|
101
|
+
})
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
function attachChunkAdjacency(adjacentChunkIdsByChunkId, fromId, toId) {
|
|
105
|
+
const existingAdjacentChunkIds = adjacentChunkIdsByChunkId[String(fromId)] ?? [];
|
|
106
|
+
if (existingAdjacentChunkIds.includes(toId)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
adjacentChunkIdsByChunkId[String(fromId)] = [
|
|
110
|
+
...existingAdjacentChunkIds,
|
|
111
|
+
toId
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
function clustersConnected(graph, leftCluster, rightCluster) {
|
|
115
|
+
for (const leftChunkId of leftCluster) {
|
|
116
|
+
for (const rightChunkId of rightCluster) {
|
|
117
|
+
if (graph.edgeByKey[getReadingEdgeKey(leftChunkId, rightChunkId)] !== void 0 || graph.edgeByKey[getReadingEdgeKey(rightChunkId, leftChunkId)] !== void 0) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
function compareChunkBySentence(left, right) {
|
|
125
|
+
const [leftSerialId, leftSentenceIndex] = left.sentenceId;
|
|
126
|
+
const [rightSerialId, rightSentenceIndex] = right.sentenceId;
|
|
127
|
+
if (leftSerialId !== rightSerialId) {
|
|
128
|
+
return leftSerialId - rightSerialId;
|
|
129
|
+
}
|
|
130
|
+
if (leftSentenceIndex !== rightSentenceIndex) {
|
|
131
|
+
return leftSentenceIndex - rightSentenceIndex;
|
|
132
|
+
}
|
|
133
|
+
return left.id - right.id;
|
|
134
|
+
}
|
|
135
|
+
function compareEdgeQueueEntry(left, right) {
|
|
136
|
+
if (left.value !== right.value) {
|
|
137
|
+
return right.value - left.value;
|
|
138
|
+
}
|
|
139
|
+
if (left.leftClusterId !== right.leftClusterId) {
|
|
140
|
+
return left.leftClusterId - right.leftClusterId;
|
|
141
|
+
}
|
|
142
|
+
return left.rightClusterId - right.rightClusterId;
|
|
143
|
+
}
|
|
144
|
+
function compareNumber(left, right) {
|
|
145
|
+
return left - right;
|
|
146
|
+
}
|
|
147
|
+
function computeAllFingerprints(graph) {
|
|
148
|
+
const fingerprints = createNumberMatrixRecord();
|
|
149
|
+
for (const startChunkId of graph.sortedChunkIds) {
|
|
150
|
+
const concentrations = createNumberRecord();
|
|
151
|
+
let currentLayer = [startChunkId];
|
|
152
|
+
const visitedChunkIds = createBooleanRecord();
|
|
153
|
+
concentrations[String(startChunkId)] = 1;
|
|
154
|
+
visitedChunkIds[String(startChunkId)] = true;
|
|
155
|
+
while (currentLayer.length > 0) {
|
|
156
|
+
const nextLayerConcentrations = createNumberRecord();
|
|
157
|
+
for (const currentChunkId of currentLayer) {
|
|
158
|
+
const currentConcentration = concentrations[String(currentChunkId)] ?? 0;
|
|
159
|
+
let totalWeight = 0;
|
|
160
|
+
const neighbors = [];
|
|
161
|
+
for (const edge of graph.incomingEdgesByChunkId[String(currentChunkId)] ?? []) {
|
|
162
|
+
if (visitedChunkIds[String(edge.fromId)] === true) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const weight = graph.fingerprintEdgeWeightsByKey[getReadingEdgeKey(edge.fromId, currentChunkId)] ?? graph.fingerprintEdgeWeightsByKey[getReadingEdgeKey(currentChunkId, edge.fromId)] ?? DEFAULT_LINK_STRENGTH_WEIGHT;
|
|
166
|
+
neighbors.push([edge.fromId, weight]);
|
|
167
|
+
totalWeight += weight;
|
|
168
|
+
}
|
|
169
|
+
for (const edge of graph.outgoingEdgesByChunkId[String(currentChunkId)] ?? []) {
|
|
170
|
+
if (visitedChunkIds[String(edge.toId)] === true) {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
const weight = graph.fingerprintEdgeWeightsByKey[getReadingEdgeKey(currentChunkId, edge.toId)] ?? graph.fingerprintEdgeWeightsByKey[getReadingEdgeKey(edge.toId, currentChunkId)] ?? DEFAULT_LINK_STRENGTH_WEIGHT;
|
|
174
|
+
neighbors.push([edge.toId, weight]);
|
|
175
|
+
totalWeight += weight;
|
|
176
|
+
}
|
|
177
|
+
if (totalWeight <= 0) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
for (const [neighborChunkId, weight] of neighbors) {
|
|
181
|
+
const contribution = currentConcentration * (weight / totalWeight) * DECAY_FACTOR;
|
|
182
|
+
nextLayerConcentrations[String(neighborChunkId)] = (nextLayerConcentrations[String(neighborChunkId)] ?? 0) + contribution;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
currentLayer = Object.keys(nextLayerConcentrations).map(Number);
|
|
186
|
+
for (const nextChunkId of currentLayer) {
|
|
187
|
+
concentrations[String(nextChunkId)] = nextLayerConcentrations[String(nextChunkId)] ?? 0;
|
|
188
|
+
visitedChunkIds[String(nextChunkId)] = true;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const totalConcentration = Object.values(concentrations).reduce(
|
|
192
|
+
(sum, concentration) => sum + concentration,
|
|
193
|
+
0
|
|
194
|
+
);
|
|
195
|
+
if (totalConcentration > 0) {
|
|
196
|
+
for (const chunkId of Object.keys(concentrations)) {
|
|
197
|
+
concentrations[chunkId] = (concentrations[chunkId] ?? 0) / totalConcentration;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
fingerprints[String(startChunkId)] = concentrations;
|
|
201
|
+
}
|
|
202
|
+
return fingerprints;
|
|
203
|
+
}
|
|
204
|
+
function computeClusterWordsCount(graph, cluster) {
|
|
205
|
+
return cluster.reduce((sum, chunkId) => {
|
|
206
|
+
return sum + (graph.chunksById[String(chunkId)]?.wordsCount ?? 0);
|
|
207
|
+
}, 0);
|
|
208
|
+
}
|
|
209
|
+
function computeMergeValue(graph, leftCluster, rightCluster, fingerprints) {
|
|
210
|
+
let edgeCount = 0;
|
|
211
|
+
let minValue = Number.POSITIVE_INFINITY;
|
|
212
|
+
for (const leftChunkId of leftCluster) {
|
|
213
|
+
for (const rightChunkId of rightCluster) {
|
|
214
|
+
const edge = graph.edgeByKey[getReadingEdgeKey(leftChunkId, rightChunkId)] ?? graph.edgeByKey[getReadingEdgeKey(rightChunkId, leftChunkId)];
|
|
215
|
+
if (edge === void 0) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
edgeCount += 1;
|
|
219
|
+
const leftFingerprint = fingerprints[String(leftChunkId)] ?? {};
|
|
220
|
+
const rightFingerprint = fingerprints[String(rightChunkId)] ?? {};
|
|
221
|
+
let squaredSum = 0;
|
|
222
|
+
for (const targetChunkId of Object.keys(leftFingerprint)) {
|
|
223
|
+
const diff = (leftFingerprint[targetChunkId] ?? 0) - (rightFingerprint[targetChunkId] ?? 0);
|
|
224
|
+
squaredSum += diff * diff;
|
|
225
|
+
}
|
|
226
|
+
let deltaValue = getLinkStrengthWeight(edge.strength);
|
|
227
|
+
const leftChunk = graph.chunksById[String(leftChunkId)];
|
|
228
|
+
const rightChunk = graph.chunksById[String(rightChunkId)];
|
|
229
|
+
if (leftChunk?.retention !== void 0 && rightChunk?.retention !== void 0) {
|
|
230
|
+
deltaValue += ATTRIBUTE_BONUS_WEIGHT;
|
|
231
|
+
}
|
|
232
|
+
if (leftChunk?.importance !== void 0 && rightChunk?.importance !== void 0) {
|
|
233
|
+
deltaValue += ATTRIBUTE_BONUS_WEIGHT;
|
|
234
|
+
}
|
|
235
|
+
const distance = Math.sqrt(squaredSum);
|
|
236
|
+
const value = (1 - distance / 2) * deltaValue;
|
|
237
|
+
minValue = Math.min(minValue, value);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (edgeCount === 0) {
|
|
241
|
+
return Number.NEGATIVE_INFINITY;
|
|
242
|
+
}
|
|
243
|
+
return minValue;
|
|
244
|
+
}
|
|
245
|
+
function createBooleanRecord() {
|
|
246
|
+
return /* @__PURE__ */ Object.create(null);
|
|
247
|
+
}
|
|
248
|
+
function createDetectorGraph(chunks, edges) {
|
|
249
|
+
const chunksById = createChunkRecord();
|
|
250
|
+
const edgeByKey = createEdgeRecord();
|
|
251
|
+
const incomingEdgesByChunkId = createReadingEdgeListRecord();
|
|
252
|
+
const outgoingEdgesByChunkId = createReadingEdgeListRecord();
|
|
253
|
+
const sortedChunkIds = [...chunks].map((chunk) => chunk.id).sort(compareNumber);
|
|
254
|
+
const undirectedAdjacentChunkIdsByChunkId = createNumberListRecord();
|
|
255
|
+
for (const chunk of chunks) {
|
|
256
|
+
chunksById[String(chunk.id)] = chunk;
|
|
257
|
+
}
|
|
258
|
+
for (const edge of edges) {
|
|
259
|
+
if (chunksById[String(edge.fromId)] === void 0 || chunksById[String(edge.toId)] === void 0) {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
const edgeKey = getReadingEdgeKey(edge.fromId, edge.toId);
|
|
263
|
+
edgeByKey[edgeKey] = edge;
|
|
264
|
+
if (incomingEdgesByChunkId[String(edge.toId)] === void 0) {
|
|
265
|
+
incomingEdgesByChunkId[String(edge.toId)] = [];
|
|
266
|
+
}
|
|
267
|
+
if (outgoingEdgesByChunkId[String(edge.fromId)] === void 0) {
|
|
268
|
+
outgoingEdgesByChunkId[String(edge.fromId)] = [];
|
|
269
|
+
}
|
|
270
|
+
incomingEdgesByChunkId[String(edge.toId)]?.push(edge);
|
|
271
|
+
outgoingEdgesByChunkId[String(edge.fromId)]?.push(edge);
|
|
272
|
+
attachChunkAdjacency(
|
|
273
|
+
undirectedAdjacentChunkIdsByChunkId,
|
|
274
|
+
edge.fromId,
|
|
275
|
+
edge.toId
|
|
276
|
+
);
|
|
277
|
+
attachChunkAdjacency(
|
|
278
|
+
undirectedAdjacentChunkIdsByChunkId,
|
|
279
|
+
edge.toId,
|
|
280
|
+
edge.fromId
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
chunksById,
|
|
285
|
+
edgeByKey,
|
|
286
|
+
fingerprintEdgeWeightsByKey: computeFingerprintEdgeWeights(
|
|
287
|
+
chunksById,
|
|
288
|
+
edges
|
|
289
|
+
),
|
|
290
|
+
incomingEdgesByChunkId,
|
|
291
|
+
outgoingEdgesByChunkId,
|
|
292
|
+
sortedChunkIds,
|
|
293
|
+
undirectedAdjacentChunkIdsByChunkId
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function createChunkRecord() {
|
|
297
|
+
return /* @__PURE__ */ Object.create(null);
|
|
298
|
+
}
|
|
299
|
+
function createEdgeQueueEntry(leftClusterId, rightClusterId, value) {
|
|
300
|
+
return {
|
|
301
|
+
leftClusterId,
|
|
302
|
+
rightClusterId,
|
|
303
|
+
value
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function createEdgeRecord() {
|
|
307
|
+
return /* @__PURE__ */ Object.create(null);
|
|
308
|
+
}
|
|
309
|
+
function createReadingEdgeListRecord() {
|
|
310
|
+
return /* @__PURE__ */ Object.create(null);
|
|
311
|
+
}
|
|
312
|
+
function createNumberMatrixRecord() {
|
|
313
|
+
return /* @__PURE__ */ Object.create(null);
|
|
314
|
+
}
|
|
315
|
+
function createNumberListRecord() {
|
|
316
|
+
return /* @__PURE__ */ Object.create(null);
|
|
317
|
+
}
|
|
318
|
+
function createNumberRecord() {
|
|
319
|
+
return /* @__PURE__ */ Object.create(null);
|
|
320
|
+
}
|
|
321
|
+
function createOptionalNumberRecord() {
|
|
322
|
+
return /* @__PURE__ */ Object.create(null);
|
|
323
|
+
}
|
|
324
|
+
function getClusterPairKey(leftClusterId, rightClusterId) {
|
|
325
|
+
return leftClusterId < rightClusterId ? getReadingEdgeKey(leftClusterId, rightClusterId) : getReadingEdgeKey(rightClusterId, leftClusterId);
|
|
326
|
+
}
|
|
327
|
+
function getLinkStrengthWeight(strength) {
|
|
328
|
+
switch (strength) {
|
|
329
|
+
case "critical":
|
|
330
|
+
return 9;
|
|
331
|
+
case "important":
|
|
332
|
+
return 3;
|
|
333
|
+
case "helpful":
|
|
334
|
+
return 1;
|
|
335
|
+
default:
|
|
336
|
+
return DEFAULT_LINK_STRENGTH_WEIGHT;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function greedyMerge(graph, fingerprints, config, initialClusters) {
|
|
340
|
+
const clusters = initialClusters === void 0 ? new Map(
|
|
341
|
+
graph.sortedChunkIds.map((chunkId) => [chunkId, [chunkId]])
|
|
342
|
+
) : new Map(
|
|
343
|
+
[...initialClusters.entries()].map(([clusterId, chunkIds]) => [
|
|
344
|
+
clusterId,
|
|
345
|
+
[...chunkIds]
|
|
346
|
+
])
|
|
347
|
+
);
|
|
348
|
+
const nodeToCluster = createOptionalNumberRecord();
|
|
349
|
+
const edgeQueue = [];
|
|
350
|
+
const queuedClusterPairs = createBooleanRecord();
|
|
351
|
+
for (const [clusterId, chunkIds] of clusters.entries()) {
|
|
352
|
+
for (const chunkId of chunkIds) {
|
|
353
|
+
nodeToCluster[String(chunkId)] = clusterId;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
for (const leftClusterId of clusters.keys()) {
|
|
357
|
+
for (const rightClusterId of clusters.keys()) {
|
|
358
|
+
if (leftClusterId >= rightClusterId) {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const leftCluster = clusters.get(leftClusterId);
|
|
362
|
+
const rightCluster = clusters.get(rightClusterId);
|
|
363
|
+
if (leftCluster === void 0 || rightCluster === void 0) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
if (!clustersConnected(graph, leftCluster, rightCluster)) {
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
edgeQueue.push(
|
|
370
|
+
createEdgeQueueEntry(
|
|
371
|
+
leftClusterId,
|
|
372
|
+
rightClusterId,
|
|
373
|
+
computeMergeValue(graph, leftCluster, rightCluster, fingerprints)
|
|
374
|
+
)
|
|
375
|
+
);
|
|
376
|
+
queuedClusterPairs[getClusterPairKey(leftClusterId, rightClusterId)] = true;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
while (edgeQueue.length > 0) {
|
|
380
|
+
edgeQueue.sort(compareEdgeQueueEntry);
|
|
381
|
+
const nextEntry = edgeQueue.shift();
|
|
382
|
+
if (nextEntry === void 0) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
const currentLeftClusterId = nodeToCluster[String(nextEntry.leftClusterId)];
|
|
386
|
+
const currentRightClusterId = nodeToCluster[String(nextEntry.rightClusterId)];
|
|
387
|
+
if (currentLeftClusterId === void 0 || currentRightClusterId === void 0 || currentLeftClusterId === currentRightClusterId) {
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
const leftCluster = clusters.get(currentLeftClusterId);
|
|
391
|
+
const rightCluster = clusters.get(currentRightClusterId);
|
|
392
|
+
if (leftCluster === void 0 || rightCluster === void 0) {
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
if (!clustersConnected(graph, leftCluster, rightCluster)) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
if (config.enableBonus && leftCluster.length >= 2 && rightCluster.length >= 2) {
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
if (computeClusterWordsCount(graph, leftCluster) + computeClusterWordsCount(graph, rightCluster) > config.snakeWordsCount) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
leftCluster.push(...rightCluster);
|
|
405
|
+
clusters.delete(currentRightClusterId);
|
|
406
|
+
for (const chunkId of rightCluster) {
|
|
407
|
+
nodeToCluster[String(chunkId)] = currentLeftClusterId;
|
|
408
|
+
}
|
|
409
|
+
const neighborChunkIds = /* @__PURE__ */ new Set();
|
|
410
|
+
for (const chunkId of leftCluster) {
|
|
411
|
+
for (const neighborChunkId of graph.undirectedAdjacentChunkIdsByChunkId[String(chunkId)] ?? []) {
|
|
412
|
+
neighborChunkIds.add(neighborChunkId);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
for (const neighborChunkId of neighborChunkIds) {
|
|
416
|
+
const neighborClusterId = nodeToCluster[String(neighborChunkId)];
|
|
417
|
+
if (neighborClusterId === void 0 || neighborClusterId === currentLeftClusterId) {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
const neighborCluster = clusters.get(neighborClusterId);
|
|
421
|
+
if (neighborCluster === void 0) {
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
const clusterPairKey = getClusterPairKey(
|
|
425
|
+
currentLeftClusterId,
|
|
426
|
+
neighborClusterId
|
|
427
|
+
);
|
|
428
|
+
if (queuedClusterPairs[clusterPairKey] === true) {
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
edgeQueue.push(
|
|
432
|
+
createEdgeQueueEntry(
|
|
433
|
+
Math.min(currentLeftClusterId, neighborClusterId),
|
|
434
|
+
Math.max(currentLeftClusterId, neighborClusterId),
|
|
435
|
+
computeMergeValue(graph, leftCluster, neighborCluster, fingerprints)
|
|
436
|
+
)
|
|
437
|
+
);
|
|
438
|
+
queuedClusterPairs[clusterPairKey] = true;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return clusters;
|
|
442
|
+
}
|
|
443
|
+
function isWeaklyConnected(graph) {
|
|
444
|
+
const firstChunkId = graph.sortedChunkIds[0];
|
|
445
|
+
if (firstChunkId === void 0) {
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
const visitedChunkIds = createBooleanRecord();
|
|
449
|
+
const stack = [firstChunkId];
|
|
450
|
+
visitedChunkIds[String(firstChunkId)] = true;
|
|
451
|
+
while (stack.length > 0) {
|
|
452
|
+
const currentChunkId = stack.pop();
|
|
453
|
+
if (currentChunkId === void 0) {
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
for (const nextChunkId of graph.undirectedAdjacentChunkIdsByChunkId[String(currentChunkId)] ?? []) {
|
|
457
|
+
if (visitedChunkIds[String(nextChunkId)] === true) {
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
visitedChunkIds[String(nextChunkId)] = true;
|
|
461
|
+
stack.push(nextChunkId);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return graph.sortedChunkIds.every(
|
|
465
|
+
(chunkId) => visitedChunkIds[String(chunkId)] === true
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
function validateFingerprints(fingerprints) {
|
|
469
|
+
const firstChunkId = Object.keys(fingerprints)[0];
|
|
470
|
+
if (firstChunkId === void 0) {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const referenceChunkIds = Object.keys(
|
|
474
|
+
fingerprints[firstChunkId] ?? {}
|
|
475
|
+
).sort();
|
|
476
|
+
for (const [chunkId, fingerprint] of Object.entries(fingerprints)) {
|
|
477
|
+
const fingerprintChunkIds = Object.keys(fingerprint).sort();
|
|
478
|
+
if (fingerprintChunkIds.length !== referenceChunkIds.length || fingerprintChunkIds.some(
|
|
479
|
+
(targetChunkId, index) => targetChunkId !== referenceChunkIds[index]
|
|
480
|
+
)) {
|
|
481
|
+
throw new Error(`Fingerprint structure mismatch for chunk ${chunkId}`);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
function computeFingerprintEdgeWeights(chunksById, edges) {
|
|
486
|
+
const totalStrengthsByChunkId = createNumberRecord();
|
|
487
|
+
for (const edge of edges) {
|
|
488
|
+
if (chunksById[String(edge.fromId)] === void 0 || chunksById[String(edge.toId)] === void 0) {
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const strengthWeight = getLinkStrengthWeight(edge.strength);
|
|
492
|
+
totalStrengthsByChunkId[String(edge.fromId)] = (totalStrengthsByChunkId[String(edge.fromId)] ?? 0) + strengthWeight;
|
|
493
|
+
totalStrengthsByChunkId[String(edge.toId)] = (totalStrengthsByChunkId[String(edge.toId)] ?? 0) + strengthWeight;
|
|
494
|
+
}
|
|
495
|
+
const edgeWeightsByKey = createNumberRecord();
|
|
496
|
+
for (const edge of edges) {
|
|
497
|
+
const fromChunk = chunksById[String(edge.fromId)];
|
|
498
|
+
const toChunk = chunksById[String(edge.toId)];
|
|
499
|
+
if (fromChunk === void 0 || toChunk === void 0) {
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
const strengthWeight = getLinkStrengthWeight(edge.strength);
|
|
503
|
+
const fromTotalStrength = totalStrengthsByChunkId[String(edge.fromId)] ?? 0;
|
|
504
|
+
const toTotalStrength = totalStrengthsByChunkId[String(edge.toId)] ?? 0;
|
|
505
|
+
const fromHalfWeight = fromTotalStrength === 0 ? 0 : fromChunk.weight * (strengthWeight / fromTotalStrength);
|
|
506
|
+
const toHalfWeight = toTotalStrength === 0 ? 0 : toChunk.weight * (strengthWeight / toTotalStrength);
|
|
507
|
+
const finalWeight = Math.max(
|
|
508
|
+
fromHalfWeight + toHalfWeight,
|
|
509
|
+
MIN_EDGE_WEIGHT
|
|
510
|
+
);
|
|
511
|
+
edgeWeightsByKey[getReadingEdgeKey(edge.fromId, edge.toId)] = finalWeight;
|
|
512
|
+
edgeWeightsByKey[getReadingEdgeKey(edge.toId, edge.fromId)] = finalWeight;
|
|
513
|
+
}
|
|
514
|
+
return edgeWeightsByKey;
|
|
515
|
+
}
|
|
516
|
+
export {
|
|
517
|
+
detectSnakesInComponent,
|
|
518
|
+
splitConnectedComponents
|
|
519
|
+
};
|
|
520
|
+
//# sourceMappingURL=snake-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/topology/snake-detector.ts"],"sourcesContent":["import type { ChunkRecord, ReadingEdgeRecord } from \"../document/index.js\";\nimport { getReadingEdgeKey } from \"./weights.js\";\n\nconst ATTRIBUTE_BONUS_WEIGHT = 3;\nconst DEFAULT_LINK_STRENGTH_WEIGHT = 1;\nconst DEFAULT_SNAKE_WORDS_COUNT = 280;\nconst DECAY_FACTOR = 0.75;\nconst MIN_EDGE_WEIGHT = 0.1;\n\ninterface DetectorGraph {\n readonly chunksById: Readonly<Record<string, ChunkRecord | undefined>>;\n readonly edgeByKey: Readonly<Record<string, ReadingEdgeRecord | undefined>>;\n readonly fingerprintEdgeWeightsByKey: Readonly<Record<string, number>>;\n readonly incomingEdgesByChunkId: Readonly<\n Record<string, readonly ReadingEdgeRecord[] | undefined>\n >;\n readonly outgoingEdgesByChunkId: Readonly<\n Record<string, readonly ReadingEdgeRecord[] | undefined>\n >;\n readonly sortedChunkIds: readonly number[];\n readonly undirectedAdjacentChunkIdsByChunkId: Readonly<\n Record<string, readonly number[] | undefined>\n >;\n}\n\ninterface MergeConfig {\n readonly enableBonus: boolean;\n readonly snakeWordsCount: number;\n}\n\nexport function splitConnectedComponents(input: {\n chunkIds: readonly number[];\n edges: readonly ReadingEdgeRecord[];\n}): number[][] {\n const sortedChunkIds = [...input.chunkIds].sort(compareNumber);\n const chunkIdRecord = createBooleanRecord();\n const adjacentChunkIdsByChunkId = createNumberListRecord();\n const visitedChunkIds = createBooleanRecord();\n const components: number[][] = [];\n\n for (const chunkId of sortedChunkIds) {\n chunkIdRecord[String(chunkId)] = true;\n }\n\n for (const edge of input.edges) {\n if (\n chunkIdRecord[String(edge.fromId)] !== true ||\n chunkIdRecord[String(edge.toId)] !== true\n ) {\n continue;\n }\n\n attachChunkAdjacency(adjacentChunkIdsByChunkId, edge.fromId, edge.toId);\n attachChunkAdjacency(adjacentChunkIdsByChunkId, edge.toId, edge.fromId);\n }\n\n for (const chunkId of sortedChunkIds) {\n if (visitedChunkIds[String(chunkId)] === true) {\n continue;\n }\n\n const stack = [chunkId];\n const component: number[] = [];\n visitedChunkIds[String(chunkId)] = true;\n\n while (stack.length > 0) {\n const currentChunkId = stack.pop();\n\n if (currentChunkId === undefined) {\n continue;\n }\n\n component.push(currentChunkId);\n\n for (const nextChunkId of adjacentChunkIdsByChunkId[\n String(currentChunkId)\n ] ?? []) {\n if (visitedChunkIds[String(nextChunkId)] === true) {\n continue;\n }\n\n visitedChunkIds[String(nextChunkId)] = true;\n stack.push(nextChunkId);\n }\n }\n\n component.sort(compareNumber);\n components.push(component);\n }\n\n components.sort((left, right) => {\n const leftMinChunkId = left[0] ?? Number.POSITIVE_INFINITY;\n const rightMinChunkId = right[0] ?? Number.POSITIVE_INFINITY;\n\n return leftMinChunkId - rightMinChunkId;\n });\n\n return components;\n}\n\nexport function detectSnakesInComponent(input: {\n chunks: readonly ChunkRecord[];\n edges: readonly ReadingEdgeRecord[];\n snakeWordsCount?: number;\n}): number[][] {\n if (input.chunks.length === 0) {\n return [];\n }\n\n const graph = createDetectorGraph(input.chunks, input.edges);\n\n if (!isWeaklyConnected(graph)) {\n throw new Error(\n \"Snake detector requires a weakly connected component input\",\n );\n }\n\n const snakeWordsCount = input.snakeWordsCount ?? DEFAULT_SNAKE_WORDS_COUNT;\n const totalWordsCount = input.chunks.reduce((sum, chunk) => {\n return sum + chunk.wordsCount;\n }, 0);\n\n if (totalWordsCount <= snakeWordsCount) {\n return [\n [...input.chunks].sort(compareChunkBySentence).map((chunk) => chunk.id),\n ];\n }\n\n const fingerprints = computeAllFingerprints(graph);\n\n validateFingerprints(fingerprints);\n\n const phaseOneClusters = greedyMerge(\n graph,\n fingerprints,\n {\n enableBonus: true,\n snakeWordsCount,\n },\n undefined,\n );\n const phaseTwoClusters = greedyMerge(\n graph,\n fingerprints,\n {\n enableBonus: false,\n snakeWordsCount,\n },\n phaseOneClusters,\n );\n\n return [...phaseTwoClusters.values()].map((cluster) =>\n [...cluster].sort((leftId, rightId) => {\n const leftChunk = graph.chunksById[String(leftId)];\n const rightChunk = graph.chunksById[String(rightId)];\n\n if (leftChunk === undefined || rightChunk === undefined) {\n return leftId - rightId;\n }\n\n return compareChunkBySentence(leftChunk, rightChunk);\n }),\n );\n}\n\nfunction attachChunkAdjacency(\n adjacentChunkIdsByChunkId: Record<string, number[] | undefined>,\n fromId: number,\n toId: number,\n): void {\n const existingAdjacentChunkIds =\n adjacentChunkIdsByChunkId[String(fromId)] ?? [];\n\n if (existingAdjacentChunkIds.includes(toId)) {\n return;\n }\n\n adjacentChunkIdsByChunkId[String(fromId)] = [\n ...existingAdjacentChunkIds,\n toId,\n ];\n}\n\nfunction clustersConnected(\n graph: DetectorGraph,\n leftCluster: readonly number[],\n rightCluster: readonly number[],\n): boolean {\n for (const leftChunkId of leftCluster) {\n for (const rightChunkId of rightCluster) {\n if (\n graph.edgeByKey[getReadingEdgeKey(leftChunkId, rightChunkId)] !==\n undefined ||\n graph.edgeByKey[getReadingEdgeKey(rightChunkId, leftChunkId)] !==\n undefined\n ) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nfunction compareChunkBySentence(left: ChunkRecord, right: ChunkRecord): number {\n const [leftSerialId, leftSentenceIndex] = left.sentenceId;\n const [rightSerialId, rightSentenceIndex] = right.sentenceId;\n\n if (leftSerialId !== rightSerialId) {\n return leftSerialId - rightSerialId;\n }\n\n if (leftSentenceIndex !== rightSentenceIndex) {\n return leftSentenceIndex - rightSentenceIndex;\n }\n\n return left.id - right.id;\n}\n\nfunction compareEdgeQueueEntry(\n left: EdgeQueueEntry,\n right: EdgeQueueEntry,\n): number {\n if (left.value !== right.value) {\n return right.value - left.value;\n }\n\n if (left.leftClusterId !== right.leftClusterId) {\n return left.leftClusterId - right.leftClusterId;\n }\n\n return left.rightClusterId - right.rightClusterId;\n}\n\nfunction compareNumber(left: number, right: number): number {\n return left - right;\n}\n\nfunction computeAllFingerprints(\n graph: DetectorGraph,\n): Readonly<Record<string, Readonly<Record<string, number>>>> {\n const fingerprints = createNumberMatrixRecord();\n\n for (const startChunkId of graph.sortedChunkIds) {\n const concentrations = createNumberRecord();\n let currentLayer = [startChunkId];\n const visitedChunkIds = createBooleanRecord();\n\n concentrations[String(startChunkId)] = 1;\n visitedChunkIds[String(startChunkId)] = true;\n\n while (currentLayer.length > 0) {\n const nextLayerConcentrations = createNumberRecord();\n\n for (const currentChunkId of currentLayer) {\n const currentConcentration =\n concentrations[String(currentChunkId)] ?? 0;\n let totalWeight = 0;\n const neighbors: Array<readonly [number, number]> = [];\n\n for (const edge of graph.incomingEdgesByChunkId[\n String(currentChunkId)\n ] ?? []) {\n if (visitedChunkIds[String(edge.fromId)] === true) {\n continue;\n }\n\n const weight =\n graph.fingerprintEdgeWeightsByKey[\n getReadingEdgeKey(edge.fromId, currentChunkId)\n ] ??\n graph.fingerprintEdgeWeightsByKey[\n getReadingEdgeKey(currentChunkId, edge.fromId)\n ] ??\n DEFAULT_LINK_STRENGTH_WEIGHT;\n\n neighbors.push([edge.fromId, weight]);\n totalWeight += weight;\n }\n\n for (const edge of graph.outgoingEdgesByChunkId[\n String(currentChunkId)\n ] ?? []) {\n if (visitedChunkIds[String(edge.toId)] === true) {\n continue;\n }\n\n const weight =\n graph.fingerprintEdgeWeightsByKey[\n getReadingEdgeKey(currentChunkId, edge.toId)\n ] ??\n graph.fingerprintEdgeWeightsByKey[\n getReadingEdgeKey(edge.toId, currentChunkId)\n ] ??\n DEFAULT_LINK_STRENGTH_WEIGHT;\n\n neighbors.push([edge.toId, weight]);\n totalWeight += weight;\n }\n\n if (totalWeight <= 0) {\n continue;\n }\n\n for (const [neighborChunkId, weight] of neighbors) {\n const contribution =\n currentConcentration * (weight / totalWeight) * DECAY_FACTOR;\n\n nextLayerConcentrations[String(neighborChunkId)] =\n (nextLayerConcentrations[String(neighborChunkId)] ?? 0) +\n contribution;\n }\n }\n\n currentLayer = Object.keys(nextLayerConcentrations).map(Number);\n\n for (const nextChunkId of currentLayer) {\n concentrations[String(nextChunkId)] =\n nextLayerConcentrations[String(nextChunkId)] ?? 0;\n visitedChunkIds[String(nextChunkId)] = true;\n }\n }\n\n const totalConcentration = Object.values(concentrations).reduce(\n (sum, concentration) => sum + concentration,\n 0,\n );\n\n if (totalConcentration > 0) {\n for (const chunkId of Object.keys(concentrations)) {\n concentrations[chunkId] =\n (concentrations[chunkId] ?? 0) / totalConcentration;\n }\n }\n\n fingerprints[String(startChunkId)] = concentrations;\n }\n\n return fingerprints;\n}\n\nfunction computeClusterWordsCount(\n graph: DetectorGraph,\n cluster: readonly number[],\n): number {\n return cluster.reduce((sum, chunkId) => {\n return sum + (graph.chunksById[String(chunkId)]?.wordsCount ?? 0);\n }, 0);\n}\n\nfunction computeMergeValue(\n graph: DetectorGraph,\n leftCluster: readonly number[],\n rightCluster: readonly number[],\n fingerprints: Readonly<Record<string, Readonly<Record<string, number>>>>,\n): number {\n let edgeCount = 0;\n let minValue = Number.POSITIVE_INFINITY;\n\n for (const leftChunkId of leftCluster) {\n for (const rightChunkId of rightCluster) {\n const edge =\n graph.edgeByKey[getReadingEdgeKey(leftChunkId, rightChunkId)] ??\n graph.edgeByKey[getReadingEdgeKey(rightChunkId, leftChunkId)];\n\n if (edge === undefined) {\n continue;\n }\n\n edgeCount += 1;\n\n const leftFingerprint = fingerprints[String(leftChunkId)] ?? {};\n const rightFingerprint = fingerprints[String(rightChunkId)] ?? {};\n let squaredSum = 0;\n\n for (const targetChunkId of Object.keys(leftFingerprint)) {\n const diff =\n (leftFingerprint[targetChunkId] ?? 0) -\n (rightFingerprint[targetChunkId] ?? 0);\n\n squaredSum += diff * diff;\n }\n\n let deltaValue = getLinkStrengthWeight(edge.strength);\n const leftChunk = graph.chunksById[String(leftChunkId)];\n const rightChunk = graph.chunksById[String(rightChunkId)];\n\n if (\n leftChunk?.retention !== undefined &&\n rightChunk?.retention !== undefined\n ) {\n deltaValue += ATTRIBUTE_BONUS_WEIGHT;\n }\n if (\n leftChunk?.importance !== undefined &&\n rightChunk?.importance !== undefined\n ) {\n deltaValue += ATTRIBUTE_BONUS_WEIGHT;\n }\n\n const distance = Math.sqrt(squaredSum);\n const value = (1 - distance / 2) * deltaValue;\n\n minValue = Math.min(minValue, value);\n }\n }\n\n if (edgeCount === 0) {\n return Number.NEGATIVE_INFINITY;\n }\n\n return minValue;\n}\n\nfunction createBooleanRecord(): Record<string, boolean | undefined> {\n return Object.create(null) as Record<string, boolean | undefined>;\n}\n\nfunction createDetectorGraph(\n chunks: readonly ChunkRecord[],\n edges: readonly ReadingEdgeRecord[],\n): DetectorGraph {\n const chunksById = createChunkRecord();\n const edgeByKey = createEdgeRecord();\n const incomingEdgesByChunkId = createReadingEdgeListRecord();\n const outgoingEdgesByChunkId = createReadingEdgeListRecord();\n const sortedChunkIds = [...chunks]\n .map((chunk) => chunk.id)\n .sort(compareNumber);\n const undirectedAdjacentChunkIdsByChunkId = createNumberListRecord();\n\n for (const chunk of chunks) {\n chunksById[String(chunk.id)] = chunk;\n }\n\n for (const edge of edges) {\n if (\n chunksById[String(edge.fromId)] === undefined ||\n chunksById[String(edge.toId)] === undefined\n ) {\n continue;\n }\n\n const edgeKey = getReadingEdgeKey(edge.fromId, edge.toId);\n\n edgeByKey[edgeKey] = edge;\n if (incomingEdgesByChunkId[String(edge.toId)] === undefined) {\n incomingEdgesByChunkId[String(edge.toId)] = [];\n }\n if (outgoingEdgesByChunkId[String(edge.fromId)] === undefined) {\n outgoingEdgesByChunkId[String(edge.fromId)] = [];\n }\n\n incomingEdgesByChunkId[String(edge.toId)]?.push(edge);\n outgoingEdgesByChunkId[String(edge.fromId)]?.push(edge);\n attachChunkAdjacency(\n undirectedAdjacentChunkIdsByChunkId,\n edge.fromId,\n edge.toId,\n );\n attachChunkAdjacency(\n undirectedAdjacentChunkIdsByChunkId,\n edge.toId,\n edge.fromId,\n );\n }\n\n return {\n chunksById,\n edgeByKey,\n fingerprintEdgeWeightsByKey: computeFingerprintEdgeWeights(\n chunksById,\n edges,\n ),\n incomingEdgesByChunkId,\n outgoingEdgesByChunkId,\n sortedChunkIds,\n undirectedAdjacentChunkIdsByChunkId,\n };\n}\n\nfunction createChunkRecord(): Record<string, ChunkRecord | undefined> {\n return Object.create(null) as Record<string, ChunkRecord | undefined>;\n}\n\nfunction createEdgeQueueEntry(\n leftClusterId: number,\n rightClusterId: number,\n value: number,\n): EdgeQueueEntry {\n return {\n leftClusterId,\n rightClusterId,\n value,\n };\n}\n\nfunction createEdgeRecord(): Record<string, ReadingEdgeRecord | undefined> {\n return Object.create(null) as Record<string, ReadingEdgeRecord | undefined>;\n}\n\nfunction createReadingEdgeListRecord(): Record<\n string,\n ReadingEdgeRecord[] | undefined\n> {\n return Object.create(null) as Record<string, ReadingEdgeRecord[] | undefined>;\n}\n\nfunction createNumberMatrixRecord(): Record<string, Record<string, number>> {\n return Object.create(null) as Record<string, Record<string, number>>;\n}\n\nfunction createNumberListRecord(): Record<string, number[] | undefined> {\n return Object.create(null) as Record<string, number[] | undefined>;\n}\n\nfunction createNumberRecord(): Record<string, number> {\n return Object.create(null) as Record<string, number>;\n}\n\nfunction createOptionalNumberRecord(): Record<string, number | undefined> {\n return Object.create(null) as Record<string, number | undefined>;\n}\n\nfunction getClusterPairKey(\n leftClusterId: number,\n rightClusterId: number,\n): string {\n return leftClusterId < rightClusterId\n ? getReadingEdgeKey(leftClusterId, rightClusterId)\n : getReadingEdgeKey(rightClusterId, leftClusterId);\n}\n\nfunction getLinkStrengthWeight(strength: string | undefined): number {\n switch (strength) {\n case \"critical\":\n return 9;\n case \"important\":\n return 3;\n case \"helpful\":\n return 1;\n default:\n return DEFAULT_LINK_STRENGTH_WEIGHT;\n }\n}\n\nfunction greedyMerge(\n graph: DetectorGraph,\n fingerprints: Readonly<Record<string, Readonly<Record<string, number>>>>,\n config: MergeConfig,\n initialClusters: ReadonlyMap<number, readonly number[]> | undefined,\n): Map<number, number[]> {\n const clusters =\n initialClusters === undefined\n ? new Map<number, number[]>(\n graph.sortedChunkIds.map((chunkId) => [chunkId, [chunkId]]),\n )\n : new Map(\n [...initialClusters.entries()].map(([clusterId, chunkIds]) => [\n clusterId,\n [...chunkIds],\n ]),\n );\n const nodeToCluster = createOptionalNumberRecord();\n const edgeQueue: EdgeQueueEntry[] = [];\n const queuedClusterPairs = createBooleanRecord();\n\n for (const [clusterId, chunkIds] of clusters.entries()) {\n for (const chunkId of chunkIds) {\n nodeToCluster[String(chunkId)] = clusterId;\n }\n }\n\n for (const leftClusterId of clusters.keys()) {\n for (const rightClusterId of clusters.keys()) {\n if (leftClusterId >= rightClusterId) {\n continue;\n }\n\n const leftCluster = clusters.get(leftClusterId);\n const rightCluster = clusters.get(rightClusterId);\n\n if (leftCluster === undefined || rightCluster === undefined) {\n continue;\n }\n if (!clustersConnected(graph, leftCluster, rightCluster)) {\n continue;\n }\n\n edgeQueue.push(\n createEdgeQueueEntry(\n leftClusterId,\n rightClusterId,\n computeMergeValue(graph, leftCluster, rightCluster, fingerprints),\n ),\n );\n queuedClusterPairs[getClusterPairKey(leftClusterId, rightClusterId)] =\n true;\n }\n }\n\n while (edgeQueue.length > 0) {\n edgeQueue.sort(compareEdgeQueueEntry);\n\n const nextEntry = edgeQueue.shift();\n\n if (nextEntry === undefined) {\n continue;\n }\n\n const currentLeftClusterId = nodeToCluster[String(nextEntry.leftClusterId)];\n const currentRightClusterId =\n nodeToCluster[String(nextEntry.rightClusterId)];\n\n if (\n currentLeftClusterId === undefined ||\n currentRightClusterId === undefined ||\n currentLeftClusterId === currentRightClusterId\n ) {\n continue;\n }\n\n const leftCluster = clusters.get(currentLeftClusterId);\n const rightCluster = clusters.get(currentRightClusterId);\n\n if (leftCluster === undefined || rightCluster === undefined) {\n continue;\n }\n if (!clustersConnected(graph, leftCluster, rightCluster)) {\n continue;\n }\n\n if (\n config.enableBonus &&\n leftCluster.length >= 2 &&\n rightCluster.length >= 2\n ) {\n continue;\n }\n\n if (\n computeClusterWordsCount(graph, leftCluster) +\n computeClusterWordsCount(graph, rightCluster) >\n config.snakeWordsCount\n ) {\n continue;\n }\n\n leftCluster.push(...rightCluster);\n clusters.delete(currentRightClusterId);\n\n for (const chunkId of rightCluster) {\n nodeToCluster[String(chunkId)] = currentLeftClusterId;\n }\n\n const neighborChunkIds = new Set<number>();\n\n for (const chunkId of leftCluster) {\n for (const neighborChunkId of graph.undirectedAdjacentChunkIdsByChunkId[\n String(chunkId)\n ] ?? []) {\n neighborChunkIds.add(neighborChunkId);\n }\n }\n\n for (const neighborChunkId of neighborChunkIds) {\n const neighborClusterId = nodeToCluster[String(neighborChunkId)];\n\n if (\n neighborClusterId === undefined ||\n neighborClusterId === currentLeftClusterId\n ) {\n continue;\n }\n\n const neighborCluster = clusters.get(neighborClusterId);\n\n if (neighborCluster === undefined) {\n continue;\n }\n\n const clusterPairKey = getClusterPairKey(\n currentLeftClusterId,\n neighborClusterId,\n );\n\n if (queuedClusterPairs[clusterPairKey] === true) {\n continue;\n }\n\n edgeQueue.push(\n createEdgeQueueEntry(\n Math.min(currentLeftClusterId, neighborClusterId),\n Math.max(currentLeftClusterId, neighborClusterId),\n computeMergeValue(graph, leftCluster, neighborCluster, fingerprints),\n ),\n );\n queuedClusterPairs[clusterPairKey] = true;\n }\n }\n\n return clusters;\n}\n\nfunction isWeaklyConnected(graph: DetectorGraph): boolean {\n const firstChunkId = graph.sortedChunkIds[0];\n\n if (firstChunkId === undefined) {\n return true;\n }\n\n const visitedChunkIds = createBooleanRecord();\n const stack = [firstChunkId];\n\n visitedChunkIds[String(firstChunkId)] = true;\n\n while (stack.length > 0) {\n const currentChunkId = stack.pop();\n\n if (currentChunkId === undefined) {\n continue;\n }\n\n for (const nextChunkId of graph.undirectedAdjacentChunkIdsByChunkId[\n String(currentChunkId)\n ] ?? []) {\n if (visitedChunkIds[String(nextChunkId)] === true) {\n continue;\n }\n\n visitedChunkIds[String(nextChunkId)] = true;\n stack.push(nextChunkId);\n }\n }\n\n return graph.sortedChunkIds.every(\n (chunkId) => visitedChunkIds[String(chunkId)] === true,\n );\n}\n\nfunction validateFingerprints(\n fingerprints: Readonly<Record<string, Readonly<Record<string, number>>>>,\n): void {\n const firstChunkId = Object.keys(fingerprints)[0];\n\n if (firstChunkId === undefined) {\n return;\n }\n\n const referenceChunkIds = Object.keys(\n fingerprints[firstChunkId] ?? {},\n ).sort();\n\n for (const [chunkId, fingerprint] of Object.entries(fingerprints)) {\n const fingerprintChunkIds = Object.keys(fingerprint).sort();\n\n if (\n fingerprintChunkIds.length !== referenceChunkIds.length ||\n fingerprintChunkIds.some(\n (targetChunkId, index) => targetChunkId !== referenceChunkIds[index],\n )\n ) {\n throw new Error(`Fingerprint structure mismatch for chunk ${chunkId}`);\n }\n }\n}\n\nfunction computeFingerprintEdgeWeights(\n chunksById: Readonly<Record<string, ChunkRecord | undefined>>,\n edges: readonly ReadingEdgeRecord[],\n): Readonly<Record<string, number>> {\n const totalStrengthsByChunkId = createNumberRecord();\n\n for (const edge of edges) {\n if (\n chunksById[String(edge.fromId)] === undefined ||\n chunksById[String(edge.toId)] === undefined\n ) {\n continue;\n }\n\n const strengthWeight = getLinkStrengthWeight(edge.strength);\n\n totalStrengthsByChunkId[String(edge.fromId)] =\n (totalStrengthsByChunkId[String(edge.fromId)] ?? 0) + strengthWeight;\n totalStrengthsByChunkId[String(edge.toId)] =\n (totalStrengthsByChunkId[String(edge.toId)] ?? 0) + strengthWeight;\n }\n\n const edgeWeightsByKey = createNumberRecord();\n\n for (const edge of edges) {\n const fromChunk = chunksById[String(edge.fromId)];\n const toChunk = chunksById[String(edge.toId)];\n\n if (fromChunk === undefined || toChunk === undefined) {\n continue;\n }\n\n const strengthWeight = getLinkStrengthWeight(edge.strength);\n const fromTotalStrength = totalStrengthsByChunkId[String(edge.fromId)] ?? 0;\n const toTotalStrength = totalStrengthsByChunkId[String(edge.toId)] ?? 0;\n const fromHalfWeight =\n fromTotalStrength === 0\n ? 0\n : fromChunk.weight * (strengthWeight / fromTotalStrength);\n const toHalfWeight =\n toTotalStrength === 0\n ? 0\n : toChunk.weight * (strengthWeight / toTotalStrength);\n const finalWeight = Math.max(\n fromHalfWeight + toHalfWeight,\n MIN_EDGE_WEIGHT,\n );\n\n edgeWeightsByKey[getReadingEdgeKey(edge.fromId, edge.toId)] = finalWeight;\n edgeWeightsByKey[getReadingEdgeKey(edge.toId, edge.fromId)] = finalWeight;\n }\n\n return edgeWeightsByKey;\n}\n\ninterface EdgeQueueEntry {\n readonly leftClusterId: number;\n readonly rightClusterId: number;\n readonly value: number;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ChunkRecord, ReadingEdgeRecord } from '../document/types.js';
|
|
2
|
+
|
|
3
|
+
interface SnakeGraphEdge {
|
|
4
|
+
readonly fromSnakeIndex: number;
|
|
5
|
+
readonly toSnakeIndex: number;
|
|
6
|
+
readonly weight: number;
|
|
7
|
+
}
|
|
8
|
+
declare function buildSnakeGraph(input: {
|
|
9
|
+
chunksById: Readonly<Record<string, ChunkRecord | undefined>>;
|
|
10
|
+
edges: readonly ReadingEdgeRecord[];
|
|
11
|
+
snakes: readonly (readonly number[])[];
|
|
12
|
+
}): SnakeGraphEdge[];
|
|
13
|
+
|
|
14
|
+
export { type SnakeGraphEdge, buildSnakeGraph };
|