project management – How to explain a coding problem to a manager who think it a simple problem

I don’t know if this is a right place to ask this question.

How should an engineer explain a technical problem to a manager who don’t know about coding and think it’s a simple problem and should be solved in a minute, but you know it takes a month.

Do the engineer need to gather technical reference or what?

optimization – variance in performance of very simple programs

I’ve written a very simple C program to demonstrate something I’m seeing with a more complex program that I am trying to optimize. Here’s the simple example:

#include <stdio.h>
#include <unistd.h>
#include <inttypes.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>
#include <ctype.h>

int main(int argc, char *argv())
{
    uint64_t loops = 0;
    uint64_t count;

    if (argc > 1) {
        if (sscanf(argv(1), "%" SCNx64, &loops) != 1) {
            fprintf(stderr, "invalid loops %sn", argv(1));
            exit(-1);
        }
    }

    printf("loops = %" PRIx64 "n", loops);
    for (count = 0; count < loops; ++count) {

    }

    return 0;
}

So now I run it a few times on my ubuntu 20.04 lenovo laptop using the same number of loops and the date and time commands to measure how long it takes to execute:

jeff@jeff-ThinkPad-E15:~/opengl/matrix_code/timing$ date; time ./a.out 1000000000; date
Tue 11 May 2021 06:21:51 PM PDT
loops = 1000000000

real    2m15.489s
user    2m15.433s
sys 0m0.004s
Tue 11 May 2021 06:24:07 PM PDT
jeff@jeff-ThinkPad-E15:~/opengl/matrix_code/timing$ date; time ./a.out 1000000000; date
Tue 11 May 2021 06:25:56 PM PDT
loops = 1000000000

real    2m7.822s
user    2m7.792s
sys 0m0.001s
Tue 11 May 2021 06:28:04 PM PDT
jeff@jeff-ThinkPad-E15:~/opengl/matrix_code/timing$

I’d expect such a simple program to execute in closer to constant time, yet as can be seen there’s a 5% difference in execution time. In my more complex program, the variance is much larger, despite the fact that it is doing no I/O. It allocates memory, does a bunch of integer and double float math and frees memory. That’s it.

Is there something I can do to get these numbers more consistent. I was hoping to rely on differences in these timings to determine if optimizations I am doing have the desired effect, but if the exact same code with the exact same data varies so much, my optimization efforts will be blinded by this noise.

Or perhaps I can use some other strategy?

Thanks

spellcasting – I need help with distance scaling in a homebrew RPG – from “your body” to “the whole planet” in 10 simple steps

Square Cube Law

When we increase the range os a spell by a simple value, we increase its area of effect by the square and the volume of effect by the cube. Or rather:

$$R$$ $$A=pi R^2$$ $$V=frac 4 3 pi R^3$$

Energy density is defined as energy per volume. So our power scale should follow the Volumetric scaling, not a linear one. From one step to the next, you increase the energy needed by the third potence.

Self

A typical human body has about a weight of 100 kilos if we are rather broad. A human body also has a density of 1 ton per cubic meter, so a human is 1/10th of a cubic meter or $1 times 10^{-1} text m^3$. That’s, if condensed into a sphere, one of about 30 cm radius. $$frac V pi frac 3 4=R^3$$ $$R=0.287 text{ meters}$$

Planet

Mother earth has a volume of $1.08 times 10^{21} text m^3$.

Scaling the difference

We want to stretch between $1 times 10^{-1} text m^3$ and $1.08 times 10^{21} text m^3$ in 10 steps. That’s -1, 0 and 1 to 21, so 23 numerals for the exponent to scale the volume. Let’s try to get a nice progression, with a factor 1 in front.

  1. $10^{-1} text m^3$ – That’s the volume of our human, so self
  2. $10^{0} text m^3 = 1 text m^3$ – a 1x1x1 meter cube, or anything you can easily touch with one arm.
  3. $10^{1} text m^3 = 10 text m^3$ – Anything within 1.3 meters, or about 2 steps
  4. $10^{3} text m^3$ – Anything within 6.2 meters – about a small building or large room
  5. $10^{6} text m^3$ – Anything within 62 meters – or almost a Manhattan city block (technically that’d be 80.5 meters)
  6. $10^{9} text m^3$ – Anythign within 620 meters – about 8 blocks or a city quarter or village
  7. $10^{12} text m^3$ – Anything within 6.2 kilometers – or if you’d stand in the center of Manhatten, almost the whole of the peninsula. So let’s round that to Town.
  8. $10^{15} text m^3$ – Anything within 62 kilometers – or about the size of an average county or shire or halfway to space
  9. $10^{18} text m^3$ – Anything within 620 kilometers – or whatever is within an about a single European country if you are centered in it.
  10. $10^{21} text m^3$ – Anything within 6203 kilometers – or a sphere as big as earth centered around you. This sphere encompasses a whole continent. Yes, it means you affect less than half the planet, and only a small fraction of the distance to the moon, but this compromise keeps the scaling somewhat nicely.

The scaling here is clearly logarithmic, with two distinct areas: the “short” ranges (steps 1-3) and then the Magnitude steps from 4 to 10. This allows to differentiate better on the low end, and then proceeds into a smooth large scale, offering useful intermediate steps.

enter image description here

Why this scale?!

So, why did I choose this scale, which focusses on the low end?

First of all: game usability & realism

Most spells that a typical player character could or should use need to be in distances that are within sight or useable in what accounts for typical combat ranges. These paradigms are fit up to somewhere between steps 6 and 7, depending on the weapons involved – a typical military rifle is useful all within step 6, while modern artillery would go up to 7.

The typical engagement distances of armies over time are rather short, so a focus on the short end for spells is best to model typical spells and have a difference in ranges available that allows separating between short and medium range combat spells. Some examples:

  • Spear infantry was limited at 15 feet or about 4.5 meters. That’s Range step 4.
  • Archery in the middle ages was used at ranges of about below 300 meters, so inside the range step 6.
  • modern infantry combat doesn’t go further than 500 meters usually, and in urban areas is often quoted to be below 50 meters even. Artillery, especially naval one, can stretch that.
    • in fact, the typical engagement range in WW1 was 50 to 250 meters
    • in WW2, the typical long engagement range for tanks was 500 to 800 meters while infantry fought well shorter at below 300 meters. The longest tank hit recorded was 2.5 kilometers… on a stationary target.
    • the longest ever navel artillery hit was 24 kilometers, which makes that the absolute maximum distance we can assume any engagement will happen unless missiles or drones are involved. That is a third of range step 8.
    • Drones are generally used on the same side of the planet to keep latency short by reflecting signals of one satellite only. This is pretty much Range step 10.
    • Modern ICBMs have ranges that are double the range of our step 10 – 12000 to 16000 km. They can hit literally any target on the planet but spend hours in flight. We are in the same order of magnitude though, so that’s just a little adjustment of factor 2 or something if you really want to have spells that far

Magic-propagation speed calculation

The scale also has the benefit of being roughly multiples of 60. So it can be used to quickly calculate speeds from the distances. Say our fireball with range step 5 takes 60 seconds to get to that far point, and for math sake, we round to the closest 10. 60 meters/60 seconds means it travels at 1 meter a second, or rather sluggishly and can be dodged. If the range was step 6, that’s 600 meters/60 seconds, so in the area of 10 meters a second – Olympic runner speeds! And if it takes step 6 but only takes 6 seconds, we are at 100 meters per second, that’s the speed of a longbow arrow or about half the speed of a slow bullet or a quarter of a heavy arquebus.

Look over the plate: other systems

Let me pull out GURPS. GURPS is notorious for cramming everything in spreadsheets. Including this list for range increments from 3rd edition, and I bold roughly equivalent distances to our distances above:

  • 1/10″ – 1/5″ – 1/3″ – 1/2″ – 2/3″ – 1″ – 1.5″ – 2″ – 3″ – 6″ – 12″ – 1.5′ – 2′ – 1yd – 1.5yd – 2yd – 3yd – 4.5yd 7yd 10yd 15yd 20yd 30yd 45yd 70yd 100yd 150yd 200yd 300yd 450yd – 700yd – 1000yd – 1500yd – 2000yd – 3000yd – 4500yd – 7000yd/4 mi (~6 km) – 10000yd – 10mi – 15mi – 20mi (~30 km) – 200mi – 2000mi – 20000mi – 200000mi

Those are horrible fine segments, and the modifier progression in that thing goes from -15 to +49 with 0 on the 2-foot step. But for the far distances (where GURPS goes with half my proposed distances but adds another increment in the end), the distances I propose show up, making them at least useable for a simulatoric standpoint.

The picture of putting the focus on the engagement ranges of combat however shows itself in various Fantasy RPGs:

In my decade-and-half of being the GM for various The Dark Eye groups, the longest engagement range ever wanted was 550 meters from the weapon used – a heavy trebuchet. Most TDE spells have a range well below 100 meters, even there are very few spells that have a range of as far as the eye can see or continent. I only know of one instance where such a spell was used in combat at distances further than about 100 meters – and it was aimed at a target the size of a house. Any spell that I witnessed to be used at a longer range was either a communication or clairvoyance spell. In this I am not counting any trans-planar spell: the distance to hell is one step through the invocation/banishment pentagram. As a result of the costs and targeting needed, most combat magic in this system is actually pretty close to mundane ranged weapons when it comes to their ranges, even though the efficiency/impact of the spells can be much higher.

Pathfinder 1e and D&D 3.5 have only very few spells that have ranges that are longer than half a kilometer (those exceptions are generally clairvoyance, communication, or translocation spells). Most combat spells are even limited to less than about 100 meters. Generally, magic can be (and is) treated as just another type of ranged weapon in Pathfinder, even if area-effect spells are common.

Shadowrun also fortifies this experience: Shadowrun imposes no range limit but the (optically redirectable) line of sight (and ability to see its target) of the caster. However, in the last 12 years of playing Shadowrun the longest spell directly cast by any caster I witnessed was about 250 meters using binoculars, and most spells were flung even below 50 meters. In fact, I remember only very few casts of spells further than 50 meters, unless a spirit sent on a mission was involved. As far as I witnessed, even as magic in this system is allowed to be super-long-range, generally it was used at ranges where close-combat weapons are used – and often as a replacement for such.

Mage the Ascension uses one of the magic disciplines as the limiter for distances in its rather freeform magic system, on a success scale: you need 1 to target something that you can see, 2 allows you to reach a very familiar place (like you home) no matter how distant, 3 a familiar place (your buddy’s home), 4 gets you to a place you have been once (like the capitol), 5 can get you somewhere you have only been described or seen on a photo and 6 gets you anywhere on earth you can imagine, even if you have no idea what is there. But yes, Mage is a really poor limiter in magic ranges, as it is very free in casting magic (and only clobbers you over the head with paradox for it).

simplifying expressions – Reconcile FullSimplify vs Reduce on Simple Problem

Can FullSimplify be coerced to give an answer here? If not, is it easy to say why?

FullSimplify((1 + 1/(k + 1))^(k + 1) > (1 + 1/k)^k, 
 k > 0 && k (Element) Integers)

Note that Reduce gives the correct answer with the same information.

Reduce((1 + 1/(k + 1))^(k + 1) > (1 + 1/k)^k && k > 0, k, Integers)
(* k (Element) Integers && k >= 1 *)

beginner – Simple RESTful counting API in Golang

Description

This is a simple (and hopefully) RESTful API in Golang that uses Redis. I have next to no prior experience in Golang and absolutely no prior experience with Redis. The API is a simple counter service with the feature of disabling “public” updates (cannot create new counter, and cannot increment existing counter)

The original idea was taken from CountAPI

API reference

  • /api/{key} (namespace defaults to default)
  • /api/{namespace}/{key}

{namespace} and {key} match the regex (a-zA-Z0-9_)+

The following methods are supported on the endpoints:

  • GET: get view count
  • POST: increment view count
  • PATCH: update namespace settings

Example usage

test.py:

from copy import deepcopy
from requests import get, patch, post


def test_expected(method, url, expected, ignored_fields = (), headers = {}, data = {}):
    response = method(url, headers=headers, data=data).json()
    original_response = deepcopy(response)

    print(f'{method.__name__.upper()} {url}')
    print(f'    {response}n')

    for ignored_field in ignored_fields:
        try:
            response.pop(ignored_field)
        except KeyError:
            pass

        try:
            expected.pop(ignored_field)
        except KeyError:
            pass

    assert response == expected, f'got {response}, expected {expected}'

    return original_response


if __name__ == '__main__':
    # Get view count
    test_expected(get, 'http://localhost:8080/api/default/key', {'success': True, 'data': 0})
    test_expected(get, 'http://localhost:8080/api/namespace/key', {'success': True, 'data': 0})
    test_expected(get, 'http://localhost:8080/api/default_namespace_key', {'success': True, 'data': 0})

    # Create new key ("default/key") in namespace that is public (is_public == true)
    test_expected(post, 'http://localhost:8080/api/default/key', {'success': True, 'data': 1, 'isNewNamespace': False})

    # Create new key in non-existent namespace
    response = test_expected(post, 'http://localhost:8080/api/namespace/key', {'success': True, 'data': 1, 'isNewNamespace': True}, ignored_fields=('overrideKey'))
    key = response.get('overrideKey')

    # Check that namespace is not public by default
    test_expected(post, 'http://localhost:8080/api/namespace/key', {'success': False, 'error': 'No permission to update namespace/key'})

    # Check that key in private namespace can be accessed with override key
    test_expected(post, 'http://localhost:8080/api/namespace/key', {'success': True, 'data': 2, 'isNewNamespace': False}, headers={'X-Override-Key': key})

    test_expected(patch, 'http://localhost:8080/api/namespace/key', {'success': False, 'error': 'Incorrect override key'})
    test_expected(patch, 'http://localhost:8080/api/namespace/key', {'success': False, 'error': 'Incorrect override key'}, headers={'X-Override-Key': 'foobar'})
    test_expected(patch, 'http://localhost:8080/api/namespace/key', {'success': False, 'error': 'Field to update does not exist'}, headers={'X-Override-Key': key})
    test_expected(patch, 'http://localhost:8080/api/namespace/key', {'success': True}, headers={'X-Override-Key': key}, data={'field': 'is_public', 'newValue': 'true', 'valueType': 'bool'})

    # Check that everything still works as expected
    test_expected(get, 'http://localhost:8080/api/namespace/key', {'success': True, 'data': 2})
    test_expected(post, 'http://localhost:8080/api/namespace/key', {'success': True, 'data': 3, 'isNewNamespace': False})
    test_expected(patch, 'http://localhost:8080/api/namespace/key', {'success': True}, headers={'X-Override-Key': key}, data={'field': 'is_public', 'newValue': 'false', 'valueType': 'bool'})
    test_expected(get, 'http://localhost:8080/api/namespace/key', {'success': True, 'data': 3})
    test_expected(post, 'http://localhost:8080/api/namespace/key', {'success': False, 'error': 'No permission to update namespace/key'})

    print('All tests passed')

test.py output:

GET http://localhost:8080/api/default/key
    {'success': True, 'data': 0}

GET http://localhost:8080/api/namespace/key
    {'success': True, 'data': 0}

GET http://localhost:8080/api/default_namespace_key
    {'success': True, 'data': 0}

POST http://localhost:8080/api/default/key
    {'success': True, 'data': 1, 'isNewNamespace': False}

POST http://localhost:8080/api/namespace/key
    {'success': True, 'data': 1, 'isNewNamespace': True, 'overrideKey': '+2yubkGY1GwgfIJA'}

POST http://localhost:8080/api/namespace/key
    {'success': False, 'error': 'No permission to update namespace/key'}

POST http://localhost:8080/api/namespace/key
    {'success': True, 'data': 2, 'isNewNamespace': False}

PATCH http://localhost:8080/api/namespace/key
    {'success': False, 'error': 'Incorrect override key'}

PATCH http://localhost:8080/api/namespace/key
    {'success': False, 'error': 'Incorrect override key'}

PATCH http://localhost:8080/api/namespace/key
    {'success': False, 'error': 'Field to update does not exist'}

PATCH http://localhost:8080/api/namespace/key
    {'success': True}

GET http://localhost:8080/api/namespace/key
    {'success': True, 'data': 2}

POST http://localhost:8080/api/namespace/key
    {'success': True, 'data': 3, 'isNewNamespace': False}

PATCH http://localhost:8080/api/namespace/key
    {'success': True}

GET http://localhost:8080/api/namespace/key
    {'success': True, 'data': 3}

POST http://localhost:8080/api/namespace/key
    {'success': False, 'error': 'No permission to update namespace/key'}

All tests passed

Code

WARNING: Redis database running on localhost:6379 may be modified

main.go:

package main

import (
    "encoding/json"
    "log"
    "math/rand"
    "net/http"
    "strconv"
    "strings"
    "time"

    "github.com/gomodule/redigo/redis"
    "github.com/gorilla/mux"
)

var (
    c   redis.Conn
    err error
)

const defaultNamespace = "default"

func apiMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Print(strings.Join(()string{r.RemoteAddr, r.Method, r.URL.Path}, " "))

        w.Header().Set("Content-Type", "application/json")
        next.ServeHTTP(w, r)
    })
}

func mainErrorHandler(w http.ResponseWriter, r *http.Request) {
    const page = `<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Not Found</title>
  </head>
  <body>
    <h1>Not Found</h1>
  </body>
</html>`
    w.Write(()byte(page))
}

func getNamespaceAndKey(m map(string)string) (string, string) {
    namespace := m("namespace")

    if namespace == "" {
        namespace = defaultNamespace
    }

    key := m("key")

    return namespace, key
}

func incrementViewCount(namespace string, key string) int {
    val, err := c.Do("INCR", namespace+":"+key)
    if err != nil {
        log.Fatal(err)
    }

    n, err := redis.Int(val, err)
    if err != nil {
        log.Fatal(err)
    }

    return n
}

func getViewCount(namespace string, key string) int {
    val, err := c.Do("GET", namespace+":"+key)
    if err != nil {
        log.Fatal(err)
    }

    if val == nil {
        return 0
    }

    n, err := redis.Int(val, err)
    if err != nil {
        log.Fatal(err)
    }

    return n
}

func apiErrorHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")

    type Response struct {
        Success bool   `json:"success"`
        Error   string `json:"error"`
    }

    res := Response{Success: false, Error: "Invalid route"}
    json.NewEncoder(w).Encode(res)
}

func apiGetNumViewsHandler(w http.ResponseWriter, r *http.Request) {
    type Response struct {
        Success bool `json:"success"`
        Data    int  `json:"data"`
    }

    vars := mux.Vars(r)

    namespace, key := getNamespaceAndKey(vars)

    n := getViewCount(namespace, key)

    res := Response{Success: true, Data: n}
    json.NewEncoder(w).Encode(res)
}

func namespaceExists(namespace string) bool {
    namespaceExists, err := redis.Bool(c.Do("EXISTS", namespace))
    if err != nil {
        log.Fatal(err)
    }

    return namespaceExists
}

func allowedToUpdateKey(namespace string, key string, userOverrideKey string) bool {
    if !namespaceExists(namespace) {
        return true
    }

    overrideKey, err := redis.String(c.Do("HGET", namespace, "override_key"))
    if err != nil {
        log.Fatal(err)
    }

    if userOverrideKey == overrideKey {
        return true
    }

    namespacePublic, err := redis.Bool(c.Do("HGET", namespace, "is_public"))
    if err != nil {
        log.Fatal(err)
    }

    return namespacePublic
}

var letters = ()rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-+")

// From https://stackoverflow.com/a/22892986
func randomOverrideKey(n int) string {
    b := make(()rune, n)
    for i := range b {
        b(i) = letters(rand.Intn(len(letters)))
    }
    return string(b)
}

func createNamespace(namespace string) string {
    overrideKey := randomOverrideKey(16)

    _, err := redis.Int(c.Do("HSET", namespace, "is_public", false, "override_key", overrideKey))
    if err != nil {
        log.Fatal(err)
    }

    return overrideKey
}

func apiPingHandler(w http.ResponseWriter, r *http.Request) {
    type Response struct {
        Success      bool   `json:"success"`
        Data         int    `json:"data"`
        NewNamespace bool   `json:"isNewNamespace"`
        OverrideKey  string `json:"overrideKey,omitempty"`
    }

    type ErrorResponse struct {
        Success bool   `json:"success"`
        Error   string `json:"error"`
    }

    vars := mux.Vars(r)
    namespace, key := getNamespaceAndKey(vars)
    userOverrideKey := r.Header.Get("X-Override-Key")

    if !allowedToUpdateKey(namespace, key, userOverrideKey) {
        res := ErrorResponse{Success: false, Error: "No permission to update " + namespace + "/" + key}
        json.NewEncoder(w).Encode(res)
        return
    }

    isNewNamespace := !namespaceExists(namespace)

    var overrideKey string

    if isNewNamespace {
        overrideKey = createNamespace(namespace)
    } else {
        overrideKey = ""
    }

    n := incrementViewCount(namespace, key)

    res := Response{Success: true, Data: n, NewNamespace: isNewNamespace, OverrideKey: overrideKey}
    json.NewEncoder(w).Encode(res)
}

func convertValueType(value string, valueType string) interface{} {
    var convertedValue interface{}

    // Other types at https://pkg.go.dev/github.com/gomodule/redigo/redis#pkg-index
    // Conversion at https://github.com/gomodule/redigo/blob/72af8129e040d6f962772a8c582e5e9f22085788/redis/reply.go
    switch valueType {
    case "string":
        convertedValue, err = redis.String(value, err)
        if err != nil {
            log.Fatalf(`Could not convert "%v" to type "%v" (invalid value): %v`, value, valueType, err)
        }
    case "bool":
        convertedValue, err = redis.Bool(()byte(value), err)
        if err != nil {
            log.Fatalf(`Could not convert "%v" to type "%v" (invalid value): %v`, value, valueType, err)
        }
    case "int":
        convertedValue, err = redis.Int(()byte(value), err)
        if err != nil {
            log.Fatalf(`Could not convert "%v" to type "%v" (invalid value): %v`, value, valueType, err)
        }
    default:
        log.Fatalf(`Could not convert "%v" to type "%v" (unknown type)`, value, valueType)
    }

    return convertedValue
}

func apiUpdateHandler(w http.ResponseWriter, r *http.Request) {
    userOverrideKey := r.Header.Get("X-Override-Key")

    vars := mux.Vars(r)
    namespace, _ := getNamespaceAndKey(vars)

    overrideKey, err := redis.String(c.Do("HGET", namespace, "override_key"))
    if err != nil {
        log.Fatal(err)
    }

    type Response struct {
        Success bool `json:"success"`
    }

    type ErrorResponse struct {
        Success bool   `json:"success"`
        Error   string `json:"error"`
    }

    if userOverrideKey != overrideKey {
        res := ErrorResponse{Success: false, Error: "Incorrect override key"}
        json.NewEncoder(w).Encode(res)
        return
    }

    field := r.FormValue("field")
    value := r.FormValue("newValue")
    valueType := r.FormValue("valueType")

    exists, err := redis.Int(c.Do("HEXISTS", namespace, field))
    if err != nil {
        log.Fatal(err)
    }

    if exists == 0 {
        res := ErrorResponse{Success: false, Error: "Field to update does not exist"}
        json.NewEncoder(w).Encode(res)
        return
    }

    convertedValue := convertValueType(value, valueType)

    _, err = redis.Int(c.Do("HSET", namespace, field, convertedValue))
    if err != nil {
        log.Fatal(err)
    }

    res := Response{Success: true}
    json.NewEncoder(w).Encode(res)
}

func init() {
    c, err = redis.Dial("tcp", ":6379")
    if err != nil {
        log.Fatal(err)
    }
    log.Print("Connected to database")

    s := time.Now().UnixNano()
    rand.Seed(s)
    log.Print("Seeded with " + strings.ToUpper(strconv.FormatInt(s, 16)))

    createNamespace(defaultNamespace)
    _, err = c.Do("HSET", defaultNamespace, "is_public", convertValueType("true", "bool"))
    if err != nil {
        log.Fatal(err)
    }
}

func main() {
    defer c.Close()

    r := mux.NewRouter()
    r.NotFoundHandler = http.HandlerFunc(mainErrorHandler)

    s := r.PathPrefix("/api/").Subrouter()
    s.Use(apiMiddleware)

    allowedCharsRegex := "(a-zA-Z0-9_)+"

    s.Path("/{key:" + allowedCharsRegex + "}").HandlerFunc(apiGetNumViewsHandler).Methods("GET")
    s.Path("/{namespace:" + allowedCharsRegex + "}/{key:" + allowedCharsRegex + "}").HandlerFunc(apiGetNumViewsHandler).Methods("GET")

    s.Path("/{key:" + allowedCharsRegex + "}").HandlerFunc(apiPingHandler).Methods("POST")
    s.Path("/{namespace:" + allowedCharsRegex + "}/{key:" + allowedCharsRegex + "}").HandlerFunc(apiPingHandler).Methods("POST")

    s.Path("/{key:" + allowedCharsRegex + "}").HandlerFunc(apiUpdateHandler).Methods("PATCH")
    s.Path("/{namespace:" + allowedCharsRegex + "}/{key:" + allowedCharsRegex + "}").HandlerFunc(apiUpdateHandler).Methods("PATCH")

    s.NotFoundHandler = http.HandlerFunc(apiErrorHandler)
    log.Print("Routes set up successfully")

    http.ListenAndServe(":8080", r)
}

go.mod:

module hit-counter

go 1.16

require (
    github.com/gomodule/redigo v1.8.4
    github.com/gorilla/mux v1.8.0
)

go.sum:

github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gomodule/redigo v1.8.4 h1:Z5JUg94HMTR1XpwBaSH4vq3+PNSIykBLxMdglbw10gg=
github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/gomodule/redigo/redis v0.0.0-do-not-use h1:J7XIp6Kau0WoyT4JtXHT3Ei0gA1KkSc6bc87j9v9WIo=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

python – A simple attention based text prediction model from scratch using pytorch

I have created a simple self attention based text prediction model using pytorch. The attention formula used for creating attention layer is,

enter image description here

I want to validate whether the whole code is implemented correctly, particularly my custom implementation of Attention layer.

The whole code

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

import random
random.seed(0)
torch.manual_seed(0)

# Sample text for Training
test_sentence = """Thomas Edison. The famed American inventor rose to prominence in the late
19th century because of his successes, yes, but even he felt that these successes
were the result of his many failures. He did not succeed in his work on one of his
most famous inventions, the lightbulb, on his first try nor even on his hundred and
first try. In fact, it took him more than 1,000 attempts to make the first incandescent
bulb but, along the way, he learned quite a deal. As he himself said,
"I did not fail a thousand times but instead succeeded in finding a thousand ways it would not work." 
Thus Edison demonstrated both in thought and action how instructive mistakes can be. 
""".lower().split()

# Build a list of tuples.  Each tuple is (( word_i-2, word_i-1 ), target word)
trigrams = (((test_sentence(i), test_sentence(i + 1)), test_sentence(i + 2))
            for i in range(len(test_sentence) - 2))

# print the first 3, just so you can see what they look like
print(trigrams(:3))

vocab = list(set(test_sentence))
word_to_ix2 = {word: i for i, word in enumerate(vocab)}

# Number of Epochs
EPOCHS = 25

# SEQ_SIZE is the number of words we are using as a context for the next word we want to predict
SEQ_SIZE = 2

# Embedding dimension is the size of the embedding vector
EMBEDDING_DIM = 10

# Size of the hidden layer
HIDDEN_DIM = 256

class Attention(nn.Module):
    """
    A custom self attention layer
    """
    def __init__(self, in_feat,out_feat):
        super().__init__()             
        self.Q = nn.Linear(in_feat,out_feat) # Query
        self.K = nn.Linear(in_feat,out_feat) # Key
        self.V = nn.Linear(in_feat,out_feat) # Value
        self.softmax = nn.Softmax(dim=1)

    def forward(self,x):
        Q = self.Q(x)
        K = self.K(x)
        V = self.V(x)
        d = K.shape(0) # dimension of key vector
        QK_d = (Q @ K.T)/(d)**0.5
        prob = self.softmax(QK_d)
        attention = prob @ V
        return attention

class Model(nn.Module):
    def __init__(self,vocab_size,embed_size,seq_size,hidden):
        super().__init__()
        self.embed = nn.Embedding(vocab_size,embed_size)
        self.attention = Attention(embed_size,hidden)
        self.fc1 = nn.Linear(hidden*seq_size,vocab_size) # converting n rows to 1
        self.softmax = nn.Softmax(dim=1)

    def forward(self,x):
        x = self.embed(x)
        x = self.attention(x).view(1,-1)
        x = self.fc1(x)
        log_probs = F.log_softmax(x,dim=1)
        return log_probs

learning_rate = 0.001
loss_function = nn.NLLLoss()  # negative log likelihood

model = Model(len(vocab),EMBEDDING_DIM,CONTEXT_SIZE,HIDDEN_DIM)
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

# Training
for i in range(EPOCHS):
    total_loss = 0
    for context, target in trigrams:
        # context, target = ('thomas', 'edison.') the
        
        # step 1: context id generation
        context_idxs = torch.tensor((word_to_ix2(w) for w in context), dtype=torch.long)

        # step 2: setting zero gradient for models
        model.zero_grad()

        # step 3: Forward propogation for calculating log probs
        log_probs = model(context_idxs)

        # step 4: calculating loss
        loss = loss_function(log_probs, torch.tensor((word_to_ix2(target)), dtype=torch.long))

        # step 5: finding the gradients
        loss.backward()

        #step 6: updating the weights
        optimizer.step()

        total_loss += loss.item()
    if i%2==0:
        print("Epoch: ",str(i)," Loss: ",str(total_loss))

# Prediction
with torch.no_grad():
    # Fetching a random context and target 
    rand_val = trigrams(random.randrange(len(trigrams)))
    print(rand_val)
    context = rand_val(0)
    target = rand_val(1)
    
    # Getting context and target index's
    context_idxs = torch.tensor((word_to_ix2(w) for w in context), dtype=torch.long)
    target_idxs = torch.tensor((word_to_ix2(w) for w in (target)), dtype=torch.long)
    print("Acutal indices: ", context_idxs, target_idxs)
    log_preds = model(context_idxs)
    print("Predicted indices: ",torch.argmax(log_preds))

complex analysis – Cauchy integral formula for a point outside the simple closed curve

Show that if $f$ is analytic inside and on a simple closed curve $C$ and $z_0$ not in $C$ then
$$ (n-1)!int_C frac{f^{(m)}(z)}{(z-z_0)^n}dz=(m+n-1)!int_C frac{f(z)}{(z-z_0)^{m+n}}dz$$

Since it is stated that $z_0$ is not in $C$, I believe we have to prove the statement for points both inside and outside the simple closed curve. For a point inside the curve I know the answer. We only need to evaluate the value of the $(m+n-1)th$ derivative of $f(z)$ and $(n-1)th $ derivative of $f^{(m)}(z)$ at $z_0$ using Cauchy’s integral formula and equate them. But how do I prove the same for apoint outside the simple closed curve ?