Bijektive Abbildung (Selbstabbildung) mithilfe des %-Operators in JS/ES
-
@SeppJ sagte in Bijektive Abbildung mithilfe des %-Operators in JS/ES:
13 18
18 darf auch nicht vorkommen, denn der Definitionsbereich ist zugleich auch der Wertebereich.
Edit: Selbstabbildung, Endomorphismus bzw. Permutation.
-
Ich und mein großes Maul

Das ist ja ekelhaft im allgemeinen Fall, aber das musste ich heute Abend noch durchtüfteln, nachdem ich mich über die schlechten Mathekenntnisse der KI lustig gemacht habe.Jetzt sollte hoffentlich alles passen, egal welche m und n.
Leider habe ich einen allerletzten Ausdruck, wo ich eine Fallunterscheidung habe, da ich eine Stufenfunktion brauche, die 0 für x < 0 und 1 für x >= 0 ist. Das kann man nicht mehr mit primitiven Operationen wie Plus, Minus, Mal, Geteilt schreiben, da muss man irgendwie verzweigen. Du kannst das entweder so machen wie ich, mit einem expliziten
if, oder das irgendwie verstecken hinter irgendwelchensignoderabsFunktionen (Was immer Javascript da so hat), die dann intern aber auch nix anderes machen.Der finale Ausdruck ist lang. Es gäbe auch eine Erklärung, die wäre nochmals viel länger, aber ich denke mit ausreichendem Draufgucken kann man verstehen, was da vor sich geht. Das schafft dann aber kein Drittklässler mehr, vermutlich auch die meisten Abiturienten nicht.
Da ich das in Python ausgekügelt habe, und keine Lust habe, das jetzt auch noch in LaTeX zu setzen kopiere ich einfach mein Testprogramm hier. Das sollte trivial nach Javascript übersetzbar sein, und Python ist so einfach, da muss ich wohl nicht erklären, was die Syntax bedeutet:
import math def H(x): # Stufenfunktion, wie auch immer du die in Javascript mit den erlaubten Mitteln machen würdest return 1 if x >= 0 else 0 def func(i, n, m): L = math.floor(m / n) s = m - n * L T = s * (L + 1) J = H(i - T) # Hier müssen wir feststellen, ob i-T >= 0 ist (d.h. ob i >= T) return n * ((i - T * J) % (L + 1 - J)) + (1 - J) * math.floor(i / (L + 1)) + J * (s + math.floor((i - T) / L)) n = 4 m = 18 for i in range(m): print(i, func(i, n, m))Die Geschichte mit dem J ist, dass ich es als persönliche Herausforderung gesehen habe, kein if zu nutzen. Das ganze wäre viel einfacher, wenn man mit
if i < Teinfach zwei verschiedenen Formeln nutzen würde.Die Grundidee ist, dass wir uns ausrechnen, wie viele lange Zyklen wir haben. Das ist das s . Und vor allem, wo der Übergang (T) von den langen zu den kurzen ist. Bei n = 4 und m = 18 haben wir 2 lange Zyklen mit mit 5 Werten, dann 2 kurze mit 4 Werten. Der Übergang ist daher bei i = 2 * 5 = 10.
Wenn i >= T ist, sind wir in einer kurzen Zeile. Mit diesem Wissen können wir dann den korrekten Wert innerhalb der Zeile konstruieren. Bei i < T haben wir Zyklen von Länge L + 1, ab i >= T ist die Länge L. Das ist alles in dem langen Ausdruck am Ende verpackt.
Die Ordnung der Zyklen ist natürlich willkürlich, man hätte genausogut auch anders ordnen können, aber ich mochte dass die Sequenz bei 0 mit 0 beginnt, und das schien mir die natürliche Ordnung von da an.
-
Konnte auch noch nicht schlafen (langsam ist der Kipppunkt erreicht, an dem dies ohne AC im Sommer nicht mehr geht^^)
Vielen Dank für die mathematische Aufarbeitung...
Solange Sprungfunktionen (nicht stetige) (ohne Fallunterscheidungen (1)) noch nicht erfunden wurden, ist das Ganze ziemlich abscheulich, ja das stimmt. 
Edit: 1) Ich sehe gerade, dass die Heaviside- oder Abrundungsfunktion auch ohne Fallunterscheidung über die Fourier-Reihen der fortlaufenden Sinus-Funktionen definiert werden können... Bitte nicht zu ernst nehmen.
-
@Anon-81275 sagte in Bijektive Abbildung (Selbstabbildung) mithilfe des %-Operators in JS/ES:
Edit: 1) Ich sehe gerade, dass die Heaviside- oder Abrundungsfunktion auch ohne Fallunterscheidung über die Fourier-Reihen der fortlaufenden Sinus-Funktionen definiert werden können... Bitte nicht zu ernst nehmen.
Ja. Viel Spaß, eine unendliche Reihe im Computer zu berechnen, um ein
if i<0zu sparen
Wenn man es nicht so wie ich mit der Brechstange in einen Ausdruck packen will dann geht das sogar mit der Lesbarkeit. Das sind zwei Kästchen, eines der Größe s × (L+1) und ein anderes der Größe (n-s) × L, die um T gegeneinander verschoben sind. Aus einem Index die Koordinaten in einem 2D-Kästchen zu berechnen ist Standardaufgabe, braucht man ständig für 2D-Arrays. Um T verschieben ist auch geschenkt. Und was an den Koordinaten im Kästchen stünde ist eigentlich auch ganz einfach, wenn man weiß in welchem Kästchen man ist (Das hat du selber oben schon gezeigt). Alles zusammen ist dann lang, aber lesbar, vor allem wenn man sich ein paar Hilfsfunktionen erlaubt, für die einzelnen Teile, die ich gerade beschrieben habe.
Aber es war meine eigene Sturheit, das unbedingt alles in einen einzigen Ausdruck zu schreiben, und den auch noch möglichst zu vereinfachen, die das so entartet hat. Aber ich wollte unbedingt das
if i<T wähle aus Kästchen1, sonst aus Kästchen2vermeiden, um das mehr wie Grundschulmathematik aussehen zu lassen.
-
@SeppJ Ich weiß, dass das jetzt nicht dem Ziel entspricht, aaaber:
from more_itertools import distribute r = distribute(4, range(18)) print([[*c] for c in r])Ergibt
[[0, 4, 8, 12, 16], [1, 5, 9, 13, 17], [2, 6, 10, 14], [3, 7, 11, 15]]Warum selber machen?

[gut, "this function [...] may require significant storage." wäre ein Argument]
-
Prinzipiell wäre es ja auch ein ganz einfacher Dreizeiler, ganz ohne Overhead, wenn man bloß zwei Schleifen verschachteln würde. Aber wo wäre da die Herausforderung?

-
@wob sagte in Bijektive Abbildung (Selbstabbildung) mithilfe des %-Operators in JS/ES:
Ich weiß, dass das jetzt nicht dem Ziel entspricht, aaaber:
JS hat so etwas nicht... Ich bin schon froh, wenn man nicht mehr
a * 1.0 / bschreiben muss, wenn man die Float-Division von a und b mit Nachkommastellen meint.Generell empfinde ich das Fehlen von strenger Typisierung als irritierend - gerade, wenn um so Mathematik-Krams geht.
-
@wob Ginge die Ausgabe eigentlich auch ohne die eckigen Klammern ( [ und ] ), oder ist man in Python an diesen... syntaktischen Zucker gebunden? Ich habe explizit nach einer Funktion gefragt, also nach Einzelwerten bzw. einer Zahlenreihe, und nicht nach einem Klammerintermezzo.
@SeppJ sagte in Bijektive Abbildung (Selbstabbildung) mithilfe des %-Operators in JS/ES:
Viel Spaß, eine unendliche Reihe im Computer zu berechnen, um ein if i<0 zu sparen
Ich sagte nicht, dass ich das so machen würde, nur dass die Möglichkeit bestünde.
Fallunterscheidungen oder Schleifen wären eben nicht mehr in der "kontinuierlichen" Mathematik, was ja ggü. der diskreten Mathematik immer vorzuziehen ist (glaub ich zumindest). Aber egal, bin Algorithmiker und nicht Mathematiker. Der Rechenschieber ist mein Werkzeug, nicht die Fantasie.

-
@Anon-81275 sagte in Bijektive Abbildung (Selbstabbildung) mithilfe des %-Operators in JS/ES:
@wob Ginge die Ausgabe eigentlich auch ohne die eckigen Klammern ( [ und ] ), oder ist man in Python an diesen... syntaktischen Zucker gebunden? Ich habe explizit nach einer Funktion gefragt, also nach Einzelwerten bzw. einer Zahlenreihe, und nicht nach einem Klammerintermezzo.
Das
distributeist absichtlich so, wie es ist, da es eigentlich für was anderes da ist, nämlich um m Dinge auf n kleinere Container zu verteilen. Das ist also keine Funktion, die irgendwas berechnet, sondern da werden wirklich 4 Sequenzen für diese kleinen Container erzeugt (Beziehungsweise es wird ein Objekt erstellt, das dann diese Sequenzen generieren kann; die eigentliche Erzeugung ist in dem[*c], wo dieses Generatorobjekt durch eine Liste gejagt wird). Das wird wirklich verteilt, nicht berechnet. Man hätte da auch beliebig andere Objekte anstatt der Zahlen von 0 bis 17 reinwerfen können. Das heißt, man kann nicht wie bei einer Funktion fragen "Was wäre der Wert vonf(i, n, m)?" und direkt eine Antwort bekommen, sondern müsste diese Generatoren mindestens bis zum i-ten Element auswerten, um das zu erfahren.Das liegt aber nicht an Python, sondern am Einsatzzweck von
distribute. Printen können wir natürlich auch ohne die Klammern, wir müssen bloß die Generatoren anders auswerten, so dass sie alle nacheinander in eine lange Sequenz gepackt werden. Da gibt es natürlich auch einitertooldafür, damit wir uns diesen schweren Einzeiler (der vermutlich kürzer wäre als der itertools Call) sparen können:from more_itertools import distribute import itertools r = distribute(4, "abcdefghijklmnopqr") # Werfen wir Buchstaben rein, nur um zu zeigen, dass das auch geht print(*itertools.chain.from_iterable(r))a e i m q b f j n r c g k o s d h l p
-
@SeppJ Danke. Dieses "Objekt" (... bin in Python nicht kapitelfest) zwischenspeichern ginge auch.
-
@Anon-81275 sagte in Bijektive Abbildung (Selbstabbildung) mithilfe des %-Operators in JS/ES:
@SeppJ Danke. Dieses "Objekt" (... bin in Python nicht kapitelfest) zwischenspeichern ginge auch.
Tatsächlich Nein. Das ist ein Generator. Der ist zur einmaligen Verwendung. Der erzeugt einmalig die Sequenz, danach ist er am Ende. Keine Vor- oder Zurückspringen, und kann auch nicht auf den Anfang zurück gesetzt werden. Wenn man es mehrmals benutzen will, muss man sich die erzeugte Sequenz selbst speichern.
-
@SeppJ sagte in Bijektive Abbildung (Selbstabbildung) mithilfe des %-Operators in JS/ES:
Da gibt es natürlich auch ein itertool dafür, damit wir uns diesen schweren Einzeiler (der vermutlich kürzer wäre als der itertools Call) sparen können:
Ab 3.15 geht auch
print(*(*x for x in r)), davor müsste man sowas wieprint(*(y for x in r for y in x))schreiben.
-
@SeppJ Ok. Die Speicherplatzanforderung wäre immer
n. Daran hat man offenbar nicht gedacht oder es fortan nicht für wichtig befunden. Bei einer Funktion wäre dieser natürlich nur1.Aber Thema gelöst. Ich kann jetzt aus einer Menge von
nFarben, die sich jeweils kaum unterscheiden (HSV-Farbkreis...), jeweils die nächste Farbe auswählen, die sich deutlich zur vorherigen unterscheidet.function interleaveShiftIndex(totalSteps, offset, currentIndex) { let offset2 = Math.ceil(totalSteps / offset); let virtualIndex = 0; let validCount = 0; while (true) { // <- ja, hier ist leider noch eine Schleife... let row = Math.floor(virtualIndex / offset2); let mod = virtualIndex % offset2; let target = mod * offset + row; if (target < totalSteps) { if (validCount === currentIndex) { return target; } validCount++; } virtualIndex++; } } function getNextHslColorString(currentIndex, hslLightness) { let totalSteps = 18; let offset = 4; currentIndex = interleaveShiftIndex(totalSteps, offset, currentIndex); let hue = Math.round(currentIndex / totalSteps * 360.0); let hslSaturation = 50; return `hsl(${hue}, ${hslSaturation}%, ${hslLightness}%)`; }getNextHslColorString(i+1, ...)gibt jetzt also einen Farbwert zurück, der sich deutlich vom vorherigen Farbwert füriunterscheidet. Erst abi=5oderi=6würde ein Farbewert zurückgegeben werden, der ähnlich zum allerersten Farbwert wäre.
-
@wob sagte in Bijektive Abbildung (Selbstabbildung) mithilfe des %-Operators in JS/ES:
davor müsste man sowas wie print(*(y for x in r for y in x)) schreiben
Furchtbar.

-
@wob sagte in Bijektive Abbildung (Selbstabbildung) mithilfe des %-Operators in JS/ES:
Ab 3.15 geht auch print(*(*x for x in r)),
Ich kann es kaum erwarten, bis das in 2 Jahren zu meiner Plattform durchsickert
