@doenet/doenetml 0.6.0-alpha1

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.
Files changed (549) hide show
  1. package/.prettierrc +3 -0
  2. package/LICENSE +661 -0
  3. package/README.md +146 -0
  4. package/cypress/e2e/ActivityViewer/activityVariants.cy.js +1770 -0
  5. package/cypress/e2e/ActivityViewer/compiledActivity.cy.js +83 -0
  6. package/cypress/e2e/ActivityViewer/relationshipsAmongPages.cy.js +697 -0
  7. package/cypress/e2e/answerValidation/errorinnumbers.cy.js +2125 -0
  8. package/cypress/e2e/answerValidation/factoring.cy.js +1945 -0
  9. package/cypress/e2e/answerValidation/factoringOldAlgorithm.cy.js +892 -0
  10. package/cypress/e2e/answerValidation/functionanswers.cy.js +314 -0
  11. package/cypress/e2e/answerValidation/matchingpatterns.cy.js +287 -0
  12. package/cypress/e2e/answerValidation/matchpartial.cy.js +6711 -0
  13. package/cypress/e2e/answerValidation/pointlocation.cy.js +3989 -0
  14. package/cypress/e2e/answerValidation/symbolicequality.cy.js +1893 -0
  15. package/cypress/e2e/answerValidation/videoProgress.cy.js +210 -0
  16. package/cypress/e2e/assignNames/basiccopy.cy.js +2376 -0
  17. package/cypress/e2e/assignNames/collections.cy.js +9247 -0
  18. package/cypress/e2e/assignNames/selects.cy.js +105 -0
  19. package/cypress/e2e/assignNames/sequences.cy.js +1964 -0
  20. package/cypress/e2e/baseComponent/basecomponentproperties.cy.js +999 -0
  21. package/cypress/e2e/baseComponent/doenetMLtext.cy.js +427 -0
  22. package/cypress/e2e/chemistry/atom.cy.js +201 -0
  23. package/cypress/e2e/chemistry/ion.cy.js +608 -0
  24. package/cypress/e2e/chemistry/ioniccompound.cy.js +133 -0
  25. package/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js +2653 -0
  26. package/cypress/e2e/dynamicalsystem/equilibriumcurve.cy.js +311 -0
  27. package/cypress/e2e/dynamicalsystem/equilibriumline.cy.js +279 -0
  28. package/cypress/e2e/dynamicalsystem/equilibriumpoint.cy.js +283 -0
  29. package/cypress/e2e/dynamicalsystem/odesystem.cy.js +1834 -0
  30. package/cypress/e2e/equality/mathexpressions.cy.js +948 -0
  31. package/cypress/e2e/graphing/graphreferences.cy.js +978 -0
  32. package/cypress/e2e/graphing/graphreferences2.cy.js +615 -0
  33. package/cypress/e2e/linearAlgebra/eigenDecomposition.cy.js +401 -0
  34. package/cypress/e2e/tagSpecific/angle.cy.js +3898 -0
  35. package/cypress/e2e/tagSpecific/animatefromsequence.cy.js +2306 -0
  36. package/cypress/e2e/tagSpecific/answer.cy.js +31647 -0
  37. package/cypress/e2e/tagSpecific/bestfitline.cy.js +612 -0
  38. package/cypress/e2e/tagSpecific/blockquote.cy.js +30 -0
  39. package/cypress/e2e/tagSpecific/boolean.cy.js +742 -0
  40. package/cypress/e2e/tagSpecific/booleaninput.cy.js +1283 -0
  41. package/cypress/e2e/tagSpecific/booleanlist.cy.js +588 -0
  42. package/cypress/e2e/tagSpecific/booleanoperators.cy.js +596 -0
  43. package/cypress/e2e/tagSpecific/booleanoperatorsonmath.cy.js +498 -0
  44. package/cypress/e2e/tagSpecific/callaction.cy.js +2835 -0
  45. package/cypress/e2e/tagSpecific/choiceinput.cy.js +3205 -0
  46. package/cypress/e2e/tagSpecific/circle.cy.js +22036 -0
  47. package/cypress/e2e/tagSpecific/codeeditor.cy.js +1995 -0
  48. package/cypress/e2e/tagSpecific/collect.cy.js +5035 -0
  49. package/cypress/e2e/tagSpecific/componentsize.cy.js +502 -0
  50. package/cypress/e2e/tagSpecific/conditionalcontent.cy.js +3495 -0
  51. package/cypress/e2e/tagSpecific/contentBrowser.cy.js +335 -0
  52. package/cypress/e2e/tagSpecific/contentpicker.cy.js +261 -0
  53. package/cypress/e2e/tagSpecific/copy.cy.js +12627 -0
  54. package/cypress/e2e/tagSpecific/copy2.cy.js +5698 -0
  55. package/cypress/e2e/tagSpecific/curve.bezier.cy.js +12440 -0
  56. package/cypress/e2e/tagSpecific/curve.cy.js +1716 -0
  57. package/cypress/e2e/tagSpecific/curve.function.cy.js +1471 -0
  58. package/cypress/e2e/tagSpecific/curve.parametrized.cy.js +920 -0
  59. package/cypress/e2e/tagSpecific/document.cy.js +234 -0
  60. package/cypress/e2e/tagSpecific/endpoint.cy.js +197 -0
  61. package/cypress/e2e/tagSpecific/evaluate.cy.js +8895 -0
  62. package/cypress/e2e/tagSpecific/extract.cy.js +2282 -0
  63. package/cypress/e2e/tagSpecific/feedback.cy.js +2941 -0
  64. package/cypress/e2e/tagSpecific/function.cy.js +9450 -0
  65. package/cypress/e2e/tagSpecific/functioniterates.cy.js +1178 -0
  66. package/cypress/e2e/tagSpecific/functionoperators.cy.js +4047 -0
  67. package/cypress/e2e/tagSpecific/graph.cy.js +2491 -0
  68. package/cypress/e2e/tagSpecific/group.cy.js +683 -0
  69. package/cypress/e2e/tagSpecific/hint.cy.js +204 -0
  70. package/cypress/e2e/tagSpecific/image.cy.js +770 -0
  71. package/cypress/e2e/tagSpecific/integer.cy.js +206 -0
  72. package/cypress/e2e/tagSpecific/label.cy.js +800 -0
  73. package/cypress/e2e/tagSpecific/legend.cy.js +1001 -0
  74. package/cypress/e2e/tagSpecific/line.cy.js +12167 -0
  75. package/cypress/e2e/tagSpecific/linesegment.cy.js +4749 -0
  76. package/cypress/e2e/tagSpecific/lorem.cy.js +289 -0
  77. package/cypress/e2e/tagSpecific/map.cy.js +4476 -0
  78. package/cypress/e2e/tagSpecific/matchespattern.cy.js +693 -0
  79. package/cypress/e2e/tagSpecific/math.cy.js +10990 -0
  80. package/cypress/e2e/tagSpecific/mathdisplay.cy.js +2689 -0
  81. package/cypress/e2e/tagSpecific/mathinput.cy.js +15628 -0
  82. package/cypress/e2e/tagSpecific/mathinputgraph.cy.js +566 -0
  83. package/cypress/e2e/tagSpecific/mathlist.cy.js +4073 -0
  84. package/cypress/e2e/tagSpecific/mathoperators.cy.js +13851 -0
  85. package/cypress/e2e/tagSpecific/matrix.cy.js +8825 -0
  86. package/cypress/e2e/tagSpecific/matrixinput.cy.js +16277 -0
  87. package/cypress/e2e/tagSpecific/module.cy.js +1771 -0
  88. package/cypress/e2e/tagSpecific/number.cy.js +2221 -0
  89. package/cypress/e2e/tagSpecific/numberlist.cy.js +1285 -0
  90. package/cypress/e2e/tagSpecific/p.cy.js +72 -0
  91. package/cypress/e2e/tagSpecific/paginator.cy.js +2983 -0
  92. package/cypress/e2e/tagSpecific/parabola.cy.js +14331 -0
  93. package/cypress/e2e/tagSpecific/paragraphmarkup.cy.js +104 -0
  94. package/cypress/e2e/tagSpecific/periodicset.cy.js +1439 -0
  95. package/cypress/e2e/tagSpecific/piecewisefunction.cy.js +1055 -0
  96. package/cypress/e2e/tagSpecific/pluralize.cy.js +274 -0
  97. package/cypress/e2e/tagSpecific/point.cy.js +8895 -0
  98. package/cypress/e2e/tagSpecific/point2.cy.js +10259 -0
  99. package/cypress/e2e/tagSpecific/polygon.cy.js +5039 -0
  100. package/cypress/e2e/tagSpecific/polyline.cy.js +4704 -0
  101. package/cypress/e2e/tagSpecific/problem.cy.js +2768 -0
  102. package/cypress/e2e/tagSpecific/ray.cy.js +10770 -0
  103. package/cypress/e2e/tagSpecific/rectangle.cy.js +2143 -0
  104. package/cypress/e2e/tagSpecific/ref.cy.js +420 -0
  105. package/cypress/e2e/tagSpecific/regularPolygon.cy.js +1006 -0
  106. package/cypress/e2e/tagSpecific/regularPolygon2.cy.js +100 -0
  107. package/cypress/e2e/tagSpecific/regularPolygon3.cy.js +777 -0
  108. package/cypress/e2e/tagSpecific/samplerandomnumbers.cy.js +3619 -0
  109. package/cypress/e2e/tagSpecific/sectioning.cy.js +3530 -0
  110. package/cypress/e2e/tagSpecific/select.cy.js +5376 -0
  111. package/cypress/e2e/tagSpecific/selectfromsequence.cy.js +3846 -0
  112. package/cypress/e2e/tagSpecific/selectrandomnumbers.cy.js +2914 -0
  113. package/cypress/e2e/tagSpecific/sequence.cy.js +2093 -0
  114. package/cypress/e2e/tagSpecific/shuffle.cy.js +490 -0
  115. package/cypress/e2e/tagSpecific/sidebyside.cy.js +8057 -0
  116. package/cypress/e2e/tagSpecific/singlecharactercomponents.cy.js +72 -0
  117. package/cypress/e2e/tagSpecific/slider.cy.js +914 -0
  118. package/cypress/e2e/tagSpecific/solution.cy.js +109 -0
  119. package/cypress/e2e/tagSpecific/solveequations.cy.js +1026 -0
  120. package/cypress/e2e/tagSpecific/sort.cy.js +1685 -0
  121. package/cypress/e2e/tagSpecific/spreadsheet.cy.js +5971 -0
  122. package/cypress/e2e/tagSpecific/subsetofreals.cy.js +2725 -0
  123. package/cypress/e2e/tagSpecific/substitute.cy.js +2646 -0
  124. package/cypress/e2e/tagSpecific/tabular.cy.js +36 -0
  125. package/cypress/e2e/tagSpecific/text.cy.js +975 -0
  126. package/cypress/e2e/tagSpecific/textinput.cy.js +2177 -0
  127. package/cypress/e2e/tagSpecific/textlist.cy.js +369 -0
  128. package/cypress/e2e/tagSpecific/triangle.cy.js +1936 -0
  129. package/cypress/e2e/tagSpecific/triggerset.cy.js +2023 -0
  130. package/cypress/e2e/tagSpecific/updatevalue.cy.js +3288 -0
  131. package/cypress/e2e/tagSpecific/vector.cy.js +20183 -0
  132. package/cypress/e2e/tagSpecific/video.cy.js +612 -0
  133. package/cypress/e2e/tagSpecific/when.cy.js +202 -0
  134. package/cypress/e2e/variants/specifysinglevariant.cy.js +6726 -0
  135. package/cypress/e2e/variants/uniquevariants.cy.js +4846 -0
  136. package/cypress/fixtures/example.json +5 -0
  137. package/cypress/support/commands.js +32 -0
  138. package/cypress/support/e2e.js +31 -0
  139. package/cypress.config.js +18 -0
  140. package/docs/codeSnippet.jsx +11 -0
  141. package/docs/index.html +133 -0
  142. package/docs/index.jsx +138 -0
  143. package/docs/prism.css +3 -0
  144. package/index.html +14 -0
  145. package/index.js +21 -0
  146. package/media/answer_example.png +0 -0
  147. package/media/graph_example.png +0 -0
  148. package/media/graph_markup_example.png +0 -0
  149. package/package.json +83 -0
  150. package/public/favicon.ico +0 -0
  151. package/public/fonts/files/open-sans-v18-latin-700.woff +0 -0
  152. package/public/fonts/files/open-sans-v18-latin-700.woff2 +0 -0
  153. package/public/fonts/files/open-sans-v18-latin-700italic.woff +0 -0
  154. package/public/fonts/files/open-sans-v18-latin-700italic.woff2 +0 -0
  155. package/public/fonts/files/open-sans-v18-latin-italic.woff +0 -0
  156. package/public/fonts/files/open-sans-v18-latin-italic.woff2 +0 -0
  157. package/public/fonts/files/open-sans-v18-latin-light-italic.woff +0 -0
  158. package/public/fonts/files/open-sans-v18-latin-light-italic.woff2 +0 -0
  159. package/public/fonts/files/open-sans-v18-latin-light.woff +0 -0
  160. package/public/fonts/files/open-sans-v18-latin-light.woff2 +0 -0
  161. package/public/fonts/files/open-sans-v18-latin-regular.woff +0 -0
  162. package/public/fonts/files/open-sans-v18-latin-regular.woff2 +0 -0
  163. package/src/Core/ComponentTypes.js +426 -0
  164. package/src/Core/Core.js +11852 -0
  165. package/src/Core/CoreWorker.js +127 -0
  166. package/src/Core/Dependencies.js +8226 -0
  167. package/src/Core/Numerics.js +473 -0
  168. package/src/Core/ParameterStack.js +36 -0
  169. package/src/Core/ReadOnlyProxyHandler.js +41 -0
  170. package/src/Core/StateProxyHandler.js +88 -0
  171. package/src/Core/components/Aliases.js +67 -0
  172. package/src/Core/components/Angle.js +758 -0
  173. package/src/Core/components/AnimateFromSequence.js +922 -0
  174. package/src/Core/components/Answer.js +2087 -0
  175. package/src/Core/components/AsList.js +83 -0
  176. package/src/Core/components/AttractTo.js +245 -0
  177. package/src/Core/components/AttractToAngles.js +262 -0
  178. package/src/Core/components/AttractToConstraint.js +104 -0
  179. package/src/Core/components/AttractToGrid.js +315 -0
  180. package/src/Core/components/Award.js +906 -0
  181. package/src/Core/components/BestFitLine.js +318 -0
  182. package/src/Core/components/BezierControls.js +719 -0
  183. package/src/Core/components/BlockQuote.js +35 -0
  184. package/src/Core/components/Boolean.js +500 -0
  185. package/src/Core/components/BooleanInput.js +330 -0
  186. package/src/Core/components/BooleanList.js +396 -0
  187. package/src/Core/components/BooleanOperators.js +35 -0
  188. package/src/Core/components/BooleanOperatorsOfMath.js +148 -0
  189. package/src/Core/components/CallAction.js +261 -0
  190. package/src/Core/components/Caption.js +73 -0
  191. package/src/Core/components/Case.js +56 -0
  192. package/src/Core/components/Cell.js +439 -0
  193. package/src/Core/components/CellBlock.js +64 -0
  194. package/src/Core/components/Chart.js +795 -0
  195. package/src/Core/components/Choice.js +266 -0
  196. package/src/Core/components/ChoiceInput.js +1407 -0
  197. package/src/Core/components/Circle.js +2884 -0
  198. package/src/Core/components/CodeEditor.js +647 -0
  199. package/src/Core/components/CodeViewer.js +294 -0
  200. package/src/Core/components/CollaborateGroupSetup.js +46 -0
  201. package/src/Core/components/CollaborateGroups.js +119 -0
  202. package/src/Core/components/Collect.js +850 -0
  203. package/src/Core/components/Column.js +608 -0
  204. package/src/Core/components/ConditionalContent.js +468 -0
  205. package/src/Core/components/ConsiderAsResponses.js +49 -0
  206. package/src/Core/components/ConstrainTo.js +161 -0
  207. package/src/Core/components/ConstrainToAngles.js +244 -0
  208. package/src/Core/components/ConstrainToGraph.js +142 -0
  209. package/src/Core/components/ConstrainToGrid.js +175 -0
  210. package/src/Core/components/ConstraintUnion.js +119 -0
  211. package/src/Core/components/Constraints.js +497 -0
  212. package/src/Core/components/ContentBrowser.js +441 -0
  213. package/src/Core/components/ContentPicker.js +263 -0
  214. package/src/Core/components/ControlVectors.js +25 -0
  215. package/src/Core/components/Coords.js +63 -0
  216. package/src/Core/components/Copy.js +3412 -0
  217. package/src/Core/components/Curve.js +4130 -0
  218. package/src/Core/components/CustomAttribute.js +175 -0
  219. package/src/Core/components/DataFrame.js +357 -0
  220. package/src/Core/components/DiscreteSimulationResultList.js +342 -0
  221. package/src/Core/components/DiscreteSimulationResultPolyline.js +581 -0
  222. package/src/Core/components/Divisions.js +55 -0
  223. package/src/Core/components/Document.js +888 -0
  224. package/src/Core/components/Embed.js +65 -0
  225. package/src/Core/components/Endpoint.js +62 -0
  226. package/src/Core/components/Evaluate.js +321 -0
  227. package/src/Core/components/Extract.js +656 -0
  228. package/src/Core/components/Extrema.js +556 -0
  229. package/src/Core/components/Feedback.js +200 -0
  230. package/src/Core/components/FeedbackDefinitions.js +97 -0
  231. package/src/Core/components/Figure.js +148 -0
  232. package/src/Core/components/Footnote.js +73 -0
  233. package/src/Core/components/Function.js +5344 -0
  234. package/src/Core/components/FunctionIterates.js +306 -0
  235. package/src/Core/components/FunctionOperators.js +702 -0
  236. package/src/Core/components/Graph.js +1679 -0
  237. package/src/Core/components/Group.js +7 -0
  238. package/src/Core/components/HasSameFactoring.js +407 -0
  239. package/src/Core/components/Hint.js +241 -0
  240. package/src/Core/components/Image.js +524 -0
  241. package/src/Core/components/Indexing.js +79 -0
  242. package/src/Core/components/IntComma.js +64 -0
  243. package/src/Core/components/Integer.js +81 -0
  244. package/src/Core/components/Intersection.js +328 -0
  245. package/src/Core/components/Interval.js +29 -0
  246. package/src/Core/components/Label.js +492 -0
  247. package/src/Core/components/Latex.js +104 -0
  248. package/src/Core/components/Legend.js +329 -0
  249. package/src/Core/components/Line.js +2040 -0
  250. package/src/Core/components/LineSegment.js +882 -0
  251. package/src/Core/components/Lists.js +180 -0
  252. package/src/Core/components/Lorem.js +249 -0
  253. package/src/Core/components/MMeMen.js +377 -0
  254. package/src/Core/components/Map.js +873 -0
  255. package/src/Core/components/Markers.js +101 -0
  256. package/src/Core/components/MatchesPattern.js +339 -0
  257. package/src/Core/components/Math.js +2552 -0
  258. package/src/Core/components/MathInput.js +948 -0
  259. package/src/Core/components/MathList.js +828 -0
  260. package/src/Core/components/MathOperators.js +1286 -0
  261. package/src/Core/components/Matrix.js +497 -0
  262. package/src/Core/components/MatrixInput.js +3157 -0
  263. package/src/Core/components/MdMdnMrow.js +394 -0
  264. package/src/Core/components/Module.js +16 -0
  265. package/src/Core/components/Number.js +1031 -0
  266. package/src/Core/components/NumberList.js +550 -0
  267. package/src/Core/components/Option.js +24 -0
  268. package/src/Core/components/P.js +71 -0
  269. package/src/Core/components/Paginator.js +338 -0
  270. package/src/Core/components/Panel.js +126 -0
  271. package/src/Core/components/Parabola.js +1561 -0
  272. package/src/Core/components/ParagraphMarkup.js +59 -0
  273. package/src/Core/components/Pegboard.js +43 -0
  274. package/src/Core/components/PeriodicSet.js +291 -0
  275. package/src/Core/components/PiecewiseFunction.js +832 -0
  276. package/src/Core/components/Pluralize.js +198 -0
  277. package/src/Core/components/Point.js +1295 -0
  278. package/src/Core/components/Polygon.js +408 -0
  279. package/src/Core/components/Polyline.js +841 -0
  280. package/src/Core/components/RandomizedTextList.js +225 -0
  281. package/src/Core/components/Ray.js +1737 -0
  282. package/src/Core/components/Rectangle.js +1535 -0
  283. package/src/Core/components/Ref.js +350 -0
  284. package/src/Core/components/RegionBetweenCurveXAxis.js +124 -0
  285. package/src/Core/components/RegionHalfPlane.js +107 -0
  286. package/src/Core/components/RegularPolygon.js +2118 -0
  287. package/src/Core/components/RenderDoenetML.js +181 -0
  288. package/src/Core/components/Row.js +780 -0
  289. package/src/Core/components/SampleRandomNumbers.js +653 -0
  290. package/src/Core/components/Sectioning.js +303 -0
  291. package/src/Core/components/Select.js +947 -0
  292. package/src/Core/components/SelectFromSequence.js +1242 -0
  293. package/src/Core/components/SelectRandomNumbers.js +225 -0
  294. package/src/Core/components/Sequence.js +444 -0
  295. package/src/Core/components/Setup.js +53 -0
  296. package/src/Core/components/Shuffle.js +470 -0
  297. package/src/Core/components/SideBySide.js +2130 -0
  298. package/src/Core/components/SingleCharacterComponents.js +41 -0
  299. package/src/Core/components/Slider.js +819 -0
  300. package/src/Core/components/SolutionContainer.js +67 -0
  301. package/src/Core/components/Solutions.js +334 -0
  302. package/src/Core/components/SolveEquations.js +568 -0
  303. package/src/Core/components/Sort.js +398 -0
  304. package/src/Core/components/Sources.js +108 -0
  305. package/src/Core/components/Split.js +205 -0
  306. package/src/Core/components/Spreadsheet.js +1507 -0
  307. package/src/Core/components/StyleDefinitions.js +111 -0
  308. package/src/Core/components/SubsetOfReals.js +348 -0
  309. package/src/Core/components/SubsetOfRealsInput.js +1474 -0
  310. package/src/Core/components/Substitute.js +496 -0
  311. package/src/Core/components/SummaryStatistics.js +652 -0
  312. package/src/Core/components/Table.js +145 -0
  313. package/src/Core/components/Tabular.js +384 -0
  314. package/src/Core/components/Template.js +360 -0
  315. package/src/Core/components/Text.js +341 -0
  316. package/src/Core/components/TextInput.js +566 -0
  317. package/src/Core/components/TextList.js +442 -0
  318. package/src/Core/components/TextListFromString.js +137 -0
  319. package/src/Core/components/TextOperatorsOfMath.js +21 -0
  320. package/src/Core/components/Triangle.js +280 -0
  321. package/src/Core/components/TriggerSet.js +189 -0
  322. package/src/Core/components/TupleList.js +43 -0
  323. package/src/Core/components/UpdateValue.js +435 -0
  324. package/src/Core/components/VariantControl.js +36 -0
  325. package/src/Core/components/Vector.js +2478 -0
  326. package/src/Core/components/Verbatim.js +125 -0
  327. package/src/Core/components/Video.js +673 -0
  328. package/src/Core/components/When.js +198 -0
  329. package/src/Core/components/abstract/AngleListComponent.js +140 -0
  330. package/src/Core/components/abstract/BaseComponent.js +1496 -0
  331. package/src/Core/components/abstract/BlockComponent.js +5 -0
  332. package/src/Core/components/abstract/BooleanBaseOperator.js +88 -0
  333. package/src/Core/components/abstract/BooleanBaseOperatorOfMath.js +100 -0
  334. package/src/Core/components/abstract/BooleanBaseOperatorOneInput.js +44 -0
  335. package/src/Core/components/abstract/ComponentSize.js +789 -0
  336. package/src/Core/components/abstract/ComponentWithSelectableType.js +537 -0
  337. package/src/Core/components/abstract/CompositeComponent.js +142 -0
  338. package/src/Core/components/abstract/ConstraintComponent.js +19 -0
  339. package/src/Core/components/abstract/FunctionBaseOperator.js +680 -0
  340. package/src/Core/components/abstract/GraphicalComponent.js +56 -0
  341. package/src/Core/components/abstract/InlineComponent.js +5 -0
  342. package/src/Core/components/abstract/InlineRenderInlineChildren.js +63 -0
  343. package/src/Core/components/abstract/Input.js +192 -0
  344. package/src/Core/components/abstract/IntervalListComponent.js +218 -0
  345. package/src/Core/components/abstract/LineListComponent.js +114 -0
  346. package/src/Core/components/abstract/MathBaseOperator.js +631 -0
  347. package/src/Core/components/abstract/MathBaseOperatorOneInput.js +112 -0
  348. package/src/Core/components/abstract/PointListComponent.js +238 -0
  349. package/src/Core/components/abstract/SectioningComponent.js +1262 -0
  350. package/src/Core/components/abstract/SingleCharacterInline.js +23 -0
  351. package/src/Core/components/abstract/TextBaseOperatorOfMath.js +47 -0
  352. package/src/Core/components/abstract/TextOrInline.js +66 -0
  353. package/src/Core/components/abstract/VariableName.js +31 -0
  354. package/src/Core/components/abstract/VariableNameList.js +83 -0
  355. package/src/Core/components/abstract/VectorListComponent.js +235 -0
  356. package/src/Core/components/chemistry/Atom.js +910 -0
  357. package/src/Core/components/chemistry/ElectronConfiguration.js +36 -0
  358. package/src/Core/components/chemistry/Ion.js +684 -0
  359. package/src/Core/components/chemistry/IonicCompound.js +189 -0
  360. package/src/Core/components/chemistry/OrbitalDiagram.js +175 -0
  361. package/src/Core/components/chemistry/OrbitalDiagramInput.js +753 -0
  362. package/src/Core/components/chemistry/index.js +6 -0
  363. package/src/Core/components/commonsugar/breakstrings.js +627 -0
  364. package/src/Core/components/commonsugar/lists.js +177 -0
  365. package/src/Core/components/dynamicalSystems/CobwebPolyline.js +913 -0
  366. package/src/Core/components/dynamicalSystems/EquilibriumCurve.js +95 -0
  367. package/src/Core/components/dynamicalSystems/EquilibriumLine.js +93 -0
  368. package/src/Core/components/dynamicalSystems/EquilibriumPoint.js +93 -0
  369. package/src/Core/components/dynamicalSystems/ODESystem.js +943 -0
  370. package/src/Core/components/dynamicalSystems/index.js +5 -0
  371. package/src/Core/components/linearAlgebra/EigenDecomposition.js +294 -0
  372. package/src/Core/utils/array.js +30 -0
  373. package/src/Core/utils/booleanLogic.js +965 -0
  374. package/src/Core/utils/checkEquality.js +818 -0
  375. package/src/Core/utils/cid.js +29 -0
  376. package/src/Core/utils/componentInfoObjects.js +100 -0
  377. package/src/Core/utils/constraints.js +23 -0
  378. package/src/Core/utils/copy.js +572 -0
  379. package/src/Core/utils/deepFunctions.js +173 -0
  380. package/src/Core/utils/descendants.js +252 -0
  381. package/src/Core/utils/enumeration.js +234 -0
  382. package/src/Core/utils/feedback.js +84 -0
  383. package/src/Core/utils/function.js +1343 -0
  384. package/src/Core/utils/graphical.js +196 -0
  385. package/src/Core/utils/label.js +396 -0
  386. package/src/Core/utils/math.js +1056 -0
  387. package/src/Core/utils/naming.js +45 -0
  388. package/src/Core/utils/periodicSetEquality.js +403 -0
  389. package/src/Core/utils/randomNumbers.js +70 -0
  390. package/src/Core/utils/retrieveMedia.js +98 -0
  391. package/src/Core/utils/retrieveTextFile.js +140 -0
  392. package/src/Core/utils/returnAllPossibleVariants.js +73 -0
  393. package/src/Core/utils/rounding.js +316 -0
  394. package/src/Core/utils/sequence.js +754 -0
  395. package/src/Core/utils/serializedStateProcessing.js +4049 -0
  396. package/src/Core/utils/size.js +22 -0
  397. package/src/Core/utils/stateVariables.js +138 -0
  398. package/src/Core/utils/style.js +535 -0
  399. package/src/Core/utils/subset-of-reals.js +796 -0
  400. package/src/Core/utils/table.js +41 -0
  401. package/src/Core/utils/text.js +16 -0
  402. package/src/Core/utils/triggering.js +167 -0
  403. package/src/Core/utils/variants.js +477 -0
  404. package/src/DoenetML.css +308 -0
  405. package/src/DoenetML.jsx +201 -0
  406. package/src/Parser/doenet.grammar +90 -0
  407. package/src/Parser/doenet.js +33 -0
  408. package/src/Parser/doenet.terms.js +20 -0
  409. package/src/Parser/parser.js +266 -0
  410. package/src/Parser/tokens.js +129 -0
  411. package/src/Tools/CodeMirror.jsx +440 -0
  412. package/src/Tools/DarkmodeController.jsx +21 -0
  413. package/src/Tools/Footers/MathInputSelector.jsx +34 -0
  414. package/src/Tools/Footers/VirtualKeyboard.jsx +751 -0
  415. package/src/Tools/cypressTest/CypressTest.jsx +341 -0
  416. package/src/Tools/cypressTest/index.html +102 -0
  417. package/src/Tools/cypressTest/index.jsx +40 -0
  418. package/src/Viewer/ActivityViewer.jsx +1461 -0
  419. package/src/Viewer/PageViewer.jsx +1329 -0
  420. package/src/Viewer/renderers/alert.jsx +17 -0
  421. package/src/Viewer/renderers/angle.jsx +209 -0
  422. package/src/Viewer/renderers/answer.jsx +206 -0
  423. package/src/Viewer/renderers/asList.jsx +25 -0
  424. package/src/Viewer/renderers/blockQuote.jsx +41 -0
  425. package/src/Viewer/renderers/boolean.jsx +17 -0
  426. package/src/Viewer/renderers/booleanInput.css +105 -0
  427. package/src/Viewer/renderers/booleanInput.jsx +636 -0
  428. package/src/Viewer/renderers/button.jsx +369 -0
  429. package/src/Viewer/renderers/c.jsx +17 -0
  430. package/src/Viewer/renderers/callAction.jsx +18 -0
  431. package/src/Viewer/renderers/cell.jsx +59 -0
  432. package/src/Viewer/renderers/chart.jsx +83 -0
  433. package/src/Viewer/renderers/choiceInput.css +223 -0
  434. package/src/Viewer/renderers/choiceInput.jsx +535 -0
  435. package/src/Viewer/renderers/circle.jsx +990 -0
  436. package/src/Viewer/renderers/cobwebPolyline.jsx +442 -0
  437. package/src/Viewer/renderers/codeEditor.jsx +248 -0
  438. package/src/Viewer/renderers/codeViewer.jsx +105 -0
  439. package/src/Viewer/renderers/containerBlock.jsx +41 -0
  440. package/src/Viewer/renderers/containerInline.jsx +17 -0
  441. package/src/Viewer/renderers/contentBrowser.jsx +159 -0
  442. package/src/Viewer/renderers/contentPicker.jsx +160 -0
  443. package/src/Viewer/renderers/curve.jsx +1072 -0
  444. package/src/Viewer/renderers/ellipsis.jsx +17 -0
  445. package/src/Viewer/renderers/em.jsx +17 -0
  446. package/src/Viewer/renderers/embed.jsx +110 -0
  447. package/src/Viewer/renderers/feedback.jsx +74 -0
  448. package/src/Viewer/renderers/figure.jsx +131 -0
  449. package/src/Viewer/renderers/footnote.jsx +52 -0
  450. package/src/Viewer/renderers/graph.jsx +925 -0
  451. package/src/Viewer/renderers/hint.jsx +142 -0
  452. package/src/Viewer/renderers/image.jsx +581 -0
  453. package/src/Viewer/renderers/jsxgraph-distrib/jsxgraphcore.mjs +2 -0
  454. package/src/Viewer/renderers/jsxgraph-distrib/jsxgraphcore.mjs.map +1 -0
  455. package/src/Viewer/renderers/label.jsx +470 -0
  456. package/src/Viewer/renderers/legend.jsx +306 -0
  457. package/src/Viewer/renderers/line.jsx +511 -0
  458. package/src/Viewer/renderers/lineSegment.jsx +754 -0
  459. package/src/Viewer/renderers/list.jsx +111 -0
  460. package/src/Viewer/renderers/lq.jsx +12 -0
  461. package/src/Viewer/renderers/lsq.jsx +12 -0
  462. package/src/Viewer/renderers/math.jsx +582 -0
  463. package/src/Viewer/renderers/mathInput.css +10 -0
  464. package/src/Viewer/renderers/mathInput.jsx +425 -0
  465. package/src/Viewer/renderers/mathInputog.jsx +534 -0
  466. package/src/Viewer/renderers/mathList.jsx +39 -0
  467. package/src/Viewer/renderers/matrixInput.jsx +317 -0
  468. package/src/Viewer/renderers/mdash.jsx +12 -0
  469. package/src/Viewer/renderers/nbsp.jsx +12 -0
  470. package/src/Viewer/renderers/ndash.jsx +12 -0
  471. package/src/Viewer/renderers/number.jsx +454 -0
  472. package/src/Viewer/renderers/numberList.jsx +35 -0
  473. package/src/Viewer/renderers/orbitalDiagram.jsx +247 -0
  474. package/src/Viewer/renderers/orbitalDiagramInput.jsx +450 -0
  475. package/src/Viewer/renderers/p.jsx +38 -0
  476. package/src/Viewer/renderers/paginatorControls.jsx +41 -0
  477. package/src/Viewer/renderers/pegboard.jsx +239 -0
  478. package/src/Viewer/renderers/point.jsx +649 -0
  479. package/src/Viewer/renderers/polygon.jsx +612 -0
  480. package/src/Viewer/renderers/polyline.jsx +608 -0
  481. package/src/Viewer/renderers/pre.jsx +34 -0
  482. package/src/Viewer/renderers/q.jsx +17 -0
  483. package/src/Viewer/renderers/ray.jsx +410 -0
  484. package/src/Viewer/renderers/ref.jsx +149 -0
  485. package/src/Viewer/renderers/regionBetweenCurveXAxis.jsx +182 -0
  486. package/src/Viewer/renderers/renderDoenetML.jsx +56 -0
  487. package/src/Viewer/renderers/row.jsx +31 -0
  488. package/src/Viewer/renderers/rq.jsx +12 -0
  489. package/src/Viewer/renderers/rsq.jsx +12 -0
  490. package/src/Viewer/renderers/section.jsx +427 -0
  491. package/src/Viewer/renderers/sideBySide.jsx +80 -0
  492. package/src/Viewer/renderers/slider.jsx +800 -0
  493. package/src/Viewer/renderers/solution.jsx +134 -0
  494. package/src/Viewer/renderers/spreadsheet.jsx +83 -0
  495. package/src/Viewer/renderers/sq.jsx +17 -0
  496. package/src/Viewer/renderers/styles/global.css +14 -0
  497. package/src/Viewer/renderers/subsetOfRealsInput.jsx +392 -0
  498. package/src/Viewer/renderers/summaryStatistics.jsx +83 -0
  499. package/src/Viewer/renderers/table.jsx +78 -0
  500. package/src/Viewer/renderers/tabular.jsx +58 -0
  501. package/src/Viewer/renderers/tag.jsx +26 -0
  502. package/src/Viewer/renderers/text.jsx +439 -0
  503. package/src/Viewer/renderers/textInput.jsx +774 -0
  504. package/src/Viewer/renderers/textList.jsx +30 -0
  505. package/src/Viewer/renderers/triggerSet.jsx +52 -0
  506. package/src/Viewer/renderers/updateValue.jsx +30 -0
  507. package/src/Viewer/renderers/utils/css.js +13 -0
  508. package/src/Viewer/renderers/utils/graph.js +159 -0
  509. package/src/Viewer/renderers/utils/offGraphIndicators.js +91 -0
  510. package/src/Viewer/renderers/vector.jsx +678 -0
  511. package/src/Viewer/renderers/video.jsx +494 -0
  512. package/src/Viewer/useDoenetRenderer.jsx +128 -0
  513. package/src/main.jsx +16 -0
  514. package/src/media/fonts/files/open-sans-v18-latin-700.woff +0 -0
  515. package/src/media/fonts/files/open-sans-v18-latin-700.woff2 +0 -0
  516. package/src/media/fonts/files/open-sans-v18-latin-700italic.woff +0 -0
  517. package/src/media/fonts/files/open-sans-v18-latin-700italic.woff2 +0 -0
  518. package/src/media/fonts/files/open-sans-v18-latin-italic.woff +0 -0
  519. package/src/media/fonts/files/open-sans-v18-latin-italic.woff2 +0 -0
  520. package/src/media/fonts/files/open-sans-v18-latin-light-italic.woff +0 -0
  521. package/src/media/fonts/files/open-sans-v18-latin-light-italic.woff2 +0 -0
  522. package/src/media/fonts/files/open-sans-v18-latin-light.woff +0 -0
  523. package/src/media/fonts/files/open-sans-v18-latin-light.woff2 +0 -0
  524. package/src/media/fonts/files/open-sans-v18-latin-regular.woff +0 -0
  525. package/src/media/fonts/files/open-sans-v18-latin-regular.woff2 +0 -0
  526. package/src/test/testCode.doenet +26 -0
  527. package/src/test/testViewer.jsx +158 -0
  528. package/src/uiComponents/ActionButton.jsx +157 -0
  529. package/src/uiComponents/ActionButtonGroup.jsx +93 -0
  530. package/src/uiComponents/Button.jsx +160 -0
  531. package/src/uiComponents/ButtonGroup.jsx +56 -0
  532. package/src/uiComponents/ToggleButton.jsx +194 -0
  533. package/src/uiComponents/ToggleButtonGroup.jsx +77 -0
  534. package/src/utils/activityUtils.js +713 -0
  535. package/src/utils/array.js +17 -0
  536. package/src/utils/cid.js +34 -0
  537. package/src/utils/componentInfoObjects.js +89 -0
  538. package/src/utils/deepFunctions.js +165 -0
  539. package/src/utils/enumeration.js +226 -0
  540. package/src/utils/math.js +624 -0
  541. package/src/utils/naming.js +44 -0
  542. package/src/utils/retrieveTextFile.js +156 -0
  543. package/src/utils/returnAllPossibleVariants.js +81 -0
  544. package/src/utils/sequence.js +715 -0
  545. package/src/utils/serialize.js +29 -0
  546. package/src/utils/serializedStateProcessing.js +2587 -0
  547. package/src/utils/subset-of-reals.js +783 -0
  548. package/src/utils/url.js +19 -0
  549. package/vite.config.js +14 -0
@@ -0,0 +1,1242 @@
1
+ import Sequence from "./Sequence";
2
+ import { enumerateSelectionCombinations } from "../utils/enumeration";
3
+ import { processAssignNames } from "../utils/serializedStateProcessing";
4
+ import { getFromText } from "../utils/math";
5
+ import {
6
+ calculateSequenceParameters,
7
+ lettersToNumber,
8
+ returnSequenceValueForIndex,
9
+ returnSequenceValues,
10
+ } from "../utils/sequence";
11
+ import { convertAttributesForComponentType } from "../utils/copy";
12
+ import { returnRoundingAttributes } from "../utils/rounding";
13
+
14
+ export default class SelectFromSequence extends Sequence {
15
+ static componentType = "selectFromSequence";
16
+
17
+ static assignNamesToReplacements = true;
18
+
19
+ static createsVariants = true;
20
+
21
+ static createAttributesObject() {
22
+ let attributes = super.createAttributesObject();
23
+ attributes.assignNamesSkip = {
24
+ createPrimitiveOfType: "number",
25
+ };
26
+ attributes.numToSelect = {
27
+ createComponentOfType: "integer",
28
+ createStateVariable: "numToSelect",
29
+ defaultValue: 1,
30
+ public: true,
31
+ };
32
+ attributes.withReplacement = {
33
+ createComponentOfType: "boolean",
34
+ createStateVariable: "withReplacement",
35
+ defaultValue: false,
36
+ public: true,
37
+ };
38
+ attributes.sortResults = {
39
+ createComponentOfType: "boolean",
40
+ createStateVariable: "sortResults",
41
+ defaultValue: false,
42
+ public: true,
43
+ };
44
+ attributes.excludeCombinations = {
45
+ createComponentOfType: "_componentListOfListsWithSelectableType",
46
+ };
47
+ return attributes;
48
+ }
49
+
50
+ static returnStateVariableDefinitions() {
51
+ let stateVariableDefinitions = super.returnStateVariableDefinitions();
52
+
53
+ stateVariableDefinitions.excludedCombinations = {
54
+ returnDependencies: () => ({
55
+ excludeCombinations: {
56
+ dependencyType: "attributeComponent",
57
+ attributeName: "excludeCombinations",
58
+ variableNames: ["lists"],
59
+ },
60
+ type: {
61
+ dependencyType: "stateVariable",
62
+ variableName: "type",
63
+ },
64
+ numToSelect: {
65
+ dependencyType: "stateVariable",
66
+ variableName: "numToSelect",
67
+ },
68
+ }),
69
+ definition: function ({ dependencyValues }) {
70
+ if (dependencyValues.excludeCombinations !== null) {
71
+ let excludedCombinations =
72
+ dependencyValues.excludeCombinations.stateValues.lists
73
+ .map((x) => x.slice(0, dependencyValues.numToSelect))
74
+ .filter((x) => x.length === dependencyValues.numToSelect);
75
+
76
+ if (dependencyValues.type === "number") {
77
+ while (true) {
78
+ let result = mergeContainingCombinations(excludedCombinations);
79
+ if (result.merged) {
80
+ excludedCombinations = result.combinations;
81
+ } else {
82
+ break;
83
+ }
84
+ }
85
+ }
86
+
87
+ return {
88
+ setValue: { excludedCombinations },
89
+ };
90
+ } else {
91
+ return { setValue: { excludedCombinations: [] } };
92
+ }
93
+ },
94
+ };
95
+
96
+ stateVariableDefinitions.variants = {
97
+ returnDependencies: () => ({
98
+ variants: {
99
+ dependencyType: "variants",
100
+ },
101
+ }),
102
+ definition: function ({ dependencyValues }) {
103
+ return { setValue: { variants: dependencyValues.variants } };
104
+ },
105
+ };
106
+
107
+ stateVariableDefinitions.selectedValues = {
108
+ immutable: true,
109
+ hasEssential: true,
110
+ shadowVariable: true,
111
+ additionalStateVariablesDefined: [
112
+ {
113
+ variableName: "selectedIndices",
114
+ hasEssential: true,
115
+ shadowVariable: true,
116
+ immutable: true,
117
+ },
118
+ ],
119
+ returnDependencies: ({ sharedParameters }) => ({
120
+ numToSelect: {
121
+ dependencyType: "stateVariable",
122
+ variableName: "numToSelect",
123
+ },
124
+ withReplacement: {
125
+ dependencyType: "stateVariable",
126
+ variableName: "withReplacement",
127
+ },
128
+ length: {
129
+ dependencyType: "stateVariable",
130
+ variableName: "length",
131
+ },
132
+ from: {
133
+ dependencyType: "stateVariable",
134
+ variableName: "from",
135
+ },
136
+ step: {
137
+ dependencyType: "stateVariable",
138
+ variableName: "step",
139
+ },
140
+ exclude: {
141
+ dependencyType: "stateVariable",
142
+ variableName: "exclude",
143
+ },
144
+ excludedCombinations: {
145
+ dependencyType: "stateVariable",
146
+ variableName: "excludedCombinations",
147
+ },
148
+ type: {
149
+ dependencyType: "stateVariable",
150
+ variableName: "type",
151
+ },
152
+ lowercase: {
153
+ dependencyType: "stateVariable",
154
+ variableName: "lowercase",
155
+ },
156
+ sortResults: {
157
+ dependencyType: "stateVariable",
158
+ variableName: "sortResults",
159
+ },
160
+ variants: {
161
+ dependencyType: "stateVariable",
162
+ variableName: "variants",
163
+ },
164
+ variantRng: {
165
+ dependencyType: "value",
166
+ value: sharedParameters.variantRng,
167
+ doNotProxy: true,
168
+ },
169
+ }),
170
+ definition: makeSelection,
171
+ };
172
+
173
+ stateVariableDefinitions.isVariantComponent = {
174
+ returnDependencies: () => ({}),
175
+ definition: () => ({ setValue: { isVariantComponent: true } }),
176
+ };
177
+
178
+ stateVariableDefinitions.generatedVariantInfo = {
179
+ returnDependencies: () => ({
180
+ selectedIndices: {
181
+ dependencyType: "stateVariable",
182
+ variableName: "selectedIndices",
183
+ },
184
+ }),
185
+ definition({ dependencyValues, componentName }) {
186
+ let generatedVariantInfo = {
187
+ indices: dependencyValues.selectedIndices,
188
+ meta: { createdBy: componentName },
189
+ };
190
+
191
+ return { setValue: { generatedVariantInfo } };
192
+ },
193
+ };
194
+
195
+ let originalReturnDependencies =
196
+ stateVariableDefinitions.readyToExpandWhenResolved.returnDependencies;
197
+ stateVariableDefinitions.readyToExpandWhenResolved.returnDependencies =
198
+ function () {
199
+ let deps = originalReturnDependencies();
200
+
201
+ deps.selectedValues = {
202
+ dependencyType: "stateVariable",
203
+ variableName: "selectedValues",
204
+ };
205
+
206
+ return deps;
207
+ };
208
+
209
+ return stateVariableDefinitions;
210
+ }
211
+
212
+ static async createSerializedReplacements({
213
+ component,
214
+ componentInfoObjects,
215
+ flags,
216
+ }) {
217
+ let componentType = await component.stateValues.type;
218
+ if (componentType === "letters") {
219
+ componentType = "text";
220
+ }
221
+
222
+ let newNamespace = component.attributes.newNamespace?.primitive;
223
+
224
+ let attributesToConvert = {};
225
+ for (let attr of ["fixed", ...Object.keys(returnRoundingAttributes())]) {
226
+ if (attr in component.attributes) {
227
+ attributesToConvert[attr] = component.attributes[attr];
228
+ }
229
+ }
230
+
231
+ // allow one to override the fixed (default true) attribute
232
+ // as well as rounding settings
233
+ // by specifying it on the sequence
234
+ let attributesFromComposite = {};
235
+
236
+ if (Object.keys(attributesToConvert).length > 0) {
237
+ attributesFromComposite = convertAttributesForComponentType({
238
+ attributes: attributesToConvert,
239
+ componentType,
240
+ componentInfoObjects,
241
+ compositeCreatesNewNamespace: newNamespace,
242
+ flags,
243
+ });
244
+ }
245
+
246
+ let replacements = [];
247
+
248
+ for (let value of await component.stateValues.selectedValues) {
249
+ replacements.push({
250
+ componentType,
251
+ attributes: attributesFromComposite,
252
+ state: { value, fixed: true },
253
+ });
254
+ }
255
+
256
+ let processResult = processAssignNames({
257
+ assignNames: component.doenetAttributes.assignNames,
258
+ serializedComponents: replacements,
259
+ parentName: component.componentName,
260
+ parentCreatesNewNamespace: newNamespace,
261
+ componentInfoObjects,
262
+ });
263
+
264
+ return { replacements: processResult.serializedComponents };
265
+ }
266
+
267
+ static calculateReplacementChanges() {
268
+ return [];
269
+ }
270
+
271
+ static determineNumberOfUniqueVariants({ serializedComponent }) {
272
+ let numToSelect = 1,
273
+ withReplacement = false;
274
+
275
+ let sequenceType = serializedComponent.attributes.type.primitive;
276
+
277
+ let numToSelectComponent =
278
+ serializedComponent.attributes.numToSelect?.component;
279
+ if (numToSelectComponent) {
280
+ // only implemented if have an integer with a single string child
281
+ if (
282
+ numToSelectComponent.componentType === "integer" &&
283
+ numToSelectComponent.children?.length === 1 &&
284
+ typeof numToSelectComponent.children[0] === "string"
285
+ ) {
286
+ numToSelect = Number(numToSelectComponent.children[0]);
287
+
288
+ if (!(Number.isInteger(numToSelect) && numToSelect >= 0)) {
289
+ console.log(
290
+ `cannot determine unique variants of selectFromSequence as numToSelect isn't a non-negative integer.`,
291
+ );
292
+ return { success: false };
293
+ }
294
+ } else {
295
+ console.log(
296
+ `cannot determine unique variants of selectFromSequence as numToSelect isn't constant number.`,
297
+ );
298
+ return { success: false };
299
+ }
300
+ }
301
+
302
+ let withReplacementComponent =
303
+ serializedComponent.attributes.withReplacement?.component;
304
+ if (withReplacementComponent) {
305
+ // only implemented if have an boolean with a boolean value or a single string child
306
+ if (withReplacementComponent.componentType === "boolean") {
307
+ if (
308
+ withReplacementComponent.children?.length === 1 &&
309
+ typeof withReplacementComponent.children[0] === "string"
310
+ ) {
311
+ withReplacement =
312
+ withReplacementComponent.children[0].toLowerCase() === "true";
313
+ } else if (
314
+ (withReplacementComponent.children === undefined ||
315
+ withReplacementComponent.children.length === 0) &&
316
+ typeof withReplacementComponent.state?.value === "boolean"
317
+ ) {
318
+ withReplacement = withReplacementComponent.state.value;
319
+ } else {
320
+ console.log(
321
+ `cannot determine unique variants of selectFromSequence as withReplacement isn't constant boolean.`,
322
+ );
323
+ return { success: false };
324
+ }
325
+ } else {
326
+ console.log(
327
+ `cannot determine unique variants of selectFromSequence as withReplacement isn't constant boolean.`,
328
+ );
329
+ return { success: false };
330
+ }
331
+ }
332
+
333
+ let sequencePars = {
334
+ from: null,
335
+ to: null,
336
+ step: null,
337
+ length: null,
338
+ };
339
+
340
+ let fromComponent = serializedComponent.attributes.from?.component;
341
+ if (fromComponent) {
342
+ // from itself is a component with selectable type
343
+ let fromComponent2 = fromComponent.children[0];
344
+ // only implemented if have a single string child
345
+ if (
346
+ fromComponent2.children?.length === 1 &&
347
+ typeof fromComponent2.children[0] === "string"
348
+ ) {
349
+ let from;
350
+
351
+ if (sequenceType === "number") {
352
+ from = Number(fromComponent2.children[0]);
353
+ if (!Number.isFinite(from)) {
354
+ console.log(
355
+ `cannot determine unique variants of selectFromSequence of number type as from isn't a number.`,
356
+ );
357
+ return { success: false };
358
+ }
359
+ } else if (sequenceType === "letters") {
360
+ from = lettersToNumber(fromComponent2.children[0]);
361
+ if (!Number.isFinite(from)) {
362
+ console.log(
363
+ `cannot determine unique variants of selectFromSequence of letters type as from isn't a combination of letters.`,
364
+ );
365
+ return { success: false };
366
+ }
367
+ } else {
368
+ let fromText = getFromText({
369
+ functionSymbols: ["f", "g"],
370
+ });
371
+ try {
372
+ from = fromText(fromComponent2.children[0]);
373
+ } catch (e) {
374
+ console.log(
375
+ `cannot determine unique variants of selectFromSequence of math type as from isn't a valid math expression.`,
376
+ );
377
+ return { success: false };
378
+ }
379
+ }
380
+ sequencePars.from = from;
381
+ } else {
382
+ console.log(
383
+ `cannot determine unique variants of selectFromSequence as from isn't a constant.`,
384
+ );
385
+ return { success: false };
386
+ }
387
+ }
388
+
389
+ let toComponent = serializedComponent.attributes.to?.component;
390
+ if (toComponent) {
391
+ // to itself is a component with selectable type
392
+ let toComponent2 = toComponent.children[0];
393
+ // only implemented if have a single string child
394
+ if (
395
+ toComponent2.children?.length === 1 &&
396
+ typeof toComponent2.children[0] === "string"
397
+ ) {
398
+ let to;
399
+
400
+ if (sequenceType === "number") {
401
+ to = Number(toComponent2.children[0]);
402
+ if (!Number.isFinite(to)) {
403
+ console.log(
404
+ `cannot determine unique variants of selectFromSequence of number type as to isn't a number.`,
405
+ );
406
+ return { success: false };
407
+ }
408
+ } else if (sequenceType === "letters") {
409
+ to = lettersToNumber(toComponent2.children[0]);
410
+ if (!Number.isFinite(to)) {
411
+ console.log(
412
+ `cannot determine unique variants of selectFromSequence of letters type as to isn't a combination of letters.`,
413
+ );
414
+ return { success: false };
415
+ }
416
+ } else {
417
+ let fromText = getFromText({
418
+ functionSymbols: ["f", "g"],
419
+ });
420
+ try {
421
+ to = fromText(toComponent2.children[0]);
422
+ } catch (e) {
423
+ console.log(
424
+ `cannot determine unique variants of selectFromSequence of math type as to isn't a valid math expression.`,
425
+ );
426
+ return { success: false };
427
+ }
428
+ }
429
+ sequencePars.to = to;
430
+ } else {
431
+ console.log(
432
+ `cannot determine unique variants of selectFromSequence as to isn't a constant.`,
433
+ );
434
+ return { success: false };
435
+ }
436
+ }
437
+
438
+ let stepComponent = serializedComponent.attributes.step?.component;
439
+ if (stepComponent) {
440
+ // only implemented if have a single string child
441
+ if (
442
+ stepComponent.children?.length === 1 &&
443
+ typeof stepComponent.children[0] === "string"
444
+ ) {
445
+ let step;
446
+
447
+ if (sequenceType === "number") {
448
+ step = Number(stepComponent.children[0]);
449
+ if (!Number.isFinite(step)) {
450
+ console.log(
451
+ `cannot determine unique variants of selectFromSequence of number type as step isn't a number.`,
452
+ );
453
+ return { success: false };
454
+ }
455
+ } else if (sequenceType === "letters") {
456
+ step = Number(stepComponent.children[0]);
457
+ if (!Number.isInteger(step)) {
458
+ console.log(
459
+ `cannot determine unique variants of selectFromSequence of letters type as step isn't an integer.`,
460
+ );
461
+ return { success: false };
462
+ }
463
+ } else {
464
+ let fromText = getFromText({
465
+ functionSymbols: ["f", "g"],
466
+ });
467
+ try {
468
+ step = fromText(stepComponent.children[0]);
469
+ } catch (e) {
470
+ console.log(
471
+ `cannot determine unique variants of selectFromSequence of math type as step isn't a valid math expression.`,
472
+ );
473
+ return { success: false };
474
+ }
475
+ }
476
+ sequencePars.step = step;
477
+ } else {
478
+ console.log(
479
+ `cannot determine unique variants of selectFromSequence as step isn't a constant.`,
480
+ );
481
+ return { success: false };
482
+ }
483
+ }
484
+
485
+ let lengthComponent = serializedComponent.attributes.length?.component;
486
+ if (lengthComponent) {
487
+ // only implemented if have a single string child
488
+ if (
489
+ lengthComponent.children?.length === 1 &&
490
+ typeof lengthComponent.children[0] === "string"
491
+ ) {
492
+ let length = Number(lengthComponent.children[0]);
493
+ if (!Number.isInteger(length)) {
494
+ console.log(
495
+ `cannot determine unique variants of selectFromSequence as length isn't an integer.`,
496
+ );
497
+ return { success: false };
498
+ }
499
+ sequencePars.length = length;
500
+ } else {
501
+ console.log(
502
+ `cannot determine unique variants of selectFromSequence as length isn't a constant.`,
503
+ );
504
+ return { success: false };
505
+ }
506
+ }
507
+
508
+ if (serializedComponent.attributes.excludeCombinations) {
509
+ console.log(
510
+ "have not implemented unique variants of a selectFromSequence with excludeCombinations",
511
+ );
512
+ return { success: false };
513
+ }
514
+
515
+ let excludes = [];
516
+
517
+ let excludeComponent = serializedComponent.attributes.exclude?.component;
518
+ if (excludeComponent) {
519
+ if (sequenceType === "math") {
520
+ console.log(
521
+ "have not implemented unique variants of a selectFromSequence of type math with exclude",
522
+ );
523
+ return { success: false };
524
+ }
525
+ if (
526
+ !excludeComponent.children.every(
527
+ (x) => x.children?.length === 1 && typeof x.children[0] === "string",
528
+ )
529
+ ) {
530
+ console.log(
531
+ "have not implemented unique variants of a selectFromSequence with non-constant exclude",
532
+ );
533
+ return { success: false };
534
+ }
535
+ if (sequenceType === "letters") {
536
+ excludes = excludeComponent.children.map((x) =>
537
+ lettersToNumber(x.children[0]),
538
+ );
539
+ } else {
540
+ excludes = excludeComponent.children.map((x) => Number(x.children[0]));
541
+ }
542
+
543
+ if (!excludes.every(Number.isFinite)) {
544
+ console.log(
545
+ "have not implemented unique variants of a selectFromSequence with non-constant exclude",
546
+ );
547
+ return { success: false };
548
+ }
549
+ }
550
+
551
+ sequencePars = calculateSequenceParameters(sequencePars);
552
+
553
+ let nOptions = sequencePars.length;
554
+ let excludeIndices = [];
555
+ if (excludes.length > 0) {
556
+ if (sequenceType !== "math") {
557
+ excludes.sort((a, b) => a - b);
558
+ excludes = excludes.filter((x, ind, a) => x != a[ind - 1]); // remove duplicates
559
+ for (let item of excludes) {
560
+ if (item < sequencePars.from) {
561
+ continue;
562
+ }
563
+ let ind = (item - sequencePars.from) / sequencePars.step;
564
+ if (ind > sequencePars.length - 1 + 1e-10) {
565
+ break;
566
+ }
567
+ if (Math.abs(ind - Math.round(ind)) < 1e-10) {
568
+ nOptions--;
569
+ excludeIndices.push(ind);
570
+ }
571
+ }
572
+ }
573
+ }
574
+
575
+ if (nOptions <= 0) {
576
+ return { success: false };
577
+ }
578
+
579
+ let uniqueVariantData = {
580
+ excludeIndices,
581
+ nOptions,
582
+ numToSelect,
583
+ withReplacement,
584
+ };
585
+
586
+ serializedComponent.variants.uniqueVariantData = uniqueVariantData;
587
+
588
+ let numberOfVariants;
589
+
590
+ if (withReplacement || numToSelect === 1) {
591
+ numberOfVariants = Math.pow(nOptions, numToSelect);
592
+ } else {
593
+ numberOfVariants = nOptions;
594
+ for (let n = nOptions - 1; n > nOptions - numToSelect; n--) {
595
+ numberOfVariants *= n;
596
+ }
597
+ }
598
+
599
+ serializedComponent.variants.numberOfVariants = numberOfVariants;
600
+
601
+ return {
602
+ success: true,
603
+ numberOfVariants: numberOfVariants,
604
+ };
605
+ }
606
+
607
+ static getUniqueVariant({ serializedComponent, variantIndex }) {
608
+ let numberOfVariants = serializedComponent.variants?.numberOfVariants;
609
+ if (numberOfVariants === undefined) {
610
+ return { success: false };
611
+ }
612
+
613
+ if (
614
+ !Number.isInteger(variantIndex) ||
615
+ variantIndex < 1 ||
616
+ variantIndex > numberOfVariants
617
+ ) {
618
+ return { success: false };
619
+ }
620
+
621
+ let uniqueVariantData = serializedComponent.variants.uniqueVariantData;
622
+ let excludeIndices = uniqueVariantData.excludeIndices;
623
+ let nOptions = uniqueVariantData.nOptions;
624
+ let numToSelect = uniqueVariantData.numToSelect;
625
+ let withReplacement = uniqueVariantData.withReplacement;
626
+
627
+ let getSingleIndex = function (num) {
628
+ let ind = num;
629
+ for (let excludeInd of excludeIndices) {
630
+ if (ind >= excludeInd) {
631
+ ind++;
632
+ }
633
+ }
634
+
635
+ return ind;
636
+ };
637
+
638
+ if (numToSelect === 1) {
639
+ return {
640
+ success: true,
641
+ desiredVariant: { indices: [getSingleIndex(variantIndex - 1) + 1] },
642
+ };
643
+ }
644
+
645
+ let numbers = enumerateSelectionCombinations({
646
+ numberOfIndices: numToSelect,
647
+ numberOfOptions: nOptions,
648
+ maxNumber: variantIndex,
649
+ withReplacement,
650
+ })[variantIndex - 1];
651
+ let indices = numbers.map(getSingleIndex).map((x) => x + 1);
652
+ return { success: true, desiredVariant: { indices: indices } };
653
+ }
654
+ }
655
+
656
+ function makeSelection({ dependencyValues }) {
657
+ // console.log(`make selection`)
658
+ // console.log(dependencyValues)
659
+
660
+ if (dependencyValues.numToSelect < 1) {
661
+ return {
662
+ setEssentialValue: {
663
+ selectedValues: [],
664
+ selectedIndices: [],
665
+ },
666
+ setValue: {
667
+ selectedValues: [],
668
+ selectedIndices: [],
669
+ },
670
+ };
671
+ }
672
+
673
+ let numberUniqueRequired = 1;
674
+ if (!dependencyValues.withReplacement) {
675
+ numberUniqueRequired = dependencyValues.numToSelect;
676
+ }
677
+
678
+ if (numberUniqueRequired > dependencyValues.length) {
679
+ throw Error(
680
+ "Cannot select " +
681
+ numberUniqueRequired +
682
+ " values from a sequence of length " +
683
+ dependencyValues.length,
684
+ );
685
+ }
686
+
687
+ // if desiredIndices is specfied, use those
688
+ if (
689
+ dependencyValues.variants &&
690
+ dependencyValues.variants.desiredVariant !== undefined
691
+ ) {
692
+ let desiredIndices = dependencyValues.variants.desiredVariant.indices;
693
+ if (desiredIndices !== undefined) {
694
+ if (desiredIndices.length !== dependencyValues.numToSelect) {
695
+ throw Error(
696
+ "Number of indices specified for select must match number to select",
697
+ );
698
+ }
699
+ desiredIndices = desiredIndices.map(Number);
700
+ if (!desiredIndices.every(Number.isInteger)) {
701
+ throw Error("All indices specified for select must be integers");
702
+ }
703
+ let n = dependencyValues.length;
704
+ desiredIndices = desiredIndices.map((x) => ((((x - 1) % n) + n) % n) + 1);
705
+
706
+ let selectedValues = [];
707
+ for (let indexFrom1 of desiredIndices) {
708
+ let componentValue = returnSequenceValueForIndex({
709
+ index: indexFrom1 - 1,
710
+ from: dependencyValues.from,
711
+ step: dependencyValues.step,
712
+ length: dependencyValues.length,
713
+ exclude: dependencyValues.exclude,
714
+ type: dependencyValues.type,
715
+ lowercase: dependencyValues.lowercase,
716
+ });
717
+
718
+ if (componentValue === null) {
719
+ throw Error(
720
+ "Specified index of selectfromsequence that was excluded",
721
+ );
722
+ }
723
+
724
+ selectedValues.push(componentValue);
725
+ }
726
+
727
+ if (
728
+ checkForExcludedCombination({
729
+ type: dependencyValues.type,
730
+ excludedCombinations: dependencyValues.excludedCombinations,
731
+ values: selectedValues,
732
+ })
733
+ ) {
734
+ throw Error(
735
+ "Specified indices of selectfromsequence that was an excluded combination",
736
+ );
737
+ }
738
+
739
+ return {
740
+ setEssentialValue: { selectedValues, selectedIndices: desiredIndices },
741
+ setValue: { selectedValues, selectedIndices: desiredIndices },
742
+ };
743
+ }
744
+ }
745
+
746
+ let numberCombinationsExcluded = dependencyValues.excludedCombinations.length;
747
+
748
+ if (dependencyValues.type === "number") {
749
+ // account for fact that an excluded combination with a NaN is a wildcard
750
+ // this could be an overestimate, as different combinations could match the same value
751
+ numberCombinationsExcluded = 0;
752
+ let numValues = dependencyValues.length - dependencyValues.exclude.length;
753
+ for (let comb of dependencyValues.excludedCombinations) {
754
+ let numNans = comb.reduce((a, c) => a + (Number.isNaN(c) ? 1 : 0), 0);
755
+
756
+ if (numNans > 0) {
757
+ if (dependencyValues.withReplacement) {
758
+ numberCombinationsExcluded += Math.pow(numValues, numNans);
759
+ } else {
760
+ let n = numValues - dependencyValues.numToSelect + numNans;
761
+ let nExcl = n;
762
+ for (let i = 1; i < numNans; i++) {
763
+ nExcl *= n - i;
764
+ }
765
+ numberCombinationsExcluded += nExcl;
766
+ }
767
+ } else {
768
+ numberCombinationsExcluded += 1;
769
+ }
770
+ }
771
+ }
772
+
773
+ let selectedValues, selectedIndices;
774
+
775
+ if (numberCombinationsExcluded === 0) {
776
+ let selectedObj = selectValuesAndIndices({
777
+ stateValues: dependencyValues,
778
+ numberUniqueRequired: numberUniqueRequired,
779
+ numToSelect: dependencyValues.numToSelect,
780
+ withReplacement: dependencyValues.withReplacement,
781
+ rng: dependencyValues.variantRng,
782
+ });
783
+
784
+ selectedValues = selectedObj.selectedValues;
785
+ selectedIndices = selectedObj.selectedIndices;
786
+ } else {
787
+ let numberPossibilitiesLowerBound =
788
+ dependencyValues.length - dependencyValues.exclude.length;
789
+
790
+ if (dependencyValues.withReplacement) {
791
+ numberPossibilitiesLowerBound = Math.pow(
792
+ numberPossibilitiesLowerBound,
793
+ dependencyValues.numToSelect,
794
+ );
795
+ } else {
796
+ let n = numberPossibilitiesLowerBound;
797
+ for (let i = 1; i < dependencyValues.numToSelect; i++) {
798
+ numberPossibilitiesLowerBound *= n - i;
799
+ }
800
+ }
801
+
802
+ if (numberCombinationsExcluded > 0.7 * numberPossibilitiesLowerBound) {
803
+ // may have excluded over 70% of combinations
804
+ // need to determine actual number of possibilities
805
+ // to see if really have excluded that many combinations
806
+
807
+ let numberPossibilities = 0;
808
+ for (let index = 0; index < dependencyValues.length; index++) {
809
+ if (
810
+ returnSequenceValueForIndex({
811
+ index,
812
+ from: dependencyValues.from,
813
+ step: dependencyValues.step,
814
+ length: dependencyValues.length,
815
+ exclude: dependencyValues.exclude,
816
+ type: dependencyValues.type,
817
+ }) !== null
818
+ ) {
819
+ numberPossibilities++;
820
+ }
821
+ }
822
+
823
+ if (dependencyValues.withReplacement) {
824
+ numberPossibilities = Math.pow(
825
+ numberPossibilities,
826
+ dependencyValues.numToSelect,
827
+ );
828
+ } else {
829
+ let n = numberPossibilities;
830
+ for (let i = 1; i < dependencyValues.numToSelect; i++) {
831
+ numberPossibilities *= n - i;
832
+ }
833
+ }
834
+
835
+ if (numberCombinationsExcluded > 0.7 * numberPossibilities) {
836
+ if (
837
+ dependencyValues.type === "number" &&
838
+ dependencyValues.excludedCombinations.some((x) =>
839
+ x.some(Number.isNaN),
840
+ )
841
+ ) {
842
+ let numberDuplicated = estimateNumberOfDuplicateCombinations(
843
+ dependencyValues.excludedCombinations,
844
+ dependencyValues.length - dependencyValues.exclude.length,
845
+ dependencyValues.withReplacement,
846
+ );
847
+
848
+ numberCombinationsExcluded -= numberDuplicated;
849
+
850
+ if (numberCombinationsExcluded > 0.7 * numberPossibilities) {
851
+ throw Error(
852
+ "Excluded over 70% of combinations in selectFromSequence",
853
+ );
854
+ }
855
+ } else {
856
+ throw Error(
857
+ "Excluded over 70% of combinations in selectFromSequence",
858
+ );
859
+ }
860
+ }
861
+ }
862
+
863
+ // with 200 chances with at least 70% success,
864
+ // prob of failure less than 10^(-30)
865
+ let foundValidCombination = false;
866
+ for (let sampnum = 0; sampnum < 200; sampnum++) {
867
+ let selectedObj = selectValuesAndIndices({
868
+ stateValues: dependencyValues,
869
+ numberUniqueRequired: numberUniqueRequired,
870
+ numToSelect: dependencyValues.numToSelect,
871
+ withReplacement: dependencyValues.withReplacement,
872
+ rng: dependencyValues.variantRng,
873
+ });
874
+
875
+ selectedValues = selectedObj.selectedValues;
876
+ selectedIndices = selectedObj.selectedIndices;
877
+
878
+ // try again if hit excluded combination
879
+ if (
880
+ checkForExcludedCombination({
881
+ type: dependencyValues.type,
882
+ excludedCombinations: dependencyValues.excludedCombinations,
883
+ values: selectedValues,
884
+ })
885
+ ) {
886
+ continue;
887
+ }
888
+
889
+ foundValidCombination = true;
890
+ break;
891
+ }
892
+
893
+ if (!foundValidCombination) {
894
+ // this won't happen, as occurs with prob < 10^(-30)
895
+ throw Error(
896
+ "By extremely unlikely fluke, couldn't select combination of random values",
897
+ );
898
+ }
899
+ }
900
+
901
+ if (dependencyValues.sortResults) {
902
+ // combine selectedIndices and selectedValues to sort together
903
+ let combinedList = [];
904
+ for (let [ind, val] of selectedValues.entries()) {
905
+ combinedList.push({ value: val, index: selectedIndices[ind] });
906
+ }
907
+
908
+ if (dependencyValues.type === "number") {
909
+ combinedList.sort((a, b) => a.value - b.value);
910
+ } else if (dependencyValues.type === "letters") {
911
+ // sort according to their numerical value, not as words
912
+ combinedList.sort(
913
+ (a, b) => lettersToNumber(a.value) - lettersToNumber(b.value),
914
+ );
915
+ }
916
+
917
+ selectedValues = combinedList.map((x) => x.value);
918
+ selectedIndices = combinedList.map((x) => x.index);
919
+
920
+ // don't sort type math
921
+ }
922
+
923
+ return {
924
+ setEssentialValue: { selectedValues, selectedIndices },
925
+ setValue: { selectedValues, selectedIndices },
926
+ };
927
+ }
928
+
929
+ function selectValuesAndIndices({
930
+ stateValues,
931
+ numberUniqueRequired = 1,
932
+ numToSelect = 1,
933
+ withReplacement = false,
934
+ rng,
935
+ }) {
936
+ let selectedValues = [];
937
+ let selectedIndices = [];
938
+
939
+ if (
940
+ stateValues.exclude.length + numberUniqueRequired <
941
+ 0.5 * stateValues.length
942
+ ) {
943
+ // the simplest case where the likelihood of getting excluded is less than 50%
944
+ // just randomly select from all possibilities
945
+ // and use rejection method to resample if an excluded is hit
946
+ // or repeat a value when withReplacement=false
947
+
948
+ for (let ind = 0; ind < numToSelect; ind++) {
949
+ // with 100 chances with at least 50% success,
950
+ // prob of failure less than 10^(-30)
951
+ let foundValid = false;
952
+ let componentValue;
953
+ let selectedIndex;
954
+ for (let sampnum = 0; sampnum < 100; sampnum++) {
955
+ // random number in [0, 1)
956
+ let rand = rng();
957
+ // random integer from 1 to length
958
+ selectedIndex = Math.floor(rand * stateValues.length) + 1;
959
+
960
+ if (!withReplacement && selectedIndices.includes(selectedIndex)) {
961
+ continue;
962
+ }
963
+
964
+ componentValue = returnSequenceValueForIndex({
965
+ index: selectedIndex - 1,
966
+ from: stateValues.from,
967
+ step: stateValues.step,
968
+ exclude: stateValues.exclude,
969
+ type: stateValues.type,
970
+ lowercase: stateValues.lowercase,
971
+ });
972
+
973
+ // try again if hit excluded value
974
+ if (componentValue === null) {
975
+ continue;
976
+ }
977
+
978
+ foundValid = true;
979
+ break;
980
+ }
981
+
982
+ if (!foundValid) {
983
+ // this won't happen, as occurs with prob < 10^(-30)
984
+ throw Error(
985
+ "By extremely unlikely fluke, couldn't select random value",
986
+ );
987
+ }
988
+
989
+ selectedValues.push(componentValue);
990
+ selectedIndices.push(selectedIndex);
991
+ }
992
+
993
+ return { selectedValues, selectedIndices };
994
+ }
995
+
996
+ // for cases when a large fraction might be excluded
997
+ // we will generate the list of possible values and pick from those
998
+
999
+ let possibleValuesAndIndices = returnSequenceValues(stateValues, true);
1000
+
1001
+ let numPossibleValues = possibleValuesAndIndices.length;
1002
+
1003
+ if (numberUniqueRequired > numPossibleValues) {
1004
+ throw Error(
1005
+ "Cannot select " +
1006
+ numberUniqueRequired +
1007
+ " unique values from sequence of length " +
1008
+ numPossibleValues,
1009
+ );
1010
+ }
1011
+
1012
+ if (numberUniqueRequired === 1) {
1013
+ for (let ind = 0; ind < numToSelect; ind++) {
1014
+ // random number in [0, 1)
1015
+ let rand = rng();
1016
+ // random integer from 0 to numPossibleValues-1
1017
+ let ind = Math.floor(rand * numPossibleValues);
1018
+
1019
+ selectedIndices.push(possibleValuesAndIndices[ind].originalIndex + 1);
1020
+ selectedValues.push(possibleValuesAndIndices[ind].value);
1021
+ }
1022
+
1023
+ return { selectedValues, selectedIndices };
1024
+ }
1025
+
1026
+ // need to select more than one value without replacement
1027
+ // shuffle array and choose first elements
1028
+ // https://stackoverflow.com/a/12646864
1029
+ for (let i = possibleValuesAndIndices.length - 1; i > 0; i--) {
1030
+ const rand = rng();
1031
+ const j = Math.floor(rand * (i + 1));
1032
+ [possibleValuesAndIndices[i], possibleValuesAndIndices[j]] = [
1033
+ possibleValuesAndIndices[j],
1034
+ possibleValuesAndIndices[i],
1035
+ ];
1036
+ }
1037
+
1038
+ let selectedValuesAndIndices = possibleValuesAndIndices.slice(0, numToSelect);
1039
+ selectedValues = selectedValuesAndIndices.map((x) => x.value);
1040
+ selectedIndices = selectedValuesAndIndices.map((x) => x.originalIndex + 1);
1041
+
1042
+ return { selectedValues, selectedIndices };
1043
+ }
1044
+
1045
+ function checkForExcludedCombination({ type, excludedCombinations, values }) {
1046
+ if (type === "math") {
1047
+ return excludedCombinations.some((x) =>
1048
+ x.every((v, i) => v.equals(values[i])),
1049
+ );
1050
+ } else if (type === "number") {
1051
+ // if one entry of excluded combinations is NaN, then it is a wildcard
1052
+ // that will match any value
1053
+ return excludedCombinations.some((x) =>
1054
+ x.every(
1055
+ (v, i) =>
1056
+ Number.isNaN(v) ||
1057
+ Math.abs(v - values[i]) <=
1058
+ 1e-14 * Math.max(Math.abs(v), Math.abs(values[i])),
1059
+ ),
1060
+ );
1061
+ } else {
1062
+ return excludedCombinations.some((x) => x.every((v, i) => v === values[i]));
1063
+ }
1064
+ }
1065
+
1066
+ function mergeContainingCombinations(combinations) {
1067
+ if (combinations.length === 0) {
1068
+ return { merged: false, combinations: [] };
1069
+ }
1070
+
1071
+ let mergedCombinations = [combinations[0]];
1072
+
1073
+ let mergedAtLeastOne = false;
1074
+
1075
+ for (let comb of combinations.slice(1)) {
1076
+ let newCombinations = [];
1077
+ let merged = false;
1078
+
1079
+ for (let oldComb of mergedCombinations) {
1080
+ if (merged) {
1081
+ newCombinations.push(oldComb);
1082
+ continue;
1083
+ }
1084
+ let newComb = [];
1085
+ merged = true;
1086
+ let mergingInto = null;
1087
+ for (let k = 0; k < comb.length; k++) {
1088
+ let v1 = comb[k],
1089
+ v2 = oldComb[k];
1090
+ if (Number.isNaN(v1)) {
1091
+ if (Number.isNaN(v2)) {
1092
+ newComb.push(NaN);
1093
+ } else {
1094
+ // want to merge into 1
1095
+ if (mergingInto === 2) {
1096
+ // already merging into 2, so cannot merge
1097
+ merged = false;
1098
+ break;
1099
+ } else {
1100
+ newComb.push(NaN);
1101
+ mergingInto = 1;
1102
+ }
1103
+ }
1104
+ } else if (Number.isNaN(v2)) {
1105
+ // want to merge into 2
1106
+ if (mergingInto === 1) {
1107
+ // already merging into 1, so cannot merge
1108
+ merged = false;
1109
+ break;
1110
+ } else {
1111
+ newComb.push(NaN);
1112
+ mergingInto = 2;
1113
+ }
1114
+ } else {
1115
+ if (v1 === v2) {
1116
+ newComb.push(v1);
1117
+ } else {
1118
+ merged = false;
1119
+ break;
1120
+ }
1121
+ }
1122
+ }
1123
+
1124
+ if (merged) {
1125
+ newCombinations.push(newComb);
1126
+ } else {
1127
+ newCombinations.push(oldComb);
1128
+ }
1129
+ }
1130
+
1131
+ if (merged) {
1132
+ mergedAtLeastOne = true;
1133
+ } else {
1134
+ newCombinations.push(comb);
1135
+ }
1136
+
1137
+ mergedCombinations = newCombinations;
1138
+ }
1139
+
1140
+ return {
1141
+ merged: mergedAtLeastOne,
1142
+ combinations: mergedCombinations,
1143
+ };
1144
+ }
1145
+
1146
+ function estimateNumberOfDuplicateCombinations(
1147
+ combinations,
1148
+ numValues,
1149
+ withReplacement,
1150
+ ) {
1151
+ // if have wildcards, get better estimate of number excluded
1152
+
1153
+ let nCombs = combinations.length;
1154
+
1155
+ if (nCombs === 0) {
1156
+ return 0;
1157
+ }
1158
+
1159
+ let duplicateCombinations = [];
1160
+ for (let i = 0; i < nCombs; i++) {
1161
+ let comb1 = combinations[i];
1162
+ for (let j = i + 1; j < nCombs; j++) {
1163
+ let comb2 = combinations[j];
1164
+ let foundDuplicate = true;
1165
+ let duplicate = [];
1166
+ for (let k = 0; k < comb1.length; k++) {
1167
+ let v1 = comb1[k],
1168
+ v2 = comb2[k];
1169
+ if (Number.isNaN(v1)) {
1170
+ if (Number.isNaN(v2)) {
1171
+ duplicate.push(NaN);
1172
+ } else {
1173
+ duplicate.push(v2);
1174
+ }
1175
+ } else if (Number.isNaN(v2)) {
1176
+ duplicate.push(v1);
1177
+ } else {
1178
+ if (v1 === v2) {
1179
+ duplicate.push(v1);
1180
+ } else {
1181
+ foundDuplicate = false;
1182
+ break;
1183
+ }
1184
+ }
1185
+ }
1186
+
1187
+ if (foundDuplicate) {
1188
+ if (withReplacement) {
1189
+ duplicateCombinations.push(duplicate);
1190
+ } else {
1191
+ let nonNanEntries = duplicate.filter((x) => !Number.isNaN(x));
1192
+ if ([...new Set(nonNanEntries)].length === nonNanEntries.length) {
1193
+ duplicateCombinations.push(duplicate);
1194
+ }
1195
+ }
1196
+ }
1197
+ }
1198
+ }
1199
+
1200
+ // TODO: get a more accurate count of the number of excluded combinations.
1201
+ // This is just a heuristic to reduce the count
1202
+ while (true) {
1203
+ let result = mergeContainingCombinations(duplicateCombinations);
1204
+
1205
+ if (result.merged) {
1206
+ duplicateCombinations = result.combinations;
1207
+ } else {
1208
+ break;
1209
+ }
1210
+ }
1211
+
1212
+ let numberDuplicated = 0;
1213
+
1214
+ if (duplicateCombinations.length > 0) {
1215
+ for (let comb of duplicateCombinations) {
1216
+ let numNans = comb.reduce((a, c) => a + (Number.isNaN(c) ? 1 : 0), 0);
1217
+
1218
+ if (numNans > 0) {
1219
+ if (withReplacement) {
1220
+ numberDuplicated += Math.pow(numValues, numNans);
1221
+ } else {
1222
+ let n = numValues - comb.length + numNans;
1223
+ let nDup = n;
1224
+ for (let i = 1; i < numNans; i++) {
1225
+ nDup *= n - i;
1226
+ }
1227
+ numberDuplicated += nDup;
1228
+ }
1229
+ } else {
1230
+ numberDuplicated += 1;
1231
+ }
1232
+ }
1233
+ }
1234
+
1235
+ numberDuplicated -= estimateNumberOfDuplicateCombinations(
1236
+ duplicateCombinations,
1237
+ numValues,
1238
+ withReplacement,
1239
+ );
1240
+
1241
+ return numberDuplicated;
1242
+ }