diff --git a/e2e/integration_tests/backends_test.ts b/e2e/integration_tests/backends_test.ts index 139ede3ea84..06b819c8801 100644 --- a/e2e/integration_tests/backends_test.ts +++ b/e2e/integration_tests/backends_test.ts @@ -116,4 +116,80 @@ describe(`${SMOKE} backends`, () => { expect(after).toBe(webglBefore); }); }); + + it('can execute op with data from mixed backends', async () => { + const numTensors = tfc.memory().numTensors; + const webglNumDataIds = tfc.findBackend('webgl').numDataIds(); + const cpuNumDataIds = tfc.findBackend('cpu').numDataIds(); + + await tfc.setBackend('cpu'); + // This scalar lives in cpu. + const a = tfc.scalar(5); + + await tfc.setBackend('webgl'); + // This scalar lives in webgl. + const b = tfc.scalar(3); + + // Verify that ops can execute with mixed backend data. + tfc.engine().startScope(); + + await tfc.setBackend('cpu'); + const result = tfc.add(a, b); + tfc.test_util.expectArraysClose(await result.data(), [8]); + expect(tfc.findBackend('cpu').numDataIds()).toBe(cpuNumDataIds + 3); + + await tfc.setBackend('webgl'); + tfc.test_util.expectArraysClose(await tfc.add(a, b).data(), [8]); + expect(tfc.findBackend('webgl').numDataIds()).toBe(webglNumDataIds + 3); + + tfc.engine().endScope(); + + expect(tfc.memory().numTensors).toBe(numTensors + 2); + expect(tfc.findBackend('webgl').numDataIds()).toBe(webglNumDataIds + 2); + expect(tfc.findBackend('cpu').numDataIds()).toBe(cpuNumDataIds); + + tfc.dispose([a, b]); + + expect(tfc.memory().numTensors).toBe(numTensors); + expect(tfc.findBackend('webgl').numDataIds()).toBe(webglNumDataIds); + expect(tfc.findBackend('cpu').numDataIds()).toBe(cpuNumDataIds); + }); + + // tslint:disable-next-line: ban + xit('can move complex tensor from cpu to webgl.', async () => { + await tfc.setBackend('cpu'); + + const real1 = tfc.tensor1d([1]); + const imag1 = tfc.tensor1d([2]); + const complex1 = tfc.complex(real1, imag1); + + await tfc.setBackend('webgl'); + + const real2 = tfc.tensor1d([3]); + const imag2 = tfc.tensor1d([4]); + const complex2 = tfc.complex(real2, imag2); + + const result = complex1.add(complex2); + + tfc.test_util.expectArraysClose(await result.data(), [4, 6]); + }); + + // tslint:disable-next-line: ban + xit('can move complex tensor from webgl to cpu.', async () => { + await tfc.setBackend('webgl'); + + const real1 = tfc.tensor1d([1]); + const imag1 = tfc.tensor1d([2]); + const complex1 = tfc.complex(real1, imag1); + + await tfc.setBackend('cpu'); + + const real2 = tfc.tensor1d([3]); + const imag2 = tfc.tensor1d([4]); + const complex2 = tfc.complex(real2, imag2); + + const result = complex1.add(complex2); + + tfc.test_util.expectArraysClose(await result.data(), [4, 6]); + }); }); diff --git a/e2e/yarn.lock b/e2e/yarn.lock index c4566e401bc..0f69da94fa9 100644 --- a/e2e/yarn.lock +++ b/e2e/yarn.lock @@ -11,7 +11,7 @@ "@babel/compat-data@^7.10.4", "@babel/compat-data@^7.11.0": version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.11.0.tgz#e9f73efe09af1355b723a7f39b11bad637d7c99c" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.11.0.tgz#e9f73efe09af1355b723a7f39b11bad637d7c99c" integrity sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ== dependencies: browserslist "^4.12.0" @@ -19,18 +19,18 @@ semver "^5.5.0" "@babel/core@^7.11.1": - version "7.11.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.4.tgz#4301dfdfafa01eeb97f1896c5501a3f0655d4229" - integrity sha512-5deljj5HlqRXN+5oJTY7Zs37iH3z3b++KjiKtIsJy1NrjOOVSEaJHEetLBhyu0aQOSNNZ/0IuEAan9GzRuDXHg== + version "7.11.6" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651" + integrity sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg== dependencies: "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.4" + "@babel/generator" "^7.11.6" "@babel/helper-module-transforms" "^7.11.0" "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.11.4" + "@babel/parser" "^7.11.5" "@babel/template" "^7.10.4" - "@babel/traverse" "^7.11.0" - "@babel/types" "^7.11.0" + "@babel/traverse" "^7.11.5" + "@babel/types" "^7.11.5" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -40,25 +40,25 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.11.0", "@babel/generator@^7.11.4": - version "7.11.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.4.tgz#1ec7eec00defba5d6f83e50e3ee72ae2fee482be" - integrity sha512-Rn26vueFx0eOoz7iifCN2UHT6rGtnkSGWSoDRIy8jZN3B91PzeSULbswfLoOWuTuAcNwpG/mxy+uCTDnZ9Mp1g== +"@babel/generator@^7.11.5", "@babel/generator@^7.11.6": + version "7.11.6" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620" + integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA== dependencies: - "@babel/types" "^7.11.0" + "@babel/types" "^7.11.5" jsesc "^2.5.1" source-map "^0.5.0" "@babel/helper-annotate-as-pure@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== dependencies: "@babel/types" "^7.10.4" "@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" + resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== dependencies: "@babel/helper-explode-assignable-expression" "^7.10.4" @@ -66,7 +66,7 @@ "@babel/helper-compilation-targets@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2" integrity sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ== dependencies: "@babel/compat-data" "^7.10.4" @@ -77,7 +77,7 @@ "@babel/helper-create-class-features-plugin@^7.10.4": version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d" integrity sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A== dependencies: "@babel/helper-function-name" "^7.10.4" @@ -89,7 +89,7 @@ "@babel/helper-create-regexp-features-plugin@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" + resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== dependencies: "@babel/helper-annotate-as-pure" "^7.10.4" @@ -98,7 +98,7 @@ "@babel/helper-define-map@^7.10.4": version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30" + resolved "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30" integrity sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ== dependencies: "@babel/helper-function-name" "^7.10.4" @@ -107,14 +107,14 @@ "@babel/helper-explode-assignable-expression@^7.10.4": version "7.11.4" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz#2d8e3470252cc17aba917ede7803d4a7a276a41b" + resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz#2d8e3470252cc17aba917ede7803d4a7a276a41b" integrity sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ== dependencies: "@babel/types" "^7.10.4" "@babel/helper-function-name@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== dependencies: "@babel/helper-get-function-arity" "^7.10.4" @@ -123,35 +123,35 @@ "@babel/helper-get-function-arity@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== dependencies: "@babel/types" "^7.10.4" "@babel/helper-hoist-variables@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA== dependencies: "@babel/types" "^7.10.4" "@babel/helper-member-expression-to-functions@^7.10.4", "@babel/helper-member-expression-to-functions@^7.10.5": version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== dependencies: "@babel/types" "^7.11.0" "@babel/helper-module-imports@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== dependencies: "@babel/types" "^7.10.4" "@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.11.0": version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== dependencies: "@babel/helper-module-imports" "^7.10.4" @@ -164,26 +164,26 @@ "@babel/helper-optimise-call-expression@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== dependencies: "@babel/types" "^7.10.4" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== "@babel/helper-regex@^7.10.4": version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" + resolved "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== dependencies: lodash "^4.17.19" "@babel/helper-remap-async-to-generator@^7.10.4": version "7.11.4" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz#4474ea9f7438f18575e30b0cac784045b402a12d" + resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz#4474ea9f7438f18575e30b0cac784045b402a12d" integrity sha512-tR5vJ/vBa9wFy3m5LLv2faapJLnDFxNWff2SAYkSE4rLUdbp7CdObYFgI7wK4T/Mj4UzpjPwzR8Pzmr5m7MHGA== dependencies: "@babel/helper-annotate-as-pure" "^7.10.4" @@ -193,7 +193,7 @@ "@babel/helper-replace-supers@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== dependencies: "@babel/helper-member-expression-to-functions" "^7.10.4" @@ -203,7 +203,7 @@ "@babel/helper-simple-access@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== dependencies: "@babel/template" "^7.10.4" @@ -211,14 +211,14 @@ "@babel/helper-skip-transparent-expression-wrappers@^7.11.0": version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729" + resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729" integrity sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q== dependencies: "@babel/types" "^7.11.0" "@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== dependencies: "@babel/types" "^7.11.0" @@ -230,7 +230,7 @@ "@babel/helper-wrap-function@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" + resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug== dependencies: "@babel/helper-function-name" "^7.10.4" @@ -240,7 +240,7 @@ "@babel/helpers@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== dependencies: "@babel/template" "^7.10.4" @@ -256,14 +256,14 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.4": - version "7.11.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.4.tgz#6fa1a118b8b0d80d0267b719213dc947e88cc0ca" - integrity sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA== +"@babel/parser@^7.10.4", "@babel/parser@^7.11.5": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" + integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q== "@babel/plugin-proposal-async-generator-functions@^7.10.4": version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz#3491cabf2f7c179ab820606cec27fed15e0e8558" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz#3491cabf2f7c179ab820606cec27fed15e0e8558" integrity sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -272,7 +272,7 @@ "@babel/plugin-proposal-class-properties@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== dependencies: "@babel/helper-create-class-features-plugin" "^7.10.4" @@ -280,7 +280,7 @@ "@babel/plugin-proposal-dynamic-import@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e" integrity sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -288,7 +288,7 @@ "@babel/plugin-proposal-export-namespace-from@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz#570d883b91031637b3e2958eea3c438e62c05f54" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz#570d883b91031637b3e2958eea3c438e62c05f54" integrity sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -296,7 +296,7 @@ "@babel/plugin-proposal-json-strings@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db" integrity sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -304,7 +304,7 @@ "@babel/plugin-proposal-logical-assignment-operators@^7.11.0": version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz#9f80e482c03083c87125dee10026b58527ea20c8" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz#9f80e482c03083c87125dee10026b58527ea20c8" integrity sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -312,7 +312,7 @@ "@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -320,7 +320,7 @@ "@babel/plugin-proposal-numeric-separator@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06" integrity sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -328,7 +328,7 @@ "@babel/plugin-proposal-object-rest-spread@^7.11.0": version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -337,7 +337,7 @@ "@babel/plugin-proposal-optional-catch-binding@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd" integrity sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -345,7 +345,7 @@ "@babel/plugin-proposal-optional-chaining@^7.11.0": version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" integrity sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -354,7 +354,7 @@ "@babel/plugin-proposal-private-methods@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw== dependencies: "@babel/helper-create-class-features-plugin" "^7.10.4" @@ -362,7 +362,7 @@ "@babel/plugin-proposal-unicode-property-regex@^7.10.4", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.10.4" @@ -370,98 +370,98 @@ "@babel/plugin-syntax-async-generators@^7.8.0": version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-class-properties@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c" integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import@^7.8.0": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-export-namespace-from@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== dependencies: "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-json-strings@^7.8.0": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-numeric-separator@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.0": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding@^7.8.0": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-chaining@^7.8.0": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-top-level-await@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d" integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-arrow-functions@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd" integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-async-to-generator@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37" integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ== dependencies: "@babel/helper-module-imports" "^7.10.4" @@ -470,21 +470,21 @@ "@babel/plugin-transform-block-scoped-functions@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8" integrity sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-block-scoping@^7.10.4": version "7.11.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215" integrity sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-classes@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA== dependencies: "@babel/helper-annotate-as-pure" "^7.10.4" @@ -498,21 +498,21 @@ "@babel/plugin-transform-computed-properties@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb" integrity sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-destructuring@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-dotall-regex@^7.10.4", "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.10.4" @@ -520,14 +520,14 @@ "@babel/plugin-transform-duplicate-keys@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47" integrity sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-exponentiation-operator@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e" + resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e" integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw== dependencies: "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" @@ -535,14 +535,14 @@ "@babel/plugin-transform-for-of@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9" integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-function-name@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7" integrity sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg== dependencies: "@babel/helper-function-name" "^7.10.4" @@ -550,21 +550,21 @@ "@babel/plugin-transform-literals@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c" integrity sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-member-expression-literals@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7" + resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7" integrity sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-modules-amd@^7.10.4": version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz#1b9cddaf05d9e88b3aad339cb3e445c4f020a9b1" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz#1b9cddaf05d9e88b3aad339cb3e445c4f020a9b1" integrity sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw== dependencies: "@babel/helper-module-transforms" "^7.10.5" @@ -573,7 +573,7 @@ "@babel/plugin-transform-modules-commonjs@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w== dependencies: "@babel/helper-module-transforms" "^7.10.4" @@ -583,7 +583,7 @@ "@babel/plugin-transform-modules-systemjs@^7.10.4": version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz#6270099c854066681bae9e05f87e1b9cadbe8c85" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz#6270099c854066681bae9e05f87e1b9cadbe8c85" integrity sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw== dependencies: "@babel/helper-hoist-variables" "^7.10.4" @@ -593,7 +593,7 @@ "@babel/plugin-transform-modules-umd@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e" integrity sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA== dependencies: "@babel/helper-module-transforms" "^7.10.4" @@ -601,21 +601,21 @@ "@babel/plugin-transform-named-capturing-groups-regex@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6" integrity sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.10.4" "@babel/plugin-transform-new-target@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888" + resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888" integrity sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-object-super@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894" integrity sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -623,7 +623,7 @@ "@babel/plugin-transform-parameters@^7.10.4": version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a" integrity sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw== dependencies: "@babel/helper-get-function-arity" "^7.10.4" @@ -631,35 +631,35 @@ "@babel/plugin-transform-property-literals@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0" integrity sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-regenerator@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" + resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw== dependencies: regenerator-transform "^0.14.2" "@babel/plugin-transform-reserved-words@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd" + resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd" integrity sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-shorthand-properties@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-spread@^7.11.0": version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc" integrity sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -667,7 +667,7 @@ "@babel/plugin-transform-sticky-regex@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d" + resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d" integrity sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -675,7 +675,7 @@ "@babel/plugin-transform-template-literals@^7.10.4": version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c" integrity sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw== dependencies: "@babel/helper-annotate-as-pure" "^7.10.4" @@ -683,38 +683,38 @@ "@babel/plugin-transform-typeof-symbol@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc" integrity sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-unicode-escapes@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007" integrity sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-unicode-regex@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8" integrity sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" "@babel/polyfill@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.10.4.tgz#915e5bfe61490ac0199008e35ca9d7d151a8e45a" - integrity sha512-8BYcnVqQ5kMD2HXoHInBH7H1b/uP3KdnwCYXOqFnXqguOyuu443WXusbIUbWEfY3Z0Txk0M1uG/8YuAMhNl6zg== + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.11.5.tgz#df550b2ec53abbc2ed599367ec59e64c7a707bb5" + integrity sha512-FunXnE0Sgpd61pKSj2OSOs1D44rKTD3pGOfGilZ6LGrrIH0QEtJlTjqOqdF8Bs98JmjfGhni2BBkTfv9KcKJ9g== dependencies: core-js "^2.6.5" regenerator-runtime "^0.13.4" "@babel/preset-env@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.11.0.tgz#860ee38f2ce17ad60480c2021ba9689393efb796" - integrity sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg== + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.5.tgz#18cb4b9379e3e92ffea92c07471a99a2914e4272" + integrity sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA== dependencies: "@babel/compat-data" "^7.11.0" "@babel/helper-compilation-targets" "^7.10.4" @@ -778,7 +778,7 @@ "@babel/plugin-transform-unicode-escapes" "^7.10.4" "@babel/plugin-transform-unicode-regex" "^7.10.4" "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.11.0" + "@babel/types" "^7.11.5" browserslist "^4.12.0" core-js-compat "^3.6.2" invariant "^2.2.2" @@ -786,9 +786,9 @@ semver "^5.5.0" "@babel/preset-modules@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" - integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== + version "0.1.4" + resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" + integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" @@ -798,39 +798,39 @@ "@babel/runtime@^7.8.4": version "7.11.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== dependencies: regenerator-runtime "^0.13.4" "@babel/template@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== dependencies: "@babel/code-frame" "^7.10.4" "@babel/parser" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.0.tgz#9b996ce1b98f53f7c3e4175115605d56ed07dd24" - integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg== +"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3" + integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ== dependencies: "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.0" + "@babel/generator" "^7.11.5" "@babel/helper-function-name" "^7.10.4" "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.11.0" - "@babel/types" "^7.11.0" + "@babel/parser" "^7.11.5" + "@babel/types" "^7.11.5" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.4.4": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d" - integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA== +"@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.4.4": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" + integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q== dependencies: "@babel/helper-validator-identifier" "^7.10.4" lodash "^4.17.19" @@ -870,7 +870,7 @@ "@types/color-name@^1.1.1": version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== "@types/detect-browser@^4.0.0": @@ -901,9 +901,9 @@ form-data "^3.0.0" "@types/node@*": - version "14.0.26" - resolved "https://registry.npmjs.org/@types/node/-/node-14.0.26.tgz#22a3b8a46510da8944b67bfc27df02c34a35331c" - integrity sha512-W+fpe5s91FBGE0pEa0lnqGLL4USgpLgs4nokw16SrBBco/gQxuua7KnArSEOd5iaMqbbSHV10vUDkJYJJqpXKA== + version "14.6.4" + resolved "https://registry.npmjs.org/@types/node/-/node-14.6.4.tgz#a145cc0bb14ef9c4777361b7bbafa5cf8e3acb5a" + integrity sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ== "@types/offscreencanvas@~2019.3.0": version "2019.3.0" @@ -950,7 +950,7 @@ acorn-walk@^6.1.1: acorn-walk@^7.2.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== acorn@^6.0.5: @@ -975,10 +975,10 @@ agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" -ajv@^6.5.5: - version "6.12.3" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706" - integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA== +ajv@^6.12.3: + version "6.12.4" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234" + integrity sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" @@ -1016,7 +1016,7 @@ ansi-styles@^3.2.1: ansi-styles@^4.1.0: version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== dependencies: "@types/color-name" "^1.1.1" @@ -1060,7 +1060,7 @@ arg@^4.1.0: argparse@^1.0.10, argparse@^1.0.7: version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" @@ -1090,14 +1090,15 @@ arraybuffer.slice@~0.0.7: resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== -asn1.js@^4.0.0: - version "4.10.1" - resolved "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" - integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== dependencies: bn.js "^4.0.0" inherits "^2.0.1" minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" asn1@~0.2.3: version "0.2.4" @@ -1166,13 +1167,13 @@ aws-sign2@~0.7.0: integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: - version "1.10.0" - resolved "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" - integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA== + version "1.10.1" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428" + integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA== babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + resolved "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== dependencies: object.assign "^4.1.0" @@ -1255,9 +1256,9 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0: integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== bn.js@^5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0" - integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA== + version "5.1.3" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" + integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== body-parser@^1.16.1: version "1.19.0" @@ -1342,15 +1343,15 @@ browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: randombytes "^2.0.1" browserify-sign@^4.0.0: - version "4.2.0" - resolved "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz#545d0b1b07e6b2c99211082bf1b12cce7a0b0e11" - integrity sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA== + version "4.2.1" + resolved "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== dependencies: bn.js "^5.1.1" browserify-rsa "^4.0.1" create-hash "^1.2.0" create-hmac "^1.1.7" - elliptic "^6.5.2" + elliptic "^6.5.3" inherits "^2.0.4" parse-asn1 "^5.1.5" readable-stream "^3.6.0" @@ -1364,12 +1365,12 @@ browserify-zlib@^0.2.0: pako "~1.0.5" browserslist@^4.12.0, browserslist@^4.8.5: - version "4.14.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.0.tgz#2908951abfe4ec98737b72f34c3bcedc8d43b000" - integrity sha512-pUsXKAF2lVwhmtpeA3LJrZ76jXuusrNyhduuQs7CDFf9foT4Y38aQOserd2lMe5DSSrjf3fx34oHwryuvxAUgQ== + version "4.14.1" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.14.1.tgz#cb2b490ba881d45dc3039078c7ed04411eaf3fa3" + integrity sha512-zyBTIHydW37pnb63c7fHFXUG6EcqWOqoMdDx6cdyaDFriZ20EoVxcE95S54N+heRqY8m8IUgB5zYta/gCwSaaA== dependencies: - caniuse-lite "^1.0.30001111" - electron-to-chromium "^1.3.523" + caniuse-lite "^1.0.30001124" + electron-to-chromium "^1.3.562" escalade "^3.0.2" node-releases "^1.1.60" @@ -1467,10 +1468,10 @@ camelcase@^2.0.0: resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= -caniuse-lite@^1.0.30001111: - version "1.0.30001118" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001118.tgz#116a9a670e5264aec895207f5e918129174c6f62" - integrity sha512-RNKPLojZo74a0cP7jFMidQI7nvLER40HgNfgKQEJ2PFm225L0ectUungNQoK3Xk3StQcFbpBPNEvoWD59436Hg== +caniuse-lite@^1.0.30001124: + version "1.0.30001124" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001124.tgz#5d9998190258e11630d674fc50ea8e579ae0ced2" + integrity sha512-zQW8V3CdND7GHRH6rxm6s59Ww4g/qGWTheoboW9nfeMg7sUoopIfKCcNZUjwYRCOrvereh3kwDpZj4VLQ7zGtA== caseless@~0.12.0: version "0.12.0" @@ -1495,16 +1496,16 @@ chalk@^2.0.0, chalk@^2.3.0: chalk@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" chokidar@^3.0.0: - version "3.4.1" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.4.1.tgz#e905bdecf10eaa0a0b1db0c664481cc4cbc22ba1" - integrity sha512-TQTJyr2stihpC4Sya9hs2Xh+O2wf+igjL36Y75xx2WdHuiICcn/XJza46Jwt0eT5hVpQOzo3FpY3cj3RVYLX0g== + version "3.4.2" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d" + integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A== dependencies: anymatch "~3.1.1" braces "~3.0.2" @@ -1557,7 +1558,7 @@ color-convert@^1.9.0: color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" @@ -1569,7 +1570,7 @@ color-name@1.1.3: color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== colors@^1.1.0: @@ -1673,7 +1674,7 @@ cookie@0.3.1: core-js-compat@^3.6.2: version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" + resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng== dependencies: browserslist "^4.8.5" @@ -1686,7 +1687,7 @@ core-js@3, core-js@^3.1.3: core-js@^2.6.5: version "2.6.11" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== core-util-is@1.0.2, core-util-is@~1.0.0: @@ -1695,12 +1696,12 @@ core-util-is@1.0.2, core-util-is@~1.0.0: integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= create-ecdh@^4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" - integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + version "4.0.4" + resolved "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== dependencies: bn.js "^4.1.0" - elliptic "^6.0.0" + elliptic "^6.5.3" create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: version "1.2.0" @@ -1768,7 +1769,7 @@ date-format@^2.0.0, date-format@^2.1.0: date-format@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/date-format/-/date-format-3.0.0.tgz#eb8780365c7d2b1511078fb491e6479780f3ad95" + resolved "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz#eb8780365c7d2b1511078fb491e6479780f3ad95" integrity sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w== dateformat@^1.0.6: @@ -1933,12 +1934,12 @@ ee-first@1.1.1: resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.523: - version "1.3.550" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.550.tgz#bf9bbb78182aac0fe2d23d3bd1483dde4483f512" - integrity sha512-MWDHoJsSieBaJ6mObvi3V0eKZufR1iMJl56VIGdXCgFHyCUbVDGm2IMXUNjDxgbGbKa3tA5+zJmHuBQqRxGiLA== +electron-to-chromium@^1.3.562: + version "1.3.564" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.564.tgz#e9c319ae437b3eb8bbf3e3bae4bead5a21945961" + integrity sha512-fNaYN3EtKQWLQsrKXui8mzcryJXuA0LbCLoizeX6oayG2emBaS5MauKjCPAvc29NEY4FpLHIUWiP+Y0Bfrs5dg== -elliptic@^6.0.0, elliptic@^6.5.2: +elliptic@^6.5.3: version "6.5.3" resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw== @@ -2053,7 +2054,7 @@ es6-promisify@^5.0.0: escalade@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4" integrity sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ== escape-html@~1.0.3: @@ -2104,9 +2105,9 @@ esutils@^2.0.2: integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== eventemitter3@^4.0.0: - version "4.0.4" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" - integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== + version "4.0.7" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== events@^3.0.0: version "3.2.0" @@ -2193,9 +2194,9 @@ flatted@^2.0.0, flatted@^2.0.1: integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== follow-redirects@^1.0.0: - version "1.12.1" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.12.1.tgz#de54a6205311b93d60398ebc01cf7015682312b6" - integrity sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg== + version "1.13.0" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" + integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== foreach@^2.0.5: version "2.0.5" @@ -2248,7 +2249,7 @@ fs-extra@^7.0.1: fs-extra@^8.1.0: version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== dependencies: graceful-fs "^4.2.0" @@ -2303,7 +2304,7 @@ gauge@~2.7.3: gensync@^1.0.0-beta.1: version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== get-stdin@^4.0.1: @@ -2350,13 +2351,13 @@ glob@^7.0.0, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3: globals@^11.1.0: version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== google-protobuf@^3.9.2: - version "3.12.2" - resolved "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" - integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== + version "3.13.0" + resolved "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.13.0.tgz#909c5983d75dd6101ed57c79e0528d000cdc3251" + integrity sha512-ZIf3qfLFayVrPvAjeKKxO5FRF1/NwRxt6Dko+fWEMuHwHbZx8/fcaAao9b0wCM6kr8qeg2te8XTpyuvKuD9aKw== graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.4" @@ -2381,11 +2382,11 @@ har-schema@^2.0.0: integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + version "5.1.5" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== dependencies: - ajv "^6.5.5" + ajv "^6.12.3" har-schema "^2.0.0" has-binary2@~1.0.2: @@ -2412,7 +2413,7 @@ has-flag@^3.0.0: has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-symbols@^1.0.0, has-symbols@^1.0.1: @@ -2568,7 +2569,7 @@ inline-source-map@~0.6.0: invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== dependencies: loose-envify "^1.0.0" @@ -2661,9 +2662,9 @@ is-plain-object@^2.0.4: isobject "^3.0.1" is-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff" - integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw== + version "1.1.1" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" + integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== dependencies: has-symbols "^1.0.1" @@ -2784,12 +2785,12 @@ jsbn@~0.1.0: jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== jsesc@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= json-schema-traverse@^0.4.1: @@ -2809,7 +2810,7 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: json5@^2.1.2: version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + resolved "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== dependencies: minimist "^1.2.5" @@ -2866,7 +2867,7 @@ karma-jasmine@~1.1.0: karma-typescript-es6-transform@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/karma-typescript-es6-transform/-/karma-typescript-es6-transform-5.1.0.tgz#8e22349f45c6308598c2447c5ca911ce9d9577d1" + resolved "https://registry.npmjs.org/karma-typescript-es6-transform/-/karma-typescript-es6-transform-5.1.0.tgz#8e22349f45c6308598c2447c5ca911ce9d9577d1" integrity sha512-ReniuuReJ6J+ul4ewndMjB3CKOET1a+b8ta7XI4yvGLFjyo2wLJZ+eM/cWrQqnO7aKenLchYJ1B71XM5pF1a8g== dependencies: "@babel/core" "^7.11.1" @@ -2957,12 +2958,12 @@ karma@~4.2.0: leven@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== levenary@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + resolved "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== dependencies: leven "^3.1.0" @@ -2996,14 +2997,9 @@ lodash.memoize@~3.0.3: resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" integrity sha1-LcvSwofLwKVcxCMovQxzYVDVPj8= -lodash@^4.17.0, lodash@^4.17.11, lodash@^4.17.14: - version "4.17.19" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" - integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== - -lodash@^4.17.19: +lodash@^4.17.0, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.19: version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== log4js@^4.0.0, log4js@^4.0.1: @@ -3019,7 +3015,7 @@ log4js@^4.0.0, log4js@^4.0.1: log4js@^6.3.0: version "6.3.0" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb" + resolved "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb" integrity sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw== dependencies: date-format "^3.0.0" @@ -3030,7 +3026,7 @@ log4js@^6.3.0: loose-envify@^1.0.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" @@ -3053,7 +3049,7 @@ lru-cache@4.1.x: magic-string@^0.25.7: version "0.25.7" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== dependencies: sourcemap-codec "^1.4.4" @@ -3197,9 +3193,9 @@ ms@^2.1.1: integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== needle@^2.2.1: - version "2.5.0" - resolved "https://registry.npmjs.org/needle/-/needle-2.5.0.tgz#e6fc4b3cc6c25caed7554bd613a5cf0bac8c31c0" - integrity sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA== + version "2.5.2" + resolved "https://registry.npmjs.org/needle/-/needle-2.5.2.tgz#cf1a8fce382b5a280108bba90a14993c00e4010a" + integrity sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ== dependencies: debug "^3.2.6" iconv-lite "^0.4.4" @@ -3238,7 +3234,7 @@ node-pre-gyp@0.14.0: node-releases@^1.1.60: version "1.1.60" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.60.tgz#6948bdfce8286f0b5d0e5a88e8384e954dfe7084" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz#6948bdfce8286f0b5d0e5a88e8384e954dfe7084" integrity sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA== nopt@3.x: @@ -3425,13 +3421,12 @@ pako@~1.0.5: integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.5" - resolved "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" - integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ== + version "5.1.6" + resolved "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== dependencies: - asn1.js "^4.0.0" + asn1.js "^5.2.0" browserify-aes "^1.0.0" - create-hash "^1.1.0" evp_bytestokey "^1.0.0" pbkdf2 "^3.0.3" safe-buffer "^5.1.1" @@ -3719,14 +3714,14 @@ redent@^1.0.0: regenerate-unicode-properties@^8.2.0: version "8.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== dependencies: regenerate "^1.4.0" regenerate@^1.4.0: version "1.4.1" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5: @@ -3736,14 +3731,14 @@ regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5: regenerator-transform@^0.14.2: version "0.14.5" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== dependencies: "@babel/runtime" "^7.8.4" regexpu-core@^4.7.0: version "4.7.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== dependencies: regenerate "^1.4.0" @@ -3755,12 +3750,12 @@ regexpu-core@^4.7.0: regjsgen@^0.5.1: version "0.5.2" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== regjsparser@^0.6.4: version "0.6.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== dependencies: jsesc "~0.5.0" @@ -3883,7 +3878,7 @@ seedrandom@2.4.3: semver@7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== set-blocking@~2.0.0: @@ -3992,7 +3987,7 @@ source-map@~0.2.0: sourcemap-codec@^1.4.4: version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== spdx-correct@^3.0.0: @@ -4077,7 +4072,7 @@ streamroller@^1.0.6: streamroller@^2.2.4: version "2.2.4" - resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-2.2.4.tgz#c198ced42db94086a6193608187ce80a5f2b0e53" + resolved "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz#c198ced42db94086a6193608187ce80a5f2b0e53" integrity sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ== dependencies: date-format "^2.1.0" @@ -4179,9 +4174,9 @@ supports-color@^5.3.0: has-flag "^3.0.0" supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" @@ -4247,7 +4242,7 @@ to-array@0.1.4: to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-regex-range@^5.0.1: @@ -4397,9 +4392,9 @@ typescript@3.5.3: integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== uglify-js@^3.1.4: - version "3.10.0" - resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz#397a7e6e31ce820bfd1cb55b804ee140c587a9e7" - integrity sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA== + version "3.10.4" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.4.tgz#dd680f5687bc0d7a93b14a3482d16db6eba2bfbb" + integrity sha512-kBFT3U4Dcj4/pJ52vfjCSfyLyvG9VYYuGYPmrPvAxRw/i7xHiT4VvCev+uiEMcEEiu6UNB6KgWmGtSUYIWScbw== ultron@~1.1.0: version "1.1.1" @@ -4408,12 +4403,12 @@ ultron@~1.1.0: unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== unicode-match-property-ecmascript@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== dependencies: unicode-canonical-property-names-ecmascript "^1.0.4" @@ -4421,12 +4416,12 @@ unicode-match-property-ecmascript@^1.0.4: unicode-match-property-value-ecmascript@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== unicode-property-aliases-ecmascript@^1.0.4: version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== universalify@^0.1.0: @@ -4455,9 +4450,9 @@ unzipper@^0.9.3: setimmediate "~1.0.4" uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + version "4.4.0" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" + integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== dependencies: punycode "^2.1.0" diff --git a/tfjs-backend-cpu/src/backend_cpu.ts b/tfjs-backend-cpu/src/backend_cpu.ts index b80f7b9abe9..e0736c021bb 100644 --- a/tfjs-backend-cpu/src/backend_cpu.ts +++ b/tfjs-backend-cpu/src/backend_cpu.ts @@ -52,10 +52,8 @@ export interface TensorData { dtype: D; // For complex numbers, the real and imaginary parts are stored as their own // individual tensors, with a parent joining the two with the - // complexTensors field. - // TODO(smilkov): Replace Tensor with TensorInfo when you modularize ops - // that work with complex tensors. - complexTensors?: {real: Tensor, imag: Tensor}; + // complexTensorInfos field. + complexTensorInfos?: {real: TensorInfo, imag: TensorInfo}; // refCount keeps track of how many tensors reference it. Used for memory // management. refCount: number; @@ -97,6 +95,20 @@ export class MathBackendCPU extends KernelBackend { return dataId; } + /** + * Create a data bucket in cpu backend. + * @param shape Shape of the `TensorInfo`. + * @param dtype DType of the `TensorInfo`. + * @param values The value of the `TensorInfo` stored as a flattened array. + */ + makeTensorInfo( + shape: number[], dtype: DataType, + values?: backend_util.BackendValues): TensorInfo { + const outId = this.write(values, shape, dtype); + + return {dataId: outId, shape, dtype}; + } + /** Increase refCount of a `TensorData`. */ incRef(dataId: DataId): void { const tensorData = this.data.get(dataId); @@ -125,14 +137,16 @@ export class MathBackendCPU extends KernelBackend { return this.readSync(dataId); } readSync(dataId: DataId): backend_util.BackendValues { - const {dtype, complexTensors} = this.data.get(dataId); + const {dtype, complexTensorInfos} = this.data.get(dataId); + if (dtype === 'complex64') { const realValues = - this.readSync(complexTensors.real.dataId) as Float32Array; + this.readSync(complexTensorInfos.real.dataId) as Float32Array; const imagValues = - this.readSync(complexTensors.imag.dataId) as Float32Array; + this.readSync(complexTensorInfos.imag.dataId) as Float32Array; return backend_util.mergeRealAndImagArrays(realValues, imagValues); } + return this.data.get(dataId).values; } @@ -158,11 +172,13 @@ export class MathBackendCPU extends KernelBackend { disposeData(dataId: DataId): void { if (this.data.has(dataId)) { - const {complexTensors} = this.data.get(dataId); - if (complexTensors != null) { - complexTensors.real.dispose(); - complexTensors.imag.dispose(); + const {complexTensorInfos} = this.data.get(dataId); + + if (complexTensorInfos != null) { + this.disposeData(complexTensorInfos.real.dataId); + this.disposeData(complexTensorInfos.imag.dataId); } + this.data.delete(dataId); } } @@ -198,52 +214,6 @@ export class MathBackendCPU extends KernelBackend { }; } - complex(real: T, imag: T): T { - const result = this.makeOutput(null, real.shape, 'complex64'); - - const resultData = this.data.get(result.dataId); - // The backend owns the reference to the underlying real and imaginary - // clones. These will explicitly get disposed when the complex tensor is - // disposed. - resultData.complexTensors = { - real: engine().keep(real.clone()), - imag: engine().keep(imag.clone()) - }; - - return result as T; - } - real(input: T): T { - const resultData = this.data.get(input.dataId); - return resultData.complexTensors.real.clone() as T; - } - imag(input: T): T { - const resultData = this.data.get(input.dataId); - return resultData.complexTensors.imag.clone() as T; - } - - slice(x: T, begin: number[], size: number[]): T { - assertNotComplex(x, 'slice'); - - const isContinous = slice_util.isSliceContinous(x.shape, begin, size); - if (isContinous) { - const flatOffset = slice_util.computeFlatOffset(begin, x.strides); - const length = util.sizeFromShape(size); - const vals = this.readSync(x.dataId) as TypedArray; - return tf.tensor( - vals.subarray(flatOffset, flatOffset + length), size, - x.dtype) as T; - } - - const buffer = tf.buffer(size, x.dtype); - const xBuf = this.bufferSync(x); - for (let i = 0; i < buffer.size; ++i) { - const loc = buffer.indexToLoc(i); - const xLoc = loc.map((idx, j) => idx + begin[j]); - buffer.values[i] = xBuf.get(...xLoc); - } - return buffer.toTensor() as T; - } - stridedSlice( x: T, begin: number[], end: number[], strides: number[]): T { assertNotComplex(x, 'stridedSlice'); @@ -295,7 +265,7 @@ export class MathBackendCPU extends KernelBackend { const res = new Array(num); for (let i = 0; i < res.length; i++) { begin[axis] = i; - res[i] = this.slice(x, begin, size).reshape(outShape); + res[i] = tf.slice(x, begin, size).reshape(outShape); } return res; } @@ -316,66 +286,11 @@ export class MathBackendCPU extends KernelBackend { return buffer.toTensor() as T; } - concat(tensors: Tensor[], axis: number): Tensor { - if (tensors[0].dtype === 'complex64') { - const reals = tensors.map((t) => tf.real(t)); - const imags = tensors.map((t) => tf.imag(t)); - return tf.complex(this.concat(reals, axis), this.concat(imags, axis)); - } - const tensors2D = tensors.map(t => { - const innerSize = util.sizeFromShape(t.shape.slice(axis)); - return t.as2D(-1, innerSize); - }); - const outShape = - backend_util.computeOutShape(tensors2D.map(t => t.shape), 1 /* axis - */); - const values = - tf.buffer(outShape as [number, number], tensors[0].dtype as 'float32') - .values; - if (tensors2D[0].shape[0] === 1) { - // Use built-in TypedArray.set() method for speed. - let offset = 0; - tensors2D.forEach(t => { - values.set(this.readSync(t.dataId) as TypedArray, offset); - offset += t.size; - }); - } else { - let colOffset = 0; - tensors2D.forEach(t => { - const tVals = this.readSync(t.dataId) as TypedArray; - let tIdx = 0; - for (let row = 0; row < t.shape[0]; ++row) { - const resIdx = row * outShape[1] + colOffset; - for (let col = 0; col < t.shape[1]; ++col) { - values[resIdx + col] = tVals[tIdx++]; - } - } - colOffset += t.shape[1]; - }); - } - const finalOutShape = - backend_util.computeOutShape(tensors.map(t => t.shape), axis); - return tf.tensor(values, finalOutShape, tensors[0].dtype); - } - neg(x: T): T { assertNotComplex(x, 'neg'); - return this.multiply(tf.scalar(-1), x) as T; - } - - add(a: Tensor, b: Tensor): Tensor { - if (a.dtype === 'complex64' || b.dtype === 'complex64') { - return this.broadcastedBinaryComplexOp( - a.cast('complex64'), b.cast('complex64'), - (aReal, aImag, bReal, bImag) => { - return {real: aReal + bReal, imag: aImag + bImag}; - }); - } - - return this.broadcastedBinaryOp( - a, b, upcastType(a.dtype, b.dtype), - (aValue, bValue) => aValue + bValue); + // TODO(lina128): Use mul directly once neg is modularized. + return tf.mul(tf.scalar(-1), x); } addN(tensors: T[]): T { @@ -400,7 +315,9 @@ export class MathBackendCPU extends KernelBackend { const maxLogit = max(logits, axes); const expandedShape = backend_util.expandShapeToKeepDim(maxLogit.shape, axes); - const a = this.subtract(logits, maxLogit.reshape(expandedShape)); + + // TODO(lina128): Use sub directly once softmax is modularized. + const a = tf.sub(logits, maxLogit.reshape(expandedShape)); const b = this.exp(a); const sumExp = this.sum(b, axes).reshape(expandedShape); @@ -409,20 +326,6 @@ export class MathBackendCPU extends KernelBackend { return tf.div(b, sumExp); } - subtract(a: Tensor, b: Tensor): Tensor { - if (a.dtype === 'complex64' || b.dtype === 'complex64') { - return this.broadcastedBinaryComplexOp( - a.cast('complex64'), b.cast('complex64'), - (aReal, aImag, bReal, bImag) => { - return {real: aReal - bReal, imag: aImag - bImag}; - }); - } - - return this.broadcastedBinaryOp( - a, b, upcastType(a.dtype, b.dtype), - (aValue, bValue) => aValue - bValue); - } - pow(a: T, b: Tensor): T { assertNotComplex([a, b], 'pow'); @@ -487,7 +390,8 @@ export class MathBackendCPU extends KernelBackend { backend_util.FusedBatchMatMulConfig): Tensor3D { let result = this.batchMatMul(a, b, transposeA, transposeB); if (bias) { - result = this.add(result, bias) as Tensor3D; + // TODO(lina128): Use add directly once fusedBatchMatMul is modularized. + result = tf.add(result, bias); } if (activation) { result = @@ -498,23 +402,6 @@ export class MathBackendCPU extends KernelBackend { return result; } - multiply(a: Tensor, b: Tensor): Tensor { - if (a.dtype === 'complex64' || b.dtype === 'complex64') { - return this.broadcastedBinaryComplexOp( - a.cast('complex64'), b.cast('complex64'), - (aReal, aImag, bReal, bImag) => { - return { - real: aReal * bReal - aImag * bImag, - imag: aReal * bImag + aImag * bReal - }; - }); - } - - return this.broadcastedBinaryOp( - a, b, upcastType(a.dtype, b.dtype), - (aValue, bValue) => aValue * bValue); - } - floorDiv(a: Tensor, b: Tensor): Tensor { assertNotComplex([a, b], 'floorDiv'); @@ -1208,17 +1095,6 @@ export class MathBackendCPU extends KernelBackend { return this.makeOutput(resultValues, x.shape, 'float32'); } - int(x: T): T { - assertNotComplex(x, 'int'); - - const resultValues = new Int32Array(x.size); - const values = this.readSync(x.dataId) as TypedArray; - for (let i = 0; i < values.length; ++i) { - resultValues[i] = values[i]; - } - return this.makeOutput(resultValues, x.shape, 'int32'); - } - sigmoid(x: T): T { assertNotComplex(x, 'sigmoid'); @@ -1442,7 +1318,8 @@ export class MathBackendCPU extends KernelBackend { let result = this.conv2d(input, filter, convInfo); if (bias) { - result = this.add(result, bias) as Tensor4D; + // TODO(lina128): Use add directly once fusedConv2d is modularized. + result = tf.add(result, bias); } if (activation) { result = @@ -1891,7 +1768,9 @@ export class MathBackendCPU extends KernelBackend { let result = this.depthwiseConv2D(input, filter, convInfo); if (bias) { - result = this.add(result, bias) as Tensor4D; + // TODO(lina128): Use add directly once fusedDepthwiseConv2D is + // modularized. + result = tf.add(result, bias); } if (activation) { result = @@ -2599,10 +2478,6 @@ export class MathBackendCPU extends KernelBackend { return dx.toTensor(); } - cast(x: T, dtype: DataType): T { - return backend_util.castTensor(x, dtype, this); - } - avgPool(x: Tensor4D, convInfo: backend_util.Conv2DInfo): Tensor4D { assertNotComplex(x, 'avgPool'); assertNotComplex(x, 'maxPool'); @@ -3089,123 +2964,6 @@ export class MathBackendCPU extends KernelBackend { boxesVals, scoresVals, maxOutputSize, iouThreshold, scoreThreshold); } - fft(x: Tensor2D): Tensor2D { - return this.fftBatch(x, false); - } - - ifft(x: Tensor2D): Tensor2D { - return this.fftBatch(x, true); - } - - /** - * Calculate FFT of inner most elements of batch tensor. - */ - private fftBatch(x: Tensor2D, inverse: boolean): Tensor2D { - const batch = x.shape[0]; - const innerDim = x.shape[1]; - // Collects real and imaginary values separately. - const realResult = tf.buffer(x.shape, 'float32'); - const imagResult = tf.buffer(x.shape, 'float32'); - - const real = tf.real(x).as2D(batch, innerDim); - const imag = tf.imag(x).as2D(batch, innerDim); - - for (let b = 0; b < batch; b++) { - // TODO: Support slice ops for complex type. - const r = real.slice([b, 0], [1, innerDim]); - const i = imag.slice([b, 0], [1, innerDim]); - const input = tf.complex(r, i); - // Run FFT by batch element. - const res = - this.readSync(this.fftImpl(input, inverse).dataId) as Float32Array; - for (let d = 0; d < innerDim; d++) { - const c = backend_util.getComplexWithIndex(res, d); - realResult.values[b * innerDim + d] = c.real; - imagResult.values[b * innerDim + d] = c.imag; - } - } - - const t = tf.complex(realResult.toTensor(), imagResult.toTensor()); - return t.as2D(batch, innerDim); - } - - private fftImpl(x: Tensor2D, inverse: boolean): Tensor2D { - const x1D = x.as1D(); - - const n = x1D.size; - - if (this.isExponentOf2(n)) { - let result = this.fftRadix2(x1D, n, inverse).as2D(x.shape[0], x.shape[1]); - if (inverse) { - result = tf.complex( - tf.real(result).div(tf.scalar(n)), - tf.imag(result).div(tf.scalar(n))) as Tensor2D; - } - return result; - } else { - const data = this.readSync(x.dataId) as TypedArray; - const rawOutput = - this.fourierTransformByMatmul(data, n, inverse) as Float32Array; - const output = backend_util.splitRealAndImagArrays(rawOutput); - return tf.complex(output.real, output.imag).as2D(x.shape[0], x.shape[1]); - } - } - - private isExponentOf2(size: number): boolean { - return (size & size - 1) === 0; - } - - // FFT using Cooley-Tukey algorithm on radix 2 dimensional input. - private fftRadix2(input: Tensor1D, size: number, inverse: boolean): Tensor1D { - if (size === 1) { - return input; - } - const data = this.readSync(input.dataId) as TypedArray as Float32Array; - const half = size / 2; - const evenComplex = backend_util.complexWithEvenIndex(data); - let evenTensor = tf.complex(evenComplex.real, evenComplex.imag).as1D(); - const oddComplex = backend_util.complexWithOddIndex(data); - let oddTensor = tf.complex(oddComplex.real, oddComplex.imag).as1D(); - - // Recursive call for half part of original input. - evenTensor = this.fftRadix2(evenTensor, half, inverse); - oddTensor = this.fftRadix2(oddTensor, half, inverse); - - const e = backend_util.exponents(size, inverse); - const exponent = tf.complex(e.real, e.imag).mul(oddTensor); - - const addPart = evenTensor.add(exponent); - const subPart = evenTensor.sub(exponent); - - const realTensor = tf.real(addPart).concat(tf.real(subPart)); - const imagTensor = tf.imag(addPart).concat(tf.imag(subPart)); - - return tf.complex(realTensor, imagTensor).as1D(); - } - - // Calculate fourier transform by multplying sinusoid matrix. - private fourierTransformByMatmul( - data: TypedArray, size: number, inverse: boolean): TypedArray { - const ret = new Float32Array(size * 2); - // TODO: Use matmul instead once it supports complex64 type. - for (let r = 0; r < size; r++) { - let real = 0.0; - let imag = 0.0; - for (let c = 0; c < size; c++) { - const e = backend_util.exponent(r * c, size, inverse); - const term = backend_util.getComplexWithIndex(data as Float32Array, c); - real += term.real * e.real - term.imag * e.imag; - imag += term.real * e.imag + term.imag * e.real; - } - if (inverse) { - real /= size; - imag /= size; - } - backend_util.assignToTypedArray(ret, real, imag, r); - } - return ret; - } - depthToSpace(x: Tensor4D, blockSize: number, dataFormat: 'NHWC'|'NCHW'): Tensor4D { util.assert( @@ -3287,62 +3045,6 @@ export class MathBackendCPU extends KernelBackend { return result.toTensor(); } - private broadcastedBinaryComplexOp( - a: Tensor, b: Tensor, - op: - (aReal: number, aImag: number, bReal: number, - bImag: number) => {real: number, imag: number}): Tensor { - const newShape = backend_util.assertAndGetBroadcastShape(a.shape, b.shape); - const realResult = tf.buffer(newShape, 'float32'); - const imagResult = tf.buffer(newShape, 'float32'); - - const aVals = this.readSync(a.dataId) as TypedArray; - const bVals = this.readSync(b.dataId) as TypedArray; - const aBroadcastDims = backend_util.getBroadcastDims(a.shape, newShape); - const bBroadcastDims = backend_util.getBroadcastDims(b.shape, newShape); - - const realVals = realResult.values; - const imagVals = imagResult.values; - - if (aBroadcastDims.length + bBroadcastDims.length === 0) { - for (let i = 0; i < realVals.length; i++) { - const aIdx = i % aVals.length; - const bIdx = i % bVals.length; - - const result = - op(aVals[aIdx * 2], aVals[aIdx * 2 + 1], bVals[bIdx * 2], - bVals[bIdx * 2 + 1]); - - realVals[i] = result.real; - imagVals[i] = result.imag; - } - } else { - const aRealBuf = - this.bufferSync(this.data.get(a.dataId).complexTensors.real); - const bRealBuf = - this.bufferSync(this.data.get(b.dataId).complexTensors.real); - for (let i = 0; i < realVals.length; i++) { - const loc = realResult.indexToLoc(i); - - const aLoc = loc.slice(-a.rank); - aBroadcastDims.forEach(d => aLoc[d] = 0); - const aIndex = aRealBuf.locToIndex(aLoc); - - const bLoc = loc.slice(-b.rank); - bBroadcastDims.forEach(d => bLoc[d] = 0); - const bIndex = bRealBuf.locToIndex(bLoc); - - const opResult = - op(aVals[aIndex * 2], aVals[aIndex * 2 + 1], bVals[bIndex * 2], - bVals[bIndex * 2 + 1]); - - realVals[i] = opResult.real; - imagVals[i] = opResult.imag; - } - } - return this.complex(realResult.toTensor(), imagResult.toTensor()); - } - split(x: T, sizeSplits: number[], axis: number): T[] { return split(x, sizeSplits, axis); } diff --git a/tfjs-backend-cpu/src/kernels/Add.ts b/tfjs-backend-cpu/src/kernels/Add.ts new file mode 100644 index 00000000000..34f46ace993 --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/Add.ts @@ -0,0 +1,30 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {Add, KernelConfig} from '@tensorflow/tfjs-core'; +import {binaryKernelFunc} from '../utils/kernel_utils'; + +export const add = + binaryKernelFunc(Add, ((a, b) => a + b), ((aReal, aImag, bReal, bImag) => { + return {real: aReal + bReal, imag: aImag + bImag}; + })); + +export const addConfig: KernelConfig = { + kernelName: Add, + backendName: 'cpu', + kernelFunc: add +}; diff --git a/tfjs-backend-cpu/src/kernels/Cast.ts b/tfjs-backend-cpu/src/kernels/Cast.ts new file mode 100644 index 00000000000..b83b53d308c --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/Cast.ts @@ -0,0 +1,96 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ +import * as tf from '@tensorflow/tfjs-core'; +import {Cast, CastAttrs, CastInputs, KernelConfig, KernelFunc, TensorInfo, TypedArray, util} from '@tensorflow/tfjs-core'; + +import {MathBackendCPU} from '../backend_cpu'; +import {createSimpleBinaryKernelImpl} from '../utils/binary_impl'; + +import {complex} from './Complex'; +import {identity} from './Identity'; +import {real} from './Real'; + +export function cast( + args: {inputs: CastInputs, backend: MathBackendCPU, attrs: CastAttrs}): + TensorInfo { + const {inputs, backend, attrs} = args; + const {x} = inputs; + const {dtype} = attrs; + + // Casting to complex64. + if (dtype === 'complex64') { + if (x.dtype === 'complex64') { + return identity({inputs: {x}, backend}); + } + + // TODO(lina128): Import kernel function once zeros is modularized. + const zerosTensor = tf.zeros(x.shape); + const floatX = cast({inputs: {x}, backend, attrs: {dtype: 'float32'}}); + + const result = + complex({inputs: {real: floatX, imag: zerosTensor}, backend}); + + zerosTensor.dispose(); + backend.disposeIntermediateTensorInfo(floatX); + + return result; + } + + // Casting from complex64 + if (x.dtype === 'complex64') { + const realPart = real({inputs: {input: x}, backend}); + const result = cast({inputs: {x: realPart}, backend, attrs: {dtype}}); + + backend.disposeIntermediateTensorInfo(realPart); + + return result; + } + + if (!util.hasEncodingLoss(x.dtype, dtype)) { + // We don't change the underlying data, since we cast to higher + // precision. + const result = identity({inputs: {x}, backend}); + return {dataId: result.dataId, shape: result.shape, dtype}; + } + + if (dtype === 'int32') { + const values = backend.data.get(x.dataId).values as TypedArray; + const resultValues = Int32Array.from(values); + return backend.makeTensorInfo(x.shape, 'int32', resultValues); + } + + if (dtype === 'bool') { + // This is essentially the result of notEqual(x, 0). We avoid using + // kernel notEqual to avoid circular dependency, i.e. binary_utils -> + // cast -> notEqual -> binary_utils. + const xVals = backend.data.get(x.dataId).values as TypedArray; + const zero = util.toTypedArray([0], x.dtype); + + const [resultData, resultShape] = createSimpleBinaryKernelImpl( + (a, b) => (a !== b) ? 1 : 0)(x.shape, [], xVals, zero, 'bool'); + + return backend.makeTensorInfo(resultShape, 'bool', resultData); + } + + throw new Error(`Error in Cast: failed to cast ${x.dtype} to ${dtype}`); +} + +export const castConfig: KernelConfig = { + kernelName: Cast, + backendName: 'cpu', + kernelFunc: cast as {} as KernelFunc +}; diff --git a/tfjs-backend-cpu/src/kernels/Complex.ts b/tfjs-backend-cpu/src/kernels/Complex.ts new file mode 100644 index 00000000000..5272dfe3c5e --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/Complex.ts @@ -0,0 +1,49 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {Complex, ComplexInputs, KernelConfig, KernelFunc, TensorInfo, TypedArray} from '@tensorflow/tfjs-core'; + +import {MathBackendCPU} from '../backend_cpu'; + +export function complex(args: {inputs: ComplexInputs, backend: MathBackendCPU}): + TensorInfo { + const {inputs, backend} = args; + const {real, imag} = inputs; + + const realVals = backend.data.get(real.dataId).values as TypedArray; + const imagVals = backend.data.get(imag.dataId).values as TypedArray; + + const complexInfo = backend.makeTensorInfo(real.shape, 'complex64'); + + const complex = backend.data.get(complexInfo.dataId); + + // The complex tensor owns the underlying real and imag tensorInfos, only the + // complex tensor tracks refCount, when complexData is disposed the + // underlying tensorData will be disposed. + complex.complexTensorInfos = { + real: backend.makeTensorInfo(real.shape, 'float32', realVals), + imag: backend.makeTensorInfo(imag.shape, 'float32', imagVals) + }; + + return complexInfo; +} + +export const complexConfig: KernelConfig = { + kernelName: Complex, + backendName: 'cpu', + kernelFunc: complex as {} as KernelFunc +}; diff --git a/tfjs-backend-cpu/src/kernels/Complex_test.ts b/tfjs-backend-cpu/src/kernels/Complex_test.ts new file mode 100644 index 00000000000..5650c5816c4 --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/Complex_test.ts @@ -0,0 +1,214 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import * as tf from '@tensorflow/tfjs-core'; +import {test_util} from '@tensorflow/tfjs-core'; + +const {expectArraysClose} = test_util; +// tslint:disable-next-line: no-imports-from-dist +import {describeWithFlags, ALL_ENVS} from '@tensorflow/tfjs-core/dist/jasmine_util'; + +describeWithFlags('Complex.', ALL_ENVS, () => { + it('memory usage.', async () => { + let numTensors = tf.memory().numTensors; + let numDataIds = tf.engine().backend.numDataIds(); + const startTensors = numTensors; + const startDataIds = numDataIds; + + const real1 = tf.tensor1d([1]); + const imag1 = tf.tensor1d([2]); + + // 2 new Tensors: real1, imag1. + expect(tf.memory().numTensors).toBe(numTensors + 2); + expect(tf.engine().backend.numDataIds()).toBe(numDataIds + 2); + numTensors = tf.memory().numTensors; + numDataIds = tf.engine().backend.numDataIds(); + + const complex1 = tf.complex(real1, imag1); + + // 1 new Tensor and 3 new TensorData for complex, real and imag. + expect(tf.memory().numTensors).toBe(numTensors + 1); + expect(tf.engine().backend.numDataIds()).toBe(numDataIds + 3); + numTensors = tf.memory().numTensors; + numDataIds = tf.engine().backend.numDataIds(); + + const real2 = tf.tensor1d([3]); + const imag2 = tf.tensor1d([4]); + + // 2 new Tensors: real2, imag2. + expect(tf.memory().numTensors).toBe(numTensors + 2); + expect(tf.engine().backend.numDataIds()).toBe(numDataIds + 2); + numTensors = tf.memory().numTensors; + numDataIds = tf.engine().backend.numDataIds(); + + const complex2 = tf.complex(real2, imag2); + + // 1 new Tensor and 3 new TensorData for complex, real and imag. + expect(tf.memory().numTensors).toBe(numTensors + 1); + expect(tf.engine().backend.numDataIds()).toBe(numDataIds + 3); + numTensors = tf.memory().numTensors; + numDataIds = tf.engine().backend.numDataIds(); + + const result = complex1.add(complex2); + + // A complex tensor is created, which is composed of real and imag parts. + // They should not increase tensor count, only complex tensor does. + // 3 new tensorData is created for complex, real and imag. + expect(tf.memory().numTensors).toBe(numTensors + 1); + expect(tf.engine().backend.numDataIds()).toBe(numDataIds + 3); + numTensors = tf.memory().numTensors; + numDataIds = tf.engine().backend.numDataIds(); + + expect(result.dtype).toBe('complex64'); + expect(result.shape).toEqual([1]); + expectArraysClose(await result.data(), [4, 6]); + + const real = tf.real(result); + + // A new tensor is created. A new tensorData is created. + expect(tf.memory().numTensors).toBe(numTensors + 1); + expect(tf.engine().backend.numDataIds()).toBe(numDataIds + 1); + numTensors = tf.memory().numTensors; + numDataIds = tf.engine().backend.numDataIds(); + + expectArraysClose(await real.data(), [4]); + + const imag = tf.imag(result); + + // A new tensor is created. A new tensorData is created. + expect(tf.memory().numTensors).toBe(numTensors + 1); + expect(tf.engine().backend.numDataIds()).toBe(numDataIds + 1); + numTensors = tf.memory().numTensors; + numDataIds = tf.engine().backend.numDataIds(); + + expectArraysClose(await imag.data(), [6]); + + // After disposing, there should be no tensors. + real1.dispose(); + imag1.dispose(); + real2.dispose(); + imag2.dispose(); + complex1.dispose(); + complex2.dispose(); + result.dispose(); + real.dispose(); + imag.dispose(); + expect(tf.memory().numTensors).toBe(startTensors); + expect(tf.engine().backend.numDataIds()).toBe(startDataIds); + }); + + it('tf.complex disposing underlying tensors', async () => { + const numTensors = tf.memory().numTensors; + const numDataIds = tf.engine().backend.numDataIds(); + + const real = tf.tensor1d([3, 30]); + const imag = tf.tensor1d([4, 40]); + expect(tf.memory().numTensors).toEqual(numTensors + 2); + expect(tf.engine().backend.numDataIds()).toEqual(numDataIds + 2); + + const complex = tf.complex(real, imag); + + // 1 new tensor is created for complex. real and imag tensorData is created. + expect(tf.memory().numTensors).toEqual(numTensors + 3); + expect(tf.engine().backend.numDataIds()).toEqual(numDataIds + 5); + + real.dispose(); + imag.dispose(); + + expect(tf.memory().numTensors).toEqual(numTensors + 1); + expect(tf.engine().backend.numDataIds()).toEqual(numDataIds + 3); + + expect(complex.dtype).toBe('complex64'); + expect(complex.shape).toEqual(real.shape); + expectArraysClose(await complex.data(), [3, 4, 30, 40]); + + complex.dispose(); + + expect(tf.memory().numTensors).toEqual(numTensors); + expect(tf.engine().backend.numDataIds()).toEqual(numDataIds); + }); + + it('reshape', async () => { + const memoryBefore = tf.memory(); + const numDataIdsBefore = tf.engine().backend.numDataIds(); + + const a = tf.complex([[1, 3, 5], [7, 9, 11]], [[2, 4, 6], [8, 10, 12]]); + + // 1 new tensor, the complex64 tensor + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 1); + // 1 new tensor and 2 underlying tensors for real and imag. + expect(tf.engine().backend.numDataIds()).toBe(numDataIdsBefore + 3); + + const b = a.reshape([6]); + + // 1 new tensor from the reshape. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 2); + // No new tensor data. + expect(tf.engine().backend.numDataIds()).toBe(numDataIdsBefore + 3); + + expect(b.dtype).toBe('complex64'); + expect(b.shape).toEqual([6]); + expectArraysClose(await a.data(), await b.data()); + + b.dispose(); + // 1 complex tensor should be disposed. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 1); + // Tensor data not deleted yet. + expect(tf.engine().backend.numDataIds()).toBe(numDataIdsBefore + 3); + + a.dispose(); + + // All the tensors should now be disposed. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors); + expect(tf.engine().backend.numDataIds()).toBe(numDataIdsBefore); + }); + + it('clone', async () => { + const memoryBefore = tf.memory(); + const numDataIdsBefore = tf.engine().backend.numDataIds(); + + const a = tf.complex([[1, 3, 5], [7, 9, 11]], [[2, 4, 6], [8, 10, 12]]); + + // 1 new tensor, the complex64 tensor + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 1); + // 1 new tensor and 2 underlying tensors for real and imag. + expect(tf.engine().backend.numDataIds()).toBe(numDataIdsBefore + 3); + + const b = a.clone(); + + // 1 new tensor from the clone. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 2); + // No new tensor data. + expect(tf.engine().backend.numDataIds()).toBe(numDataIdsBefore + 3); + + expect(b.dtype).toBe('complex64'); + expectArraysClose(await a.data(), await b.data()); + + b.dispose(); + + // 1 complex tensor should be disposed. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 1); + // Tensor data not deleted yet. + expect(tf.engine().backend.numDataIds()).toBe(numDataIdsBefore + 3); + + a.dispose(); + + // All the tensors should now be disposed. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors); + expect(tf.engine().backend.numDataIds()).toBe(numDataIdsBefore); + }); +}); diff --git a/tfjs-backend-cpu/src/kernels/Concat.ts b/tfjs-backend-cpu/src/kernels/Concat.ts new file mode 100644 index 00000000000..98e146049cf --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/Concat.ts @@ -0,0 +1,131 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {backend_util, Concat, ConcatAttrs, ConcatInputs, KernelConfig, KernelFunc, TensorInfo, TypedArray, util} from '@tensorflow/tfjs-core'; + +import {MathBackendCPU} from '../backend_cpu'; + +import {complex} from './Complex'; +import {imag} from './Imag'; +import {real} from './Real'; +import {reshape} from './Reshape'; + +export function concat( + args: {inputs: ConcatInputs, backend: MathBackendCPU, attrs: ConcatAttrs}): + TensorInfo { + const {inputs, backend, attrs} = args; + const {axis} = attrs; + + const $axis = util.parseAxisParam(axis, inputs[0].shape)[0]; + let outShape = backend_util.computeOutShape(inputs.map(t => t.shape), $axis); + + if (util.sizeFromShape(outShape) === 0) { + return backend.makeTensorInfo(outShape, inputs[0].dtype, []); + } + + // Keep only non-empty tensors (ignore tensors with 0 in their shape). + const $inputs = inputs.filter(t => util.sizeFromShape(t.shape) > 0); + if ($inputs.length === 1) { + return $inputs[0]; + } + + const shapes = $inputs.map(t => t.shape); + backend_util.assertParamsConsistent(shapes, $axis); + + if ($inputs[0].dtype === 'complex64') { + const reals = $inputs.map((t) => real({inputs: {input: t}, backend})); + const imags = $inputs.map((t) => imag({inputs: {input: t}, backend})); + + const realConcated = concat({inputs: reals, backend, attrs: {axis}}); + const imagConcated = concat({inputs: imags, backend, attrs: {axis}}); + + const result = + complex({inputs: {real: realConcated, imag: imagConcated}, backend}); + + reals.forEach(r => backend.disposeIntermediateTensorInfo(r)); + imags.forEach(i => backend.disposeIntermediateTensorInfo(i)); + backend.disposeIntermediateTensorInfo(realConcated); + backend.disposeIntermediateTensorInfo(imagConcated); + + return result; + } + + // Any concat of n-dimensional tensors across any axis can be reduced to + // a concatenation of two-dimensional tensors across the axis 1 by first + // partitioning the axes of the original tensors into those less than the + // axis to be concatenated and the rest. Then reshape the tensors + // into a two-dimensional tensor by collapsing these two sets of axes and + // concatenate the resulting matrices across the axis 1, finally reshaping + // the result to have the proper shape. + const inputs2D = $inputs.map(t => { + const innerSize = util.sizeFromShape(t.shape.slice($axis)); + const shape = [-1, innerSize]; + return reshape({inputs: {x: t}, backend, attrs: {shape}}); + }); + + // Concats 2d tensors along axis=1. + outShape = + backend_util.computeOutShape(inputs2D.map(t => t.shape), 1 /* axis */); + + const outVals = util.getTypedArrayFromDType( + $inputs[0].dtype as 'float32', util.sizeFromShape(outShape)); + + if (inputs2D[0].shape[0] === 1) { + // Use built-in TypedArray.set() method for speed. + let offset = 0; + inputs2D.forEach(t => { + const val = backend.data.get(t.dataId).values as TypedArray; + const size = util.sizeFromShape(t.shape); + + outVals.set(val, offset); + offset += size; + }); + } else { + let colOffset = 0; + + inputs2D.forEach(t => { + const tVals = backend.data.get(t.dataId).values as TypedArray; + + let tIdx = 0; + + for (let row = 0; row < t.shape[0]; ++row) { + const resIdx = row * outShape[1] + colOffset; + for (let col = 0; col < t.shape[1]; ++col) { + outVals[resIdx + col] = tVals[tIdx++]; + } + } + + colOffset += t.shape[1]; + }); + } + + const finalOutShape = + backend_util.computeOutShape($inputs.map(t => t.shape), $axis); + + const outInfo = + backend.makeTensorInfo(finalOutShape, inputs[0].dtype, outVals); + + inputs2D.forEach(t => backend.disposeIntermediateTensorInfo(t)); + + return outInfo; +} + +export const concatConfig: KernelConfig = { + kernelName: Concat, + backendName: 'cpu', + kernelFunc: concat as {} as KernelFunc +}; diff --git a/tfjs-backend-cpu/src/kernels/FFT.ts b/tfjs-backend-cpu/src/kernels/FFT.ts new file mode 100644 index 00000000000..5ab79cde337 --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/FFT.ts @@ -0,0 +1,56 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {FFT, FFTInputs, KernelConfig, KernelFunc, TensorInfo, util} from '@tensorflow/tfjs-core'; + +import {MathBackendCPU} from '../backend_cpu'; +import {fftBatch} from '../utils/fft_utils'; +import {reshape} from './Reshape'; + +export function fft(args: {inputs: FFTInputs, backend: MathBackendCPU}): + TensorInfo { + const {inputs, backend} = args; + const {input} = inputs; + + const inputSize = util.sizeFromShape(input.shape); + + // Collapse all outer dimensions to a single batch dimension. + const innerDimensionSize = input.shape[input.shape.length - 1]; + const batch = inputSize / innerDimensionSize; + + const input2D = reshape({ + inputs: {x: input}, + backend, + attrs: {shape: [batch, innerDimensionSize]} + }); + + const result = fftBatch(input2D, false, backend); + + const resultReshaped = + reshape({inputs: {x: result}, backend, attrs: {shape: input.shape}}); + + backend.disposeIntermediateTensorInfo(input2D); + backend.disposeIntermediateTensorInfo(result); + + return resultReshaped; +} + +export const fftConfig: KernelConfig = { + kernelName: FFT, + backendName: 'cpu', + kernelFunc: fft as {} as KernelFunc +}; diff --git a/tfjs-backend-cpu/src/kernels/IFFT.ts b/tfjs-backend-cpu/src/kernels/IFFT.ts new file mode 100644 index 00000000000..f2f7562979f --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/IFFT.ts @@ -0,0 +1,56 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {IFFT, IFFTInputs, KernelConfig, KernelFunc, TensorInfo, util} from '@tensorflow/tfjs-core'; + +import {MathBackendCPU} from '../backend_cpu'; +import {fftBatch} from '../utils/fft_utils'; +import {reshape} from './Reshape'; + +export function ifft(args: {inputs: IFFTInputs, backend: MathBackendCPU}): + TensorInfo { + const {inputs, backend} = args; + const {input} = inputs; + + const inputSize = util.sizeFromShape(input.shape); + + // Collapse all outer dimensions to a single batch dimension. + const innerDimensionSize = input.shape[input.shape.length - 1]; + const batch = inputSize / innerDimensionSize; + + const input2D = reshape({ + inputs: {x: input}, + backend, + attrs: {shape: [batch, innerDimensionSize]} + }); + + const result = fftBatch(input2D, true, backend); + + const resultReshaped = + reshape({inputs: {x: result}, backend, attrs: {shape: input.shape}}); + + backend.disposeIntermediateTensorInfo(input2D); + backend.disposeIntermediateTensorInfo(result); + + return resultReshaped; +} + +export const ifftConfig: KernelConfig = { + kernelName: IFFT, + backendName: 'cpu', + kernelFunc: ifft as {} as KernelFunc +}; diff --git a/tfjs-backend-cpu/src/kernels/Imag.ts b/tfjs-backend-cpu/src/kernels/Imag.ts new file mode 100644 index 00000000000..563abf8ca38 --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/Imag.ts @@ -0,0 +1,40 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {Imag, ImagInputs, KernelConfig, KernelFunc, TensorInfo} from '@tensorflow/tfjs-core'; + +import {MathBackendCPU} from '../backend_cpu'; + +export function imag(args: {inputs: ImagInputs, backend: MathBackendCPU}): + TensorInfo { + const {inputs, backend} = args; + const {input} = inputs; + + const imag = backend.data.get(input.dataId).complexTensorInfos.imag; + const imagVal = backend.data.get(imag.dataId).values; + + // When complex tensor is disposed, its underlying parts will be disposed too. + // Make new tensor out of the imag value of the complex. This makes sure the + // value is still accessible even if complex tensor is disposed. + return backend.makeTensorInfo(imag.shape, imag.dtype, imagVal); +} + +export const imagConfig: KernelConfig = { + kernelName: Imag, + backendName: 'cpu', + kernelFunc: imag as {} as KernelFunc +}; diff --git a/tfjs-backend-cpu/src/kernels/Multiply.ts b/tfjs-backend-cpu/src/kernels/Multiply.ts new file mode 100644 index 00000000000..c62653d685b --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/Multiply.ts @@ -0,0 +1,34 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {KernelConfig, Multiply} from '@tensorflow/tfjs-core'; +import {binaryKernelFunc} from '../utils/kernel_utils'; + +export const multiply = binaryKernelFunc( + Multiply, ((aValue, bValue) => aValue * bValue), + ((aReal, aImag, bReal, bImag) => { + return { + real: aReal * bReal - aImag * bImag, + imag: aReal * bImag + aImag * bReal + }; + })); + +export const multiplyConfig: KernelConfig = { + kernelName: Multiply, + backendName: 'cpu', + kernelFunc: multiply +}; diff --git a/tfjs-backend-cpu/src/kernels/NotEqual.ts b/tfjs-backend-cpu/src/kernels/NotEqual.ts index bd8ad16d284..ee57e71dd77 100644 --- a/tfjs-backend-cpu/src/kernels/NotEqual.ts +++ b/tfjs-backend-cpu/src/kernels/NotEqual.ts @@ -16,11 +16,10 @@ */ import {KernelConfig, NotEqual} from '@tensorflow/tfjs-core'; - import {binaryKernelFunc} from '../utils/kernel_utils'; -export const notEqual = - binaryKernelFunc(NotEqual, ((a, b) => (a !== b) ? 1 : 0), 'bool'); +export const notEqual = binaryKernelFunc( + NotEqual, ((a, b) => (a !== b) ? 1 : 0), null /* complexOp */, 'bool'); export const notEqualConfig: KernelConfig = { kernelName: NotEqual, diff --git a/tfjs-backend-cpu/src/kernels/Real.ts b/tfjs-backend-cpu/src/kernels/Real.ts new file mode 100644 index 00000000000..068c39d58c6 --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/Real.ts @@ -0,0 +1,40 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {KernelConfig, KernelFunc, Real, RealInputs, TensorInfo} from '@tensorflow/tfjs-core'; + +import {MathBackendCPU} from '../backend_cpu'; + +export function real(args: {inputs: RealInputs, backend: MathBackendCPU}): + TensorInfo { + const {inputs, backend} = args; + const {input} = inputs; + + const real = backend.data.get(input.dataId).complexTensorInfos.real; + const realVal = backend.data.get(real.dataId).values; + + // When complex tensor is disposed, its underlying parts will be disposed too. + // Make new tensor out of the real value of the complex. This makes sure the + // value is still accessible even if complex tensor is disposed. + return backend.makeTensorInfo(real.shape, real.dtype, realVal); +} + +export const realConfig: KernelConfig = { + kernelName: Real, + backendName: 'cpu', + kernelFunc: real as {} as KernelFunc +}; diff --git a/tfjs-backend-cpu/src/kernels/Reshape.ts b/tfjs-backend-cpu/src/kernels/Reshape.ts index e9a878b6346..1a80cd6d61b 100644 --- a/tfjs-backend-cpu/src/kernels/Reshape.ts +++ b/tfjs-backend-cpu/src/kernels/Reshape.ts @@ -15,7 +15,7 @@ * ============================================================================= */ -import {KernelConfig, KernelFunc, Reshape, ReshapeAttrs, ReshapeInputs, TensorInfo} from '@tensorflow/tfjs-core'; +import {KernelConfig, KernelFunc, Reshape, ReshapeAttrs, ReshapeInputs, TensorInfo, util} from '@tensorflow/tfjs-core'; import {MathBackendCPU} from '../backend_cpu'; @@ -27,9 +27,29 @@ export function reshape( const {x} = inputs; const {shape} = attrs; + const xSize = util.sizeFromShape(x.shape); + const $shape = util.inferFromImplicitShape(shape, xSize); + const $xSize = util.sizeFromShape($shape); + + util.assert( + xSize === $xSize, + () => `The new shape (${$shape}) has ${$xSize} elements and the old ` + + `shape (${x.shape}) has ${xSize} elements. The new shape and old ` + + `shape must have the same number of elements.`); + backend.incRef(x.dataId); - return {dataId: x.dataId, shape, dtype: x.dtype}; + const xData = backend.data.get(x.dataId); + + if (xData.complexTensorInfos != null) { + const real = xData.complexTensorInfos.real; + const imag = xData.complexTensorInfos.imag; + + real.shape = $shape; + imag.shape = $shape; + } + + return {dataId: x.dataId, shape: $shape, dtype: x.dtype}; } export const reshapeConfig: KernelConfig = { diff --git a/tfjs-backend-cpu/src/kernels/Slice.ts b/tfjs-backend-cpu/src/kernels/Slice.ts new file mode 100644 index 00000000000..7f6b93785a3 --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/Slice.ts @@ -0,0 +1,67 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {KernelConfig, KernelFunc, NumericDataType, Slice, slice_util, SliceAttrs, SliceInputs, TensorInfo, TypedArray, util} from '@tensorflow/tfjs-core'; + +import {MathBackendCPU} from '../backend_cpu'; +import {assertNotComplex} from '../cpu_util'; + +export function slice( + args: {inputs: SliceInputs, backend: MathBackendCPU, attrs: SliceAttrs}): + TensorInfo { + const {inputs, backend, attrs} = args; + const {x} = inputs; + const {begin, size} = attrs; + + assertNotComplex(x, 'slice'); + + const xRank = x.shape.length; + const xStrides = util.computeStrides(x.shape); + + const [$begin, $size] = slice_util.parseSliceParams(x, begin, size); + slice_util.assertParamsValid(x, $begin, $size); + + const isContinous = slice_util.isSliceContinous(x.shape, $begin, $size); + const vals = backend.data.get(x.dataId).values as TypedArray; + const length = util.sizeFromShape($size); + + if (isContinous) { + const flatOffset = slice_util.computeFlatOffset($begin, xStrides); + const resultVals = vals.subarray(flatOffset, flatOffset + length); + return backend.makeTensorInfo($size, x.dtype, resultVals); + } + + const outVals = + util.getTypedArrayFromDType(x.dtype as NumericDataType, length); + + for (let i = 0; i < length; ++i) { + const rank = $size.length; + const strides = util.computeStrides($size); + const loc = util.indexToLoc(i, rank, strides); + const xLoc = loc.map((idx: number, j) => idx + $begin[j]); + const xIndex = util.locToIndex(xLoc, xRank, xStrides); + outVals[i] = vals[xIndex]; + } + + return backend.makeTensorInfo($size, x.dtype, outVals); +} + +export const sliceConfig: KernelConfig = { + kernelName: Slice, + backendName: 'cpu', + kernelFunc: slice as {} as KernelFunc +}; diff --git a/tfjs-backend-cpu/src/kernels/SquaredDifference.ts b/tfjs-backend-cpu/src/kernels/SquaredDifference.ts index 12f8424dc06..7f6fb1d6aad 100644 --- a/tfjs-backend-cpu/src/kernels/SquaredDifference.ts +++ b/tfjs-backend-cpu/src/kernels/SquaredDifference.ts @@ -19,11 +19,10 @@ import {KernelConfig, SquaredDifference} from '@tensorflow/tfjs-core'; import {binaryKernelFunc} from '../utils/kernel_utils'; -export const squaredDifference = - binaryKernelFunc(SquaredDifference, (aVal, bVal) => { - const diff = aVal - bVal; - return diff * diff; - }); +export const squaredDifference = binaryKernelFunc(SquaredDifference, (a, b) => { + const diff = a - b; + return diff * diff; +}); export const squaredDifferenceConfig: KernelConfig = { kernelName: SquaredDifference, diff --git a/tfjs-backend-cpu/src/kernels/Sub.ts b/tfjs-backend-cpu/src/kernels/Sub.ts new file mode 100644 index 00000000000..83b8d57124f --- /dev/null +++ b/tfjs-backend-cpu/src/kernels/Sub.ts @@ -0,0 +1,31 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {KernelConfig, Sub} from '@tensorflow/tfjs-core'; +import {binaryKernelFunc} from '../utils/kernel_utils'; + +export const sub = binaryKernelFunc( + Sub, ((aValue, bValue) => aValue - bValue), + ((aReal, aImag, bReal, bImag) => { + return {real: aReal - bReal, imag: aImag - bImag}; + })); + +export const subConfig: KernelConfig = { + kernelName: Sub, + backendName: 'cpu', + kernelFunc: sub +}; diff --git a/tfjs-backend-cpu/src/register_all_kernels.ts b/tfjs-backend-cpu/src/register_all_kernels.ts index c761093e4ad..5051806001c 100644 --- a/tfjs-backend-cpu/src/register_all_kernels.ts +++ b/tfjs-backend-cpu/src/register_all_kernels.ts @@ -19,34 +19,69 @@ // the contents of this file and import only the kernels that are needed. import {KernelConfig, registerKernel} from '@tensorflow/tfjs-core'; +import {addConfig} from './kernels/Add'; +import {castConfig} from './kernels/Cast'; +import {complexConfig} from './kernels/Complex'; +import {concatConfig} from './kernels/Concat'; import {cosConfig} from './kernels/Cos'; import {dilation2dConfig} from './kernels/Dilation2D'; import {dilation2dBackpropFilterConfig} from './kernels/Dilation2DBackpropFilter'; import {dilation2dBackpropInputConfig} from './kernels/Dilation2DBackpropInput'; import {divConfig} from './kernels/Div'; +import {fftConfig} from './kernels/FFT'; import {flipLeftRightConfig} from './kernels/FlipLeftRight'; import {identityConfig} from './kernels/Identity'; +import {ifftConfig} from './kernels/IFFT'; +import {imagConfig} from './kernels/Imag'; import {maxConfig} from './kernels/Max'; import {maxPoolWithArgmaxConfig} from './kernels/MaxPoolWithArgmax'; +import {multiplyConfig} from './kernels/Multiply'; import {nonMaxSuppressionV4Config} from './kernels/NonMaxSuppressionV4'; import {nonMaxSuppressionV5Config} from './kernels/NonMaxSuppressionV5'; import {notEqualConfig} from './kernels/NotEqual'; import {padV2Config} from './kernels/PadV2'; +import {realConfig} from './kernels/Real'; import {reshapeConfig} from './kernels/Reshape'; import {rotateWithOffsetConfig} from './kernels/RotateWithOffset'; +import {sliceConfig} from './kernels/Slice'; import {spaceToBatchNDConfig} from './kernels/SpaceToBatchND'; import {squareConfig} from './kernels/Square'; import {squaredDifferenceConfig} from './kernels/SquaredDifference'; +import {subConfig} from './kernels/Sub'; import {transposeConfig} from './kernels/Transpose'; // List all kernel configs here const kernelConfigs: KernelConfig[] = [ - cosConfig, dilation2dConfig, dilation2dBackpropInputConfig, - dilation2dBackpropFilterConfig, divConfig, flipLeftRightConfig, - identityConfig, maxPoolWithArgmaxConfig, maxConfig, nonMaxSuppressionV4Config, - nonMaxSuppressionV5Config, notEqualConfig, padV2Config, reshapeConfig, - rotateWithOffsetConfig, spaceToBatchNDConfig, squareConfig, - squaredDifferenceConfig, transposeConfig + addConfig, + castConfig, + complexConfig, + concatConfig, + cosConfig, + dilation2dConfig, + dilation2dBackpropInputConfig, + dilation2dBackpropFilterConfig, + divConfig, + fftConfig, + flipLeftRightConfig, + identityConfig, + ifftConfig, + imagConfig, + maxPoolWithArgmaxConfig, + maxConfig, + multiplyConfig, + nonMaxSuppressionV4Config, + nonMaxSuppressionV5Config, + notEqualConfig, + padV2Config, + realConfig, + reshapeConfig, + rotateWithOffsetConfig, + sliceConfig, + spaceToBatchNDConfig, + squareConfig, + squaredDifferenceConfig, + subConfig, + transposeConfig ]; for (const kernelConfig of kernelConfigs) { diff --git a/tfjs-backend-cpu/src/utils/binary_impl.ts b/tfjs-backend-cpu/src/utils/binary_impl.ts new file mode 100644 index 00000000000..0e8b96c23a3 --- /dev/null +++ b/tfjs-backend-cpu/src/utils/binary_impl.ts @@ -0,0 +1,69 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {backend_util, DataType, NumericDataType, TypedArray, util} from '@tensorflow/tfjs-core'; + +import {SimpleBinaryKernelImpl, SimpleBinaryOperation} from './binary_types'; + +/** + * Template that creates implementation for binary ops. Supports broadcast. + */ +export function createSimpleBinaryKernelImpl(op: SimpleBinaryOperation): + SimpleBinaryKernelImpl { + return (aShape: number[], bShape: number[], aVals: TypedArray, + bVals: TypedArray, dtype: DataType): [TypedArray, number[]] => { + const newShape = backend_util.assertAndGetBroadcastShape(aShape, bShape); + + const resultRank = newShape.length; + const resultStrides = util.computeStrides(newShape); + const resultSize = util.sizeFromShape(newShape); + + const result = + util.getTypedArrayFromDType(dtype as NumericDataType, resultSize); + + const aRank = aShape.length; + const bRank = bShape.length; + + const aStrides = util.computeStrides(aShape); + const bStrides = util.computeStrides(bShape); + + const aBroadcastDims = backend_util.getBroadcastDims(aShape, newShape); + const bBroadcastDims = backend_util.getBroadcastDims(bShape, newShape); + + if (aBroadcastDims.length + bBroadcastDims.length === 0) { + for (let i = 0; i < result.length; ++i) { + result[i] = op(aVals[i % aVals.length], bVals[i % bVals.length]); + } + } else { + for (let i = 0; i < result.length; ++i) { + const loc = util.indexToLoc(i, resultRank, resultStrides); + + const aLoc = loc.slice(-aRank); + aBroadcastDims.forEach(d => aLoc[d] = 0); + const aIndex = util.locToIndex(aLoc, aRank, aStrides); + + const bLoc = loc.slice(-bRank); + bBroadcastDims.forEach(d => bLoc[d] = 0); + const bIndex = util.locToIndex(bLoc, bRank, bStrides); + + result[i] = op(aVals[aIndex], bVals[bIndex]); + } + } + + return [result, newShape]; + }; +} diff --git a/tfjs-backend-cpu/src/utils/binary_types.ts b/tfjs-backend-cpu/src/utils/binary_types.ts new file mode 100644 index 00000000000..ac0b01f2b17 --- /dev/null +++ b/tfjs-backend-cpu/src/utils/binary_types.ts @@ -0,0 +1,31 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {DataType, TypedArray} from '@tensorflow/tfjs-core'; + +export type SimpleBinaryOperation = (a: number, b: number) => number; +export type SimpleBinaryKernelImpl = + (aShape: number[], bShape: number[], aVals: TypedArray, bVals: TypedArray, + dtype: DataType) => [TypedArray, number[]]; +export type ComplexBinaryOperation = + (aReal: number, aImag: number, bReal: number, bImag: number) => { + real: number, imag: number + }; +export type ComplexBinaryKernelImpl = + (aShape: number[], bShape: number[], aRealVals: Float32Array, + aImagVals: Float32Array, bRealVals: Float32Array, + bImagVals: Float32Array) => [TypedArray, TypedArray, number[]]; diff --git a/tfjs-backend-cpu/src/utils/fft_utils.ts b/tfjs-backend-cpu/src/utils/fft_utils.ts new file mode 100644 index 00000000000..f732fc9cfe6 --- /dev/null +++ b/tfjs-backend-cpu/src/utils/fft_utils.ts @@ -0,0 +1,339 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import {backend_util, Tensor, TensorInfo, TypedArray, util} from '@tensorflow/tfjs-core'; + +import {MathBackendCPU} from '../backend_cpu'; +import {add} from '../kernels/Add'; +import {complex} from '../kernels/Complex'; +import {concat} from '../kernels/Concat'; +import {divConfig} from '../kernels/Div'; +import {identity} from '../kernels/Identity'; +import {imag} from '../kernels/Imag'; +import {multiply} from '../kernels/Multiply'; +import {real} from '../kernels/Real'; +import {slice} from '../kernels/Slice'; +import {sub} from '../kernels/Sub'; + +/** + * Calculate FFT of inner most elements of batch tensor. + */ +export function fftBatch( + input: TensorInfo, inverse: boolean, + cpuBackend: MathBackendCPU): TensorInfo { + const inputShape = input.shape; + const batch = inputShape[0]; + const innerDim = inputShape[1]; + + const inputVals = cpuBackend.data.get(input.dataId); + + const real2D = inputVals.complexTensorInfos.real; + const imag2D = inputVals.complexTensorInfos.imag; + + // Collects real and imaginary values separately. + const resultShape = [batch, innerDim]; + const resultSize = util.sizeFromShape(resultShape); + const resultReal = util.getTypedArrayFromDType('float32', resultSize); + const resultImag = util.getTypedArrayFromDType('float32', resultSize); + + for (let b = 0; b < batch; b++) { + // TODO: Support slice ops for complex type. + const r = slice({ + inputs: {x: real2D}, + backend: cpuBackend, + attrs: {begin: [b, 0], size: [1, innerDim]} + }); + const i = slice({ + inputs: {x: imag2D}, + backend: cpuBackend, + attrs: {begin: [b, 0], size: [1, innerDim]} + }); + + const input = complex({inputs: {real: r, imag: i}, backend: cpuBackend}); + + // Run FFT by batch element. + const {real, imag} = fftImpl(input, inverse, cpuBackend); + const res = backend_util.mergeRealAndImagArrays(real, imag); + + for (let d = 0; d < innerDim; d++) { + const c = backend_util.getComplexWithIndex(res, d); + resultReal[b * innerDim + d] = c.real; + resultImag[b * innerDim + d] = c.imag; + } + + cpuBackend.disposeIntermediateTensorInfo(r); + cpuBackend.disposeIntermediateTensorInfo(i); + cpuBackend.disposeIntermediateTensorInfo(input); + } + + const $realInfo: TensorInfo = + cpuBackend.makeTensorInfo(resultShape, 'float32', resultReal); + const $imagInfo: TensorInfo = + cpuBackend.makeTensorInfo(resultShape, 'float32', resultImag); + + const result = complex( + {inputs: {real: $realInfo, imag: $imagInfo}, backend: cpuBackend}); + + cpuBackend.disposeIntermediateTensorInfo($realInfo); + cpuBackend.disposeIntermediateTensorInfo($imagInfo); + + return result; +} + +export function fftImpl( + input: TensorInfo, inverse: boolean, + cpuBackend: MathBackendCPU): {real: Float32Array, imag: Float32Array} { + const inputSize = util.sizeFromShape(input.shape); + + const inputVals = cpuBackend.data.get(input.dataId); + + const realVals = + cpuBackend.data.get(inputVals.complexTensorInfos.real.dataId).values as + Float32Array; + + const imagVals = + cpuBackend.data.get(inputVals.complexTensorInfos.imag.dataId).values as + Float32Array; + + if (isExponentOf2(inputSize)) { + const result = + fftRadix2(realVals, imagVals, inputSize, inverse, cpuBackend); + + const resultShape = [input.shape[0], input.shape[1]]; + + if (inverse) { + const realInfo: TensorInfo = + cpuBackend.makeTensorInfo(resultShape, 'float32', result.real); + const imagInfo: TensorInfo = + cpuBackend.makeTensorInfo(resultShape, 'float32', result.imag); + + const sizeInfo: TensorInfo = cpuBackend.makeTensorInfo( + [], 'float32', + util.createScalarValue(inputSize as {} as 'float32', 'float32')); + const sizeInfoCopy = + identity({inputs: {x: sizeInfo}, backend: cpuBackend}); + + const divRealInfo = + divConfig.kernelFunc( + {inputs: {a: realInfo, b: sizeInfo}, backend: cpuBackend}) as + TensorInfo; + const divImagInfo = + divConfig.kernelFunc( + {inputs: {a: imagInfo, b: sizeInfoCopy}, backend: cpuBackend}) as + TensorInfo; + + const divRealVals = + cpuBackend.data.get(divRealInfo.dataId).values as Float32Array; + const divImagVals = + cpuBackend.data.get(divImagInfo.dataId).values as Float32Array; + + cpuBackend.disposeIntermediateTensorInfo(realInfo); + cpuBackend.disposeIntermediateTensorInfo(imagInfo); + cpuBackend.disposeIntermediateTensorInfo(sizeInfo); + cpuBackend.disposeIntermediateTensorInfo(sizeInfoCopy); + cpuBackend.disposeIntermediateTensorInfo(divRealInfo); + cpuBackend.disposeIntermediateTensorInfo(divImagInfo); + + return {real: divRealVals, imag: divImagVals}; + } + + return result; + } else { + const data = backend_util.mergeRealAndImagArrays(realVals, imagVals); + + const rawOutput = + fourierTransformByMatmul(data, inputSize, inverse) as Float32Array; + + return backend_util.splitRealAndImagArrays(rawOutput); + } +} + +function isExponentOf2(size: number): boolean { + return (size & size - 1) === 0; +} + +// FFT using Cooley-Tukey algorithm on radix 2 dimensional input. +function fftRadix2( + realVals: Float32Array, imagVals: Float32Array, size: number, + inverse: boolean, + cpuBackend: MathBackendCPU): {real: Float32Array, imag: Float32Array} { + if (size === 1) { + return {real: realVals, imag: imagVals}; + } + + const data = backend_util.mergeRealAndImagArrays(realVals, imagVals); + + const half = size / 2; + + const evenComplex = backend_util.complexWithEvenIndex(data); + + const evenRealVals = evenComplex.real; + const evenImagVals = evenComplex.imag; + + const evenShape = [evenRealVals.length]; + + const evenRealInfo = + cpuBackend.makeTensorInfo(evenShape, 'float32', evenRealVals); + const evenImagInfo = + cpuBackend.makeTensorInfo(evenShape, 'float32', evenImagVals); + + const evenTensorInfo = complex( + {inputs: {real: evenRealInfo, imag: evenImagInfo}, backend: cpuBackend}); + + const oddComplex = backend_util.complexWithOddIndex(data); + + const oddRealVals = oddComplex.real; + const oddImagVals = oddComplex.imag; + + const oddShape = [oddRealVals.length]; + + const oddRealInfo = + cpuBackend.makeTensorInfo(oddShape, 'float32', oddRealVals); + const oddImagInfo = + cpuBackend.makeTensorInfo(oddShape, 'float32', oddImagVals); + + const oddTensorInfo = complex( + {inputs: {real: oddRealInfo, imag: oddImagInfo}, backend: cpuBackend}); + + // Recursive call for half part of original input. + const $evenComplex = + fftRadix2(evenRealVals, evenImagVals, half, inverse, cpuBackend); + + const $evenRealVals = $evenComplex.real; + const $evenImagVals = $evenComplex.imag; + + const $evenShape = [$evenRealVals.length]; + + const $evenRealInfo = + cpuBackend.makeTensorInfo($evenShape, 'float32', $evenRealVals); + const $evenImagInfo = + cpuBackend.makeTensorInfo($evenShape, 'float32', $evenImagVals); + + const $evenTensorInfo = complex({ + inputs: {real: $evenRealInfo, imag: $evenImagInfo}, + backend: cpuBackend + }); + + const $oddComplex = + fftRadix2(oddRealVals, oddImagVals, half, inverse, cpuBackend); + + const $oddRealVals = $oddComplex.real; + const $oddImagVals = $oddComplex.imag; + + const $oddShape = [$oddRealVals.length]; + + const $oddRealInfo = + cpuBackend.makeTensorInfo($oddShape, 'float32', $oddRealVals); + const $oddImagInfo = + cpuBackend.makeTensorInfo($oddShape, 'float32', $oddImagVals); + + const $oddTensorInfo = complex( + {inputs: {real: $oddRealInfo, imag: $oddImagInfo}, backend: cpuBackend}); + + const e = backend_util.exponents(size, inverse); + const eShape = [e.real.length]; + + const eRealInfo = cpuBackend.makeTensorInfo(eShape, 'float32', e.real); + const eImagInfo = cpuBackend.makeTensorInfo(eShape, 'float32', e.imag); + + const complexInfo = complex( + {inputs: {real: eRealInfo, imag: eImagInfo}, backend: cpuBackend}); + + const exponentInfo = + multiply( + {inputs: {a: complexInfo, b: $oddTensorInfo}, backend: cpuBackend}) as + TensorInfo; + + const addPart = add({ + inputs: {a: $evenTensorInfo, b: exponentInfo}, + backend: cpuBackend + }) as TensorInfo; + const subPart = sub({ + inputs: {a: $evenTensorInfo, b: exponentInfo}, + backend: cpuBackend + }) as TensorInfo; + + const addPartReal = real({inputs: {input: addPart}, backend: cpuBackend}); + const subPartReal = real({inputs: {input: subPart}, backend: cpuBackend}); + + const addPartImag = imag({inputs: {input: addPart}, backend: cpuBackend}); + const subPartImag = imag({inputs: {input: subPart}, backend: cpuBackend}); + + const $real = concat({ + inputs: [addPartReal as Tensor, subPartReal as Tensor], + backend: cpuBackend, + attrs: {axis: 0} + }); + const $imag = concat({ + inputs: [addPartImag as Tensor, subPartImag as Tensor], + backend: cpuBackend, + attrs: {axis: 0} + }); + + const $realVals = cpuBackend.data.get($real.dataId).values as Float32Array; + const $imagVals = cpuBackend.data.get($imag.dataId).values as Float32Array; + + cpuBackend.disposeIntermediateTensorInfo(evenRealInfo); + cpuBackend.disposeIntermediateTensorInfo(evenImagInfo); + cpuBackend.disposeIntermediateTensorInfo(evenTensorInfo); + cpuBackend.disposeIntermediateTensorInfo(oddRealInfo); + cpuBackend.disposeIntermediateTensorInfo(oddImagInfo); + cpuBackend.disposeIntermediateTensorInfo(oddTensorInfo); + cpuBackend.disposeIntermediateTensorInfo($evenRealInfo); + cpuBackend.disposeIntermediateTensorInfo($evenImagInfo); + cpuBackend.disposeIntermediateTensorInfo($evenTensorInfo); + cpuBackend.disposeIntermediateTensorInfo($oddRealInfo); + cpuBackend.disposeIntermediateTensorInfo($oddImagInfo); + cpuBackend.disposeIntermediateTensorInfo($oddTensorInfo); + cpuBackend.disposeIntermediateTensorInfo(eRealInfo); + cpuBackend.disposeIntermediateTensorInfo(eImagInfo); + cpuBackend.disposeIntermediateTensorInfo(complexInfo); + cpuBackend.disposeIntermediateTensorInfo(exponentInfo); + cpuBackend.disposeIntermediateTensorInfo(addPart); + cpuBackend.disposeIntermediateTensorInfo(subPart); + cpuBackend.disposeIntermediateTensorInfo(addPartReal); + cpuBackend.disposeIntermediateTensorInfo(addPartImag); + cpuBackend.disposeIntermediateTensorInfo(subPartReal); + cpuBackend.disposeIntermediateTensorInfo(subPartImag); + cpuBackend.disposeIntermediateTensorInfo($real); + cpuBackend.disposeIntermediateTensorInfo($imag); + + return {real: $realVals, imag: $imagVals}; +} + +// Calculate fourier transform by multplying sinusoid matrix. +function fourierTransformByMatmul( + data: TypedArray, size: number, inverse: boolean): TypedArray { + const ret = new Float32Array(size * 2); + // TODO: Use matmul instead once it supports complex64 type. + for (let r = 0; r < size; r++) { + let real = 0.0; + let imag = 0.0; + for (let c = 0; c < size; c++) { + const e = backend_util.exponent(r * c, size, inverse); + const term = backend_util.getComplexWithIndex(data as Float32Array, c); + real += term.real * e.real - term.imag * e.imag; + imag += term.real * e.imag + term.imag * e.real; + } + if (inverse) { + real /= size; + imag /= size; + } + backend_util.assignToTypedArray(ret, real, imag, r); + } + return ret; +} diff --git a/tfjs-backend-cpu/src/utils/kernel_utils.ts b/tfjs-backend-cpu/src/utils/kernel_utils.ts index 2a88dc3722f..86d2f36cff1 100644 --- a/tfjs-backend-cpu/src/utils/kernel_utils.ts +++ b/tfjs-backend-cpu/src/utils/kernel_utils.ts @@ -15,75 +15,155 @@ * ============================================================================= */ -import {BinaryInputs, KernelFunc} from '@tensorflow/tfjs-core'; -import {DataType, NumericDataType, TypedArray} from '@tensorflow/tfjs-core'; -import {backend_util} from '@tensorflow/tfjs-core'; +import {backend_util, BinaryInputs, DataType, KernelFunc, TypedArray, util} from '@tensorflow/tfjs-core'; -import {util} from '@tensorflow/tfjs-core'; import {MathBackendCPU} from '../backend_cpu'; import {assertNotComplex} from '../cpu_util'; +import {cast} from '../kernels/Cast'; +import {complex} from '../kernels/Complex'; -export type SimpleBinaryOperation = (a: number, b: number) => number; -export type SimpleBinaryKernelImpl = - (aShape: number[], bShape: number[], aVals: TypedArray, bVals: TypedArray, - dtype: DataType) => [TypedArray, number[]]; +import {createSimpleBinaryKernelImpl} from './binary_impl'; +import {ComplexBinaryKernelImpl, ComplexBinaryOperation, SimpleBinaryOperation} from './binary_types'; /** * Template that creates a `KernelFunc` for binary ops. * @param name Kernel name. - * @param op A `SimpleBinaryKernelImpl` of the kernel. + * @param op A `SimpleBinaryOperation` for the kernel. + * @param ComplexOp Optional. If exists, represents a `ComplexBinaryOperation` + * for the kernel, will be used when input dtype is `complex64`. * @param dtype Optional. If set, the result has this dtype. Otherwise, the - * result has the same dtype as the the first input. This is mainly used - * in comparison kernels, such as Equal, Less, Greater, etc. + * result has the same dtype as the first input. This is mainly used in + * comparison kernels, such as Equal, Less, Greater, etc. */ export function binaryKernelFunc( - name: string, op: SimpleBinaryOperation, dtype?: DataType): KernelFunc { + name: string, op: SimpleBinaryOperation, complexOp?: ComplexBinaryOperation, + dtype?: DataType): KernelFunc { + if (complexOp == null) { + return ({inputs, backend}) => { + const {a, b} = inputs as BinaryInputs; + const cpuBackend = backend as MathBackendCPU; + + assertNotComplex([a, b], name); + + const aVals = cpuBackend.data.get(a.dataId).values as TypedArray; + const bVals = cpuBackend.data.get(b.dataId).values as TypedArray; + + const $dtype = dtype || a.dtype; + + const [resultData, resultShape] = createSimpleBinaryKernelImpl(op)( + a.shape, b.shape, aVals, bVals, $dtype); + + return cpuBackend.makeTensorInfo(resultShape, $dtype, resultData); + }; + } + return ({inputs, backend}) => { const {a, b} = inputs as BinaryInputs; const cpuBackend = backend as MathBackendCPU; - assertNotComplex([a, b], name); - const aVals = cpuBackend.data.get(a.dataId).values as TypedArray; - const bVals = cpuBackend.data.get(b.dataId).values as TypedArray; + if (a.dtype === 'complex64' || b.dtype === 'complex64') { + const $aComplex = cast( + {inputs: {x: a}, backend: cpuBackend, attrs: {dtype: 'complex64'}}); + + const $aComplexVals = cpuBackend.data.get($aComplex.dataId); + + const aReal = $aComplexVals.complexTensorInfos.real; + const aImag = $aComplexVals.complexTensorInfos.imag; + + const aRealVals = + cpuBackend.data.get(aReal.dataId).values as Float32Array; + const aImagVals = + cpuBackend.data.get(aImag.dataId).values as Float32Array; - const $dtype = dtype || a.dtype; + const $bComplex = cast( + {inputs: {x: b}, backend: cpuBackend, attrs: {dtype: 'complex64'}}); - const [resultData, resultShape] = - createBinaryKernelImpl(op)(a.shape, b.shape, aVals, bVals, $dtype); + const $bComplexVals = cpuBackend.data.get($bComplex.dataId); - const dataId = cpuBackend.write(resultData, resultShape, $dtype); - return {dataId, shape: resultShape, dtype: $dtype}; + const bReal = $bComplexVals.complexTensorInfos.real; + const bImag = $bComplexVals.complexTensorInfos.imag; + + const bRealVals = + cpuBackend.data.get(bReal.dataId).values as Float32Array; + const bImagVals = + cpuBackend.data.get(bImag.dataId).values as Float32Array; + + const [resultRealData, resultImagData, resultShape] = + createComplexBinaryKernelImpl(complexOp)( + a.shape, b.shape, aRealVals, aImagVals, bRealVals, bImagVals); + + const resultReal = + cpuBackend.makeTensorInfo(resultShape, 'float32', resultRealData); + + const resultImag = + cpuBackend.makeTensorInfo(resultShape, 'float32', resultImagData); + + const result = complex( + {inputs: {real: resultReal, imag: resultImag}, backend: cpuBackend}); + + cpuBackend.disposeIntermediateTensorInfo($aComplex); + cpuBackend.disposeIntermediateTensorInfo($bComplex); + cpuBackend.disposeIntermediateTensorInfo(resultReal); + cpuBackend.disposeIntermediateTensorInfo(resultImag); + + return result; + } else { + const aVals = cpuBackend.data.get(a.dataId).values as TypedArray; + const bVals = cpuBackend.data.get(b.dataId).values as TypedArray; + + const $dtype = dtype || a.dtype; + + const [resultData, resultShape] = createSimpleBinaryKernelImpl(op)( + a.shape, b.shape, aVals, bVals, $dtype); + + return cpuBackend.makeTensorInfo(resultShape, $dtype, resultData); + } }; } -export function createBinaryKernelImpl(op: SimpleBinaryOperation): - SimpleBinaryKernelImpl { - return (aShape: number[], bShape: number[], aVals: TypedArray, - bVals: TypedArray, dtype: DataType): [TypedArray, number[]] => { - const newShape = backend_util.assertAndGetBroadcastShape(aShape, bShape); +/** + * Template that creates the complex type implementation for binary ops. + * Supports broadcast. + */ +export function createComplexBinaryKernelImpl(op: ComplexBinaryOperation): + ComplexBinaryKernelImpl { + return (aShape: number[], bShape: number[], aRealVals: Float32Array, + aImagVals: Float32Array, bRealVals: Float32Array, + bImagVals: Float32Array): [TypedArray, TypedArray, number[]] => { + const resultShape = backend_util.assertAndGetBroadcastShape(aShape, bShape); + const resultSize = util.sizeFromShape(resultShape); + const resultRank = resultShape.length; + const resultStrides = util.computeStrides(resultShape); - const resultRank = newShape.length; - const resultStrides = util.computeStrides(newShape); - const resultSize = util.sizeFromShape(newShape); + const resultRealVals = util.getTypedArrayFromDType('float32', resultSize); + const resultImagVals = util.getTypedArrayFromDType('float32', resultSize); - const result = - util.getTypedArrayFromDType(dtype as NumericDataType, resultSize); + const aBroadcastDims = backend_util.getBroadcastDims(aShape, resultShape); + const bBroadcastDims = backend_util.getBroadcastDims(bShape, resultShape); - const aRank = aShape.length; - const bRank = bShape.length; + const aVals = backend_util.mergeRealAndImagArrays(aRealVals, aImagVals); + const bVals = backend_util.mergeRealAndImagArrays(bRealVals, bImagVals); + const aRank = aShape.length; const aStrides = util.computeStrides(aShape); - const bStrides = util.computeStrides(bShape); - const aBroadcastDims = backend_util.getBroadcastDims(aShape, newShape); - const bBroadcastDims = backend_util.getBroadcastDims(bShape, newShape); + const bRank = bShape.length; + const bStrides = util.computeStrides(bShape); if (aBroadcastDims.length + bBroadcastDims.length === 0) { - for (let i = 0; i < result.length; ++i) { - result[i] = op(aVals[i % aVals.length], bVals[i % bVals.length]); + for (let i = 0; i < resultRealVals.length; i++) { + const aIdx = i % aVals.length; + const bIdx = i % bVals.length; + + const result = + op(aVals[aIdx * 2], aVals[aIdx * 2 + 1], bVals[bIdx * 2], + bVals[bIdx * 2 + 1]); + + resultRealVals[i] = result.real; + resultImagVals[i] = result.imag; } } else { - for (let i = 0; i < result.length; ++i) { + for (let i = 0; i < resultRealVals.length; i++) { const loc = util.indexToLoc(i, resultRank, resultStrides); const aLoc = loc.slice(-aRank); @@ -94,10 +174,14 @@ export function createBinaryKernelImpl(op: SimpleBinaryOperation): bBroadcastDims.forEach(d => bLoc[d] = 0); const bIndex = util.locToIndex(bLoc, bRank, bStrides); - result[i] = op(aVals[aIndex], bVals[bIndex]); + const opResult = + op(aVals[aIndex * 2], aVals[aIndex * 2 + 1], bVals[bIndex * 2], + bVals[bIndex * 2 + 1]); + + resultRealVals[i] = opResult.real; + resultImagVals[i] = opResult.imag; } } - - return [result, newShape]; + return [resultRealVals, resultImagVals, resultShape]; }; } diff --git a/tfjs-backend-wasm/src/kernels/Concat.ts b/tfjs-backend-wasm/src/kernels/Concat.ts index 510c182eee0..cd1a56afe52 100644 --- a/tfjs-backend-wasm/src/kernels/Concat.ts +++ b/tfjs-backend-wasm/src/kernels/Concat.ts @@ -26,16 +26,30 @@ function concat( const axis = util.parseAxisParam(args.attrs.axis, inputs[0].shape)[0]; const outShape = backend_util.computeOutShape(inputs.map(t => t.shape), axis); + const out = backend.makeOutput(outShape, inputs[0].dtype); - const batchDim = util.sizeFromShape(inputs[0].shape.slice(0, axis)); + if (util.sizeFromShape(outShape) === 0) { + return out; + } + + // Keep only non-empty tensors (ignore tensors with 0 in their shape). + const $inputs = inputs.filter(t => util.sizeFromShape(t.shape) > 0); + if ($inputs.length === 1) { + return $inputs[0]; + } + + const shapes = $inputs.map(t => t.shape); + backend_util.assertParamsConsistent(shapes, axis); + + const batchDim = util.sizeFromShape($inputs[0].shape.slice(0, axis)); let sumInnerDims = 0; - const innerDims = inputs.map(input => { + const innerDims = $inputs.map(input => { const innerDim = util.sizeFromShape(input.shape.slice(axis)); sumInnerDims += innerDim; return innerDim; }); - const inVals = inputs.map(input => backend.typedArrayFromHeap(input)); + const inVals = $inputs.map(input => backend.typedArrayFromHeap(input)); const outVals = backend.typedArrayFromHeap(out); for (let b = 0; b < batchDim; b++) { let outOffset = b * sumInnerDims; diff --git a/tfjs-backend-wasm/src/kernels/Reshape.ts b/tfjs-backend-wasm/src/kernels/Reshape.ts index 40db6db2333..2b4226fd2ae 100644 --- a/tfjs-backend-wasm/src/kernels/Reshape.ts +++ b/tfjs-backend-wasm/src/kernels/Reshape.ts @@ -15,7 +15,7 @@ * ============================================================================= */ -import {KernelConfig, NamedAttrMap, NamedTensorInfoMap, Reshape, ReshapeAttrs, ReshapeInputs} from '@tensorflow/tfjs-core'; +import {KernelConfig, NamedAttrMap, NamedTensorInfoMap, Reshape, ReshapeAttrs, ReshapeInputs, util} from '@tensorflow/tfjs-core'; import {BackendWasm} from '../backend_wasm'; @@ -27,7 +27,16 @@ export function reshape(args: { const {inputs, attrs} = args; const {x} = inputs as {} as ReshapeInputs; const {shape} = attrs as {} as ReshapeAttrs; - return {dataId: x.dataId, shape, dtype: x.dtype}; + + const xSize = util.sizeFromShape(x.shape); + const $shape = util.inferFromImplicitShape(shape, xSize); + + util.assert( + xSize === util.sizeFromShape($shape), + () => `new shape: ${$shape}, old shape: ${x.shape}. New shape and old ` + + `shape must have the same number of elements.`); + + return {dataId: x.dataId, shape: $shape, dtype: x.dtype}; } export const reshapeConfig: KernelConfig = { diff --git a/tfjs-backend-wasm/src/kernels/Slice.ts b/tfjs-backend-wasm/src/kernels/Slice.ts index 998f733698f..c86810df145 100644 --- a/tfjs-backend-wasm/src/kernels/Slice.ts +++ b/tfjs-backend-wasm/src/kernels/Slice.ts @@ -15,7 +15,7 @@ * ============================================================================= */ -import {backend_util, buffer, KernelConfig, KernelFunc, Slice, slice_util, SliceAttrs, SliceInputs, Tensor, util} from '@tensorflow/tfjs-core'; +import {backend_util, buffer, KernelConfig, KernelFunc, Slice, slice_util, SliceAttrs, SliceInputs, util} from '@tensorflow/tfjs-core'; import {TensorInfo} from '@tensorflow/tfjs-core'; import {BackendWasm} from '../backend_wasm'; @@ -23,7 +23,9 @@ import {BackendWasm} from '../backend_wasm'; export function slice( args: {inputs: SliceInputs, attrs: SliceAttrs, backend: BackendWasm}) { const {inputs: {x}, attrs: {begin, size}, backend} = args; - const [begin_, size_] = slice_util.parseSliceParams(x as Tensor, begin, size); + + const [begin_, size_] = slice_util.parseSliceParams(x, begin, size); + const isContinous = slice_util.isSliceContinous(x.shape, begin_, size_); const xVals = backend.typedArrayFromHeap(x); const out = backend.makeOutput(size_, x.dtype); diff --git a/tfjs-backend-webgl/src/kernels/Complex_test.ts b/tfjs-backend-webgl/src/kernels/Complex_test.ts new file mode 100644 index 00000000000..0120234c069 --- /dev/null +++ b/tfjs-backend-webgl/src/kernels/Complex_test.ts @@ -0,0 +1,188 @@ +/** + * @license + * Copyright 2020 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +import * as tf from '@tensorflow/tfjs-core'; +import {test_util} from '@tensorflow/tfjs-core'; + +const {expectArraysClose} = test_util; +// tslint:disable-next-line: no-imports-from-dist +import {describeWithFlags, ALL_ENVS} from '@tensorflow/tfjs-core/dist/jasmine_util'; + +const BYTES_PER_COMPLEX_ELEMENT = 4 * 2; +describeWithFlags('complex64 memory', ALL_ENVS, () => { + it('usage', async () => { + let numTensors = tf.memory().numTensors; + let numBuffers = tf.memory().numDataBuffers; + const startTensors = numTensors; + + const real1 = tf.tensor1d([1]); + const imag1 = tf.tensor1d([2]); + const complex1 = tf.complex(real1, imag1); + + // 5 new Tensors: real1, imag1, complex1, and two internal clones. + expect(tf.memory().numTensors).toBe(numTensors + 5); + // Only 3 new data buckets are actually created. + expect(tf.memory().numDataBuffers).toBe(numBuffers + 3); + numTensors = tf.memory().numTensors; + numBuffers = tf.memory().numDataBuffers; + + const real2 = tf.tensor1d([3]); + const imag2 = tf.tensor1d([4]); + const complex2 = tf.complex(real2, imag2); + + // 5 new Tensors: real1, imag1, complex1, and two internal clones. + expect(tf.memory().numTensors).toBe(numTensors + 5); + // Only 3 new data buckets are actually created. + expect(tf.memory().numDataBuffers).toBe(numBuffers + 3); + numTensors = tf.memory().numTensors; + numBuffers = tf.memory().numDataBuffers; + + const result = complex1.add(complex2); + + // A complex tensor is created, which is composed of 2 underlying tensors. + expect(tf.memory().numTensors).toBe(numTensors + 3); + numTensors = tf.memory().numTensors; + + expect(result.dtype).toBe('complex64'); + expect(result.shape).toEqual([1]); + expectArraysClose(await result.data(), [4, 6]); + + const real = tf.real(result); + + expect(tf.memory().numTensors).toBe(numTensors + 1); + numTensors = tf.memory().numTensors; + + expectArraysClose(await real.data(), [4]); + + const imag = tf.imag(result); + + expect(tf.memory().numTensors).toBe(numTensors + 1); + numTensors = tf.memory().numTensors; + + expectArraysClose(await imag.data(), [6]); + + // After disposing, there should be no tensors. + real1.dispose(); + imag1.dispose(); + real2.dispose(); + imag2.dispose(); + complex1.dispose(); + complex2.dispose(); + result.dispose(); + real.dispose(); + imag.dispose(); + expect(tf.memory().numTensors).toBe(startTensors); + }); + + it('tf.complex disposing underlying tensors', async () => { + const numTensors = tf.memory().numTensors; + + const real = tf.tensor1d([3, 30]); + const imag = tf.tensor1d([4, 40]); + expect(tf.memory().numTensors).toEqual(numTensors + 2); + + const complex = tf.complex(real, imag); + + // real and imag are cloned. + expect(tf.memory().numTensors).toEqual(numTensors + 5); + + real.dispose(); + imag.dispose(); + + // A copy of real and imag still exist, the one owned by the complex tensor. + expect(tf.memory().numTensors).toEqual(numTensors + 3); + + expect(complex.dtype).toBe('complex64'); + expect(complex.shape).toEqual(real.shape); + expectArraysClose(await complex.data(), [3, 4, 30, 40]); + + complex.dispose(); + + expect(tf.memory().numTensors).toEqual(numTensors); + }); + + it('reshape', async () => { + const memoryBefore = tf.memory(); + + const a = tf.complex([[1, 3, 5], [7, 9, 11]], [[2, 4, 6], [8, 10, 12]]); + + // 3 new tensors, the complex64 tensor and the 2 underlying float32 tensors. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 3); + // Bytes should be counted once. + expect(tf.memory().numBytes) + .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); + + const b = a.reshape([6]); + // 1 new tensor from the reshape. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 4); + // No new bytes from a reshape. + expect(tf.memory().numBytes) + .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); + + expect(b.dtype).toBe('complex64'); + expect(b.shape).toEqual([6]); + expectArraysClose(await a.data(), await b.data()); + + b.dispose(); + // 1 complex tensor should be disposed. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 3); + // Byte count should not change because the refcounts are all 1. + expect(tf.memory().numBytes) + .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); + + a.dispose(); + // All the tensors should now be disposed. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors); + // The underlying memory should now be released. + expect(tf.memory().numBytes).toBe(memoryBefore.numBytes); + }); + + it('clone', async () => { + const memoryBefore = tf.memory(); + + const a = tf.complex([[1, 3, 5], [7, 9, 11]], [[2, 4, 6], [8, 10, 12]]); + + // 3 new tensors, the complex64 tensor and the 2 underlying float32 tensors. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 3); + // Bytes should be counted once + expect(tf.memory().numBytes) + .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); + + const b = a.clone(); + // 1 new tensor from the clone. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 4); + // No new bytes from a clone. + expect(tf.memory().numBytes) + .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); + + expect(b.dtype).toBe('complex64'); + expectArraysClose(await a.data(), await b.data()); + + b.dispose(); + // 1 complex tensor should be disposed. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 3); + // Byte count should not change because the refcounts are all 1. + expect(tf.memory().numBytes) + .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); + + a.dispose(); + // All the tensors should now be disposed. + expect(tf.memory().numTensors).toBe(memoryBefore.numTensors); + // The underlying memory should now be released. + expect(tf.memory().numBytes).toBe(memoryBefore.numBytes); + }); +}); diff --git a/tfjs-core/src/backends/backend_util.ts b/tfjs-core/src/backends/backend_util.ts index c18d8cac38f..e9361713b21 100644 --- a/tfjs-core/src/backends/backend_util.ts +++ b/tfjs-core/src/backends/backend_util.ts @@ -14,7 +14,6 @@ * limitations under the License. * ============================================================================= */ - import {ENGINE} from '../engine'; import {cast} from '../ops/cast'; import {scalar} from '../ops/scalar'; diff --git a/tfjs-core/src/engine_test.ts b/tfjs-core/src/engine_test.ts index f6178b2103f..adae369bf4b 100644 --- a/tfjs-core/src/engine_test.ts +++ b/tfjs-core/src/engine_test.ts @@ -546,6 +546,10 @@ describeWithFlags( }); it('can execute op with data from mixed backends', async () => { + const kernelFunc = tf.getKernel('Add', 'cpu').kernelFunc; + tf.registerKernel({kernelName: 'Add', backendName: 'cpu1', kernelFunc}); + tf.registerKernel({kernelName: 'Add', backendName: 'cpu2', kernelFunc}); + tf.setBackend('cpu1'); // This scalar lives in cpu1. const a = tf.scalar(5); @@ -562,13 +566,8 @@ describeWithFlags( tf.setBackend('cpu2'); expectArraysClose(await tf.add(a, b).data(), [8]); ENGINE.endScope(); - expect(tf.memory().numTensors).toBe(2); - expect(tf.memory().numDataBuffers).toBe(2); tf.dispose([a, b]); - - expect(tf.memory().numTensors).toBe(0); - expect(tf.memory().numDataBuffers).toBe(0); }); }); diff --git a/tfjs-core/src/ops/complex_ops_test.ts b/tfjs-core/src/ops/complex_ops_test.ts index a0e202c1071..2c7539ad3a5 100644 --- a/tfjs-core/src/ops/complex_ops_test.ts +++ b/tfjs-core/src/ops/complex_ops_test.ts @@ -56,168 +56,3 @@ describeWithFlags('complex64', ALL_ENVS, () => { expect(() => tf.complex(real, imag)).toThrowError(re); }); }); - -const BYTES_PER_COMPLEX_ELEMENT = 4 * 2; -describeWithFlags('complex64 memory', ALL_ENVS, () => { - it('usage', async () => { - let numTensors = tf.memory().numTensors; - let numBuffers = tf.memory().numDataBuffers; - const startTensors = numTensors; - - const real1 = tf.tensor1d([1]); - const imag1 = tf.tensor1d([2]); - const complex1 = tf.complex(real1, imag1); - - // 5 new Tensors: real1, imag1, complex1, and two internal clones. - expect(tf.memory().numTensors).toBe(numTensors + 5); - // Only 3 new data buckets are actually created. - expect(tf.memory().numDataBuffers).toBe(numBuffers + 3); - numTensors = tf.memory().numTensors; - numBuffers = tf.memory().numDataBuffers; - - const real2 = tf.tensor1d([3]); - const imag2 = tf.tensor1d([4]); - const complex2 = tf.complex(real2, imag2); - - // 5 new Tensors: real1, imag1, complex1, and two internal clones. - expect(tf.memory().numTensors).toBe(numTensors + 5); - // Only 3 new data buckets are actually created. - expect(tf.memory().numDataBuffers).toBe(numBuffers + 3); - numTensors = tf.memory().numTensors; - numBuffers = tf.memory().numDataBuffers; - - const result = complex1.add(complex2); - - // A complex tensor is created, which is composed of 2 underlying tensors. - expect(tf.memory().numTensors).toBe(numTensors + 3); - numTensors = tf.memory().numTensors; - - expect(result.dtype).toBe('complex64'); - expect(result.shape).toEqual([1]); - expectArraysClose(await result.data(), [4, 6]); - - const real = tf.real(result); - - expect(tf.memory().numTensors).toBe(numTensors + 1); - numTensors = tf.memory().numTensors; - - expectArraysClose(await real.data(), [4]); - - const imag = tf.imag(result); - - expect(tf.memory().numTensors).toBe(numTensors + 1); - numTensors = tf.memory().numTensors; - - expectArraysClose(await imag.data(), [6]); - - // After disposing, there should be no tensors. - real1.dispose(); - imag1.dispose(); - real2.dispose(); - imag2.dispose(); - complex1.dispose(); - complex2.dispose(); - result.dispose(); - real.dispose(); - imag.dispose(); - expect(tf.memory().numTensors).toBe(startTensors); - }); - - it('tf.complex disposing underlying tensors', async () => { - const numTensors = tf.memory().numTensors; - - const real = tf.tensor1d([3, 30]); - const imag = tf.tensor1d([4, 40]); - expect(tf.memory().numTensors).toEqual(numTensors + 2); - - const complex = tf.complex(real, imag); - - // real and imag are cloned. - expect(tf.memory().numTensors).toEqual(numTensors + 5); - - real.dispose(); - imag.dispose(); - - // A copy of real and imag still exist, the one owned by the complex tensor. - expect(tf.memory().numTensors).toEqual(numTensors + 3); - - expect(complex.dtype).toBe('complex64'); - expect(complex.shape).toEqual(real.shape); - expectArraysClose(await complex.data(), [3, 4, 30, 40]); - - complex.dispose(); - - expect(tf.memory().numTensors).toEqual(numTensors); - }); - - it('reshape', async () => { - const memoryBefore = tf.memory(); - - const a = tf.complex([[1, 3, 5], [7, 9, 11]], [[2, 4, 6], [8, 10, 12]]); - - // 3 new tensors, the complex64 tensor and the 2 underlying float32 tensors. - expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 3); - // Bytes should be counted once. - expect(tf.memory().numBytes) - .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); - - const b = a.reshape([6]); - // 1 new tensor from the reshape. - expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 4); - // No new bytes from a reshape. - expect(tf.memory().numBytes) - .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); - - expect(b.dtype).toBe('complex64'); - expect(b.shape).toEqual([6]); - expectArraysClose(await a.data(), await b.data()); - - b.dispose(); - // 1 complex tensor should be disposed. - expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 3); - // Byte count should not change because the refcounts are all 1. - expect(tf.memory().numBytes) - .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); - - a.dispose(); - // All the tensors should now be disposed. - expect(tf.memory().numTensors).toBe(memoryBefore.numTensors); - // The underlying memory should now be released. - expect(tf.memory().numBytes).toBe(memoryBefore.numBytes); - }); - - it('clone', async () => { - const memoryBefore = tf.memory(); - - const a = tf.complex([[1, 3, 5], [7, 9, 11]], [[2, 4, 6], [8, 10, 12]]); - - // 3 new tensors, the complex64 tensor and the 2 underlying float32 tensors. - expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 3); - // Bytes should be counted once - expect(tf.memory().numBytes) - .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); - - const b = a.clone(); - // 1 new tensor from the clone. - expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 4); - // No new bytes from a clone. - expect(tf.memory().numBytes) - .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); - - expect(b.dtype).toBe('complex64'); - expectArraysClose(await a.data(), await b.data()); - - b.dispose(); - // 1 complex tensor should be disposed. - expect(tf.memory().numTensors).toBe(memoryBefore.numTensors + 3); - // Byte count should not change because the refcounts are all 1. - expect(tf.memory().numBytes) - .toBe(memoryBefore.numBytes + 6 * BYTES_PER_COMPLEX_ELEMENT); - - a.dispose(); - // All the tensors should now be disposed. - expect(tf.memory().numTensors).toBe(memoryBefore.numTensors); - // The underlying memory should now be released. - expect(tf.memory().numBytes).toBe(memoryBefore.numBytes); - }); -}); diff --git a/tfjs-core/src/ops/concat.ts b/tfjs-core/src/ops/concat.ts index 8ebfa462142..8e387c81c00 100644 --- a/tfjs-core/src/ops/concat.ts +++ b/tfjs-core/src/ops/concat.ts @@ -71,6 +71,7 @@ function concat_(tensors: Array, axis = 0): T { assert(tensors.length >= 1, () => 'Pass at least one tensor to concat'); let $tensors = convertToTensorArray(tensors, 'tensors', 'concat'); + if ($tensors[0].dtype === 'complex64') { $tensors.forEach(tensor => { if (tensor.dtype !== 'complex64') { @@ -80,21 +81,21 @@ function concat_(tensors: Array, axis = 0): T { }); } - const $axis = parseAxisParam(axis, $tensors[0].shape)[0]; - const outShape = computeOutShape($tensors.map(t => t.shape), $axis); - if (sizeFromShape(outShape) === 0) { - return tensor([], outShape) as T; - } - // Keep only non-empty tensors (ignore tensors with 0 in their shape). - $tensors = $tensors.filter(t => t.size > 0); - if ($tensors.length === 1) { - return $tensors[0]; - } + const forward: ForwardFunc = (backend, save) => { + const $axis = parseAxisParam(axis, $tensors[0].shape)[0]; + const outShape = computeOutShape($tensors.map(t => t.shape), $axis); + if (sizeFromShape(outShape) === 0) { + return tensor([], outShape) as T; + } + // Keep only non-empty tensors (ignore tensors with 0 in their shape). + $tensors = $tensors.filter(t => t.size > 0); + if ($tensors.length === 1) { + return $tensors[0]; + } - const shapes = $tensors.map(t => t.shape); - assertParamsConsistent(shapes, $axis); + const shapes = $tensors.map(t => t.shape); + assertParamsConsistent(shapes, $axis); - const forward: ForwardFunc = (backend, save) => { const res = backend.concat($tensors, $axis); save($tensors); return res; diff --git a/tfjs-core/src/ops/reshape.ts b/tfjs-core/src/ops/reshape.ts index d07b9df2ded..fdc118604b8 100644 --- a/tfjs-core/src/ops/reshape.ts +++ b/tfjs-core/src/ops/reshape.ts @@ -56,18 +56,18 @@ import {op} from './operation'; function reshape_( x: Tensor|TensorLike, shape: ShapeMap[R]): Tensor { const $x = convertToTensor(x, 'x', 'reshape', null); - shape = util.inferFromImplicitShape(shape, $x.size) as ShapeMap[R]; - util.assert( - $x.size === util.sizeFromShape(shape), - () => 'new shape and old shape must have the same number of elements.'); const inputs: ReshapeInputs = {x: $x}; const attrs: ReshapeAttrs = {shape}; - const forward: ForwardFunc> = - (backend: KernelBackend, save: GradSaveFunc) => { - save([$x]); - return backend.reshape($x, shape); - }; + const forward: ForwardFunc< + Tensor> = (backend: KernelBackend, save: GradSaveFunc) => { + shape = util.inferFromImplicitShape(shape, $x.size) as ShapeMap[R]; + util.assert( + $x.size === util.sizeFromShape(shape), + () => 'new shape and old shape must have the same number of elements.'); + save([$x]); + return backend.reshape($x, shape); + }; return ENGINE.runKernelFunc( forward, inputs as {} as NamedTensorMap, null /* grad */, Reshape, attrs as {} as NamedAttrMap); diff --git a/tfjs-core/src/ops/slice.ts b/tfjs-core/src/ops/slice.ts index e80a4117bba..65d3926be44 100644 --- a/tfjs-core/src/ops/slice.ts +++ b/tfjs-core/src/ops/slice.ts @@ -67,10 +67,10 @@ function slice_>( if ($x.rank === 0) { throw new Error('Slicing scalar is not possible'); } - const [begin_, size_] = slice_util.parseSliceParams($x, begin, size); - slice_util.assertParamsValid($x, begin_, size_); const forward: ForwardFunc = (backend, save) => { + const [begin_, size_] = slice_util.parseSliceParams($x, begin, size); + slice_util.assertParamsValid($x, begin_, size_); save([$x]); return backend.slice($x, begin_, size_); }; diff --git a/tfjs-core/src/ops/slice_util.ts b/tfjs-core/src/ops/slice_util.ts index bd236038c96..4ea79767f99 100644 --- a/tfjs-core/src/ops/slice_util.ts +++ b/tfjs-core/src/ops/slice_util.ts @@ -15,24 +15,25 @@ * ============================================================================= */ -import {Tensor} from '../tensor'; +import {TensorInfo} from '../kernel_registry'; import * as util from '../util'; export function assertParamsValid( - input: Tensor, begin: number[], size: number[]): void { + input: TensorInfo, begin: number[], size: number[]): void { + const inputRank = input.shape.length; util.assert( - input.rank === begin.length, - () => `Error in slice${input.rank}D: Length of begin ${begin} must ` + - `match the rank of the array (${input.rank}).`); + inputRank === begin.length, + () => `Error in slice${inputRank}D: Length of begin ${begin} must ` + + `match the rank of the array (${inputRank}).`); util.assert( - input.rank === size.length, - () => `Error in slice${input.rank}D: Length of size ${size} must ` + - `match the rank of the array (${input.rank}).`); + inputRank === size.length, + () => `Error in slice${inputRank}D: Length of size ${size} must ` + + `match the rank of the array (${inputRank}).`); - for (let i = 0; i < input.rank; ++i) { + for (let i = 0; i < inputRank; ++i) { util.assert( begin[i] + size[i] <= input.shape[i], - () => `Error in slice${input.rank}D: begin[${i}] + size[${i}] ` + + () => `Error in slice${inputRank}D: begin[${i}] + size[${i}] ` + `(${begin[i] + size[i]}) would overflow input.shape[${i}] (${ input.shape[i]})`); } @@ -314,13 +315,14 @@ export function computeFlatOffset(begin: number[], strides: number[]): number { } export function parseSliceParams( - x: Tensor, begin: number|number[], size?: number|number[]) { + x: TensorInfo, begin: number|number[], size?: number|number[]) { // The following logic allows for more ergonomic calls. let begin_: number[]; + const xRank = x.shape.length; if (typeof begin === 'number') { - begin_ = [begin, ...new Array(x.rank - 1).fill(0)]; - } else if (begin.length < x.rank) { - begin_ = begin.concat(new Array(x.rank - begin.length).fill(0)); + begin_ = [begin, ...new Array(xRank - 1).fill(0)]; + } else if (begin.length < xRank) { + begin_ = begin.concat(new Array(xRank - begin.length).fill(0)); } else { begin_ = begin.slice(); } @@ -330,11 +332,11 @@ export function parseSliceParams( }); let size_: number[]; if (size == null) { - size_ = new Array(x.rank).fill(-1); + size_ = new Array(xRank).fill(-1); } else if (typeof size === 'number') { - size_ = [size, ...new Array(x.rank - 1).fill(-1)]; - } else if (size.length < x.rank) { - size_ = size.concat(new Array(x.rank - size.length).fill(-1)); + size_ = [size, ...new Array(xRank - 1).fill(-1)]; + } else if (size.length < xRank) { + size_ = size.concat(new Array(xRank - size.length).fill(-1)); } else { size_ = size; } diff --git a/tfjs-core/src/util.ts b/tfjs-core/src/util.ts index 6abddf3d028..3a634ce84d8 100644 --- a/tfjs-core/src/util.ts +++ b/tfjs-core/src/util.ts @@ -16,8 +16,7 @@ */ import {env} from './environment'; - -import {DataType, DataTypeMap, FlatVector, NumericDataType, RecursiveArray, TensorLike, TypedArray} from './types'; +import {BackendValues, DataType, DataTypeMap, FlatVector, NumericDataType, RecursiveArray, TensorLike, TypedArray} from './types'; /** * Shuffles the array in-place using Fisher-Yates algorithm. @@ -553,6 +552,18 @@ export function computeStrides(shape: number[]): number[] { return strides; } +/** + * Create typed array for scalar value. Used for storing in `DataStorage`. + */ +export function createScalarValue( + value: DataType, dtype: DataType): BackendValues { + if (dtype === 'string') { + return encodeString(value); + } + + return toTypedArray([value], dtype); +} + export function toTypedArray(a: TensorLike, dtype: DataType): TypedArray { if (dtype === 'string') { throw new Error('Cannot convert a string[] to a TypedArray'); diff --git a/tfjs-layers/src/layers/core_test.ts b/tfjs-layers/src/layers/core_test.ts index 03674f48e1e..f30c323876b 100644 --- a/tfjs-layers/src/layers/core_test.ts +++ b/tfjs-layers/src/layers/core_test.ts @@ -11,7 +11,6 @@ /** * Unit tests for core.ts. */ - import {mul, ones, scalar, Tensor, tensor2d, tensor3d, tensor4d, zeros} from '@tensorflow/tfjs-core'; import * as K from '../backend/tfjs_backend'; @@ -116,18 +115,20 @@ describeMathCPUAndGPU('Dropout Layer', () => { } }); - describe('tensor with seed get specific value', () => { - const training = true; - const rate = 0.5; - const noiseShape = [2, 3, 4]; - const x = ones([2, 3, 4]); - const seed = 23; - const dropoutLayer = tfl.layers.dropout({rate, noiseShape, seed}); - const y = dropoutLayer.apply(x, {training}) as Tensor; - const yValuesExpected = [ - 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 2, 0, 2, 2, 2, 0 - ]; - expectTensorsClose(y, tensor3d(yValuesExpected, [2, 3, 4])); + describe('tensor with seed', () => { + it('get specific value.', () => { + const training = true; + const rate = 0.5; + const noiseShape = [2, 3, 4]; + const x = ones([2, 3, 4]); + const seed = 23; + const dropoutLayer = tfl.layers.dropout({rate, noiseShape, seed}); + const y = dropoutLayer.apply(x, {training}) as Tensor; + const yValuesExpected = [ + 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 2, 0, 2, 2, 2, 0 + ]; + expectTensorsClose(y, tensor3d(yValuesExpected, [2, 3, 4])); + }); }); }); diff --git a/tfjs-layers/src/layers/normalization_test.ts b/tfjs-layers/src/layers/normalization_test.ts index a568c24dc30..1fa08c709b8 100644 --- a/tfjs-layers/src/layers/normalization_test.ts +++ b/tfjs-layers/src/layers/normalization_test.ts @@ -669,7 +669,7 @@ describeMathCPUAndGPU('BatchNormalization Layers: Tensor', () => { }); }); -describe('LayerNormalization Layer: Symbolic', () => { +describeMathCPUAndGPU('LayerNormalization Layer: Symbolic', () => { it('Invalid axis value leads to constructor error', () => { expect(() => tfl.layers.layerNormalization({ // tslint:disable-next-line:no-any