<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: WhiteBlackGoose</title>
    <description>The latest articles on DEV Community by WhiteBlackGoose (@whiteblackgoose).</description>
    <link>https://dev.to/whiteblackgoose</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F487276%2F3e429657-5d96-4be1-ae3a-3dd8f0946b0b.png</url>
      <title>DEV Community: WhiteBlackGoose</title>
      <link>https://dev.to/whiteblackgoose</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/whiteblackgoose"/>
    <language>en</language>
    <item>
      <title>Create static website yourself. No 3rd party services</title>
      <dc:creator>WhiteBlackGoose</dc:creator>
      <pubDate>Wed, 20 Jul 2022 08:25:35 +0000</pubDate>
      <link>https://dev.to/whiteblackgoose/create-static-website-yourself-no-3rd-party-services-1314</link>
      <guid>https://dev.to/whiteblackgoose/create-static-website-yourself-no-3rd-party-services-1314</guid>
      <description>&lt;p&gt;... except github.&lt;/p&gt;

&lt;p&gt;I didn't mention in the title the language we're going to use, because at this point I'm gonna use the &lt;strong&gt;right tool&lt;/strong&gt;. The right tool being .NET, more specifically, F#.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dotnet.microsoft.com/en-us/download" rel="noopener noreferrer"&gt;.NET SDK&lt;/a&gt; is required.&lt;/p&gt;

&lt;p&gt;So this is a short step-by-step guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Create a repository on github.com
&lt;/h2&gt;

&lt;p&gt;This one is easy. I'm gonna create a repo with some list of repos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9aqmg01tj70pgy5jx8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9aqmg01tj70pgy5jx8j.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Clone it locally
&lt;/h2&gt;

&lt;p&gt;I'm gonna open my favorite terminal and type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/WhiteBlackGoose/MyFunRepos
cd MyFunRepos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Initialize the project
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new console -n WebsiteGenerator -lang F#
cd WebsiteGenerator
dotnet add package Giraffe.ViewEngine --prerelease
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates you an project in F#! Also adds a package that allows to create html tags right in code. Soon about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Open the project
&lt;/h2&gt;

&lt;p&gt;We're creating something very simple, so you can either open &lt;code&gt;Program.fs&lt;/code&gt; with your favorite text editor, or just open the &lt;code&gt;fsproj&lt;/code&gt; file with an IDE.&lt;/p&gt;

&lt;p&gt;I'm gonna use nvim for it.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpsmtjwz7fqn0so98isj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpsmtjwz7fqn0so98isj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  5. Create your first webpage
&lt;/h2&gt;

&lt;p&gt;Let's create an empty html page which just has a header and some random text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;﻿open Giraffe.ViewEngine


html [] [
    body [] [
        h1 [] [ Text "Hello, world" ]
        p [] [
            Text "Some text"
        ]
    ]
]
|&amp;gt; RenderView.AsString.htmlNode
|&amp;gt; fun code -&amp;gt; System.IO.File.WriteAllText("./index.html",  code)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quite readable, right? Let's run it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet run
firefox index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't have firefox, you can try&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xdg-open index.html  # linux
start index.html     # windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or just open the html page from your file explorer!&lt;/p&gt;

&lt;p&gt;Works for me:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0u1p3z87wsb55y7x0srj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0u1p3z87wsb55y7x0srj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Add some data to it
&lt;/h2&gt;

&lt;p&gt;You could've made that page with just html. Why do you need F# for it?&lt;/p&gt;

&lt;p&gt;Okay, let's complicate the story. This time we're gonna add a list of data and some condition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;﻿open Giraffe.ViewEngine

type Repo = {
    name : string
    lang : string
}

let myFunReposList = [
    { name = "MyFunRepos";             lang = "F#" }
    { name = "FStarHelloWorld";        lang = "F*" }
    { name = "LambdaCalculusFSharp";   lang = "F#" }
    { name = "AsmToDelegate";          lang = "C#" }
]

html [] [
    body [] [
        h1 [] [ Text "My Fun Repos" ]
        ul [] [
            for { name = name; lang = lang } in myFunReposList do
                li [] [
                    p [] [ Text $"Repo {name}" ]
                    a [_href $"https://github.com/WhiteBlackGoose/{name}"] [ Text name ]
                    p [] [
                        Text "Made in "
                        if lang = "F#" || lang = "C#" then
                            Text $".NET {lang}"
                        else
                            Text lang
                    ]
                ]
        ]        
    ]
]
|&amp;gt; RenderView.AsString.htmlNode
|&amp;gt; fun code -&amp;gt; System.IO.File.WriteAllText("./index.html",  code)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, what are we doing here? We created a record &lt;code&gt;Repo&lt;/code&gt;, which has two fields (for simplicity). Then I'm creating a list of my repos willing those fields.&lt;/p&gt;

&lt;p&gt;There's no string concatenation and no hell with parentheses. We don't even have commas in the end of each line.&lt;/p&gt;

&lt;p&gt;Now the most interesting part. See, I'm inserting a regular &lt;code&gt;for&lt;/code&gt; loop right in the &lt;code&gt;ul&lt;/code&gt; element! I'm not creating it in a separate variable or function or anything, I &lt;em&gt;just&lt;/em&gt; write it inside the hmtl tag. As if it's some template engine, but it's not, it's a regular language.&lt;/p&gt;

&lt;p&gt;I even inserted an &lt;code&gt;if&lt;/code&gt; condition there, which also reads very well!&lt;/p&gt;

&lt;p&gt;Let's see what we got for this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Friubi6abbmbl93lwz1o1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Friubi6abbmbl93lwz1o1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This created a simple html page. That's it. No template engine. This code is written in &lt;em&gt;one&lt;/em&gt; programming language, and you can debug it. You're in full control!&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Automatic website creation
&lt;/h2&gt;

&lt;p&gt;Ok, we made an html page. But it's not a website yet. What we want is that our website could be automatically published on every push. So let's write our Github Actions workflow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Website publish&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup .NET &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-dotnet@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;dotnet-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;6.0.x'&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run generator&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;mkdir generated &amp;amp;&amp;amp; cd generated&lt;/span&gt;
        &lt;span class="s"&gt;dotnet run --project ../WebsiteGenerator/WebsiteGenerator.fsproj&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Push to gh-pages&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JamesIves/github-pages-deploy-action@4.1.4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh-pages&lt;/span&gt;
        &lt;span class="na"&gt;folder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./generated&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file is quite readable on its own. We install .NET SDK, then we run our generator from a certain folder, and then we just push the folder to the &lt;code&gt;gh-pages&lt;/code&gt; branch! That is it.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Activate Pages
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to your repo's settings&lt;/li&gt;
&lt;li&gt;Go to Pages&lt;/li&gt;
&lt;li&gt;Choose gh-pages as source branch&lt;/li&gt;
&lt;li&gt;Press Save&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1qjhttyqj61kmpmyhfb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1qjhttyqj61kmpmyhfb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Enjoy the result!
&lt;/h2&gt;

&lt;p&gt;My url looks like this: &lt;a href="https://whiteblackgoose.github.io/MyFunRepos/" rel="noopener noreferrer"&gt;whiteblackgoose.github.io/MyFunRepos/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now I can easily add content to the page, or create many pages, as well as add some data, maybe even downloading some dataset and then displaying it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;We created a simple static website in F#! Here's main features of this setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have full control of it. No static website generator were used&lt;/li&gt;
&lt;li&gt;Syntax of F# is really handy here. You can insert loops, conditionals, and some other control flow constructions right in the page!&lt;/li&gt;
&lt;li&gt;Free hosting and free default domain (but you can set your own domain if you want)&lt;/li&gt;
&lt;li&gt;It takes 5-30 minutes to set up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for your attention! My &lt;a href="https://github.com/WhiteBlackGoose" rel="noopener noreferrer"&gt;github&lt;/a&gt;, &lt;a href="https://twitter.com/WhiteBlackGoose" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/WhiteBlackGoose/MyFunRepos" rel="noopener noreferrer"&gt;Sources&lt;/a&gt;&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>webdev</category>
      <category>github</category>
      <category>opensource</category>
    </item>
    <item>
      <title>A Tensor Library in a Week</title>
      <dc:creator>WhiteBlackGoose</dc:creator>
      <pubDate>Sun, 11 Oct 2020 11:42:34 +0000</pubDate>
      <link>https://dev.to/whiteblackgoose/a-tensor-library-in-a-week-5259</link>
      <guid>https://dev.to/whiteblackgoose/a-tensor-library-in-a-week-5259</guid>
      <description>&lt;p&gt;Hello!&lt;/p&gt;

&lt;p&gt;For this article we take Tensor as a N-dimensional array whose last two axes might be interpreted as Matrix and/or the last axis might be interpreted as Vector. For TLDR the result is &lt;a href="https://github.com/asc-community/GenericTensor"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What do we want?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Tensors (N-dimensional storage)&lt;/li&gt;
&lt;li&gt;Implementation of methods and functions for working with tensors as with data storages&lt;/li&gt;
&lt;li&gt;Implementation of mathematical operations with matrices and vectors&lt;/li&gt;
&lt;li&gt;Arbitary type support (not only numeric/built-in ones)&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  What is already implemented?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/ZacharyPatten/Towel"&gt;Towel&lt;/a&gt; has generic matrices, but&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does not support tensors&lt;/li&gt;
&lt;li&gt;Its transposition is an active operation that works for the number of elements&lt;/li&gt;
&lt;li&gt;No multithreading and not super-performant in most operations thanks to delegates (a minor issue, but still)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is also &lt;code&gt;System.Numerics.Tensor&lt;/code&gt;, but it supports neither arbitary type nor mathematical operations.&lt;/p&gt;

&lt;p&gt;Also, there are some computational libraries like &lt;a href="https://github.com/john-h-k/MathSharp"&gt;MathSharp&lt;/a&gt;, &lt;a href="https://github.com/SciSharp/NumSharp"&gt;NumSharp&lt;/a&gt;, &lt;a href="https://github.com/SciSharp/Torch.NET"&gt;Torch.NET&lt;/a&gt;, and &lt;a href="https://github.com/migueldeicaza/TensorFlowSharp"&gt;TensorFlow&lt;/a&gt;, but they all are about built-in numeric types and far from supporting custom.&lt;/p&gt;

&lt;p&gt;Let's get to the implementation of our own mini-library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storing elements, subtensor, transposition
&lt;/h2&gt;

&lt;p&gt;We store elements in a &lt;em&gt;linear array&lt;/em&gt;. To access an element means to multiply indices by some coefficients. Those coefficients are stored in array &lt;code&gt;blocks&lt;/code&gt; of the same length the tensor's shape is. For example, if we have &lt;code&gt;[3 x 4 x 5]&lt;/code&gt;-shaped tensor, our last elements in &lt;code&gt;blocks&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt; (always 1), then 1 * 5 = &lt;code&gt;5&lt;/code&gt;, then 1 * 4 * 5 = &lt;code&gt;20&lt;/code&gt;. &lt;code&gt;blocks&lt;/code&gt; is &lt;code&gt;[20, 5, 1]&lt;/code&gt;. If we access index &lt;code&gt;[1, 0, 4]&lt;/code&gt; then the linear index will be &lt;code&gt;20 * 1 + 5 * 0 + 1 * 4 = 24&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transposition
&lt;/h3&gt;

&lt;p&gt;For this article, we take Transposition as axes order change. The easy way to do so is to create a new tensor and move elements there in the new order. However, sometimes we do not need to copy a tensor, so our &lt;code&gt;Transpose&lt;/code&gt; should work for &lt;code&gt;O(1)&lt;/code&gt; without copying a tensor (which is quite expensive). Let's have a look at the function that computes the linear index for custom indices:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;GetFlattenedIndexSilent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;LinOffset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we could see, we can simulate transposing by swapping elements in &lt;code&gt;blocks&lt;/code&gt;. That is as easy as it sounds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Transpose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;axis1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;axis2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;axis1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;axis2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;axis2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;axis1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;axis1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;axis2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;axis2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;axis1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it, we just change the order of &lt;code&gt;blocks&lt;/code&gt; and &lt;code&gt;Shape&lt;/code&gt; (array of dimensions).&lt;/p&gt;

&lt;h3&gt;
  
  
  Subtensor
&lt;/h3&gt;

&lt;p&gt;We need our &lt;code&gt;Subtensor&lt;/code&gt; function also work for &lt;code&gt;O(1)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Subtensor of a N-dimensional tensor is its one element or its subtensor's one element. For example, if we take a tensor of the &lt;code&gt;[2 x 3 x 4]&lt;/code&gt; shape, its &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; elements are subtensors of shape &lt;code&gt;[3 x 4]&lt;/code&gt;. We actually only need the offset in our linear array, let's see how we can compute it.&lt;/p&gt;

&lt;p&gt;Imagine that we are going to get the n-th subtensor. Then its first element is &lt;code&gt;[n, 0, 0, ...]&lt;/code&gt; in the intial array. Its linear index is &lt;code&gt;n * blocks[0] + 0 * blocks[1] + 0 * blocks[2] + ...&lt;/code&gt; which is &lt;code&gt;n * blocks[0]&lt;/code&gt;. That is the desired offset. So then we create a new tensor with the same &lt;code&gt;linear array&lt;/code&gt; (shared data) but with one number changed: offset, and also &lt;code&gt;blocks[0]&lt;/code&gt; and &lt;code&gt;Shape[0]&lt;/code&gt; removed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other composition operations
&lt;/h3&gt;

&lt;p&gt;All others' implementations come from those two:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SetSubtensor gets a subtensor with shared data and sets all the necessary values to it&lt;/li&gt;
&lt;li&gt;Concat concatenates two tensors by their first axis (for example, &lt;code&gt;concat([3 x 4 x 5], [6 x 4 x 5])&lt;/code&gt; -&amp;gt; &lt;code&gt;[9 x 4 x 5]&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Stack unites a number of tensors into one with additional axis (for example, &lt;code&gt;stack([3 x 4], [3 x 4])&lt;/code&gt; -&amp;gt; &lt;code&gt;[2 x 3 x 4]&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Slice stacks a few subtensors&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All composition operations are described &lt;a href="https://github.com/asc-community/GenericTensor#composition"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mathematical operations
&lt;/h2&gt;

&lt;p&gt;This must be more or less easy since the necessary composition functions are implemented.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Piecewise operations (an operation is performed on two same-coordinates points from two tensors and its result goes to the third tensor)&lt;/li&gt;
&lt;li&gt;Matrix operations. Multiplication, inverse, they all are more or less clear, while I have to say something about computing a determinant.

What's wrong with determinant?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are a few ways to compute determinant. The most obvious way is to use Laplace's method which works for &lt;code&gt;O(1)&lt;/code&gt;. We obviously need something more performant, so we take the method of Gaussian elimination (triangulation &amp;amp; product of all diagonal elements).&lt;/p&gt;

&lt;p&gt;However, if you blindly take this method for, say, &lt;code&gt;int&lt;/code&gt;, you will get unexpectedly wrong answer, not even close to the real one. It is because most implementations of it perform the division operation somewhere during the computation.&lt;/p&gt;

&lt;p&gt;What we should do is implement some kind of &lt;code&gt;SafeFraction&lt;/code&gt;-tensor instead of normal element-wise tensor, where these &lt;code&gt;SafeFraction&lt;/code&gt;'s numerator and denonimator are normal elements. Its operators will be defined as normal operators for fractions: &lt;code&gt;a / b + c / d = (a * d + b * c) / (b * d)&lt;/code&gt;. Likewise, we difne the rest of the operators.&lt;/p&gt;

&lt;p&gt;Unfortunately, there is a disadvantage of this method as well. It is overflow: we accumulate all numbers in both numerator and denominator, and, for example, instead of getting 6 at the end, we get 6'000'000/1'000'000. What we do is just keep both methods (one is with safe division, another one is simple).&lt;br&gt;
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vector operations (dot and cross product)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Full list of them is presented &lt;a href="https://github.com/asc-community/GenericTensor#math-operations"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimization
&lt;/h2&gt;

&lt;p&gt;It should work fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  Templates?
&lt;/h3&gt;

&lt;p&gt;C# does &lt;strong&gt;not&lt;/strong&gt; have templates. One could call the &lt;code&gt;+&lt;/code&gt; operator via reflection and a long spaghetti code of &lt;code&gt;if&lt;/code&gt;s for built-in types (aka &lt;code&gt;if (typeof(T) == typeof(int))&lt;/code&gt;...).&lt;/p&gt;

&lt;p&gt;I wanted full customization, so I declared an &lt;a href="https://github.com/asc-community/GenericTensor/blob/master/GenericTensor/Core/IOperations.cs#L7"&gt;interface&lt;/a&gt; which should be inherited from a struct to be passed as a generic type. I use its methods as static ones, even though today's shapes do not support straight &lt;code&gt;static&lt;/code&gt; methods. This&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TWrapper&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Addition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gets inlined into your struct's overriden method. &lt;a href="https://github.com/asc-community/GenericTensor/blob/master/GenericTensor/Functions/DefaultWrappers.cs#L42"&gt;Here&lt;/a&gt; is an example of such a struct.&lt;/p&gt;

&lt;h3&gt;
  
  
  Indexing
&lt;/h3&gt;

&lt;p&gt;It seems like we should use arbitary number of arguments in &lt;code&gt;this&lt;/code&gt; like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;params&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But when you access some number of arguments, instead of instancing it by number of arguments, it packs them into one array by allocating memory. It is a very expensive operation, so we have to implement many &lt;a href="https://github.com/WhiteBlackGoose/GenericTensor/blob/fcdf6533f8b0353f9b85af815eb873d37c27fced/GenericTensor/Core/Tensor/GenTensor.Iterate.cs#L65"&gt;overloads&lt;/a&gt; to avoid it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exceptions
&lt;/h3&gt;

&lt;p&gt;I wrapped all checks with &lt;code&gt;#if ALLOW_EXCEPTIONS&lt;/code&gt; construction to let the user choose whether they can spend time on checks or not. It is a little performance boost.&lt;/p&gt;

&lt;p&gt;Actually it is not a nano-optimization, there are a lot of checks so avoiding them all will only leave the necessary functional code. Why one would need it? Because some have to perform those checks before passing the tensor to this library, so why do we have to duplicate code? Let's leave it up to the user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multithreading
&lt;/h3&gt;

&lt;p&gt;Thanks to Microsoft, it appears to be extremely &lt;a href="https://github.com/WhiteBlackGoose/GenericTensor/blob/fcdf6533f8b0353f9b85af815eb873d37c27fced/GenericTensor/Functions/PiecewiseArithmetics.cs#L78"&gt;easy&lt;/a&gt; and can be implemented via &lt;code&gt;Parallel.For&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, be careful with that, sometimes it is better to keep single threading:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Kw3jK5Mb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://habrastorage.org/getpro/habr/post_images/28f/df5/2f6/28fdf52f6326d1461dda5fe1d11ccde4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Kw3jK5Mb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://habrastorage.org/getpro/habr/post_images/28f/df5/2f6/28fdf52f6326d1461dda5fe1d11ccde4.png" width="606" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is time (in &lt;code&gt;us&lt;/code&gt;) taken to perform one piecewise addition operation on differently-shaped tensors on machine with i7-7700HQ. As you could see, there is a threshold since which it is better to use multithreading. Yet I added the &lt;code&gt;Threading.Auto&lt;/code&gt; mode so that the best mode can be determined automatically.&lt;/p&gt;

&lt;p&gt;Yet it will never become as fast as those accelerated by CUDA and SIMD since we surely want it to support custom type.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That is about all, thank you for your attention. The library's main repository is &lt;a href="https://github.com/asc-community/GenericTensor"&gt;located on github&lt;/a&gt; (under MIT).&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
    Where is it used?&lt;/p&gt;

&lt;p&gt;The main GenericTensor's user is symbolic algebra library &lt;a href="https://github.com/asc-community/AngouriMath"&gt;AngouriMath&lt;/a&gt;. It uses &lt;code&gt;Entity&lt;/code&gt; class instead of numeric since &lt;code&gt;Entity&lt;/code&gt; is the main expression class of AM.&lt;/p&gt;

&lt;p&gt;For example, that is how you compute determinant symbolically in AM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MathS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Matrices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="s"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// Those letters are symbolic variables, they also could be "x + 2" or "sin(y + a) / sqrt(3)"&lt;/span&gt;
              &lt;span class="s"&gt;"D"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"E"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"F"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="s"&gt;"G"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"H"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"J"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Determinant&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Simplify&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>computerscience</category>
      <category>dotnet</category>
      <category>csharp</category>
      <category>math</category>
    </item>
  </channel>
</rss>
