Merge pull request #8 from Pagwin-Fedora/development

fixed some fuck ups in universal tutorial, started but didn't finish some blog articles and some minor css that I don't know what I wrote for so hopefully it doesn't break the site
This commit is contained in:
Pagwin 2023-08-02 00:00:04 -04:00 committed by GitHub
commit accb6c22d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 252 additions and 5 deletions

View file

@ -0,0 +1,127 @@
---
title: "Finite KCMP numbers"
description: "Fuck it my brain has a bit too much free time so why not figure out a proof for an isomorphism between programs writen in a turing complete language and natural numbers and use it to do fun stuff"
date: 2022-12-20
draft: true
---
# Finite KCMP numbers
So this blog article exists because I have too much time and realized that numbers with a finite KCMP have an isomorphism to the natural numbers among some other interesting stuff and I wanna write a blog article about it.
> Huh? KCMP? Natural numbers? Isomorphism? the fuck?
## An initial explanation
Okay maybe I should start with some explaining, KCMP is shorthand that me and a friend(their name is Micha, here's their [blog](https://lochalhost.pl/en/blog) and here's their [github](https://github.com/michalusio)) use when referring to [Kolmogorov complexity](https://en.wikipedia.org/wiki/Kolmogorov_complexity), Kolmogorov complexity is the term used to describe the length of the shortest program written in a turing complete language needed to calculate a particular value. From here on however I'm gonna write KCMP because that's shorter. If you've never heard of KCMP I don't blame you, until Micha brought the term to my attention I wasn't sure what I was thinking of had a word.
> Wait you were thinking of KCMP before you even had a word for it?
Yup, you see some months ago I started this journey with a relatively simple question "are there numbers which we can't calculate?". The answer is yes there are numbers that we cannot calculate ever these numbers are irrational numbers with infinite KCMP. For a while that was that but before we go on I should probably make sure you know what I mean by isomorphism and natural numbers.
Natural numbers are the numbers you count with, `1,2,3,4,5,6,7,...` no fractions, no negatives or anything that you can't count with infinite fingers another way to describe them would be to just say they're all the positive integers.
When I say [isomorphism](https://en.wikipedia.org/wiki/Isomorphism) I'm talking about a method that we can use to convert from objects within one set to objects in another set that we can also reverse to get back the original object.
## The beginning
The way this started is that I was thinking about the fact that natural numbers, lists and code/functions can all be used to represent each other. But going into that is a whole rabbit hole involving control flow, lambda calculus, how you can represent things with other things, abstract syntax trees and how modern electronic computers work at a basic level so I won't go into details here. All you need to know is that while I was thinking about that I made a connection to some previous random thoughts that I had between the time I first learned about KCMP and then. Those thoughts being about how I wondered what the sizes of the sets of numbers with finite and infinite KCMP.
> Wait aren't both of those infinite?
Yep but there's more than one size of infinity, the smallest infinity is the size of the set of natural numbers or [aleph](https://en.wikipedia.org/wiki/Aleph_number) null/nought. One of the infinities that's larger than that is the infinity of the real numbers. Due to that I was wondering whether the set of values with finite KCMP had the size of the naturals or the reals. Wait what was I talking about oh yeah isomorphism with naturals. The connection I made when thinking about how code/functions, lists and natural numbers are all equivalent was that I had just answered my question that I had had for a decent while and then I remembered one of the reasons why I was wondering that and got very confused.
## Why I got very confused
The reason I got very confused then is because I could apply a [diagonalization argument](https://en.wikipedia.org/wiki/Cantor%27s_diagonal_argument) to the set of all numbers with finite KCMP and get a number which shouldn't be in the set of all numbers with finite KCMP but meets all the criteria to be in that set, meaning I had found a [paradox](https://en.wikipedia.org/wiki/Paradox).
> How do you know this number should be in your set?
for the sake of making this conversation easier lets give this number the name of ψ because the symbol ψ is underutilized in math. We know that ψ if it exists(we'll get to that) has finite KCMP because the process used to generate it given the set of all finite KCMP numbers only adds a finite amount of additional KCMP on top of the KCMP of the set of all numbers with finite KCMP which we know also has finite KCMP because we can describe the creation of that set with the following python program
```py
counter = 0
finite_KCMP_set = set()
while True:
counter = counter + 1
finite_KCMP_set.add(eval_num(counter))
```
> wait but that doesn't halt and also what's this `eval_num` function you never explained the whole natural numbers as code thing
...do I really have to dive into that rabbit hole? ... Fuck it lets dive in.
## An isomorphism between natural numbers and programs for a turing machine
Alright so first thing first we need to convert a natural number into an array of bytes which is pretty trivial to do.
```py
num = random_natural()
bytes = []
i = 0
while i <= log256(num):
bytes.append(num%256)
num /= 256
i += 1
```
This array of bytes can then be treated as machine code that we run on whatever architecture thereby isomorphism between naturals and programs for a turing machine complete. ... Okay I'll be a bit more rigorous but not much. A turing machine can be constructed by having finite instructions which can operate on infinite memory so each instruction can just correspond to 1 natural number and we can read out an arbitrary natural number from our array by having the highest bit on each byte correspond to whether the value is continued in the next byte although given you don't need more than 255 instructions for a turing complete machine but doing this is convenient as we can use similar logic for the arguments to an instruction to pass in infinitely large values to instructions as jump locations or places to read data from. Anyways I'm not going into more detail beyond that, I'm sure you can get plenty creative making your own turing complete machine with infinite memory. To invert the relation you just take the byte array of a program and run it through this code
```py
num = 0
for i in range(0,len(bytes)):
num *= 256
num += bytes[i]
```
## The paradox
Anyways back to the issue at hand we have a number(ψ) that should be in a set by the definition of the set but also shouldn't be in that set due to how it got constructed. At this point I wasn't sure what to make of this but when I mentioned this to Micha and he had a few theories on what was going on.
1. ψ isn't in the set(except it is)
2. This set isn't constructible
3. the set isn't enumerable(interesting if true but obviously false)
> can you explain these statements?
sure but I don't remember how much of this I thought up vs Micha so I can't give proper credit so if that's important to you you'll need to reach out to me or Micha so we can share some discord messages.
### ψ isn't in the set
This would explain the paradox because it would mean there is no paradox however it's false because as described before the number has finite steps with finite KCMP and thereby also has finite KCMP.
### The set isn't constructible
This is the theory I'm currently in favor of as it seems to be the assumption that's made that isn't true, this also means that ψ doesn't exist.
### The set isn't enumerable
This is false because obviously the set is enumerable you enumerate by going through each natural number and evaluating the program equivalent.
## A set that actually exists
I can definitely credit the definition of this set to Micha, they gave a definition of. *"The set of all generatable tape sequences of a TM which have a limit"*. ψ isn't in this set because it doesn't have a proper limit, let n be the natural who corresponds to the program to generate ψ the nth digit of ψ can't be any number because it needs to not be equal to itself thereby meaning ψ doesn't have a limit and isn't included in our set.
## Some conjecture
With that we leave the realm of things I discussed with Micha and into the realm of increasingly stupid ideas.
With this knowledge that numbers with finite KCMP have a mapping to the integers...
> wait hold on don't those numbers include complex numbers, fractions, quaternions, irrational numbers, vectors and more? How do you know what's what from the limiting byte sequence?
Stop poking holes in my fun math thoughts anyways with the knowledge that integers correspond to finite KCMP numbers I conjecture that the fact that the infinity of the real numbers is larger than the infinity of the naturals will never come up in practice barring our current understanding of the universe being completely wrong or one or more universal constants having infinite KCMP(we'll come back to this in a second) due to all process of calculation that we have available are no more powerful than a turing machine which can only compute values which we just showed to map to the natural numbers instead of the real numbers.
## An amusing unfalsifiable hypothesis
I hypothesize that all of the universal constants have infinite KCMP due to the universe being a continuum of possible universal constants across a multi-dimensional plane and the observable universe being just one point on that plane picked at random, due to it being picked at random the probability of it being all values with infinite KCMP is practically 100%. Do I have evidence, research or anything else backing this theory up? Nope but it's interesting.
> Why is the probability practically 100% if the values are picked at random and How is that unfalsifiable?
The reason the probability is practically 100% is because the size of finite KCMP numbers is countably infinite and because the size of the real numbers is bigger that means that the set of numbers with infinite KCMP is the size of the real numbers thereby being infinitely bigger making the ratio comparable to 1:∞ meaning the probability of any universal constant having finite KCMP(assuming all are chosen fully randomly over a continuum) is 0(technically not impossible for math reasons but practically impossible).
As for the question of unfalsifiability we'd need to be able to make infinitely precise measurements to confirm it one way or the other and things like plank's constant conspire to prevent this in addition to us measuring with an error margin of 0 is pretty difficult if it's possible at all.
## Conclusion
Doing all this abstract high level math is fun though I fully expect that none of this will ever be useful in any way ever. Mildly tempted to argue otherwise in a CS ethics class I have coming up in uni soon but that probably isn't worth the effort or crappy grade.

111
content/blog/pogo_again.md Normal file
View file

@ -0,0 +1,111 @@
---
title: ""
description: "I swear I'm going to finish it this time"
date: 2023-00-00
draft: true
---
# Another blog post that mentions Pogo
Welcome to another blog about pogo aka that todo list that I way over-engineered. Anyways I started over again but this time I swear I'm gonna finish it, I promise I won't throw it out again. Oh what have I done? I have the database setup and some method for interacting with the data inside which I'm 100% going to through out in favor of raw sql queries... Wait no I promise I'm doing good this time the only reason I'm probably not gonna use existing work is because I'm going to make the api able to give back data based on what's being requested and also have things be mostly stateless because that allows scaling and... Okay I might still be over-engineering this but at least the way I'm over-engineering it is by making it scale instead of making it a mess and annoying to work on. Anyways here's some explanation of what I've done so far.
## Initial setup
So to start with I made a struct corresponding to a task in this todolist app which looked like this
```rs
#[derive(Clone)]
pub struct TaskV1{
title:String,
body:String,
connected:Vec<String>,
parents: Vec<rc::Weak<TaskV1>>,
children: Vec<rc::Rc<TaskV1>>
}
```
however after some work at time of writing it's looking like the task struct will either look like
```rs
#[derive(Clone)]
pub struct TaskV1{
id: Uuid,
title:String,
body:String,
progress:f32,
login:String
}
```
or
```rs
```
heh yeah as I said I'm considering getting rid of the methods involving tasks which would make a task struct(at least a general task struct) redundant but if you pressed me I'd tell you that
```rs
#[derive(Serialize,Deserialize)]
struct TaskSerial{
title: Option<String>,
body: Option<String>,
progress: Option<f32>,
children: Option<Vec<Uuid>>,
parents: Option<Vec<Uuid>>,
media: Option<Vec<Uuid>>
}
```
would be the task struct.
## But why?
Why would I remove some attributes like that or stick all of them into Options? Why are there a bunch of Uuids now? Also why do tasks have parents and children? These are good questions, to answer the first two I'm gonna spend a good chunk of this blog explaining what I've actually done but lemme answer the latter question real quick
## Task organization as a pseudo-tree
The reason nodes can have children is twofold: first, tasks can have subtasks and second, this allows me to avoid having a special category type which has tasks as children. This simplifies things from a code perspective and allows me to avoid duplication of functionality between categories and tasks, the only bit of redundancy is the fact that a category having progress is nonsensical but that's something I can figure out when I get to building a client. Anyways onto why Tasks underwent a bunch of change
## Abstracting task encoding away
Oh you think I started with DB stuff no no no I started by setting some stuff up to make encoding and decoding tasks as seamless as possible. Namely a versioning enum(it's boring moving on) and a Trait which was setup like this.
```rs
/// Trait that any method of encoding and decoding tasks needs to implement
#[async_trait]
pub trait TaskEncoder{
/// The type that can be gotten from a call to either provide_identifiers or
/// encode_task and if a value of it is gotten that way then should be usable with decode_task
/// to retrieve the original task it must be serializable with serde due to it being the value
/// passed around when working with tasks potentially onto disk or over network
//Specifying DeserializeOwned may be a problem in the future if I need to deal with types with
//lifetimes but until then this is good
type Identifier:serde::Serialize + serde::de::DeserializeOwned;
type EncodingError;
type DecodingError;
type IdentityFetchError;
async fn encode_task(&mut self, task:TaskVersioning, login:&str)->Result<Self::Identifier,Self::EncodingError>;
async fn decode_task(&mut self,id:Self::Identifier, login:&str)->Result<Option<TaskVersioning>,Self::DecodingError>;
async fn provide_identifiers(&mut self, login:&str)->Result<Vec<Self::Identifier>,Self::IdentityFetchError>;
}
```
Once that was done I just needed to implement it in SQL and the details involved in that made having the struct a bit more iffy. With that trait done I moved on to doing ~~your mom~~ the sql.
## Doing the sql(and remembering I need to store completion)
Yeah I forgor about the fact that I need to store task completion/progress so I added a field corresponding to that at some point but it isn't worth commenting on beyond that. Anyways as the header of this sections suggests I decided to have pogo store it's data in an sql db, specifically postgres. So I got to work making the schema making a table like this.
```sql
CREATE TABLE tasks {
id uuid,
title varchar,
body varchar
}
```
Now if you have any sql experience you'll probably understand why everything became Uuids at this point(or maybe your techniques are beyond my comprehension and you're just confused idk). The reason I added an id field in the sql is so I could look up a particular task by id corresponding to this row being added to the db is the field getting added to the struct. Where are the children, parents and content/media fields? Oh well you see from the 1 minute of googling I did postgres doesn't let you have a column which is a variable length array but more importantly I remembered that sticking structures inside of other structures isn't how sql is supposed to work. So lik a good little programmer I made some more tables. One table which you just saw is the task table which has all the tasks in it, the second table specifies parent child relations via uuids, the third table is a list of media with their own uuids and the fourth table is a relation between media ids and task ids. Combined with me not wanting to recursively fetch tasks you can see why everything is uuids now instead of having tasks in tasks. Also at some point amongst this change I added a column to the task table to specify a login via a varchar which I'm intending to use to store probably an Oauth token from google/github or alternatively an sha256hmac of their username and password, probably with additional hashing on top. Also I made some indexes over tables.
## Making the backend api
So now we've explained the first possible end point for the task struct that point being just 1 row in the task table. But what about the one with all the Options or the argument that the task struct won't be a thing anymore? Well that's due to the rest inspired http api. While I haven't finished implementing it yet I think I'm done designing the stuff related to the task object it so here are the endpoints relating to tasks.
```
GET /task/$id
PUT /task
UPDATE /task/$id
DELETE /task/$id
```
PUT just creates a task with everything set to default and gives back the uuid of that task and DELETE just deletes it. The ones which make things iffy are GET and UPDATE which both allow the client making a request to the api to only provide some of a task or for it to only update some of the task. Due to data now being optional the original task struct didn't represent what endpoints would be delivering, what's more it wasn't needed for database queries due to SQL queries being decently flexible with me using direct SQL queries through [sqlx](https://crates.io/crates/sqlx).

View file

@ -7,7 +7,7 @@ draft: false
## Prelude ## Prelude
No this isn't comprehensive, so no you won't be able to immediately go start making something after having read this and no this doesn't cover everything you might possibly run into, see [#The Asterisk](#The%20Asterisk). Also the examples will be in Pseudocode so this isn't a generic python/javascript tutorial :P. No this isn't comprehensive, so no you won't be able to immediately go start making something after having read this and no this doesn't cover everything you might possibly run into, see [#The Asterisk](#The%20Asterisk). Also the examples will be in Pseudocode so this isn't a generic python/javascript tutorial :P.
## The Asterisks ## The Asterisk
If you didn't notice the asterisk in the title next to every, now you know there is one. The reason for that asterisk is that this blog only covers stuff that is common(as built in language features) in procedural programming. If you don't know what "procedural" means don't worry about it and pretend that this covers every programming language. If you didn't notice the asterisk in the title next to every, now you know there is one. The reason for that asterisk is that this blog only covers stuff that is common(as built in language features) in procedural programming. If you don't know what "procedural" means don't worry about it and pretend that this covers every programming language.
## The Data ## The Data
@ -48,7 +48,7 @@ lists are a methodology of storing multiple data values within a single variable
``` ```
someList <- ["First item", "Second item", "meh item"] someList <- ["First item", "Second item", "meh item"]
someList[2] <- "Third item" someList[2] <- "Third item"
"First item should be when the line of code below is run" "First item should be displayed when the line of code below is run"
DISPLAY(someList[0]) DISPLAY(someList[0])
``` ```
## Loops ## Loops
@ -57,12 +57,12 @@ loops are kinda self explanatory as they loop running code repeatedly. Commonly
i <- 0 i <- 0
"initializing an empty list which will be filled with the while loop below" "initializing an empty list which will be filled with the while loop below"
dataSet = [] dataSet = []
WHILE i<50 { WHILE i < 50 {
dataSet[i] <- i + 1 dataSet[i] <- i + 1
} }
"both loops below will display all the values in the list in the var dataSet" "both loops below will display all the values in the list in the var dataSet"
i <- 0 i <- 0
while i<50 { WHILE i < 50 {
DISPLAY(dataSet[i]) DISPLAY(dataSet[i])
} }
FOREACH n <- dataSet { FOREACH n <- dataSet {
@ -77,4 +77,4 @@ That should cover the basic syntax features someone trying to learn a procedural
<a href="./#2" name="2">2</a> - most programming languages have certain specifications on what you can name your variables and there's also reccomended ways you should name your variables and both of these can vary per language so you should probably read their documentation for specifics but for my purposes I'm gonna stick to [camelCase](https://en.wikipedia.org/wiki/Camel_case) using only english letters as I'm unaware of any non-esoteric programing languages which disallow such naming <a href="./#2" name="2">2</a> - most programming languages have certain specifications on what you can name your variables and there's also reccomended ways you should name your variables and both of these can vary per language so you should probably read their documentation for specifics but for my purposes I'm gonna stick to [camelCase](https://en.wikipedia.org/wiki/Camel_case) using only english letters as I'm unaware of any non-esoteric programing languages which disallow such naming
<a href="./#3" name="3">3</a> - python will call foreach loops just for loops but most languages call them foreach loops <a href="./#3" name="3">3</a> - some programming languages will call foreach loops just for loops but most languages call them foreach loops

View file

@ -11,3 +11,12 @@ p a:hover, li a:hover{
p a:visited, li a:visited{ p a:visited, li a:visited{
color:#500; color:#500;
} }
blockquote {
background: #f9f9f9;
border-left: 10px solid #ccc;
margin: 1.5em 10px;
padding: 0.5em 10px;
}
blockquote p {
display: inline;
}