You are viewing archived messages.
Go here to search the history.

Tak Tran 2024-04-15 22:36:44

I’m playing with electronics and crocheting atm. Imagining what other ways there are to interact with a computer, other than keyboard and mouse. This is a custom made bend/pressure sensor using copper sheets, velostat as a semi-conductive layer in between, with a crochet leaf on top and felt on the bottom, for a soft, non metallic feel 🐑

Tak Tran 2024-04-15 22:37:40

Lu Wilson - funny that you have a leaf thing going on too 😂

Lu Wilson 2024-04-15 23:16:43

oh my god this is amazing

Dany 2024-04-16 05:25:13

I love it. Have you considered any other sensors than bend sensor?

Tak Tran 2024-04-16 07:07:05

Currently it’s actually quite versatile in being able to be a button, pressure sensor, and bend sensor, I’m thinking if I duplicate the circuitry with a matrix of them, it could be a trackpad of sorts but on non-flat surfaces. I think that kind of sensing fits textile materials best. Maybe a stretch sensor would be neat too. Did you have any sensors in mind @Dan Groshev?

I’ve sent you this Dan, but this is a great treasure trove of ideas for etextile sensors for anyone else interested.

Dany 2024-04-18 06:52:49

That's a great link. I think it would be cool if the shape (the way it's knitted) changes the behavior of the sensor. Measure electricity (static) directly? Then one could create software by knitting. Maybe it would look more like a Quipu (en.wikipedia.org/wiki/Quipu)..

Tak Tran 2024-04-18 12:19:55

I did notice 💬 #share-your-work@2024-03-22T15:22:09.764Z

I am looking into using conductive thread to add features more aligned with the material. Being able to digitally detect where knots are could be quite cool. Also maybe I could somehow make a material based sequencer based on weaving conductive/non conductive thread between a base sheet 🤔

[March 22nd, 2024 8:22 AM] alex952: A tangible programming interface inspired by Andean khipu that we've been working on..

Ivan Reese 2024-04-17 01:43:28

I shared some thoughts about my personal definition of reversible computing over on Mastodon today. (Yeah, I slightly mangled the example of a surjective function — should have said nonnegative integers.)

Ivan Reese 2024-04-17 01:45:01

Images here, in case you dun wan go to Masto.

image.png

image.png

Joshua Horowitz 2024-04-17 01:58:31

Not to be a total nerd about this, but what you want sorta feels like a “homotopy equivalence”.

f : X → Y and g : Y → X form a homotopy equivalence if g(f(x)) is “pretty much” like x and f(g(y)) is “pretty much” like y.* So it’s a weakening of the typical definition of inverse functions.

A reason I don’t think this is a great metaphor for you: It actually says something pretty interesting about the relationship between X and Y for there to be any homotopy equivalence at all between them. (We call X and Y “homotopy equivalent” in this situation.) I think you want to be able to reverse functions between very dissimilar / arbitrary domains. So IDK.

  • It’s actually not that g(f(x)) is “pretty much” like x for every x; it’s that the function g ∘ f is, holistically, “pretty much” like the identity function. (Homotopic.)
Ivan Reese 2024-04-17 02:05:49

You'll have to hold my hand a bit here — I'm way beyond my comfort zone wrt properties n shit — but I'm really interested here in terminology, theory, prior art, etc.

How does this homotopy equivalence work if f and/or g are non-injective, non-surjective, partial, multivalued, etc.? In other words, how close to bijective do these functions need to be for this property of homotopy equivalence to hold? Do f and g both need to be equally "close" to bijective? Or can one of them be made, say, only injective, and the other made multivalued? (Hopefully I said that correctly, or at least that you can intuit my questions)

Ivan Reese 2024-04-17 02:08:25

I think you want to be able to reverse functions between very dissimilar / arbitrary domains.

Yeah, this exactly. I want to largely disregard the relationship between X and Y (in either direction) if that allows me to achieve something that feels reversible in more situations.

Like, for the cases where X and Y are 1-to-1 in f and g, then the reversibility is trivial. But what about the cases where they're not? I want to fake it, with as convincing a fake as I can manage with low-to-medium effort ;)

Tom Lieber 2024-04-17 02:15:24

What makes this your favorite definition of reversible computing?

Ivan Reese 2024-04-17 02:19:55

I'm looking for ways to make "reversible" versions of, basically, everything in JavaScript. So I'm trying to figure out what properties would enable the best-feeling version of this.

Joshua Horowitz 2024-04-17 02:55:24

Yeah sounds like you’re interested so I’m happy to elaborate!

All this homotopy equivalence stuff is coming from topology. Hopefully you know some of the basic topology spiel: we’re talking about squishy squashy spaces where we don’t care about exact shape, just sorta the way the spaces are connected. So a doughnut is the same as a coffee mug (with a handle).

The classic example of a homotopy equivalence, as far as I’m concerned, is the equivalence between a circle C (like points in the plane distance 1 from the origin) and an annulus A (like points in the plane distance 0.9 to 1.1 from the origin).

These two objects are topologically different! For instance: Removing a single point from C will “cut” it, producing something that you can unwrap to turn it into a little line segment. But removing a single point from A just gives you, like, an annulus with an extra tiny extra hole in it.

But there’s a looser sense in which C and A have the same structure — they’re both things with a hole in them — and that sameness is captured by the fact that there’s a homotopy equivalence connecting them.

Making a map f: C → A is easy — C is already a subset of A, so you just map it in there. This is an injective function.

Making a map g: A → C is less obvious, but still pretty straightforward. For instance, you can map each point of the annulus to the point of the circle at the same angle. Which is also the closest point of the circle, FWIW. This is a surjective function.

Interestingly, in this situation, f and g are inverses of each other in one of the two directions. If I start on the circle, do f, and then do g, I get back to my original point. But no way are they going to be inverses of each other the other way around. You lose information going from A to C. So if I start with a point a ∈ A, do g, and do f, I’m going to (generally speaking) end up at a different place in A.

But it turns out (and this is where I’m gonna get very sketchy), that f ∘ g (the map that takes a to f(g(a))) is not that far off from the identity function. In particular, it’s “homotopic” to the identity: it can be continuously deformed to the identity. So that’s what makes f & g a special homotopy equivalence pair.

Now that I’ve given you the whole spiel, let me look more carefully at what you wrote there…

Joshua Horowitz 2024-04-17 02:58:04

Ok so you were curious about how close f & g have to be to being bijective. The example I gave above was a very classic sort of example, in which neither are bijective, but one is injective and the other is surjective. The image is that you have two spaces, one of which sits inside the other, and there’s a “projection” operator that sends the larger space down onto the smaller space.

Joshua Horowitz 2024-04-17 02:58:50

This is related to the idea of “deformation retraction”, illustrated here.

Screenshot 2024-04-16 at 7.58.35 PM.png

Joshua Horowitz 2024-04-17 02:59:34

(That’s from Allen Hatcher’s textbook, which is free online, very good, and well-illustrated, tho it is almost certainly impenetrable without a lot more preparation: pi.math.cornell.edu/~hatcher/AT/AT.pdf.)

Joshua Horowitz 2024-04-17 03:00:23

But homotopy equivalences themselves don’t require this structure; they’re much more general. You can come up with homotopy equivalences where neither map is injective or surjective, they’re just two sloppy mappings that happen to sort of almost invert each other in this sloppy topological way.

Joshua Horowitz 2024-04-17 03:01:45

As for multi-valued maps: Mathematicians basically don’t fuck with multi-valued maps. Anything you’d want to represent as a multi-valued map from X to Y, mathematicians prefer to see as a single-valued map from X to P(Y) (the power set, consisting of all subsets of Y).

Joshua Horowitz 2024-04-17 03:02:40

Ok that’s definitely enough gotta go. 🙏

Tom Lieber 2024-04-17 03:57:55

I just lol’d working out how to sloppy-reverse ~_*sin(x) > 0*_~ evaluating to ~_*true*_~ . glhf, man, this is gonna be wild.

Ivan Reese 2024-04-17 04:52:45

Yeah, that's a great example Tom Lieber. I'd be perfectly happy if that produced, say, ~_*1*_~ when reversed — even if the original ~_*x*_~ was something totally different — because ~_*1*_~ gets you another ~_*true*_~ when you go forward again.

Tom Lieber 2024-04-17 05:00:13

Does it matter to what you’re working on that ~_*x*_~ might be used in another expression that doesn’t have ~_*1*_~ in its domain? Is rocking forward after a rock backward going to be sloppy too?

Ivan Reese 2024-04-17 05:04:13

Yes, potentially! In addition to non-injective, non-surjective, and multivalued, I'm also interested in a notion of "reversible function" that is loose enough to cover partial functions. But I don't have any strong examples yet to help me feel out sensibilities for how I'd like them to behave.

Ivan Reese 2024-04-17 05:06:34

Like, the reverse of a non-surjective function is very likely a partial function, so I feel like one answer might be to treat a forward partial function with similar techniques (so that you can meaningfully reverse it and get something useful back).

Dany 2024-04-18 07:03:55

Can't you just use matrices? I think of a matrix as basically a couple of transform (functions) put into a neat grid. Inverting them is possible, albeit costly. So couldn't you use a really high order matrix and fit your function as close as possible. Than invert it. This coming from an armchair math expert. 🙂

Ivan Reese 2024-04-18 12:49:21

I'm interested in functions on other data types too. Also, non-affine math functions. So matrices are a great example of a bijective function, but I can't see how they'd apply to, say, array.splice()

Elliot 2024-04-20 04:17:46

I'm working on a similar, more manual approach to the problem of reversing functions with my vezwork.github.io/polylab/dist/demo/bidirectionalParse bidirectional language project. My approach, up until this point, has been to manually write the reverses of JS functions, and pair them up to form isomorphisms/multidirectional functions. i.e. I manually write three cases for plus: c = a + b, a = c - b, b = c - a. I was going to continue this approach with other data types like array.splice etc.

I like this approach because it is quite doable, and while the simple multidirectional functions themselves are not so expressive to use, once you start composing a bunch of them, you can pretty quickly build up some pretty interesting multidirectional functions, and you kind of get it for free because you can write code as if it were just normal functions, but then call them forward and sideways and backwards.

Elliot 2024-04-20 04:23:52

While I was learning about bidirectionality, I tried out MiniKanren. Its really cool because everything you write in it is a relation, which is incredibly powerful -- for example, given an output to a relation, you can get back ALL the possible inputs -- but at the cost of anything complex being hella slow. even something with a relatively simple definition like relational multiplication can get slow for reasonable size numbers I seem to remember.

Elliot 2024-04-20 04:51:52

Relating in concept to what Joshua Horowitz talked about: I think one thing to check your intuition on is continuity. What I mean is, it might be worth asking yourself these questions:

do you have some sense of "closeness" of input values to your function?

  • numbers have an obvious sense of closeness that we learn in school. |a - b| is the distance between a and b.
  • you can have a sense of closeness of strings by an "edit distance" such as "Levenshtein distance".
  • arrays also could have an edit distance. Maybe array distance is sort of defined in terms of the distance of its entries? Is ['a',1,2] close to ['ab',1,2]? It probably depends on what array modifications you expect.
  • git diffs are a sort of measure of the difference between source files.
  • etc.

and do you have a sense of closeness of output values to your function?

if a function is continuous, that means that if you "move" your original input value to a new close input value, then the new output of your function should also be close to your original output.

Is the function you are trying to reverse continuous?

The reverse of your function is also a function, is the reverse function continuous?

  • For an example, what about a reverse of the square function? the square of 4 could be 2 or -2, and generally the square root of any positive number could be positive or negative. If you want the reverse to be continuous and be single-valued then (I'm pretty sure) maybe you should definite square root to always be positive or always be negative OR you can make square root return a pair of both positive and negative and imagine that the pair lives in a 2d space. Both of these options make for a continuous reverse of the square function:
  • example 1:
  • 4 -sqrt-> 2
  • 4.1 -sqrt-> 2.02 ✅ 4.1 is close to 4 and 2.02 is close to 2 by number distance
  • example 2:
  • 4 -sqrt-> [-2,2]
  • 4.1 -sqrt-> [-2.02,2.02] ✅ 4.1 is close to 4 and [-2.02,2.02] is close to [-2,2] by distance of 2d points

Continuity is useful for thinking about user experience because as time slowly changes, or user input slowly changes, or values slowly change, continuity says that related things don't "jump around".

Elliot 2024-04-20 05:17:28

Continuity could be helpful for automating reversal of functions too. If you define some sense of closeness on a datatype, then given an original input and ouput, and given a new output thats close to the original output (maybe assuming the user nudged the output value or something) then you can search only close around the original input value to find a new input.

This could potentially narrow down the search space a lot.

Elliot 2024-04-20 05:18:23

This is still pretty theoretical though. I'll try to think about more concrete ways to approach this in JS. I'll also try to think about more concepts that can help constrain or reason about bidirectionality.

Ivan Reese 2024-04-20 05:35:39

That idea of manually writing bidirectional versions of functions actually lines up with what I have in mind. Like, my plan is to start with the simplest / dumbest thing that'll work, then gradually (likely manually) add better behaviour where it's most useful. So for instance, the "automatic" reverse version of a math function could just return 0 (or 1, or NaN), for string functions return empty string, etc. Just return values that are likely to be a fixed point, even if it's totally wrong. It'll be a useful (and quick) enabler for what I want to explore.

And then yeah, on top of that I can begin layering in different improvements. A little gradient descent here, maybe minikanren there, maybe sprinkle some GPT bullshit on top. Anything will be an improvement. The suggestions you have about nudging values and treating the error as a point on 2D space are appreciated, since that's the fuzzy frontier of my understanding for how to do a good job of this. Like, my gut says that making x + y = z reversible could be done nicely by creating a special pair of values for x and y that preserve the constraint that they must add to z. But exactly how to do that, I'm not sure yet.

Maikel van de Lisdonk 2024-04-20 07:28:58

In this video youtu.be/3vINEOECt9w I show a small celsius to fahrenheit converter (this is one of the tasks from 7Gui) that I build using my visual programming system and extended it where needed.

The solution uses an observe-variable node-type which triggers a flow when a variable gets set. I've also build a new user-input node with decimal formatting option (in the near future I will extend this to be configurable forms for collecting user-input).

You can see what happens as you type in the celsius or fahrenheit temperature in the input fields (you see the data flowing though the flow). To prevent an infinite loop, the flow-engine uses a call-stack which stops running when a node gets run twice.

I am still thinking of different solutions but for now this works (some nodes gets run unneeded, I think this can be optimized). Per node-call the node-id, scope-id and input port-name is stored on the call-stack, this is needed to keep other things working like the recursive functions in the quicksort example.

The celsius-to-fahrenheit converter can be tried out here : demo.codeflowcanvas.io via the examples dropdown.

Maikel van de Lisdonk 2024-04-20 09:09:48

this is an alternate flow which requires code changes (I haven't commited this yet). It makes more sense to do the calculations directly after the user-input nodes I think. But somehow it feels more cluttered and the data flows a bit weirdly because of the order of execution and how this is stored in the execution history. Something to think about further.

image.png

Maikel van de Lisdonk 2024-04-21 08:29:58

I changed the implementation and the example and made a small video about it: youtu.be/_rrIsdqM4ik

Something that I want to improve on further is how parallel flows are handled together with the timeline slider. The timeline slider currently shows the execution path differently then when you are executing a flow when entering data in the user-input nodes (this also happens in other scenarios for example when a flow contains the parallel node-type or when a node contains multiple outputs).