BitMagic ถูกสร้างขึ้นเป็นชุดเครื่องมือพีชคณิตของชุดสำหรับการดึงข้อมูล แต่ปัจจุบันพัฒนาเป็นไลบรารีส่วนประกอบ Data Science ทั่วไปมากขึ้นสำหรับโครงสร้างหน่วยความจำขนาดกะทัดรัดและอัลกอริธึมบนเวกเตอร์ข้อมูลที่กระชับ BitMagic ใช้บิตเวกเตอร์และคอนเทนเนอร์ (เวกเตอร์) ที่ถูกบีบอัดตามแนวคิดของการแปลงบิตสไลซ์ การบีบอัดอันดับแบบเลือก และการคำนวณแบบลอจิคัลบนโมเดลที่บีบอัดหน่วยความจำ
คอนเทนเนอร์แบบกระชับของ BitMagic ทั้งหมดสามารถซีเรียลไลซ์ได้ (พร้อมการบีบอัดโดยใช้ Binary Interpolative Coding อันทันสมัย) เพื่อการจัดเก็บข้อมูลและการถ่ายโอนเครือข่ายที่มีประสิทธิภาพ คอนเทนเนอร์ทั้งหมดสามารถค้นหาได้อย่างรวดเร็วในรูปแบบที่บีบอัด
BitMagic นำเสนอชุดวิธีการและเครื่องมือในการออกแบบแอปพลิเคชันของคุณให้ใช้เทคนิค HPC เพื่อประหยัดหน่วยความจำได้ทันที (ทำให้สามารถใส่ข้อมูลได้มากขึ้นในหน่วยประมวลผลเดียว) ปรับปรุงรูปแบบการจัดเก็บข้อมูลและการรับส่งข้อมูลเมื่อจัดเก็บเวกเตอร์และแบบจำลองข้อมูลในไฟล์หรือวัตถุ ร้านค้า (SQL หรือ noSQL) ปรับแบนด์วิธของระบบให้เหมาะสมตั้งแต่ระดับต่ำ (แคช CPU) ไปจนถึงการแลกเปลี่ยนเครือข่ายและที่เก็บข้อมูล
BitMagic อำนวยความสะดวกให้กับสถานการณ์ใหญ่สองประเภท:
BitMagic ถูกใช้เป็นส่วนประกอบสำหรับ:
กรุณาเยี่ยมชมหมายเหตุการใช้งานของเรา: http://bitmagic.io/use-case.html
ไลบรารี BitMagic เป็นไลบรารีที่มีประสิทธิภาพสูง ปรับใช้การปรับให้เหมาะสมสำหรับแพลตฟอร์มที่หลากหลายและสร้างเป้าหมาย:
BitMagic ใช้การออกแบบเวกเตอร์ข้อมูลแบบขนานโดยมีเป้าหมายที่ไม่เพียงแต่มอบประสิทธิภาพเธรดเดียวที่ดีที่สุด แต่ยังอำนวยความสะดวกในการประมวลผลแบบขนานสูงบนระบบหลายคอร์อีกด้วย
BitMagic ใช้ชุดอัลกอริธึมการบีบอัด ตัวกรอง และการแปลงเพื่อลดพื้นที่หน่วยความจำ ค่าใช้จ่ายในการจัดเก็บข้อมูล และการถ่ายโอนข้อมูลเครือข่าย http://bitmagic.io/design.html
กรุณาเยี่ยมชม tech.notes ของเรา: http://bitmagic.io/articles.html
BitMagic รองรับการตีความบิตเวกเตอร์ใหม่เป็นคอลเลกชันของช่วงที่ไม่ทับซ้อนกัน 1 วินาทีขนาบข้างด้วย 0 (เช่น 011110110) ฟังก์ชั่นการตั้งค่าปกติจัดให้มีการดำเนินการ intreval ของชุดตัด / สหภาพใช้ตัววนซ้ำช่วงเวลาและการค้นหาขอบเขตของช่วงเวลา ช่วงและช่วงเวลามีประโยชน์อย่างมากในด้านชีวสารสนเทศศาสตร์ เนื่องจากข้อมูลจีโนมิกส์มักถูกใส่คำอธิบายประกอบเป็นช่วงพิกัด BitMagic นำเสนอแบบเอกสารสำเร็จรูปสำหรับการดำเนินการที่มีประสิทธิภาพในช่วงเวลาที่เข้ารหัสเป็นบิตเวกเตอร์ (ค้นหาช่วงเวลาเริ่มต้น/สิ้นสุด ตรวจสอบว่าช่วงเป็น inetrval หรือไม่ วนซ้ำช่วงเวลา
BitMagic ใช้การดำเนินการทางลอจิคัลสำหรับตรรกะ 3 ค่าของ True/False/Unknown (รวมถึงตรรกะ trinary, trivalent, ternary) ในการแสดงเวกเตอร์สองบิตขนาดกะทัดรัด รองรับการดำเนินการ Invert และ AND, OR ตามคำจำกัดความของ Kleene https://github.com/tlk00/BitMagic/tree/master/samples/bv3vlogic
BitMagic ใช้แนวคิดของการซีเรียลไลซ์เซชัน-การดีซีเรียลไลซ์แบบสองขั้นตอน มุ่งเน้นไปที่การดีซีเรียลไลซ์อย่างรวดเร็ว BitMagic ใช้ API เพื่อการดีซีเรียลไลซ์ช่วงเวกเตอร์ที่รวดเร็ว และรวบรวม BLOB ที่บีบอัด คุณสมบัติขั้นสูงสุดของ BitMagic คือความสามารถในการทำงานกับข้อมูลที่ถูกบีบอัด
นี่คือสถานะการทำงานหลักใน RAM โดยที่เวกเตอร์จะถูกเก็บไว้ในรูปแบบหน่วยความจำขนาดเล็ก รวบรัดไม่ใช่การบีบอัด เป็นไปได้ที่จะเข้าถึงองค์ประกอบแบบสุ่มในคอนเทนเนอร์ ถอดรหัสบล็อก วนซ้ำเวกเตอร์ ทำการอัปเดต เรียกใช้อัลกอริธึมการค้นหา Stage One มีการใช้งานที่โปร่งใส โดยเวกเตอร์จะมีลักษณะคล้ายกับ STL มาก รวบรัดเป็นหน่วยความจำที่มีขนาดกะทัดรัดแต่ไม่ได้บีบอัดทั้งหมด
BitMagic สามารถทำให้คอนเทนเนอร์และเวกเตอร์ทั้งหมดเป็นอนุกรมด้วยการบีบอัดเพิ่มเติมตามบล็อกการวิเคราะห์พฤติกรรมและตัวแปลงสัญญาณ เทคนิคการเขียนโค้ดที่ใช้ได้ผล ได้แก่ Binary Interpolative Coding (BIC) และ Elias Gamma
คอนเทนเนอร์ BitMagic เรียกว่าเวกเตอร์ "กระจัดกระจาย" แต่จริงๆ แล้วรูปแบบการบีบอัดทำงานได้ดีกับข้อมูลที่กระจัดกระจายและหนาแน่น
BitMagic ได้รับการทดสอบกับชุดเกณฑ์มาตรฐาน Gov2 ของรายการกลับด้านและจำนวนชุดข้อมูลที่เป็นกรรมสิทธิ์ http://bitmagic.io/bm5-cmpr.html
การดีซีเรียลไลเซชันจะกลับไปที่ขั้นตอนที่ 1 เสมอ ดังนั้นข้อมูลจึงไม่ได้ถอดรหัสทั้งหมด แต่จะถูกถอดรหัสแทน
กระชับใน RAM เป้าหมายของเราคือการลดพื้นที่หน่วยความจำของแอปพลิเคชันและปรับปรุงเวลาแฝงของการดีซีเรียลไลซ์ อัลกอริธึมการขยายการบีบอัดรองรับการดีซีเรียลไลซ์ของช่วงที่กำหนดเอง หรือแม้แต่การรวบรวมดีซีเรียลลิซาตินขององค์ประกอบต่างๆ
BitMagic รองรับเวกเตอร์ที่กระชับ (หน่วยความจำขนาดกะทัดรัด) โดยอาศัยการแปลงบิต
หรือที่เรียกว่าการบีบอัดบิตเพลน (BPC) (aka bit-slicing) บวกกับการบีบอัดอันดับ-เลือก เวกเตอร์ที่กระชับของ BitMagic ค่อนข้างมีป้ายกำกับว่า "เบาบาง" ซึ่งทำให้เข้าใจผิด แต่พวกมันก็ใช้ได้กับเวกเตอร์ที่มีความหนาแน่นสูงได้ดี
การขนย้ายบิตช่วยแก้ปัญหาสองวัตถุประสงค์: ปลดปล่อยบิตธรรมดาที่ไม่ได้ใช้ และแยกความสม่ำเสมอและเอนโทรปีออกเป็นบิตเวกเตอร์ (กระจัดกระจาย) ที่แยกจากกัน การบีบอัดบนบิตเพลนให้ทั้งประสิทธิภาพของหน่วยความจำที่เหนือกว่าและการค้นหาที่รวดเร็ว หนึ่งในเป้าหมายการออกแบบเพื่อทำการค้นหาดัชนีฟรีบนเวกเตอร์ที่กระชับโดยใช้การดำเนินการเชิงตรรกะแบบเวกเตอร์ที่รวดเร็ว
เวกเตอร์ที่กระชับของ BitMagic นั้นสามารถค้นหาได้โดยปราศจากดัชนีในรูปแบบการบีบอัดหน่วยความจำ มันเร็วมาก!
การใช้งานการแปลงบิตแบบกระชับนั้นทำงานได้ดีสำหรับทั้งเวกเตอร์จำนวนเต็ม (แบบมีลายเซ็นหรือไม่ได้ลงนาม) เช่นเดียวกับเวกเตอร์สตริง มันแข่งขันกับแผนการที่กระชับอื่น ๆ เช่นต้นไม้นำหน้า เวกเตอร์แบบรวบรัดสามารถจัดเรียงและไม่เรียงลำดับได้ แนวคิดที่นี่คล้ายกับ Apache Arrow-Parquet แต่ต้องใช้การบีบอัดบิตเพลนและการใช้การบีบอัด Rank-Select อย่างกว้างขวาง
BitMagic รองรับวิวัฒนาการของการทำให้เป็นอนุกรม (โปรโตคอล) - หากรูปแบบการทำให้เป็นอนุกรมเปลี่ยนแปลง ข้อมูลที่บันทึกไว้เก่าจะยังคงสามารถอ่านได้ด้วยโค้ดใหม่ รหัสเก่าจะไม่สามารถอ่าน BLOB ใหม่ได้ BitMagic เปลี่ยนหมายเลขเวอร์ชันหลักเมื่อรูปแบบการทำให้เป็นอนุกรมเปลี่ยนแปลง
BitMagic ใช้การเรียกโปรไฟล์หน่วยความจำสำหรับเวกเตอร์ทั้งหมด เวกเตอร์ใดๆ สามารถสุ่มตัวอย่างสำหรับขนาดหน่วยความจำได้ ดังนั้นระบบระดับบนสุดจึงสามารถปรับการจัดการหน่วยความจำตามโปรไฟล์หน่วยความจำรันไทม์ได้ กรณีการใช้งานทั่วไปคือแคชหน่วยความจำของออบเจ็กต์ที่มีการบีบอัดไปที่ RAM จากนั้นจึงไล่ออกไปยังดิสก์ตามการใช้ทรัพยากรและต้นทุน (สมดุลแบบไดนามิกของอุปสงค์และอุปทาน)
ใช่! BitMagic รองรับ 64 บิต สามารถใช้กับพื้นที่ที่อยู่ 32 บิต (โอเวอร์เฮดน้อยกว่า) หรือพื้นที่ที่อยู่ 64 บิตเต็ม พื้นที่ที่อยู่ 32 บิตเป็นโหมดเริ่มต้นองค์ประกอบ 2^31-1 ควรเหมาะสมอย่างยิ่งสำหรับระบบ IR และระบบวิทยาศาสตร์ข้อมูลระยะสั้นถึงปานกลาง โหมดที่อยู่ 64 บิตสามารถใช้งานได้โดยใช้ #define BM64ADDR หรือ #include "bm64.h" การใช้งาน 64 บิตในปัจจุบันอนุญาตให้มีองค์ประกอบเวกเตอร์ 2^48-1 สำหรับระบบขนาดใหญ่
BitMagic รวบรวมและทำงานร่วมกับ WebAssmbly (emscripten) เวอร์ชันล่าสุดมีการปรับแต่งหลายอย่างโดยเฉพาะสำหรับแพลตฟอร์ม หมายเลขประสิทธิภาพใกล้เคียงกับโค้ดเนทิฟที่ไม่มี SIMD (บางครั้งก็อยู่หลัง) บรรทัดการคอมไพล์ตัวอย่างจะมีลักษณะดังนี้:
emcc -std=c++17 -s ALLOW_MEMORY_GROWTH=1 -O2 -s WASM=1 ...
รองรับ WebAssembly SIMD แต่ไม่ได้เปิดไว้ตามค่าเริ่มต้น ใช้: #define BMWASMSIMDOPT
เพื่อเปิดใช้งาน ตัวอย่าง cmd Emscripten:
emcc -std=c++17 -s ALLOW_MEMORY_GROWTH=1 -O2 -msse4.2 -msimd128 -D BMWASMSIMDOPT -s WASM=1 -s DISABLE_EXCEPTION_CATCHING=0 -fno-rtti
การใช้งานปัจจุบันใช้การคอมไพล์ทรานส์ SSE4.2 (ผ่านอินทรินซิกส์) ดังนั้น -msse4.2
จึงจำเป็น
BitMagic รองรับ ARM CPU อย่างสมบูรณ์ การเผยแพร่ทั้งหมดได้รับการทดสอบความเครียดด้วย Raspberry Pi 4 BitMagic ใช้การปรับแต่งอัลกอริทึมและการปรับปรุงเฉพาะสำหรับ ARM (เช่น การใช้คำสั่ง LZCNT) คอนเทนเนอร์แบบย่อของ BitMagic มีประโยชน์อย่างมากกับระบบฝังตัวสำหรับการประมวลผลแบบเอดจ์ที่มีหน่วยความจำที่จำกัด
รองรับ Arm Neon SIMD (ผ่านไลบรารี SSE2NEON)
BitMagic C++ เป็นไลบรารีส่วนหัวเท่านั้น (ง่ายต่อการสร้างและใช้ในโปรเจ็กต์ของคุณ) และมาพร้อมกับชุดตัวอย่าง ไม่แนะนำให้ใช้การทดสอบเป็นตัวอย่างโค้ดเพื่อศึกษาการใช้งานห้องสมุด การทดสอบไม่ได้แสดงให้เห็นรูปแบบและแบบจำลองการใช้งานที่ดีที่สุด และมักจะจงใจไม่มีประสิทธิภาพ
เอกสารและตัวอย่าง API: http://www.bitmagic.io/apis.html
บทช่วยสอนสำหรับพีชคณิตของชุด: http://bitmagic.io/set-algebra.html
กรณีการใช้งานและหมายเหตุการใช้งาน: http://bitmagic.io/use-case.html
หมายเหตุทางเทคนิคเกี่ยวกับการเพิ่มประสิทธิภาพ: http://bitmagic.io/articles.html
ด็อกซิเจน: http://bitmagic.io/doxygen/html/modules.html
อาปาเช่ 2.0
สำคัญ! เราขอให้คุณกล่าวถึงโครงการ BitMagic อย่างชัดเจนในงานที่ได้รับมาหรือเนื้อหาที่เผยแพร่ของเรา การอ้างอิงที่ถูกต้องในหน้าผลิตภัณฑ์/โครงการของคุณเป็นข้อกำหนดสำหรับการใช้ BitMagic Library
ไลบรารี BitMagic ให้ความสำคัญกับคุณภาพของโค้ดและความครอบคลุมของการทดสอบอย่างจริงจัง
เนื่องจากไลบรารีแบบเอกสารสำเร็จรูป BitMagic จำเป็นต้องมีความเสถียรและสอดคล้องจึงจะมีประโยชน์
เราไม่ได้พึ่งพาการทดสอบหน่วยเพียงอย่างเดียว การทดสอบของเรามักใช้ "การทดสอบความโกลาหล" (หรือที่เรียกว่า fuzzing) ซึ่งการทดสอบความเครียดจะขึ้นอยู่กับการสุ่ม ชุดที่สร้างขึ้น และการดำเนินการแบบสุ่ม เราสร้างและใช้งานชุดทดสอบสำหรับโหมด Release และ Debug เป็นประจำเพื่อการผสมผสานการปรับให้เหมาะสม SIMD ที่หลากหลาย
เวอร์ชันทดสอบทั้งหมดใช้เวลาหลายวันจึงจะรันได้ ดังนั้นจึงไม่รับประกันว่าสาขาหลักที่ใช้งานได้จะสมบูรณ์แบบตลอดเวลา สำหรับการใช้งานจริง โปรดใช้สาขาหรือการกระจาย GitHub ที่เสถียรจาก SourceForge: https://sourceforge.net/projects/bmagic/files/
ต้นแบบ GitHub ยอมรับคำขอแพทช์ นโยบายการแยกสาขาของเราคือ ต้นแบบไม่สามารถถือว่ามีเสถียรภาพอย่างสมบูรณ์ระหว่างการเปิดตัว (เพื่อความเสถียรในการผลิตโปรดใช้เวอร์ชันที่วางจำหน่าย)
ต้องการความช่วยเหลือเกี่ยวกับการแมปกับ Python และภาษาอื่น ๆ (BitMagic มีการผูก C)
BitMagic C++ เป็นแพ็คเกจซอฟต์แวร์แบบส่วนหัวเท่านั้น และคุณอาจสามารถนำแหล่งข้อมูลมาใส่ไว้ในโปรเจ็กต์ของคุณได้โดยตรง แหล่งที่มา/ส่วนหัวของไลบรารี C++ ทั้งหมดอยู่ในไดเร็กทอรี src
อย่างไรก็ตาม หากคุณต้องการใช้ makefiles ของเรา คุณต้องปฏิบัติตามคำแนะนำง่ายๆ ต่อไปนี้:
ใช้ตัวแปรสภาพแวดล้อมบางส่วนโดยการรัน bmenv.sh ในไดเร็กทอรีรากของโปรเจ็กต์:
$ source ./bmenv.sh
(โปรดใช้ "." "./bmenv.sh" เพื่อใช้ตัวแปรสภาพแวดล้อมรูท)
ใช้ GNU make (gmake) เพื่อสร้างการติดตั้ง
$make rebuild
หรือ (เวอร์ชัน DEBUG)
$gmake DEBUG=YES rebuild
คอมไพเลอร์เริ่มต้นบน Unix และ CygWin คือ g++ หากคุณต้องการเปลี่ยนค่าเริ่มต้นคุณสามารถทำได้ใน makefile.in (น่าจะทำได้ค่อนข้างง่าย)
หากคุณใช้การติดตั้ง cygwin โปรดทำตามคำแนะนำทั่วไปของ Unix MSVC - โซลูชันและโครงการพร้อมใช้งานผ่าน CMAKE
Xcode - ไฟล์โครงการพร้อมใช้งานผ่าน CMAKE
ไลบรารี BitMagic สำหรับการแมป C และ JNI
ไลบรารี BitMagic พร้อมใช้งานสำหรับภาษา C (อยู่ระหว่างดำเนินการ) วัตถุประสงค์หลักของ C build คือการเชื่อมโยง BitMagic เข้ากับภาษาการเขียนโปรแกรมอื่นๆ C build อยู่ในไดเรกทอรีย่อย "lang-maps"
C build สร้างเวอร์ชันของ BitMagic build สำหรับ SSE และ AVX และเพิ่มการระบุ CPU ดังนั้นระบบระดับบนสุดจึงสามารถรองรับการระบุ CPU แบบไดนามิกและการส่งโค้ดได้
C build ใช้คอมไพเลอร์ C++ แต่ไม่ได้ใช้ RTTI ข้อยกเว้น (จำลองด้วยการกระโดดไกล) และการจัดการหน่วยความจำ C++ ดังนั้นจึงเป็นภาษา C++ ที่เป็นกลาง โดยไม่มีการพึ่งพารันไทม์ อัลกอริทึมและพฤติกรรมใช้ร่วมกันระหว่าง C และ C++
สถานะการพัฒนาปัจจุบัน:
การสนับสนุน Python อยู่ระหว่างดำเนินการ และเราต้องการความช่วยเหลือที่นี่ หากคุณกระตือรือร้นเกี่ยวกับ Python และคิดว่าสามารถช่วยได้ โปรดติดต่อ: anatoliy.kuznetsov @ yahoo dot com
ไลบรารี BitMagic ต้องใช้ CXX-11 มันใช้ซีแมนทิกส์การย้าย, noexept, รายการตัวเริ่มต้น, เธรด เวอร์ชันสาธารณะถัดไปจะใช้ CXX-17 (constexpr ifs ฯลฯ)
###การปรับแต่งและการเพิ่มประสิทธิภาพอย่างละเอียด:
พารามิเตอร์การปรับแต่ง BitMagic ทั้งหมดถูกควบคุมโดยตัวประมวลผลล่วงหน้ากำหนด (และคีย์คอมไพเลอร์เฉพาะส่วนโค้งเป้าหมายสำหรับการสร้างโค้ด)
#กำหนด | คำอธิบาย | ความกว้าง |
---|---|---|
BMSSE2OPT | การเพิ่มประสิทธิภาพโค้ด SSE2 | 128 บิต |
BMSSE42OPT | การเพิ่มประสิทธิภาพโค้ด SSE4.2 รวมถึง POPCNT, BSF และอื่นๆ | 128 บิต |
BMAVX2OPT | การเพิ่มประสิทธิภาพ AVX2, POPCNT, LZCNT, BMI1, BMI2 | 256 บิต |
BMAVX512OPT | AVX-512 (ทดลอง) | 512 บิต |
BMWASMSIMDOPT | การเพิ่มประสิทธิภาพ WebAssembly SIMD (ผ่าน SSE4.2) | 128 บิต |
DBMNEONOPT | การเพิ่มประสิทธิภาพ Arm Neon SIMD (ผ่านการแปล SSE2) | 128 บิต |
####ข้อจำกัด:
การเพิ่มประสิทธิภาพ SIMD กำหนดให้ไม่เกิดร่วมกัน คุณไม่สามารถมี BMSSE42OPT และ BMAVX2OPT ในเวลาเดียวกันได้ เลือกเพียงอันเดียว
ไลบรารี BM ไม่รองรับเส้นทางโค้ดหลายเส้นทางและการระบุ CPU รันไทม์ คุณต้องสร้างเฉพาะสำหรับระบบเป้าหมายของคุณ หรือใช้บิลด์พกพาเริ่มต้น
####ตัวอย่าง:
ตัวอย่างและการทดสอบ BitMagic สามารถสร้างได้ด้วย GCC โดยใช้การตั้งค่า cmd-line:
make BMOPTFLAGS=-DBMAVX2OPT rebuild
หรือ
make BMOPTFLAGS=-DBMSSE42OPT rebuild
โดยจะใช้ชุดแฟล็กคอมไพเลอร์ (GCC) ที่ถูกต้องสำหรับบิลด์เป้าหมายโดยอัตโนมัติ
CMAKE
cd build
cmake -DBMOPTFLAGS:STRING=BMSSE42OPT ..
make
หรือ
cmake -DBMOPTFLAGS:STRING=BMAVX2OPT ..
ไลบรารี BM รองรับคีย์เวิร์ด "จำกัด" คอมไพเลอร์บางตัว (เช่น Intel C++) สร้างโค้ดที่ดีกว่า (ร้านค้าโหลดที่ไม่อยู่ในลำดับ) เมื่อคีย์เวิร์ดจำกัดกำลังช่วย ตัวเลือกนี้จะถูกปิดตามค่าเริ่มต้น เนื่องจากคอมไพเลอร์ C++ ส่วนใหญ่ไม่รองรับ หากต้องการเปิดใช้งาน โปรด #define BM_HASRESTRICT ในโปรเจ็กต์ของคุณ คอมไพเลอร์บางตัวใช้คีย์เวิร์ด "__restrict" เพื่อจุดประสงค์นี้ หากต้องการแก้ไขให้กำหนดแมโคร BMRESTRICT เพื่อแก้ไขคำหลัก
หากคุณต้องการใช้ไลบรารี BM ใน "โครงการ no-STL" (เช่นระบบฝังตัว) ให้กำหนด BM_NO_STL
กฎนี้ใช้กับเมธอด core bm::bvector<> เท่านั้น อัลกอริธึมเสริม ตัวอย่าง ฯลฯ ยังคงใช้ STL
ติดตามเราได้ที่ Twitter: https://twitter.com/bitmagicio
ขอบคุณที่ใช้ไลบรารี BitMagic!
อีเมล์: [email protected]
เว็บไซต์: http://bitmagic.io
GitHub: https://github.com/tlk00/BitMagic