halvseriöst försök till komprimering

Permalänk
Medlem

halvseriöst försök till komprimering

http://erik.laeskback.com/~yarrick/proj/sqrt/

jag roar mig med att bygga en komprimerare som använder sig av kvadratroten.
läs mer på länken och ge kommentarer!

Visa signatur

4 datorer: 9 cpuer (plats för 4 till), 10scsi+1satadisk, 7.75gb ram, bara Linux
http://isitfika.net http://code.kryo.se

Permalänk
Hedersmedlem
Permalänk
Medlem

oops fixat

Visa signatur

4 datorer: 9 cpuer (plats för 4 till), 10scsi+1satadisk, 7.75gb ram, bara Linux
http://isitfika.net http://code.kryo.se

Permalänk
Hedersmedlem

http://erik.laeskback.com/~yarrick/proj/sqrt/list.php?file=.....

Jasså?

Man ska aldrig få specificera fil så direkt, skapar alltid säkerhetshål.

Permalänk
Medlem

nu då?

Visa signatur

4 datorer: 9 cpuer (plats för 4 till), 10scsi+1satadisk, 7.75gb ram, bara Linux
http://isitfika.net http://code.kryo.se

Permalänk
Medlem
Permalänk
Medlem

Ooo, pimpigt

Visa signatur

[size="1"]Coder, Absynth Interactive
~ En köpt mod är knappt en mod alls ~ One software - one function(undvik bloat) ~[/size]

Permalänk
Medlem

Tvivlar på att nån sån komprimering skulle funka, om det skulle funka, vad skulle hindra att man tog det komprimerade resultatet och gjorde samma sak i igen?

Visa signatur

-dool

Permalänk
Medlem

det är det som är det tuffa, att man kan göra den flera gånger, och det kvittar hur indatan ser ut. det går att göra så att man får mindre filer när man komprimerar, men det tar BRUTALT lång tid att packa upp...

Visa signatur

4 datorer: 9 cpuer (plats för 4 till), 10scsi+1satadisk, 7.75gb ram, bara Linux
http://isitfika.net http://code.kryo.se

Permalänk
Medlem

frånsett att den "komprimerar" till samma storlek och inte klarar alla indata så verkar det lovande....

Bytes to read: 16, CRC bytes to use: 3, Binary searches: 40 (5 bytes)
Read 16 bytes: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]
Negative: false, number: 1
CRC32 checksum: 2612820931
Error!
Message: BigInteger divide by zero
Exiting

Permalänk
Hedersmedlem

Hmm. Jag är kanske trött eller nåt, men jag förstår inte. Vi tar ett exempel.

Vi läser ut talet 140 från strömmen. Roten ur 140 är 11,832.. vilket i så fall skulle avrundas till 11. 11^2 är 121. Hur får du reda på att talet egentligen ska vara 140? Jag fattar inte hur en crc kan hjälpa dig i det här fallet. Checksumman har du ju ändå beräknat på "hela strömmen" och inte bara på denna lilla del.

Förutom att jag inte förstår hur det är tänkt att fungera, så tycker jag det är ballt. Det är skönt att se lite riktig programmering här i forumet då och då

Permalänk
Medlem

Det är väl det att programmet går igenom alla möjliga kombinationer för alla de olika talen... t.ex:

37
int(kvadratroten) = 6
6² = 36
7² = 49

36 <= 37 < 49

49 - 36 = 13 tal att kolla mot CRC:n

Kalla 37 för D, och 6 för C:
C² <= D < (C + 1)²
Antal tal mellan C² o (C + 1)² är
(C + 1)² - C² = 2C + 1

Ta talen: 175, 67
Kvadratrötter: 13, 8
Sökomfång: 27, 17
27 * 17 = 459st olika kombinationer som skulle kunna stämma för den komprimerade datan (13, 8). Därför prövar man varje kombination mot CRC:n. Om en viss kombination stämmer, så är det den rätta(detta förutsätter att CRC:n är tillräckligt lång...)

Som jag förstår det, så tar det där programmet HELA filen, räknar ut CRC, multiplicerar ihop alla bytes, drar kvadratroten ur det talet, samt sparar resultatet + CRC i en fil..

edit:
Varför inte köra unsigned o slippa tänka på om talen blir negativa?

edit2:
Fan, nu blev jag sugen på komprimering... Synd att mitt adaptive-huffman-program gjorde ooptimerade träd och att jag är för lat för att optimera :/
*kastar sig på Lempel-Ziv

Visa signatur

[size="1"]Coder, Absynth Interactive
~ En köpt mod är knappt en mod alls ~ One software - one function(undvik bloat) ~[/size]

Permalänk
Hedersmedlem

Tjoppen: Jo, men skulle det inte innebära att det skulle bli sinnessjukt många kombinationer att kontrollera om den data man ska komprimera är lite längre? På bara ett par bytes är man uppe i miljoner kombinationer.

Permalänk
Medlem

Jo, men det är där den beryktade binärsökningen kommer in, tror jag bestämt...

edit:
Talet som ska dras kvadratroten ur är oxå ganska sinnessjukt stort..

Visa signatur

[size="1"]Coder, Absynth Interactive
~ En köpt mod är knappt en mod alls ~ One software - one function(undvik bloat) ~[/size]

Permalänk
Hedersmedlem
Citat:

Ursprungligen inskrivet av Tjoppen

Jo, men det är där den beryktade binärsökningen kommer in, tror jag bestämt...

Jag måste vara i min slow setting idag. Jag fattar inte var en binärsökning kommer in i bilden? Du måste väl ändå jämföra alla kombinationer mot crc:n? Det är ju inte möjligt att veta om en viss kombination är "närmre sanningen" än en annan genom att titta på crc för denna kombination.

Citat:

Ursprungligen inskrivet av Tjoppen

Talet som ska dras kvadratroten ur är oxå ganska sinnessjukt stort..

Har du gjort en egen implementation för det? Vi hade nån uppgift på högskolan förra året där vi gjorde en implementation av stora heltal i en Java-klass. Jag tror nog iofs bara att den hanterade de fyra räknesätten.

Permalänk
Medlem

Om jag förstod dig rätt vill du göra om talet X (som är heltalsrepresentationen av hela filen) så till Y så att.

Y = (floor sqrt(X), X - (floor sqrt(x))^2)
d.v.s du sparar heltalsroter ur talet först och sedan "resten".

Varför det inte fungerar:

Säg att du vill komprimera ett tal på 200 bitar.
roten ur detta tal kommer att vara ett tal på hundra bitar.

Resten kommer tyvärr också att vara ett tal på över hundra bitar i genomsnitt.
säg att heltalsroten är 1000....0, en etta följt av 100 nollor. Det sökta talet ligger då mellan (2^100)^2 och(2^100+1)^2. Första konjungatregeln ger att (2^100+1)^2 = 2^200 + 2*2^100 + 1. Skillnaden ("feltermen") kan då bli allt mellan 0 och differensen
mellan dessa två uttryck = 2*2^100 = 2^101.

Redan här har du alltså ökat storleken på filen med en bit. Dessutom tillkommer "headerbitar". T.ex behövs ett tal som anger hur många av bitarna i den komprimerade filen som anger floor sqrt(X).

Permalänk
Medlem

Man sparar inte resten, man sparar CRC:n. Förutsatt att den är tillräckligt lång, så finns endast en lösning till "ekvationen"

Citat:

Om man dessutom binärsöker på felmarginalen kan man sedan specificera ungefär var i felmarginalen talet finns, vilket tar någon byte att lagra, men snabbar upp dekompressionen kraftigt.

http://erik.laeskback.com/~yarrick/proj/sqrt/list.php?file=51...

Ta en titt på
To go: 10080519
Vilket jag förstår som hur många tal som ska sökas igenom..

Jämför det mot formeln 2C + 1, för:
C ~= 1,92414590 * 10^1285

Man kan lätt se att sökområdet minskar kraftigt..

Visa signatur

[size="1"]Coder, Absynth Interactive
~ En köpt mod är knappt en mod alls ~ One software - one function(undvik bloat) ~[/size]

Permalänk
Medlem

Om det blir roten ur 2 då, då blir heltals delen 1. Problemet är att decimal utvecklingen är oändlig.

Btw, så läste inte jag så noga.

Visa signatur

Perl - Made by Idiots, Java - Made for Idiots, C++ - Envied by Idiots

Permalänk
Medlem

väntar fortfarande på att den ska klara alla indata samt verkligen komprimera

Permalänk
Medlem

okej, nu ska jag förklara hur jag menar. Jag börjar med en exempelutmatning, och ska försöka förklara alla steg.

yarrick@boutros zip $ java Rewrite2 Rewrite2.java Bytes to read: 8, CRC bytes to use: 3, Binary searches: 8 (1 bytes) --- Programmet skriver ut antal bytes att läsa, till crc och till binärsökning. Read 8 bytes: [47,42,32,42,42,42,42,42] --- Här läser jag in 8 bytes från filen Rewrite2.java till en vektor. Negative: false, number: 3398564234272582186 --- Jag skapar en java.math.BigInteger av byte-vektorn, och talet är negtivt --- sätter jag den flaggan och fortsätter med absolutbeloppet. CRC32 checksum: 3974197824 --- Jag beräknar CRC-32-checksumman på mitt stora tal. sqrt-ing, x: 3398564234272582186, result: 1843519523 --- Jag tar roten ur mitt stora heltal, och får ett mindre Diff max: 3687039047 --- Jag beräknar den maximala felmarginalen, genom att ta --- (roten ur talet + 1)^2 - (roten ur talet)^2 Diff real: 2590434657 --- Här ser jag vad marginalen är på riktigt Doing binary search, new Diffs: --- Nu gör jag en binär sökning mellan noll och Diff max, med --- i detta fallet 8 bitar. Detta begränsar felet till ca 16 miljoner. Diff max: 2592449329 --- ny övre gräns Diff real: 2590434657 --- talet jag söker Diff min: 2578046832 --- ny nedre gräns To go: 12387825 --- ny felmarginal Search-rs: 10110011 --- resultatet av binärsökningen, 1 = höger, 0=vänster sqrt compressed size: 4 bytes, content 1843519523 --- packar mitt roten-ur tal tillbaka till bytevektor new size: 8 bytes, read from 8 bytes, ratio 1.0 --- beräknar storlek på utvektor, och fyller den CRC % 16777216 = 14774848 --- eftersom felmarginalen nu är under 24 bitar (16.7miljoner) kan --- jag skippa en byte på crcn. den kommer inte loopa ändå Write 8 bytes: [109,-31,-32,35,-31,114,64,-77] --- först fyra bytes för rotenur, sen tre för crc, sen en för binärsökning *************************************************************** * Compression complete! * * Starting decompression in 2 seconds.. * *************************************************************** Read 8 bytes: [109,-31,-32,35,-31,114,64,-77] --- då läser vi in allt igen CRC checksum: 14774848 --- extraherar crcn från byte 4-7 Negative: false, number: 1843519523 --- extraherar talet från byte 1-4 Binary search result: 10110011 --- extraherar binärsökningen från byte 8 Diff max: 3687039047 --- kalkylerar felmarginalen igen Reversing binary search, new Diffs: --- gör binärsökningen baklänges, kommer fram till samma gränser Diff max: 2592449329 Diff min: 2578046832 Max loops: 14402497 --- här ser jag maximal felmarginal. är större än talet "to go" ovan Starting iterations... --- startar loopen. kvadrerar talet jag fått, lägger till en etta i varje loop, --- beräknar sedan crc för talet, när det stämmer har jag rätt tal Starting with x = 3398564234260194360 --- detta talet är det jag börjar med Will stop at x = 3398564234274596858 --- kommer jag hit utan att crcn stämmer har nått gått fel 1000000 loops done... 2000000 loops done... 3000000 loops done... 4000000 loops done... 5000000 loops done... 6000000 loops done... 7000000 loops done... 8000000 loops done... 9000000 loops done... 10000000 loops done... 11000000 loops done... 12000000 loops done... haveCRC: 14774848 needCRC: 14774848 --- crcn stämmer have: 3398564234272582186 need: 3398564234272582186 --- talet stämmer correct number found after 12387825 loops. --- antal loopar gjorda Write 8 bytes: [47,42,32,42,42,42,42,42] --- och så har vi de ursprungliga 8 bytesen igen. yarrick@boutros zip $

jag är högst medveten om att kompressionsration inte är något att skryta med och att algoritmen bara är på lekstadiet.

edit:
ni som inte förstog innan, är det klarare nu?

Kennel: java.math.BigInteger och BigDecimal klara STORA tal... helt underbara i sådana här syften

mera edit:
titta helst när man kör med 16 bytes eller så när ni ska förstå det hela. 512 bytes bara rör till det med jättelånga tal osv

ännu en edit:
en sak man verkligen kan störa sig på är att javas förbaskade byte inte är unsigned... då hade jag sluppit en hel del problem

Visa signatur

4 datorer: 9 cpuer (plats för 4 till), 10scsi+1satadisk, 7.75gb ram, bara Linux
http://isitfika.net http://code.kryo.se

Permalänk
Medlem

Fan, detta tål att prvas i C++...

Men du.. Du säger att BigInteger bara klara upp till ~2^3000... Om alla bytes är 255, så kan progget endast packa 375B.
Tror jag ska skriva en egen class för stora heltal.. Om jag tänkt rätt, så ska den kunna palla upp till 256^4Gi, mao 4GiB(eller mer)
Problemet är att skriva den... Kommer att bli drygt.

edit:
Istf att binärsöka, kan man inte bara ha ett tal som specificerar ungefär vart mellan C² o (C + 1)² ligger?
Kalla det talet O, och det är procent..
O = (D - C²)/(2C + 1)

Vill man ha O att vara ett DWORD t.ex.:
O = ((D - C²) << 32)/(2C + 1)

Då kan man krympa felmarginalen från
C² <= D <= (C + 1)²
till
C² + (O(2C + 1) >> 32) <= D < C² + ((O + 1)(2C + 1) >> 32)

Ju fler bitar O är, desto mindre marginal, desto snabbare sökning..

edit2:
Felmarginalen minskar omvänt proportionellt mot 2^(antal bitar i O)
Lägg till en bit, halvera söktiden.

Visa signatur

[size="1"]Coder, Absynth Interactive
~ En köpt mod är knappt en mod alls ~ One software - one function(undvik bloat) ~[/size]

Permalänk
Medlem

jag har prövat att lagra tal större än 2^4000 i en BigInteger utan problem. Eftersom den har en konstruktor som tar byte[] skulle man kunna gissa att den använder byte[] för inre representation, och borde då kunna klara hur stora tal som helst. dessutom är mitt program inte tänkt att bara kunna komprimera åtta bytes, det är ju enkelt att loopa nerpackningen framtills man når EOF, och sedan samma sak vid uppackning.
Just nu har jag binärsökningen i en BigInteger för att kunna klara mer än åtta sökningar, innan hade jag en byte. Jag använder metoderna testBit() och setBit(), mycket smidigt.
binärsökningen är lika effektiv som metoden du visar. för varje bit halverar man felet, alltså efter en byte är felet endast en 256:edel av startvärdet. vid binärsökning testar man ju om talet man söker är i vänsta eller högra halvan av det nuvarande intervallet, och sedan skippar man den halvan som ratades.

edit:
mer om BigInteger:
http://java.sun.com/j2se/1.4/docs/api/java/math/BigInteger.ht...

funderar på att döpa det till LUC, lossless useless compression

mala & knarken: läs igen och se om ni förstår det hela nu

Visa signatur

4 datorer: 9 cpuer (plats för 4 till), 10scsi+1satadisk, 7.75gb ram, bara Linux
http://isitfika.net http://code.kryo.se

Permalänk
Citat:

Ursprungligen inskrivet av Tjoppen
Fan, detta tål att prvas i C++...

Men du.. Du säger att BigInteger bara klara upp till ~2^3000... Om alla bytes är 255, så kan progget endast packa 375B.
Tror jag ska skriva en egen class för stora heltal.. Om jag tänkt rätt, så ska den kunna palla upp till 256^4Gi, mao 4GiB(eller mer)
Problemet är att skriva den... Kommer att bli drygt.

Inte behöver du skriva en själv. Kolla in NTL: http://www.shoup.net/ntl/

Permalänk
Medlem

En kul grej bara:
Nåra av världens mest framgångsrika matematiker samarbetade för att utveckla en ny komprimerings algo.
Då klarade den att komprimera 100MB till 1MB

Det läste jag i en dator tidning för ett år sen kanske. Sen vet jag inget mer om det, men det är ganska fett ändå.

Visa signatur

Perl - Made by Idiots, Java - Made for Idiots, C++ - Envied by Idiots

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Knarken
En kul grej bara:
Nåra av världens mest framgångsrika matematiker samarbetade för att utveckla en ny komprimerings algo.
Då klarade den att komprimera 100MB till 1MB

Det läste jag i en dator tidning för ett år sen kanske. Sen vet jag inget mer om det, men det är ganska fett ändå.

teoretiskt går det göra med denna också. bara att det skulle krävas så mycket jobb att packa upp det, att man skulle behöva starta ett distributed-computing-projekt för det

Visa signatur

4 datorer: 9 cpuer (plats för 4 till), 10scsi+1satadisk, 7.75gb ram, bara Linux
http://isitfika.net http://code.kryo.se

Permalänk
Medlem

Tvivlar på att det funkar. Det vore bättre att läsa in nåra 100 byte och sen dela upp dom i en träd struktur. Typ som huffman blablabla.

Visa signatur

Perl - Made by Idiots, Java - Made for Idiots, C++ - Envied by Idiots

Permalänk
Medlem

Tog hem en klass som hette HINT(Huge Int), och lekte lite. Här är utmatningen från mitt program som läser in "Apan sitter, apan står.":

edit:
O = 16 bitar

D = 30787738357938930401168957289910750595392685551552655918
Sqrting................................................................................
..................
C^2 = 30787738357938930401168957285429447062712379656933230225
C = 5548669962967605663138258985
diff = 4481303532680305894619425693
O = 26464
30787738357938930401168957289910648292570006496206023370 <= 30787738357938930401
168957289910750595392685551552655918 <= 3078773835793893040116895728991081762453
9091200968692384
.. holds true!

edit2:
Yarrick: Du borde göra så att programmet kollar vidare, så att de vet att det inte finns fler lösningar...

edit3:
Ny utmatning(denna gång med 30 bitar):
D = 30787738357938930401168957289910750595392685551552655918
Sqrting.........................................................................
.........................
44 seconds
C^2 = 30787738357938930401168957285429447062712379656933230225
C = 5548669962967605663138258985
diff = 4481303532680305894619425693
O = 433596074
30787738357938930401168957289910750590411193044530052783 <= 30787738357938930401
168957289910750595392685551552655918 <= 3078773835793893040116895728991075060074
6396235735177458
.. holds true!
newdiff = 10335203191205124675
ratio = 1:433596074

Visa signatur

[size="1"]Coder, Absynth Interactive
~ En köpt mod är knappt en mod alls ~ One software - one function(undvik bloat) ~[/size]

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Yarrick
det är det som är det tuffa, att man kan göra den flera gånger, och det kvittar hur indatan ser ut. det går att göra så att man får mindre filer när man komprimerar, men det tar BRUTALT lång tid att packa upp...

Jag kan nästan garantera att det inte kommer att funka i praktiken. hur än du gör med CRC-summor så kommer du inte att kunna återställa att bytes i utsprungligt skick, såvida inte den komprimerade datan + CRC närmar sig i det okomprimerade datan i storlek..

Det finns ingen möjlighet att komprimera data hur mycket som helst.

Jag har inte tillränkliga kunskapar för att analysera din ide men kan som sagt nästan garantera att den kommer att falla på nåt sätt, många har försökt med såna här mirakelkompirmeringar och ingen har lyckats.

Visa signatur

-dool

Permalänk
Medlem

Som dool säger så finns det INGA komprimeringsalgoritmer som packar slumpdata. D.v.s det finns ingen algoritm som kan komprimera filer en enda bit i genomsnitt.

Anledningen till detta är att algoritmen måste vara inverterbar. Säg att vi vill komprimera alla de filer som är 1000 bitar långa. Om vi antar att algoritmen klarar att komprimera alla filer 1 bit så kommer de komprimerade filerna att uppta 999 bitar styck. Hur vi än vänder och vrider på det så kommer då minst en komprimerad bitserie att representera minst två okomprimerade filer. (duvhålsprincipen)

Detta gäller oberoende av algoritm. Vad gäller just din implementation så faller den som sagt på att resten är lika stor som kvadratroten. Att du sen inte uttrycker resten i klartext (varför inte?) utan som en CRC-summa betyder bara att du har förskjutit problemet med att komprimera originalfilen till att komprimera resten. Kom ihåg att varje restterm måste ha en motsvarande CRC-summa, annars är den inte inverterbar. I bästa fall får du ett 1:1 förhållande mellan antal möjliga resttermer och antal möjliga CRC-tal. Förmodligen får du det inte, och den bästa lösningen vore därför att helt enkelt skriva resten i klartext, eller ännu bättre - behålla filen som den är.

Nu kanske någon undrar hur zip kan fungera som bevisligen gör filer mindre? Svaret är helt enkelt att zip inte alls gör alla filer mindre. Tvärtom är det faktiskt så att ganska få filer av alla möjliga filer blir mindre. Testa exempelvis att zippa en fil med slumptal eller ännu enklare: testa att zippa en redan zippad fil...

Permalänk
Medlem

Men vänta här nu.. Borde det inte vara möjligt att komprimera ganska bra, fast med lite loss?
Iom att det hänger på CRC:ns upplösning, så skulle man kunna komprimera bilder t.ex., och ändå inte behöva bry sig om det blir fel(i motsats till om det skulle vara .exe t.ex.)
Fast det är klart... Jag tror inte att de tal som har samma CRC ligger speciellt nära varandra, så bilderna kommer isf bli helt olika. :/

Visa signatur

[size="1"]Coder, Absynth Interactive
~ En köpt mod är knappt en mod alls ~ One software - one function(undvik bloat) ~[/size]