1 पॉइंट द्वारा GN⁺ 2024-04-07 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • पुराने scientific और engineering computation assets, यानी Fortran numerical code को browser में लाने के लिए WebAssembly compile path की ज़रूरत होती है, और webR इसके लिए patched LLVM flang-new का उपयोग करता है
  • f2c, LFortran, Dragonegg, Classic Flang, LLVM Flang — इन सभी में modern Fortran support, target architecture, maintainability के मामले में सीमाएँ हैं, इसलिए अभी तक कोई सरल standard solution मौजूद नहीं है
  • LLVM Flang सीधे wasm32-unknown-emscripten target को support नहीं करता, इसलिए TargetWasm32 जोड़ना पड़ता है, और runtime linking में host और target के long size के अंतर से समस्या पैदा होती है
  • patched flang-new, Emscripten, और Fortran runtime static libraries को मिलाकर Fortran subroutine को C या JavaScript से call किया जा सकता है, और PRINT, ALLOCATE, CHARACTER arguments भी handle किए जा सकते हैं
  • BLAS 3.12.0 और LAPACK 3.12.0 reference implementation को WebAssembly static libraries के रूप में build करके handwritten digit classification और polynomial interpolation demo को browser में चलाया गया

मौजूदा Fortran numerical code को browser में लाना

  • Fortran 1957 में आया एक पुराना language है, लेकिन scientific और engineering computation में लंबे समय से इस्तेमाल होता रहा है, और modern Fortran अब Fortran 77 के fixed-format constraints से काफी हद तक बाहर आ चुका है
  • लक्ष्य यह है कि modern Fortran routines को WebAssembly में compile करके browser में चलाया जाए, numerical arguments लिए जाएँ, BLAS·LAPACK routines से computation किया जाए, और फिर result लौटाया जाए या console में print किया जाए
  • यह approach SciPy या R जैसे BLAS·LAPACK पर निर्भर higher-level programming environments को web पर लाने में मदद कर सकती है
  • JavaScript या Rust में numerical routines को दोबारा लिखने के बजाय, पहले से validate किए गए Fortran-आधारित tools और libraries का उपयोग किया जा सकता है
  • webR project patched LLVM flang-new compiler के साथ Fortran code को WebAssembly में compile करता है
  • मौजूदा तरीका hacks पर निर्भर है, और अधिक अनुभवी compiler developers की मदद के बिना इन बदलावों को LLVM में योगदान करना कठिन है

Fortran→WebAssembly tools की वर्तमान स्थिति

  • 2024 तक कई tools और toolchains मौजूद हैं, लेकिन पूरी तरह functional और simple solution अभी भी उपलब्ध नहीं है
  • f2c

    • f2c Fortran 77 को C code में बदलता है, और फिर Emscripten उसे WebAssembly में compile कर सकता है
    • Pyodide Fortran code वाले Python packages को compile करते समय यही तरीका उपयोग करता है
    • Pyodide roadmap में भी इस तरीके को “अच्छा काम नहीं करता” कहा गया है
    • यह modern Fortran code के लिए उपयुक्त नहीं है, और conversion के बाद भी गंभीर errors और बड़े पैमाने पर patches की ज़रूरत पड़ती है
  • LFortran

    • LFortran ने पिछले कुछ वर्षों में काफ़ी प्रगति की है और सीधे WebAssembly में compile कर सकता है
    • लेकिन यह अभी alpha stage में है, इसलिए developers के अनुसार वास्तविक code compile issues की उम्मीद की जानी चाहिए
    • MINPACK जैसे कुछ projects compile हो जाते हैं, लेकिन पूरी Fortran spec support न होने से बड़े projects fail हो सकते हैं
    • इसका development goal Fortran 2018 का full support है, और Jupyter जैसा interactive Fortran REPL इसकी खास feature है
  • Dragonegg

    • Dragonegg एक GCC plugin है जो GCC frontend का उपयोग करके LLVM IR export करता है
    • LLVM backend से WebAssembly output बनाया जा सकता है, और webR ने शुरू में Fortran source को WebAssembly में compile करने के लिए यही तरीका अपनाया था
    • लेकिन इसका latest supported version gcc-4.8 और llvm-3.3 है, इसलिए बहुत पुराने GCC·LLVM की ज़रूरत पड़ती है
    • ज़्यादातर users को VM या Docker container चाहिए होता है, और Dragonegg द्वारा export किया गया LLVM IR भी WebAssembly output के लिए अतिरिक्त post-processing माँगता है
    • 2020 में Fortran code को WebAssembly में compile करने का यह लगभग इकलौता व्यावहारिक तरीका था
  • Classic Flang

    • Classic Flang, open source किए गए PGI/NVIDIA pgfortran पर आधारित LLVM-target Fortran compiler है
    • यह 32-bit output support नहीं करता, इसलिए wasm32 target पर इस्तेमाल नहीं किया जा सकता
    • लिखे जाने के समय Firefox, Chrome, और Node wasm64 को support करते हैं, लेकिन feature flag के पीछे
    • project documentation भी संकेत देती है कि नए projects के लिए Classic Flang चुनना शायद अच्छा विचार नहीं है
  • LLVM Flang

    • LLVM Flang LLVM के लिए Fortran frontend को शुरू से दोबारा लागू करने वाला project है, और LLVM 11 से LLVM project का हिस्सा है
    • इसे अभी production-ready नहीं माना जाता, लेकिन flang-new का pre-production version वास्तविक Fortran code compile करने के लिए काफ़ी उपयोगी हो चुका है
    • default state में यह WebAssembly output नहीं बना सकता
    • LLVM की modular design का उपयोग करके Flang frontend और LLVM WebAssembly backend को साथ जोड़ा जा सकता है
    • 2020 में भी यह संभव था, लेकिन उसके लिए बड़े LLVM patches, custom math routines injection, और multi-stage compile process की ज़रूरत थी
    • अब flang-new frontend के विकास की वजह से LLVM source में छोटे बदलावों के साथ Fortran→WebAssembly compiler बनाया जा सकता है

WebAssembly के लिए LLVM Flang build करना

  • package manager से install किए गए LLVM में flang-new binary शामिल न हो, ऐसा हो सकता है
    • उदाहरण के लिए macOS Homebrew के LLVM v17.0.6 में flang-new command नहीं मिला
  • क्योंकि LLVM Flang source में बदलाव करने थे, इसलिए LLVM v18.1.1 source को सीधे build किया गया
  • CMake configuration में default target triple को wasm32-unknown-emscripten रखा गया, और WebAssembly target तथा clang;flang;mlir projects enable किए गए
  • build पूरा होने के बाद build/bin/flang-new --version में यह जानकारी दिखाई देती है
    • version: flang-new version 18.1.1
    • target: wasm32-unknown-emscripten
    • thread model: posix

पहली समस्या: wasm32 target implement नहीं है

  • साधारण Fortran subroutine foo.f08 को flang-new से compile करने पर यह error मिलता है
    • not yet implemented: target not implemented
  • वजह यह है कि flang-new में wasm32-unknown-emscripten target triple अभी implement नहीं किया गया है
  • इसका समाधान flang/lib/Optimizer/CodeGen/Target.cpp में TargetWasm32 target characteristics जोड़ने वाला patch है
    • default width को 32 पर सेट किया जाता है
    • complex arguments और return types को WebAssembly-side LLVM types में बदलने के लिए marshalling define किया जाता है
    • llvm::Triple::ArchType::wasm32 branch में TargetWasm32 को जोड़ा जाता है
  • patch के बाद दोबारा build करने पर Fortran source WebAssembly object में compile हो जाता है
    • file foo.o result: WebAssembly (wasm) binary module version 0x1 (MVP)
    • llvm-nm foo.o में foo_ symbol देखा जा सकता है

C और JavaScript से Fortran subroutine call करना

  • Fortran routines आम तौर पर arguments को reference से pass करती हैं, और INTENT() से argument के उपयोग का तरीका घोषित किया जा सकता है
  • उदाहरण Fortran subroutine foo, x, y, z integer arguments लेकर z = x + y करती है
  • native build में gfortran -c foo.f08 -o foo.o चलाने पर symbol name जैसे foo_ के अंत में underscore लग सकता है
  • C से call करते समय external symbol को extern void foo_(int*, int*, int*); की तरह declare करके arguments के addresses pass किए जाते हैं
  • WebAssembly में flang-new से बने foo.o को Emscripten से C code के साथ link किया जा सकता है
    • emcc main.c foo.o -o main.js
    • node main.js output: 1 + 1 = 2
  • JavaScript से direct call

    • C code के बिना JavaScript से Fortran subroutine को सीधे call भी किया जा सकता है
    • Emscripten link stage में _foo_, _malloc, _free export किए जाते हैं
    • emcc foo.o -sEXPORTED_FUNCTIONS=_foo_,_malloc,_free -o foo.js
    • JavaScript Module._malloc() से integers के लिए storage allocate करता है, Module.HEAPU32 में values लिखता है, फिर Module._foo_(x, y, z) call करता है
    • execution result इस प्रकार है
    • x = 123
    • y = 456
    • x + y = 579
    • browser में foo.js और standalone.js को HTML में load करके यही result JavaScript console में देखा जा सकता है

दूसरी समस्या: Fortran runtime library

  • PRINT *, "Hello, World!" वाली Fortran subroutine build करने पर link stage में runtime symbols न मिलने की error आती है
    • _FortranAioBeginExternalListOutput
    • _FortranAioOutputAscii
    • _FortranAioEndIoStatement
  • कारण यह है कि LLVM Fortran runtime library अभी WebAssembly के लिए compile नहीं की गई थी
  • runtime library LLVM source tree के llvm-project/flang/runtime में C++ में लिखी गई है
  • Emscripten के em++ और emar से runtime source build करने पर static library build/flang/runtime/libFortranRuntime.a बनाई जा सकती है
  • इस library को link करने पर Hello, World! build आगे बढ़ती है, लेकिन शुरुआत में function signature mismatch warning आती है

तीसरी समस्या: host और target के long size का अंतर

  • hello.o और Fortran runtime library को link करने पर _FortranAioOutputAscii signature mismatch warning आती है
    • Fortran object side (i32, i32, i64) -> i32 expect करती है
    • Emscripten से built runtime side (i32, i32, i32) -> i32 के रूप में define होती है
  • WebAssembly में अलग-अलग compilation units में define किए गए symbols के arguments और return types का consistent होना ज़रूरी है
  • यह समस्या सिर्फ warning पर खत्म नहीं होती, बल्कि Node में run करने पर RuntimeError: unreachable के साथ fail होती है
  • LLVM Flang के RTBuilder.h में एक TODO comment है कि sizeof का उपयोग build == host == target मान लेता है
  • modern 64-bit Unix-like hosts में sizeof(long) 8 bytes होता है, लेकिन wasm32-unknown-emscripten target में यह 4 bytes होना चाहिए
  • Fortran के CHARACTER type arguments को function या subroutine में pass करते समय string length के लिए एक hidden argument जुड़ सकता है
  • Fortran runtime library में यह length argument size_t के रूप में declare है, जो typedef chain के बाद unsigned long के बराबर बनता है
  • इसी hidden argument के size difference से i64 और i32 mismatch पैदा होता है

अस्थायी patch: 4-byte value force करना

  • आदर्श समाधान यह है कि cross-compilation के समय flang-new, host से स्वतंत्र होकर target architecture और data model के अनुसार i32 या i64 emit करे
  • फिलहाल wasm32 और Emscripten के हिसाब से long size को 4 bytes पर hardcode करने वाला patch उपयोग किया गया
  • patch दो हिस्सों में है
    • RTBuilder.h में long और unsigned long के model types को 8 * sizeof(...) के बजाय 8 * 4 पर force किया गया
    • CodeGen.cpp में malloc() call argument को 64-bit के बजाय 32-bit integer के रूप में generate किया गया, और allocation size को i32 में cast किया गया
  • इस बदलाव से Fortran 90 में आए ALLOCATE()-आधारित dynamic allocation भी ठीक हो गया
  • rebuild के बाद hello.f08 और hello.c को runtime library के साथ link करने पर warning के बिना build हो जाता है, और Node में यह output मिलता है
    • Hello, World!

BLAS को WebAssembly में build करना

  • BLAS linear algebra के common operations, जैसे matrix·vector multiplication, करने वाले low-level routines का set है
  • मूल BLAS routines 1979 में जारी हुए थे, और numerical computing में de facto standard हैं
  • reference implementation BLAS 3.12.0 Fortran 90 में लिखी गई है और netlib से प्राप्त की जा सकती है
  • make.inc में ये tools specify करके build किया जाता है
    • FC = ../build/bin/flang-new
    • FFLAGS = -O2
    • AR = emar
    • RANLIB = emranlib
  • build result के रूप में blas_LINUX.a static library बनती है
  • उदाहरण Fortran routine bar, BLAS level 2 routine ZGEMV() को call करती है
  • ZGEMV() complex matrix-vector operation करती है, और example में COMPLEX(KIND=8) arguments तथा CHARACTER config argument 'N' इस्तेमाल होता है
  • C program में complex arrays बनाकर Fortran routine को pass किया जाता है, फिर result print किया जाता है
  • Node execution result इस प्रकार है
    • Y[0]: 23.000000 + 6.000000i
    • Y[1]: 18.000000 + 10.000000i
    • Y[2]: 6.000000 + 16.000000i
  • इससे पुष्टि होती है कि Fortran 90 source से compile किया गया BLAS, WebAssembly के तहत चल रहा है

browser example: handwritten digit classifier

  • demo एक multilayer perceptron (MLP) artificial neural network के जरिए हाथ से लिखे 0–9 digits को classify करता है
  • user mouse या touchscreen से digit draw कर सकता है, और network द्वारा predict की गई relative probabilities दाईं ओर के plot में दिखाई जाती हैं
  • model weights Python में pre-train किए गए थे, लेकिन classification run time पर browser में JavaScript और WebAssembly से की जाती है
  • MLP classification प्रक्रिया मूलतः matrix-vector addition और multiplication की repeated sequence है
  • भारी computation एक Fortran subroutine करती है, जो BLAS level 2 routine DGEMV() का उपयोग करती है

LAPACK को WebAssembly में build करना

  • LAPACK linear algebra problems को numerically solve करने वाली software library है, जो BLAS के ऊपर बनी है
  • reference implementation LAPACK 3.12.0 netlib पर उपलब्ध है और modified BSD license के तहत वितरित होती है
  • make.inc.example को make.inc में copy करने के बाद ये settings बदली जाती हैं
    • FC को built flang-new के full path पर सेट किया जाता है
    • FFLAGS = -O2
    • AR = emar
    • RANLIB = emranlib
    • TIMER = INT_CPU_TIME
  • make lib command से WebAssembly static library liblapack.a बनाई जाती है
  • उसके बाद LAPACK routines को BLAS example जैसी ही पद्धति से call किया जा सकता है

browser example: linear algebra से polynomial interpolation

  • demo दिए गए points के set के लिए interpolating polynomial ढूँढता है, और दिखाता है कि LAPACK routines browser में चल सकती हैं
  • जब user plot पर click करके नया point जोड़ता है, तो सभी points से गुजरने वाला interpolating polynomial निकाला जाता है
  • इसके लिए Vandermonde’s method इस्तेमाल किया जाता है
  • इस तरह प्राप्त linear algebra equation को LAPACK की DGELS() routine से numerically solve किया जाता है
  • n data points को ठीक-ठीक शामिल करने वाला degree n-1 polynomial हमेशा पाया जा सकता है
  • n बड़ा होने पर लगातार data points के बीच polynomial में बड़ा oscillation आने वाला Runge phenomenon हो सकता है, जिसे spline interpolation से टाला जा सकता है

बाकी चुनौतियाँ और उपलब्ध tools

  • patched LLVM Flang के साथ modern Fortran code को WebAssembly object में compile किया जा सकता है
  • इस approach का फायदा यह है कि web के लिए numerical algorithms को JavaScript में दोबारा लिखने के बजाय, पहले से मौजूद Fortran tools और libraries का उपयोग किया जा सकता है
  • अगर flang-new आधिकारिक रूप से WebAssembly support करे, तो webR और R packages के लिए LLVM fork बनाए रखने का बोझ कम होगा
  • फिलहाल LLVM Flang और cross-compilation issues को सभी targets पर सही ढंग से हल करने के लिए बेहतर रास्ते की ज़रूरत है
  • जो users LLVM Flang को खुद build करना कठिन मानते हैं या करना नहीं चाहते, उनके लिए GitHub Container Registry पर patched LLVM Flang binary Docker container उपलब्ध है

1 टिप्पणियां

 
GN⁺ 2024-04-07
Hacker News की राय
  • थोड़ा बैकग्राउंड जोड़ें तो, यह Fortran exploration George के उस शानदार WebR काम का हिस्सा है जो वे R को ब्राउज़र में चलाने के लिए कर रहे हैं
    R source में काफी Fortran code है, और मेरी समझ से WebR पहले f2c से Fortran को C में compile करता था, फिर उस C को wasm में compile करता था
    LLVM Flang patch की वजह से WebR को असली Fortran compiler के साथ build करना संभव हो गया
    George ने blog post में सीधे नहीं कहा, लेकिन उन्होंने कहा था कि वे चाहते हैं कि Flang इस patch को स्वीकार करे या इसे किसी बेहतर तरीके से implement करे
    ऐसा होने पर अलग patch maintain करने की जरूरत नहीं रहेगी, और बिना modification वाला Flang wasm में compile कर सकेगा, जिससे Fortran इस्तेमाल करने वाले दूसरे projects को भी फायदा होगा
    https://docs.r-wasm.org/webr/latest/

    • Pull requests हमेशा welcome हैं(https://github.com/llvm/llvm-project), और मदद चाहिए तो LLVM Fortran development community(https://discourse.llvm.org/c/subprojects/flang/33) से संपर्क कर सकते हैं
      हालांकि मैं Nvidia के Fortran product development को पूरा करने के लिए जरूरी कामों पर focus कर रहा हूं, इसलिए इस तरह के काम के लिए मेरे पास समय नहीं बचता
    • Source-to-source conversion से F77 को JavaScript में ले जाना भी पहले से काफी ठीक है, लेकिन WASM बेहतर है
  • 20 साल पहले Xilinx में FORTRAN compile करने का काम किया था, और मुझे बस इतना याद है कि f2c.h header file में barf की definition थी
    /* f2c.h -- Standard Fortran to C header file /
    /* barf [ba:rf] 2. "He suggested using FORTRAN, and everybody barfed."
    (https://www.netlib.org/clapack/f2c.h)

    • हर जगह capital letters में FORTRAN लिखना मेरे बारे में कुछ बताता है क्या? मेरी आंखों को Fortran अजीब लगता है
  • समझाने के तरीके के रूप में सबसे सरल non-trivial example इस्तेमाल करना सच में अच्छा है
    लेख “JavaScript से BLAS function call करना” जैसी concrete समस्या पर आधारित है, इसलिए बहुत कुछ सीखने जैसा लगा, और यह बेहतरीन लेख है

  • समझ नहीं आ रहा कि प्रभावित होना चाहिए या डर जाना चाहिए, शायद दोनों ही
    f18 build करते समय llvm-project/main का latest source इस्तेमाल करने की सलाह दूंगा
    project तेजी से बदल रहा है, इसलिए पहले से ठीक हो चुकी समस्याओं को debug करना या पहले से implement हो चुके features miss करना समय की बर्बादी है

    • LLVM source को पर्याप्त नहीं समझ पाने की वजह से मुख्य बात पकड़ना मुश्किल था
      क्या मकसद WebAssembly port पर काम करके intermediate code को उस point तक ले जाना है जहां वह Fortran तक काम करे?
  • WebAssembly development के बारे में ज्यादा नहीं जानता
    consumer के नजरिए से WebAssembly अभी क्या देता है? या यह उस भविष्य के लिए foundational work जैसा है जहां programs सच में portable हो जाएंगे?
    मैंने सुना है कि WebAssembly device network या files जैसे access restrictions को आसान बना देता है, लेकिन नहीं पता यह सिर्फ theory है या पहले से implement हो चुका है

    • मूल रूप से Wasm एक virtual machine है, और portability के मामले में JVM से बहुत मिलता-जुलता है
      मुख्य फर्क यह है कि Wasm में खुद कोई standard library नहीं है और यह input/output functions expose नहीं करता
      इसलिए host, यानी VM आप खुद बना सकते हैं और Wasm binary के इस्तेमाल के लिए functions expose कर सकते हैं; Wasm binary बाहरी दुनिया तक सिर्फ उन्हीं functions के जरिए पहुंच सकती है
      एक और फायदा यह है कि binary format proprietary नहीं है और इसकी specification है, इसलिए कोई भी Wasm VM implement कर सकता है
      हालांकि अभी इसे अच्छी स्थिति में कहना मुश्किल है; यह बहुत early है, W3C जैसे groups में कई नए features standardize हो रहे हैं और प्रक्रिया भी बहुत धीमी है
    • अगर आप developer हैं या product deploy कर रहे हैं और मजबूत sandboxing चाहते हैं, तो WASM आज इस्तेमाल किए जा सकने वाले सबसे अच्छे विकल्पों में से एक है
      ज्यादातर targets पर deploy या cross-compile करने का तरीका भी है
    • अगर इसे सही तरह implement किया गया है, तो customer को पता ही नहीं चलना चाहिए
      यह वैसा ही है जैसे आम तौर पर हमें नहीं पता होता और खास फर्क नहीं पड़ता कि computer CPU ARM है या x86
      इसलिए अगर आपको इस तरह की details में रुचि नहीं है कि यह native code के रूप में चल रहा है या JVM·.NET·WASM जैसी VM पर, तो यह कहना मुश्किल है कि यह दूसरी solutions से ज्यादा क्या देता है
      आम तौर पर सिर्फ खराब cases दिखते हैं, और वही “हर Electron program फूला हुआ और resources खाने वाला monster है, और हर native app अपने-आप efficient software engineering का चमत्कार है” जैसे memes में बदल जाता है
  • काश मैंने 1981/82 में लिखा अपना Fortran 78 code संभालकर रखा होता, तो यहां चलाकर test कर सकता था
    वह Jovial programming language source code formatter था, और Fortran में करने लायक काम नहीं था, लेकिन उस समय वही एकमात्र विकल्प था

    • क्या आप Orange County के Hughes में काम करते थे?
  • क्या JavaScript में इस्तेमाल करने लायक, कुछ हद तक production-ready linear algebra ecosystem है?
    खोजने पर ज्यादातर करीब 10 साल पुराने परिचित libraries के JavaScript ports मिलते हैं, जैसे emscripten के जरिए किए गए ports; सोच रहा हूं कि कहीं मैं कुछ miss तो नहीं कर रहा

    • क्या WebGPU या WebNN के ऊपर BLAS के बराबर कुछ है?
  • LFortran को ज़्यादा गहराई से न कवर करना अजीब है
    इसका एक शानदार और हैरान कर देने वाला WASM example भी है जो online चलता है
    https://dev.lfortran.org/

    • लेख में लिखा है कि LFortran compiler पिछले कुछ वर्षों में काफ़ी आगे बढ़ा है
      2020 में इसमें बहुत-सी features मौजूद नहीं थीं और यह Fortran के बहुत छोटे subset को ही support करता था, लेकिन अब यह कहीं ज़्यादा व्यापक language features support करता है और काफ़ी Fortran code compile कर सकता है
      यह WebAssembly में भी native compile कर सकता है
      हालांकि LFortran इस्तेमाल करने में अभी भी कुछ rough edges हैं, और developers का कहना है कि project फिलहाल alpha stage में माना जाता है और वास्तविक code compile करते समय समस्याएँ आ सकती हैं
      MINPACK जैसे कुछ projects को सफलतापूर्वक compile किया जा सकता है, लेकिन क्योंकि यह अभी Fortran की पूरी specification support नहीं करता, इसलिए कई बड़े projects अब भी compile नहीं हो पाते
      LFortran developers का लक्ष्य Fortran 2018 का पूरा support देना है, और इसकी एक notable feature Jupyter जैसा interactive Fortran REPL है
      कुछ और वर्षों के development के बाद, WebAssembly के लिए Fortran code compile करने का यह एक बेहतरीन विकल्प बन सकता है
      साथ ही https://dev.lfortran.org पर LFortran demo देखने को कहा गया है, जो बहुत प्रभावशाली है, लेकिन मैंने सबसे पहले जो x * 2 को x * 3 में बदलने की कोशिश की, उसे current code generator support नहीं करता था
  • .NET और Java के ऊपर Fortran भी मौजूद है
    https://www.silverfrost.com/14/ftn95/ftn95_fortran_95_for_microsoft_dotnet_features.aspx
    https://dl.acm.org/doi/10.1145/376656.376833

  • https://medium.com/@tomasreimers/compiling-tensorflow-for-the-browser-f3387b8e1e1c पर काम करते समय मैंने सोचा था कि यह वाकई अच्छी बात है कि TensorFlow ने Fortran में लिखी लोकप्रिय math libraries BLAS/Lapack के बजाय Eigen का इस्तेमाल किया
    वरना काम कहीं ज़्यादा बढ़ जाता