Kronecker product based fractals: Difference between revisions

Content added Content deleted
m (Minor edit to C++ code)
(Add source for Rust)
Line 184: Line 184:


typedef struct{
typedef struct{
int row, col;
int row, col;
}cell;
}cell;


Line 190: Line 190:


unsigned long raiseTo(int base,int power){
unsigned long raiseTo(int base,int power){
if(power==0)
if(power==0)
return 1;
return 1;
else
else
return base*raiseTo(base,power-1);
return base*raiseTo(base,power-1);
}
}


cell* kroneckerProduct(char* inputFile,int power){
cell* kroneckerProduct(char* inputFile,int power){
FILE* fp = fopen(inputFile,"r");
FILE* fp = fopen(inputFile,"r");
int i,j,k,l;
int i,j,k,l;
unsigned long prod;
unsigned long prod;
int** matrix;
int** matrix;
cell *coreList,*tempList,*resultList;
cell *coreList,*tempList,*resultList;
fscanf(fp,"%d%d",&ROW,&COL);
fscanf(fp,"%d%d",&ROW,&COL);
matrix = (int**)malloc(ROW*sizeof(int*));
matrix = (int**)malloc(ROW*sizeof(int*));
for(i=0;i<ROW;i++){
for(i=0;i<ROW;i++){
matrix[i] = (int*)malloc(COL*sizeof(int));
matrix[i] = (int*)malloc(COL*sizeof(int));
for(j=0;j<COL;j++){
for(j=0;j<COL;j++){
fscanf(fp,"%d",&matrix[i][j]);
fscanf(fp,"%d",&matrix[i][j]);
if(matrix[i][j]==1)
if(matrix[i][j]==1)
SUM++;
SUM++;
}
}
}
}
coreList = (cell*)malloc(SUM*sizeof(cell));
coreList = (cell*)malloc(SUM*sizeof(cell));
resultList = (cell*)malloc(SUM*sizeof(cell));
resultList = (cell*)malloc(SUM*sizeof(cell));
k = 0;
k = 0;
for(i=0;i<ROW;i++){
for(i=0;i<ROW;i++){
for(j=0;j<COL;j++){
for(j=0;j<COL;j++){
if(matrix[i][j]==1){
if(matrix[i][j]==1){
coreList[k].row = i+1;
coreList[k].row = i+1;
coreList[k].col = j+1;
coreList[k].col = j+1;
resultList[k].row = i+1;
resultList[k].row = i+1;
resultList[k].col = j+1;
resultList[k].col = j+1;
k++;
k++;
}
}
}
}
}
}
prod = k;
prod = k;
for(i=2;i<=power;i++){
for(i=2;i<=power;i++){
tempList = (cell*)malloc(prod*k*sizeof(cell));
tempList = (cell*)malloc(prod*k*sizeof(cell));
l = 0;
l = 0;
for(j=0;j<prod;j++){
for(j=0;j<prod;j++){
for(k=0;k<SUM;k++){
for(k=0;k<SUM;k++){
tempList[l].row = (resultList[j].row-1)*ROW + coreList[k].row;
tempList[l].row = (resultList[j].row-1)*ROW + coreList[k].row;
tempList[l].col = (resultList[j].col-1)*COL + coreList[k].col;
tempList[l].col = (resultList[j].col-1)*COL + coreList[k].col;
l++;
l++;
}
}
}
}
free(resultList);
free(resultList);
prod *= k;
prod *= k;
resultList = (cell*)malloc(prod*sizeof(cell));
resultList = (cell*)malloc(prod*sizeof(cell));
for(j=0;j<prod;j++){
for(j=0;j<prod;j++){
resultList[j].row = tempList[j].row;
resultList[j].row = tempList[j].row;
resultList[j].col = tempList[j].col;
resultList[j].col = tempList[j].col;
}
}
free(tempList);
free(tempList);
}
}
return resultList;
return resultList;
}
}


int main(){
int main(){
char fileName[100];
char fileName[100];
int power,i,length;
int power,i,length;
cell* resultList;
cell* resultList;
printf("Enter input file name : ");
printf("Enter input file name : ");
scanf("%s",fileName);
scanf("%s",fileName);
printf("Enter power : ");
printf("Enter power : ");
scanf("%d",&power);
scanf("%d",&power);
resultList = kroneckerProduct(fileName,power);
resultList = kroneckerProduct(fileName,power);
initwindow(raiseTo(ROW,power),raiseTo(COL,power),"Kronecker Product Fractal");
initwindow(raiseTo(ROW,power),raiseTo(COL,power),"Kronecker Product Fractal");
length = raiseTo(SUM,power);
length = raiseTo(SUM,power);


for(i=0;i<length;i++){
for(i=0;i<length;i++){
putpixel(resultList[i].row,resultList[i].col,15);
putpixel(resultList[i].row,resultList[i].col,15);
}
}
getch();
getch();
closegraph();
closegraph();
return 0;
return 0;
}
}
</lang>
</lang>
Line 3,042: Line 3,042:
███
███
</pre>
</pre>

=={{header|Rust}}==

Because Rust lacks support for images, this sample contains a simple implementation of
[[Bitmap/Write a PPM file| writing PPM files]].

<lang rust>use std::{
fmt::{Debug, Display, Write},
ops::Mul,
};

// Rust has (almost) no built-in support for multi-dimensional arrays or so.
// Let's make a basic one ourselves for our use cases.

#[derive(Clone, Debug)]
pub struct Mat<T> {
col_count: usize,
row_count: usize,
items: Vec<T>,
}

impl<T> Mat<T> {
pub fn from_vec(items: Vec<T>, col_count: usize, row_count: usize) -> Self {
assert_eq!(items.len(), col_count * row_count, "mismatching dimensions");

Self {
col_count,
row_count,
items,
}
}

pub fn row_count(&self) -> usize {
self.row_count
}

pub fn col_count(&self) -> usize {
self.col_count
}

pub fn iter(&self) -> impl Iterator<Item = &T> {
self.items.iter()
}

pub fn row_iter(&self, row: usize) -> impl Iterator<Item = &T> {
assert!(row < self.row_count, "index out of bounds");
let start = row * self.col_count;
self.items[start..start + self.col_count].iter()
}

pub fn col_iter(&self, col: usize) -> impl Iterator<Item = &T> {
assert!(col < self.col_count, "index out of bounds");
self.items.iter().skip(col).step_by(self.col_count)
}
}

impl<T: Display> Display for Mat<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Compute the width of the widest item first
let mut len = 0usize;
let mut buf = String::new();
for item in (0..self.row_count).flat_map(|row| self.row_iter(row)) {
buf.clear();
write!(buf, "{}", item)?;
len = std::cmp::max(len, buf.chars().count());
}

// Then render the matrix with proper padding

len += 1; // To separate cells
let width = len * self.col_count + 1;
writeln!(f, "┌{:width$}┐", "", width = width)?;

for row in (0..self.row_count).map(|row| self.row_iter(row)) {
write!(f, "│")?;

for item in row {
write!(f, "{:>width$}", item, width = len)?;
}

writeln!(f, " │")?;
}

write!(f, "└{:width$}┘", "", width = width)
}
}

// Rust standard libraries have no graphics support. If we want to render
// an image, we can write, e.g., a PPM file.

impl<T> Mat<T> {
pub fn write_ppm(
&self,
f: &mut dyn std::io::Write,
rgb: impl Fn(&T) -> (u8, u8, u8),
) -> std::io::Result<()> {
let bytes = self
.iter()
.map(rgb)
.flat_map(|(r, g, b)| {
use std::iter::once;
once(r).chain(once(g)).chain(once(b))
})
.collect::<Vec<u8>>();

write!(f, "P6\n{} {}\n255\n", self.col_count, self.row_count)?;
f.write_all(&bytes)
}
}

mod kronecker {

use super::Mat;
use std::ops::Mul;

// Look ma, no numbers! We can combine anything with Mul (see later)

pub fn product<T, U>(a: &Mat<T>, b: &Mat<U>) -> Mat<<T as Mul<U>>::Output>
where
T: Clone + Mul<U>,
U: Clone,
{
let row_count = a.row_count() * b.row_count();
let col_count = a.col_count() * b.col_count();
let mut items = Vec::with_capacity(row_count * col_count);

for i in 0..a.row_count() {
for k in 0..b.row_count() {
for a_x in a.row_iter(i) {
for b_x in b.row_iter(k) {
items.push(a_x.clone() * b_x.clone());
}
}
}
}

Mat::from_vec(items, col_count, row_count)
}

pub fn power<T>(m: &Mat<T>, n: u32) -> Mat<T>
where
T: Clone + Mul<T, Output = T>,
{
match n {
0 => m.clone(),
_ => (1..n).fold(product(&m, &m), |result, _| product(&result, &m)),
}
}
}

// Here we make a char-like type with Mul implementation.
// We can do fancy things with that later.

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Char(char);

impl Char {
fn space() -> Self {
Char(' ')
}

fn is_space(&self) -> bool {
self.0 == ' '
}
}

impl Display for Char {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}

impl Mul for Char {
type Output = Self;

#[allow(clippy::suspicious_arithmetic_impl)]
fn mul(self, rhs: Self) -> Self {
if self.is_space() || rhs.is_space() {
Char(' ')
} else {
self
}
}
}

fn main() -> std::io::Result<()> {

// Vicsek rendered in numbers

#[rustfmt::skip]
let vicsek = Mat::<u8>::from_vec(vec![
0, 1, 0,
1, 1, 1,
0, 1, 0,
], 3, 3);

println!("{}", vicsek);
println!("{}", kronecker::power(&vicsek, 3));

// We could render something by mapping the numbers to
// something else. But we could compute with something
// else directly, right?
let s = Char::space();
let b = Char('\u{2588}');

#[rustfmt::skip]
let sierpienski = Mat::from_vec(vec![
b, b, b,
b, s, b,
b, b, b,
], 3, 3);

println!("{}", sierpienski);
println!("{}", kronecker::power(&sierpienski, 3));

#[rustfmt::skip]
let matrix = Mat::from_vec(vec![
s, s, b, s, s,
s, b, b, b, s,
b, s, b, s, b,
s, s, b, s, s,
s, b, s, b, s,
], 5, 5,);

println!("{}", kronecker::power(&matrix, 1));

// This is nicer as an actual image
kronecker::power(&matrix, 4).write_ppm(
&mut std::fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open("kronecker_power.ppm")?,
|&item| {
if item.is_space() {
(0, 0, 32)
} else {
(192, 192, 0)
}
},
)
}
</lang>


=={{header|Sidef}}==
=={{header|Sidef}}==
Line 3,088: Line 3,331:
R:=M;
R:=M;
do(n){ R=kronecker(R,M) }
do(n){ R=kronecker(R,M) }
r,c,img := R.rows, R.cols, PPM(r,c,0xFFFFFF); // white canvas
r,c,img := R.rows, R.cols, PPM(r,c,0xFFFFFF); // white canvas
foreach i,j in (r,c){ if(R[i,j]) img[i,j]=0x00FF00 } // green dots
foreach i,j in (r,c){ if(R[i,j]) img[i,j]=0x00FF00 } // green dots
println("%s: %dx%d with %,d points".fmt(fname,R.rows,R.cols,
println("%s: %dx%d with %,d points".fmt(fname,R.rows,R.cols,