Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
edg-l committed Oct 18, 2024
1 parent 9519428 commit 8b27ed8
Show file tree
Hide file tree
Showing 5 changed files with 667 additions and 377 deletions.
90 changes: 42 additions & 48 deletions programs/compile_benches/dijkstra.cairo
Original file line number Diff line number Diff line change
@@ -1,31 +1,47 @@
// Copied from: https://github.com/keep-starknet-strange/alexandria
// License: MIT

use nullable::FromNullableResult;
use core::nullable::{FromNullableResult, match_nullable};
//! Dijkstra algorithm using priority queue

#[derive(Copy, Drop)]
struct Node {
pub struct Node {
source: u32,
dest: u32,
weight: u128
}

#[generate_trait]
pub impl NodeGetters of NodeGettersTrait {
fn weight(self: @Node) -> @u128 {
self.weight
}

fn dest(self: @Node) -> @u32 {
self.dest
}

fn source(self: @Node) -> @u32 {
self.source
}
}

/// Graph representation.
struct Graph<T> {
nodes: Array<Node>,
pub struct Graph<T> {
pub(crate) nodes: Array<Node>,
adj_nodes: Felt252Dict<T>,
}

/// Graph trait.
trait GraphTrait {
pub trait GraphTrait {
/// Create a new graph instance.
fn new() -> Graph<Nullable<Span<Node>>>;
/// add an edge to graph
fn add_edge(ref self: Graph<Nullable<Span<Node>>>, source: u32, dest: u32, weight: u128);
/// return shortest path from s
fn shortest_path(ref self: Graph<Nullable<Span<Node>>>, source: u32) -> Felt252Dict<u128>;
/// return shortest path from s
fn adj_nodes(ref self: Graph<Nullable<Span<Node>>>, source: felt252) -> Nullable<Span<Node>>;
}

impl DestructGraph<T, +Drop<T>, +Felt252DictValue<T>> of Destruct<Graph<T>> {
Expand All @@ -42,7 +58,7 @@ impl GraphImpl of GraphTrait {
fn add_edge(ref self: Graph<Nullable<Span<Node>>>, source: u32, dest: u32, weight: u128) {
let adj_nodes = self.adj_nodes.get(source.into());
let mut nodes: Array<Node> = array![];
let mut is_null: bool = false;
let mut is_null = false;
let node = Node { source, dest, weight };
let mut span = match match_nullable(adj_nodes) {
FromNullableResult::Null => {
Expand All @@ -54,47 +70,41 @@ impl GraphImpl of GraphTrait {
};

// iterate over existing array to add new node
if (!is_null) {
let mut index = 0;
loop {
if index >= span.len() {
break;
}

let new_node = *span.get(index).unwrap().unbox();
nodes.append(new_node);
index += 1;
if !is_null {
for current_value in span {
nodes.append(*current_value);
};
nodes.append(node);
}
// add node
self.nodes.append(node);
// add adj node
self.adj_nodes.insert(source.into(), nullable_from_box(BoxTrait::new(nodes.span())));
self.adj_nodes.insert(source.into(), NullableTrait::new(nodes.span()));
}

fn shortest_path(ref self: Graph<Nullable<Span<Node>>>, source: u32) -> Felt252Dict<u128> {
dijkstra(ref self, source)
}


fn adj_nodes(ref self: Graph<Nullable<Span<Node>>>, source: felt252) -> Nullable<Span<Node>> {
self.adj_nodes.get(source)
}
}

fn dijkstra(ref self: Graph<Nullable<Span<Node>>>, source: u32) -> Felt252Dict<u128> {
pub fn dijkstra(ref self: Graph<Nullable<Span<Node>>>, source: u32) -> Felt252Dict<u128> {
let mut priority_queue = array![];
let mut visited_node = array![];
let mut dist: Felt252Dict<u128> = Default::default();
let node_size = self.nodes.len();
let nodes = self.nodes.span();
// add first node to pripority queue
let initial_node = Node { source: source, dest: 0, weight: 0 };
let initial_node = Node { source, dest: 0, weight: 0 };
priority_queue.append(initial_node);

// init dist with infinite value
let mut index = 0;
loop {
if index == node_size {
break;
}

while index != node_size {
let current_node = *nodes.at(index);
dist.insert(current_node.dest.into(), 255_u128);
index += 1;
Expand All @@ -106,11 +116,7 @@ fn dijkstra(ref self: Graph<Nullable<Span<Node>>>, source: u32) -> Felt252Dict<u
let mut visited = 0;
let mut no_more_adj_node = false;
// iterate while all node aren't visited
loop {
if visited == node_size {
break;
}

while visited != node_size {
let mut edge_distance: u128 = 0;
let mut new_distance: u128 = 0;
let adj_nodes = self.adj_nodes.get(visited.into());
Expand All @@ -129,11 +135,8 @@ fn dijkstra(ref self: Graph<Nullable<Span<Node>>>, source: u32) -> Felt252Dict<u
visited += 1;
let mut index = 0;

loop {
if index == adj_nodes_list.len() {
break;
}

let adj_nodes_list_len = adj_nodes_list.len();
while index != adj_nodes_list_len {
let adj_node: Node = *adj_nodes_list.get(index).unwrap().unbox();

if !is_node_visited(ref visited_node, adj_node.dest) {
Expand All @@ -145,15 +148,9 @@ fn dijkstra(ref self: Graph<Nullable<Span<Node>>>, source: u32) -> Felt252Dict<u
dist.insert(adj_node.dest.into(), new_distance);
}

let weight = dist.get(adj_node.dest.into());
// add node to priority_queue
priority_queue
.append(
Node {
source: source,
dest: adj_node.dest,
weight: dist.get(adj_node.dest.into())
}
);
priority_queue.append(Node { source, dest: adj_node.dest, weight });
}
index += 1;
};
Expand All @@ -170,20 +167,17 @@ fn dijkstra(ref self: Graph<Nullable<Span<Node>>>, source: u32) -> Felt252Dict<u
/// Check if a node has already been visited
fn is_node_visited(ref nodes: Array<u32>, current_node: u32) -> bool {
let mut index = 0;
let mut is_visited = false;
let n = nodes.span();

loop {
if index == n.len() {
break;
break false;
}

let source: u32 = *n.at(index);
if source == current_node {
is_visited = true;
break;
break true;
}
index += 1;
};
is_visited
}
}
25 changes: 8 additions & 17 deletions programs/compile_benches/extended_euclidean_algorithm.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// License: MIT

//! # Extended Euclidean Algorithm.
use integer::{u128_overflowing_sub, u128_overflowing_mul};
use core::num::traits::{OverflowingMul, OverflowingSub};

/// Extended Euclidean Algorithm.
/// # Arguments
Expand All @@ -12,7 +12,7 @@ use integer::{u128_overflowing_sub, u128_overflowing_mul};
/// * `gcd` - Greatest common divisor.
/// * `x` - First Bezout coefficient.
/// * `y` - Second Bezout coefficient.
fn extended_euclidean_algorithm(a: u128, b: u128) -> (u128, u128, u128) {
pub fn extended_euclidean_algorithm(a: u128, b: u128) -> (u128, u128, u128) {
// Initialize variables.
let mut old_r = a;
let mut rem = b;
Expand All @@ -21,30 +21,21 @@ fn extended_euclidean_algorithm(a: u128, b: u128) -> (u128, u128, u128) {
let mut old_t = 0;
let mut coeff_t = 1;

// Loop until remainder is 0.
loop {
if rem == 0 {
break (old_r, old_s, old_t);
}
while (rem != 0) {
let quotient = old_r / rem;

update_step(ref rem, ref old_r, quotient);
update_step(ref coeff_s, ref old_s, quotient);
update_step(ref coeff_t, ref old_t, quotient);
}
};
(old_r, old_s, old_t)
}

/// Update the step of the extended Euclidean algorithm.
fn update_step(ref a: u128, ref old_a: u128, quotient: u128) {
let temp = a;
let (bottom, _) = u128_overflowing_mul(quotient, temp);
a = u128_wrapping_sub(old_a, bottom);
let (bottom, _) = quotient.overflowing_mul(temp);
let (a_tmp, _) = old_a.overflowing_sub(bottom);
a = a_tmp;
old_a = temp;
}

fn u128_wrapping_sub(a: u128, b: u128) -> u128 implicits(RangeCheck) nopanic {
match u128_overflowing_sub(a, b) {
Result::Ok(x) => x,
Result::Err(x) => x,
}
}
105 changes: 78 additions & 27 deletions programs/compile_benches/fast_power.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,94 @@
// License: MIT

//! # Fast power algorithm
use array::ArrayTrait;
use option::OptionTrait;
use traits::{Into, TryInto};

// Calculate the ( base ^ power ) mod modulus
// using the fast powering algorithm # Arguments
// * ` base ` - The base of the exponentiation
// * ` power ` - The power of the exponentiation
// * ` modulus ` - The modulus used in the calculation # Returns
// * ` u128 ` - The result of ( base ^ power ) mod modulus

fn fast_power(base: u128, mut power: u128, modulus: u128) -> u128 {
// Return invalid input error
if base == 0 {
panic_with_felt252('II')
}
use core::ops::DivAssign;

if modulus == 1 {
return 0;
}
/// Calculate the base ^ power
/// using the fast powering algorithm
/// # Arguments
/// * ` base ` - The base of the exponentiation
/// * ` power ` - The power of the exponentiation
/// # Returns
/// * ` T ` - The result of base ^ power
/// # Panics
/// * ` base ` is 0
pub fn fast_power<
T,
+Div<T>,
+DivAssign<T, T>,
+Rem<T>,
+Into<u8, T>,
+Into<T, u256>,
+TryInto<u256, T>,
+PartialEq<T>,
+Copy<T>,
+Drop<T>
>(
base: T, mut power: T
) -> T {
assert!(base != 0_u8.into(), "fast_power: invalid input");

let mut base: u256 = base.into();
let modulus: u256 = modulus.into();
let mut result: u256 = 1;

let res = loop {
if power == 0 {
break result;
loop {
if power % 2_u8.into() != 0_u8.into() {
result *= base;
}
power /= 2_u8.into();
if (power == 0_u8.into()) {
break;
}
base *= base;
};

result.try_into().expect('too large to fit output type')
}

/// Calculate the ( base ^ power ) mod modulus
/// using the fast powering algorithm
/// # Arguments
/// * ` base ` - The base of the exponentiation
/// * ` power ` - The power of the exponentiation
/// * ` modulus ` - The modulus used in the calculation
/// # Returns
/// * ` T ` - The result of ( base ^ power ) mod modulus
/// # Panics
/// * ` base ` is 0
pub fn fast_power_mod<
T,
+Div<T>,
+DivAssign<T, T>,
+Rem<T>,
+Into<u8, T>,
+Into<T, u256>,
+TryInto<u256, T>,
+PartialEq<T>,
+Copy<T>,
+Drop<T>
>(
base: T, mut power: T, modulus: T
) -> T {
assert!(base != 0_u8.into(), "fast_power: invalid input");

if power % 2 != 0 {
if modulus == 1_u8.into() {
return 0_u8.into();
}

let mut base: u256 = base.into();
let modulus: u256 = modulus.into();
let mut result: u256 = 1;

loop {
if power % 2_u8.into() != 0_u8.into() {
result = (result * base) % modulus;
}

power /= 2_u8.into();
if (power == 0_u8.into()) {
break;
}
base = (base * base) % modulus;
power = power / 2;
};

res.try_into().expect('value cant be larger than u128')
result.try_into().expect('too large to fit output type')
}
Loading

0 comments on commit 8b27ed8

Please sign in to comment.