now I have also the outgoing net, which was simpler but not very simple
[breadcrumbs.git] / src / lib / Bcd / Data / Trust.pm
blob0df02facb7063fba1abc2d93a7867cc842e89a60
1 package Bcd::Data::Trust;
3 # This file is part of the breadcrumbs daemon (bcd).
4 # Copyright (C) 2007 Pasqualino Ferrentino
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
21 # Contact: lino.ferrentino@yahoo.it (in Italian, English or German).
23 use strict;
24 use warnings;
26 use Bcd::Data::Users;
28 use constant{
29 GET_TRUSTS_FROM_USER => "Trust_get_trusts_from_user",
30 GET_ALFA_BIAS_FROM_USER => "Trust_get_alfa_bias_from_user",
31 GET_ALL_USERS_IN_THIS_ANT_NEST => "Trust_get_all_users_in_this_ant_nest",
33 INSERT_NEW_TRUST =>
34 qq{insert into trusts values (? , ? , ? , ? )},
36 INSERT_NEW_TRUST_BOOKING => "Trust_insert_new_trust_booking",
37 SELECT_TRUST_BOOKING => "Trust_select_trust_booking",
38 DELETE_TRUST_BOOKING => "Trust_delete_trust_booking",
40 UPDATE_FIRST_TRUST => "Trust_update_first_trust",
41 UPDATE_SECOND_TRUST => "Trust_update_second_trust",
43 SELECT_TRUST_DIRECT => "Trust_select_trust_direct",
44 SELECT_TRUST_BACKUP => "Trust_select_trust_backup",
45 UPDATE_TRUST_BACKUP => "Trust_update_trust_backup",
46 INSERT_TRUST_BACKUP => "Trust_insert_trust_backup",
47 SELECT_ALL_BACKUPPED_TRUSTS => "Trust_select_all_backupped_trusts",
48 DELETE_TRUST_BACKUPS => "Trust_delete_trust_backups",
51 =head1
53 This method should return the backupped trusts
55 =cut
57 sub get_user_backupped_trusts {
58 my ($self, $stash, $user) = @_;
60 my $st = $stash->get_statement(SELECT_ALL_BACKUPPED_TRUSTS, $self);
61 $st->bind_param(1, $user);
62 $st->execute();
64 my $row;
65 my %backupped_trusts;
66 while (defined($row = $st->fetch())){
68 my $old_trust = $row->[2];
69 my $other_user = $row->[1];
71 $backupped_trusts{$other_user} = $old_trust;
74 return \%backupped_trusts;
77 =head1
79 This method should simply commit the trust changes
81 =cut
82 sub commit_trust_changes{
83 my ($self, $stash, $user) = @_;
85 #I simply delete the backups...
86 my $st = $stash->get_statement(DELETE_TRUST_BACKUPS, $self);
87 $st->bind_param(1, $user);
88 $st->execute();
91 =head1
93 This method should rollback the trust changes made by a certain user.
95 =cut
96 sub rollback_trust_changes{
97 my ($self, $stash, $user) = @_;
99 #I should select the user which should have the trust rollbacked.
100 #first of all I should take all the backupped trust of this user.
102 my $st = $stash->get_statement(SELECT_ALL_BACKUPPED_TRUSTS, $self);
103 $st->bind_param(1, $user);
104 $st->execute();
106 my $row;
107 while (defined($row = $st->fetch())){
109 my $am_i_second = $row->[3];
110 my $old_trust = $row->[2];
111 my $other_user = $row->[1];
113 my $st;
115 if ($am_i_second){
116 $st = $stash->get_statement(UPDATE_SECOND_TRUST, $self);
117 $st->bind_param(1, $old_trust);
118 $st->bind_param(2, $other_user);
119 $st->bind_param(3, $user);
120 } else {
121 $st = $stash->get_statement(UPDATE_FIRST_TRUST, $self);
122 $st->bind_param(1, $old_trust);
123 $st->bind_param(2, $user);
124 $st->bind_param(3, $other_user);
127 $st->execute();
131 $st = $stash->get_statement(DELETE_TRUST_BACKUPS, $self);
132 $st->bind_param(1, $user);
133 $st->execute();
136 =head1
138 This method should change a trust, making a backup, just in case
139 If a backup exists already it is overwritten
141 =cut
143 sub change_trust{
144 my ($self, $stash, $user_1, $user_2, $new_trust) = @_;
146 #first of all I get the old trust.
147 my ($old_trust, $am_i_second) = $self->_get_trust_between($stash, $user_1, $user_2);
149 #ok, now I should create a backup, or update it if exists already
150 $self->_create_or_update_trust_backup($stash, $user_1, $user_2, $old_trust, $am_i_second);
152 #ok, now I can update the trust.
154 my $st;
156 if ($am_i_second){
157 $st = $stash->get_statement(UPDATE_SECOND_TRUST, $self);
158 $st->bind_param(1, $new_trust);
159 $st->bind_param(2, $user_2);
160 $st->bind_param(3, $user_1);
161 } else {
162 #I am first, so I can update with the right indices.
163 $st = $stash->get_statement(UPDATE_FIRST_TRUST, $self);
164 $st->bind_param(1, $new_trust);
165 $st->bind_param(2, $user_1);
166 $st->bind_param(3, $user_2);
169 $st->execute();
171 #ok, all done.
174 sub _create_or_update_trust_backup{
175 my ($self, $stash, $user_1, $user_2, $old_trust, $is_user_second) = @_;
177 #is there a backup?
179 my $st = $stash->get_statement(SELECT_TRUST_BACKUP, $self);
181 $st->bind_param(1, $user_1);
182 $st->bind_param(2, $user_2);
184 $st->execute();
185 my $row = $st->fetchrow_arrayref();
187 $st->finish();
189 if (! defined ($row)){
190 #no backup, insert
191 $st = $stash->get_statement(INSERT_TRUST_BACKUP, $self);
193 $st->bind_param(1, $user_1);
194 $st->bind_param(2, $user_2);
195 $st->bind_param(3, $old_trust);
196 $st->bind_param(4, $is_user_second);
198 $st->execute();
200 } else {
202 #The backup exists already, do nothing.
204 #backup, update
205 # $st = $stash->get_statement(UPDATE_TRUST_BACKUP, $self);
207 # $st->bind_param(1, $old_trust);
208 # $st->bind_param(2, $user_1);
209 # $st->bind_param(3, $user_2);
211 # $st->execute();
215 sub _get_trust_between{
216 my ($self, $stash, $user_1, $user_2) = @_;
218 my $am_i_second = 0;
219 my $trust;
221 my $st = $stash->get_statement(SELECT_TRUST_DIRECT, $self);
222 $st->bind_param(1, $user_1);
223 $st->bind_param(2, $user_2);
225 $st->execute();
226 my $row = $st->fetchrow_arrayref();
228 if ( ! defined($row)){
229 $am_i_second = 1;
231 $st->finish();
232 $st->bind_param(1, $user_2);
233 $st->bind_param(2, $user_1);
235 $st->execute();
236 $row = $st->fetchrow_arrayref();
238 $trust = $row->[3];
239 } else {
241 $trust = $row->[2];
244 $st->finish();
245 return ($trust, $am_i_second);
249 =head1
251 This method should simply see if there is already a booking
253 =cut
254 sub exists_booking_between{
255 my ($self, $stash, $user_1, $user_2) = @_;
257 my $st = $stash->get_statement(SELECT_TRUST_BOOKING, $self);
259 $st->bind_param(1, $user_1);
260 $st->bind_param(2, $user_2);
261 $st->execute();
263 my $row = $st->fetchrow_arrayref();
265 $st->finish();
267 if ( defined($row)){
268 return 1;
269 } else {
270 return 0;
275 =head1 create_new_trust
276 This method should create a new trust between two users. The
277 booking must already be existing
278 =cut
280 sub create_new_trust{
281 #please note the inversion...
282 my ($self, $stash, $user_2, $user_1, $trust) = @_;
284 my $st = $stash->get_statement(SELECT_TRUST_BOOKING, $self);
286 $st->bind_param(1, $user_1);
287 $st->bind_param(2, $user_2);
288 $st->execute();
290 my $row = $st->fetchrow_arrayref();
292 my $trust_u1_u2 = $row->[2];
293 $st->finish();
295 #ok, now I can insert a new trust
296 $self->create_trust_between
297 ($stash, $user_1, $user_2, $trust_u1_u2, $trust);
299 #and I can delete the booking...
301 $st = $stash->get_statement(DELETE_TRUST_BOOKING, $self);
302 $st->bind_param(1, $user_1);
303 $st->bind_param(2, $user_2);
304 $st->execute();
307 =head1 create_new_trust_booking
308 This method simply creates a new trust
309 =cut
311 sub create_new_trust_booking{
312 my ($self, $stash, $user_1, $user_2, $trust) = @_;
314 my $st = $stash->get_statement(INSERT_NEW_TRUST_BOOKING, $self);
316 $st->bind_param(1, $user_1);
317 $st->bind_param(2, $user_2);
318 $st->bind_param(3, $trust);
320 $st->execute();
323 sub is_valid_trust{
324 my ($self, $trust) = @_;
326 #the trust is simply a number from (0,1];
327 #zero is NOT a valid trust, because the log of zero is not existing...
328 if (($trust <= 0) or ($trust > 1)){
329 return 0;
330 } else {
331 return 1; #all ok.
335 sub is_valid_trust_bb{
337 my ($self, $trust) = @_;
339 #the trust in bb is simply a number < 100.
341 if ($trust > 100){
342 return 0;
343 } else {
344 return 1; #all ok.
348 sub populate_the_stash{
349 my ($self, $db_stash) = @_;
351 my $sql = qq{select * from trusts where u1=? or u2=?};
352 my $sth = $db_stash->get_connection()->prepare( $sql );
353 $db_stash->insert_statement(GET_TRUSTS_FROM_USER, $sth);
355 #MAYBE THESE TWO COMMANDS SHOULD BE MOVED TO THE USERS MODULE
356 $sql = qq{select alfa, bias from users where id=?};
357 $sth = $db_stash->get_connection()->prepare( $sql );
358 $db_stash->insert_statement(GET_ALFA_BIAS_FROM_USER, $sth);
360 $sql = qq{select id, users_state from users where id_ant_nest=?};
361 $sth = $db_stash->get_connection()->prepare( $sql );
362 $db_stash->insert_statement(GET_ALL_USERS_IN_THIS_ANT_NEST, $sth);
364 #$sql =
365 #$db_stash->record_this_statement(INSERT_NEW_TRUST, $sql);
367 $sql = qq{insert into trusts_bookings values (? , ? , ? )};
368 $db_stash->record_this_statement(INSERT_NEW_TRUST_BOOKING, $sql);
370 #here you have an "and" and not an "or" because you know which user is first!
371 $sql = qq{select * from trusts_bookings where u1=? and u2=?};
372 $db_stash->record_this_statement(SELECT_TRUST_BOOKING, $sql);
374 $sql = qq{DELETE from trusts_bookings where u1=? and u2=?};
375 $db_stash->record_this_statement(DELETE_TRUST_BOOKING, $sql);
377 $sql = qq{UPDATE trusts set trust_u1_u2=? where u1=? and u2=?};
378 $db_stash->record_this_statement(UPDATE_FIRST_TRUST, $sql);
380 $sql = qq{UPDATE trusts set trust_u2_u1=? where u1=? and u2=?};
381 $db_stash->record_this_statement(UPDATE_SECOND_TRUST, $sql);
383 $sql = qq{SELECT * from trusts where u1=? AND u2=?};
384 $db_stash->record_this_statement(SELECT_TRUST_DIRECT, $sql);
386 $sql = qq{SELECT * from trusts_backups where u1=? and u2=?};
387 $db_stash->record_this_statement(SELECT_TRUST_BACKUP, $sql);
389 $sql = qq{SELECT * from trusts_backups where u1=?};
390 $db_stash->record_this_statement(SELECT_ALL_BACKUPPED_TRUSTS, $sql);
392 $sql = qq{INSERT INTO trusts_backups VALUES(?, ?, ? , ?)};
393 $db_stash->record_this_statement(INSERT_TRUST_BACKUP, $sql);
395 $sql = qq{UPDATE trusts_backups set old_trust_u1_u2=? where u1=? AND u2=?};
396 $db_stash->record_this_statement(UPDATE_TRUST_BACKUP, $sql);
398 $sql = qq{DELETE FROM trusts_backups where u1=?};
399 $db_stash->record_this_statement(DELETE_TRUST_BACKUPS, $sql);
403 sub create_trust_between{
404 my ($self, $stash, $first, $second, $first_trust, $second_trust) = @_;
405 my $st = $stash->prepare_cached(INSERT_NEW_TRUST);
407 $st->bind_param(1, $first);
408 $st->bind_param(2, $second);
409 $st->bind_param(3, $first_trust);
410 $st->bind_param(4, $second_trust);
411 $st->execute();
414 #this file is the main file for the calculation of the trust.
416 #this returns the decimal trust
417 sub get_trust_decimal{
419 my ($self, $u_start, $u_end, $stash) = @_;
421 #ok, first of all I calculate the path from $u_start to $u_end
422 my $res;
423 my $res_path;
425 ($res, $res_path) = $self->get_path($u_start, $u_end, $stash);
427 if ($res == 0){
428 return 0; #no path, no trust
431 #ok, now I calculate the trust
432 my $index = 0;
433 my $trust = 1; #this is the initial trust.
435 my ($alfa_cur, $bias_cur);
436 my ($alfa_next, $bias_next);
438 ($alfa_cur, $bias_cur) = $self->_get_alfa_bias_for_user($u_start, $stash);
440 #I start from the <second> step (the first is simply the starting user)
441 foreach(@{$res_path}[1..$#{$res_path}]){
443 #take alfa and bias from user,
444 ($alfa_next, $bias_next) = $self->_get_alfa_bias_for_user($_->[0], $stash);
446 my $coefficient = exp(-$index/$bias_next * log(10));
447 my $modified_trust = $alfa_cur * $_->[1];
449 $modified_trust = 1 if ($modified_trust > 1);
451 $trust *= $coefficient * $modified_trust;
453 $alfa_cur = $alfa_next;
455 #go on
456 $index ++;
459 return $trust;
462 #This function calculates the trust from a user to another... in bBel
463 sub get_trust{
464 my ($self, $u_start, $u_end, $stash) = @_;
465 my $trust = $self->get_trust_decimal($u_start, $u_end, $stash);
466 return bBel($trust);
469 #this function returns the trust in bBel.
470 sub bBel{
471 my $trust = shift;
473 #this is the base
474 my $coefficient = $trust / 1e-10;
476 my $bels = log ($coefficient) / log(10);
478 return sprintf("%.2f", $bels * 10);
481 #this is the inverse, from bBel to decimal
482 sub dec_from_bBel{
483 my $trust_bB = shift;
485 my $coefficient = $trust_bB / 10;
486 my $trust = exp ( $coefficient * log (10));
487 $trust *= 1e-10;
489 return $trust;
492 sub _get_alfa_bias_for_user{
493 my ($self, $user, $stash) = @_;
495 my $st = $stash->get_statement(GET_ALFA_BIAS_FROM_USER, $self);
496 $st->bind_param(1, $user); #this is the id of the user
497 $st->execute();
499 my $alfa;
500 my $bias;
502 $st->bind_columns(undef, \$alfa, \$bias);
503 $st->fetch();
504 $st->finish();
506 return ($alfa, $bias);
509 sub _get_maximum_reachable_set{
510 my ($self, $user, $stash) = @_;
512 #I simply return the set of all the ants which belongs to the same
513 #ant nest of this user
515 my %maximum_set;
517 my $ant_nest_code = Bcd::Data::Users->get_ant_nest_for_this_user($user, $stash);
519 #ok, now I should put the ant nests inside...
520 my $st = $stash->get_statement(GET_ALL_USERS_IN_THIS_ANT_NEST, $self);
521 $st->bind_param(1, $ant_nest_code);
522 $st->execute();
524 my $id_ant;
525 my $state;
526 $st->bind_columns(undef, \$id_ant, \$state);
528 while(defined($st->fetch())){
529 next if $state != Bcd::Constants::Users::NORMAL_ACTIVE_ANT;
530 $maximum_set{$id_ant} = 1;
533 $st->finish();
535 return \%maximum_set;
539 #this function should be simpler than the incoming, because I go only forward...
540 sub get_outgoing_trust_net{
541 my ($self, $stash, $u_start) = @_;
543 #the reachable set is always the same, all the ant nest.
544 my $set_to_reach = $self->_get_maximum_reachable_set($u_start, $stash);
546 #I can reach myself with no path, and the f is one
547 my $current_outgoing_net = {
548 $u_start => [[$u_start], [], 1 ],
551 my ($alfa_cur, $bias_cur) = $self->_get_alfa_bias_for_user($u_start, $stash);
553 my $cache_alfa_bias = {
554 $u_start => [$alfa_cur, $bias_cur],
557 #I have reached myself, so I can delete myself from the set
558 delete ($set_to_reach->{$u_start});
560 #the first level is only myself, from which I always start
561 my $current_level_set = {$u_start => 1,};
563 #and then I will recurse....
564 $self->_helper_recursive_for_outgoing_trust
565 ($stash, $current_level_set, $set_to_reach, $current_outgoing_net, $cache_alfa_bias);
567 return $current_outgoing_net;
570 sub _helper_recursive_for_outgoing_trust{
571 my ($self, $stash, $current_level_set, $set_to_reach, $current_outgoing_net, $cache_alfa_bias) = @_;
573 #end of recursion?
574 if (scalar(keys(%{$set_to_reach})) == 0){
575 return;
578 #the idea is simple: just take all the destinations from the
579 #current level set which are not already inside the current
580 #incoming net. For each of them you compute the trust from the
581 #current level set and you take the maximum trust.
583 #the next level set at first is empty.
584 my %next_level_set;
585 my %building_outgoing_net;
587 foreach(keys(%{$current_level_set})){
588 #print "I am $_ ! \n";
589 my $user_from = $_;
590 #ok, I get all the destinations...
591 my $list_of_reachables = $self->_get_all_destinations_from_user_within_sets
592 ($stash, $_, $current_outgoing_net, $set_to_reach);
595 foreach (@{$list_of_reachables}){
596 #print "I can reach $_->[0], with trust $_->[1]\n";
598 $self->_tentative_add_this_ant_to_the_outgoing_net
599 ($stash, $_->[0], $_->[1], $user_from, $current_outgoing_net, $cache_alfa_bias,
600 \%building_outgoing_net);
602 #this ant will in any case participate in the next recursion step...
603 $next_level_set{$_->[0]} = 1;
607 #I delete AFTER the loop the users, because they are needed inside the loop.
608 foreach(keys(%next_level_set)){
609 delete $set_to_reach->{$_};
612 #I update the current outgoing net
613 foreach(keys(%building_outgoing_net)){
614 $current_outgoing_net->{$_} = $building_outgoing_net{$_};
617 #recurse inside the next level set
618 $self->_helper_recursive_for_outgoing_trust
619 ($stash, \%next_level_set, $set_to_reach, $current_outgoing_net, $cache_alfa_bias);
622 #this function simply calculates the trust which other ants have in
623 #this user. The incoming trust is ALWAYS limited to the ant nest
624 sub get_incoming_trust_net{
625 my ($self, $stash, $u_start) = @_;
627 #the set to reach is all the ant nest
628 my $set_to_reach = $self->_get_maximum_reachable_set($u_start, $stash);
630 #ok, then I start with myself
631 #my ($alfa, $bias) = $self->_get_alfa_bias_for_user($u_start, $stash);
633 #I can reach myself with no path, and the f is one
634 my $current_incoming_net = {
635 $u_start => [[$u_start], [], 1 ],
638 my ($alfa_cur, $bias_cur) = $self->_get_alfa_bias_for_user($u_start, $stash);
640 my $cache_alfa_bias = {
641 $u_start => [$alfa_cur, $bias_cur],
644 #I have reached myself, so I can delete myself from the set
645 delete ($set_to_reach->{$u_start});
647 #the first level is only myself.
648 my $current_level_set = {$u_start => 1,};
650 #and then I will recurse....
651 $self->_helper_recursive_for_incoming_trust
652 ($stash, $current_level_set, $set_to_reach, $current_incoming_net, $cache_alfa_bias);
654 return $current_incoming_net;
659 sub _helper_recursive_for_incoming_trust{
660 my ($self, $stash, $current_level_set, $set_to_reach, $current_incoming_net, $cache_alfa_bias) = @_;
662 #ok, let's do some work
663 #print "_helper_recursive_for_incoming_trust: OK, ........ LET'S see this is the list: \n";
664 #print Dumper($current_level_set);
666 #end of recursion?
667 if (scalar(keys(%{$set_to_reach})) == 0){
668 #print "END OF RECURSION...\n";
669 return;
672 #I should for all the users in the list calculate the MAXIMUM trust towards them, using the
673 #current incoming net as a cache
675 #I start with an empty map towards the next level
676 #my $next_level_map = {};
678 my %next_level_set;
680 foreach(keys(%{$current_level_set})){
681 #print "I am $_ ! \n";
682 #get all the origins which are already computed, so they belong to the set to reach...
683 my $list_of_reachables = $self->_get_all_origins_from_user_within_sets
684 ($stash, $_, $current_incoming_net, $set_to_reach);
686 foreach (@{$list_of_reachables}){
687 #print "I can be reached by $_->[0], with trust $_->[1]\n";
688 $self->_add_this_ant_to_the_incoming_net
689 ($stash, $_->[0], $current_level_set, $current_incoming_net, $cache_alfa_bias);
691 #this will participate in the next recursion step...
692 $next_level_set{$_->[0]} = 1;
693 #BUT it does not belong to the set_to_reach anymore
694 delete $set_to_reach->{$_->[0]};
699 #recurse inside the next level list...
700 #sleep(1);
701 $self->_helper_recursive_for_incoming_trust
702 ($stash, \%next_level_set, $set_to_reach, $current_incoming_net, $cache_alfa_bias);
705 #taken courtesly from: http://www.stonehenge.com/merlyn/UnixReview/col30.html
706 sub deep_copy {
707 my $this = shift;
708 if (not ref $this) {
709 $this;
710 } elsif (ref $this eq "ARRAY") {
711 [map deep_copy($_), @$this];
712 } elsif (ref $this eq "HASH") {
713 +{map { $_ => deep_copy($this->{$_}) } keys %$this};
714 } else { die "what type is $_?" }
717 sub _tentative_add_this_ant_to_the_outgoing_net{
718 my ($self, $stash, $user, $trust_to_user, $user_from,
719 $current_outgoing_net, $cache_alfa_bias, $building_outgoing_net) = @_;
721 #I don't have to compute all the destinations or whatever, I need only the user
722 #from I come.
724 #first of all, if this is the first time let's get the alpha bias for this user...
725 my $compare_needed = 1;
726 my $trust_to_win;
728 if (! exists ($building_outgoing_net->{$user})){
729 my ($alfa_cur, $bias_cur) = $self->_get_alfa_bias_for_user($user, $stash);
730 $cache_alfa_bias->{$user} = [$alfa_cur, $bias_cur];
732 #I am the first, so in any case I win!
733 $compare_needed = 0;
734 #print "this is the first time for $user, no compare needed\n";
735 } else {
736 $trust_to_win = $building_outgoing_net->{$user}->[2];
737 #print "this is NOT THE FIRST time for $user, I must win $trust_to_win\n";
740 #ok, now I get the path which leads to the user from
741 my $path_to_user_from = $current_outgoing_net->{$user_from};
742 #print "this is the old path......\n";
743 #print Dumper($path_to_user_from);
745 #I make a copy
746 my $tentative_path = deep_copy($path_to_user_from);
747 #print "this is the new path the trust is $trust_to_user\n";
749 #I push to the right, because I am going outside!
750 push (@{$tentative_path->[0]}, $user);
751 push (@{$tentative_path->[1]}, $trust_to_user);
753 #print Dumper($tentative_path);
755 #ok, I can compute the trust of this path..
756 my $trust = $self->compute_trust_on_this_path($tentative_path, $cache_alfa_bias);
758 #print "the trust complete of this path is: $trust\n";
759 if ($compare_needed == 0 or $trust > $trust_to_win){
760 #print "this trust WINS, or the compare was not needed!\n";
761 $building_outgoing_net->{$user} = $tentative_path;
762 #and this is the winner to beat next time
763 $tentative_path->[2] = $trust;
764 } else {
765 #print "this trust LOOSES\n";
769 sub _add_this_ant_to_the_incoming_net{
770 my ($self, $stash, $user, $current_level_set, $current_incoming_net, $cache_alfa_bias) = @_;
772 #ok, I should get all the trusts for this users contained in the current level list
773 #then I should get the maximum. This will be the new incoming...
774 my $destinations = $self->_get_all_destinations_from_user($user, $current_level_set, $stash);
776 #ok, I have the destinations... now I could compute the trust for all this destinations
777 #and then I take the maximum
779 my ($alfa_cur, $bias_cur) = $self->_get_alfa_bias_for_user($user, $stash);
780 #I add this to the cache
781 $cache_alfa_bias->{$user} = [$alfa_cur, $bias_cur];
783 #I take the maximum trust
784 my $maximum_trust = 0;
785 #and the path which has given me the maximum
786 my $maximum_path;
788 #print "_add_this_ant_to_the_incoming_net: ok, I am $user\n";
790 foreach(@{$destinations}){
792 #print "I can reach $_->[0] with trust $_->[1]\n";
794 #I have a tentative path
795 my $path_to_destination = $current_incoming_net->{$_->[0]};
797 #print "this is the old path......\n";
798 #print Dumper($path_to_destination);
800 #I should copy this path, a deep copy...
801 my $tentative_path = deep_copy($path_to_destination);
805 #ok, then I add myself to the destination, with my trust
806 unshift (@{$tentative_path->[0]}, $user);
807 unshift (@{$tentative_path->[1]}, $_->[1]);
809 #print "this is the new tentative path......\n";
810 #print Dumper($tentative_path);
812 #I should compute now the trust on this tentative path
813 my $trust = $self->compute_trust_on_this_path($tentative_path, $cache_alfa_bias);
815 #print "the trust complete of this path is: $trust\n";
817 if ($trust > $maximum_trust){
818 #print "AND IT WINS\n";
819 $maximum_trust = $trust;
820 $maximum_path = $tentative_path;
821 $tentative_path->[2] = $trust;
826 #ok, I can add this path to the incoming net
827 $current_incoming_net->{$user} = $maximum_path;
830 sub compute_trust_on_this_path{
831 my ($self, $tentative_path, $cache_alfa_bias) = @_;
833 #print "{{{{{{{{{{{{{{{{{{{{{{{{{ compute_trust_on_this_path\n";
834 #sleep(1);
835 #print Dumper($tentative_path);
836 #print Dumper($cache_alfa_bias);
838 my $index = 0;
839 my $trust = 1; #this is the initial trust.
841 my $limit = scalar(@{$tentative_path->[0]})-2;
842 #print "I will make a loop from 0 to $limit\n";
843 for(0..$limit){
845 my ($alfa_mine, $bias_next);
847 #I take my alfa and the next bias
848 my $u1 = $tentative_path->[0]->[$index];
849 my $u2 = $tentative_path->[0]->[$index+1];
850 #print "u1 = $u1 u2 = $u2 the index is $index and the loop var is $_\n";
851 $alfa_mine = $cache_alfa_bias->{$tentative_path->[0]->[$index]}->[0];
852 $bias_next = $cache_alfa_bias->{$tentative_path->[0]->[$index+1]}->[1];
854 #print "I have alfa $alfa_mine and bias $bias_next\n";
856 my $coefficient = exp(-$index/$bias_next * log(10));
857 my $modified_trust = $alfa_mine * $tentative_path->[1]->[$_];
859 $modified_trust = 1 if ($modified_trust > 1);
861 $trust *= $coefficient * $modified_trust;
863 #go on
864 $index ++;
867 return $trust;
870 sub _get_all_paths_from_users_in_set_and_not_reached{
871 my ($self, $stash, $user, $reached_set, $set_to_reach, $ingoing) = @_;
873 my $st = $stash->get_statement(GET_TRUSTS_FROM_USER, $self);
874 $st->bind_param(1,$user);
875 $st->bind_param(2,$user);
876 $st->execute();
878 #ok, now I get all the paths... from user
879 my $u1;
880 my $u2;
881 my $t_u1_u2;
882 my $t_u2_u1;
883 $st->bind_columns(undef, \$u1, \$u2, \$t_u1_u2, \$t_u2_u1);
885 my @paths = ();
887 while ( defined($st->fetch()) ) {
889 my @path;
891 if ($u1 == $user){
892 #ok, I am on the left, I am u1
893 next if exists($reached_set->{$u2});
894 next if !exists($set_to_reach->{$u2});
896 push (@path, $u2);
897 if ($ingoing == 1){
898 push (@path, $t_u2_u1);
899 } else {
900 push (@path, $t_u1_u2);
902 } else {
903 #I am on the right side, I am u2
904 next if exists($reached_set->{$u1});
905 next if !exists($set_to_reach->{$u1});
907 push (@path, $u1);
909 if ($ingoing == 1){
910 push (@path, $t_u1_u2);
911 } else {
912 push (@path, $t_u2_u1);
916 push(@paths, \@path);
918 $st->finish();
920 return \@paths;
924 sub _get_all_destinations_from_user_within_sets{
925 my ($self, $stash, $user, $reached_set, $set_to_reach) = @_;
927 return $self->_get_all_paths_from_users_in_set_and_not_reached
928 ($stash, $user, $reached_set, $set_to_reach, 0);
931 sub _get_all_origins_from_user_within_sets{
932 my ($self, $stash, $user, $reached_set, $set_to_reach) = @_;
934 return $self->_get_all_paths_from_users_in_set_and_not_reached
935 ($stash, $user, $reached_set, $set_to_reach, 1);
938 #This functions returns the reachable set inside the ant nest.
939 sub get_reachable_users_from_user_trust_limited{
940 my ($self, $u_start, $t_lim, $stash) = @_;
942 #ok, I must search all the paths
943 #the initial trust is one, the initial level is zero
944 my %set_of_reachables;
945 my $maximum_reachable_set; #this is the set of all the ants in this ant nest
947 #first of all I get the ant nest of this user
948 $maximum_reachable_set = $self->_get_maximum_reachable_set($u_start, $stash);
950 my ($alfa, $bias) = $self->_get_alfa_bias_for_user($u_start, $stash);
952 $self->helper_recursive_for_get_reachable_users
953 ($u_start, $alfa, undef, 0, 1, $t_lim, \%set_of_reachables, $stash, $maximum_reachable_set);
955 #I KNOW that I can reach myself, this is a bogus data...
956 delete $set_of_reachables{$u_start};
958 return \%set_of_reachables;
961 #this function returns the list of all the users with no limit in the
962 #ant nests which are reachable from the selected user
963 sub get_reachable_users_from_user_trust_no_limit{
964 #I have the starting point and the trust limit
965 my ($self, $u_start, $t_lim, $stash) = @_;
967 #ok, I must search all the paths
968 #the initial trust is one, the initial level is zero
969 my %set_of_reachables;
971 my ($alfa, $bias) = $self->_get_alfa_bias_for_user($u_start, $stash);
973 $self->helper_recursive_for_get_reachable_users
974 ($u_start, $alfa, undef, 0, 1, $t_lim, \%set_of_reachables, $stash, undef);
976 #I KNOW that I can reach myself, this is a bogus data...
977 delete $set_of_reachables{$u_start};
979 return \%set_of_reachables;
982 #this is the recursive core for the
983 #get_reachable_users_from_user_trust_no_limit function
985 #this version does not detect cycles (but they cause no harm...)
986 sub helper_recursive_for_get_reachable_users{
987 my ($self, $user, $alfa_prev, $user_from,
988 $level, $t_cur, $t_lim, $reachables, $stash, $max_reach_set) = @_;
990 if (defined ($user_from)){
991 #print "RECURSE FROM $user_from user $user alfa $alfa_prev lev $level t_cur $t_cur \n";
992 } else {
993 #print "RECURSE FIRST.... user $user alfa $alfa_prev lev $level t_cur $t_cur \n";
996 #well myself is obviously reached, if I have found a maximum store it!
997 if ( exists $reachables->{$user}){
998 if ($reachables->{$user} < $t_cur){
999 $reachables->{$user} = $t_cur;
1001 } else {
1002 $reachables->{$user} = $t_cur;
1006 #Ok, now I should get all the destinations for this user.
1007 my $destinations = $self->_get_all_destinations_from_user($user, $max_reach_set, $stash);
1009 #ok, now I make a cycle on all the nodes...
1010 foreach(@{$destinations}){
1012 #print "My destinations are:\n";
1013 #print Dumper($destinations);
1015 if (defined($user_from) && $_->[0] == $user_from){
1016 #print " I don't return!\n";
1017 next;
1020 #I should get alfa and bias for this initial user
1021 my ($alfa_cur, $bias_cur) = $self->_get_alfa_bias_for_user($_->[0], $stash);
1023 #I should calculate the coefficient
1024 my $test_trust = $t_cur;
1026 #print "I am using alfa $alfa_prev bias $bias_cur\n";
1028 my $coefficient = exp(-$level/$bias_cur * log(10));
1029 my $modified_trust = $alfa_prev * $_->[1];
1030 $modified_trust = 1 if ($modified_trust > 1);
1032 $test_trust *= $coefficient * $modified_trust;
1034 if ( $test_trust > $t_lim ){
1035 #ok! I can recurse inside...
1036 #print "I can reach $_->[0] with trust $test_trust... ok\n";
1037 $self->helper_recursive_for_get_reachable_users
1038 ($_->[0], $alfa_cur, $user, $level+1, $test_trust, $t_lim, $reachables, $stash);
1039 } else {
1040 #print "I COULD reach $_->[0] with trust $test_trust... NO SUFFICIENT t lim is $t_lim\n";
1046 sub get_path{
1047 my ($self, $u_start, $u_end, $stash) = @_;
1049 #I initialize the set of the visited nodes
1052 my $recursion_limit = 0;
1053 my $res;
1054 my $res_path;
1056 my %visited_nodes;
1057 my @first_step = ($u_start, 1);
1058 my @path = \@first_step; #I start from the user u_start...
1060 ($res, $res_path) = $self->_get_path_recursive($u_start, $u_end, $stash, \%visited_nodes, \@path, 0,
1061 $recursion_limit);
1062 $recursion_limit ++;
1063 } until($res==1 || $res == 0);
1065 return ($res, $res_path);
1068 sub exists_direct_trust_between{
1069 my ($self, $stash, $u_start, $u_end) = @_;
1070 #I simply must get a path with recursion limit = 1;
1072 my %visited_nodes;
1073 my @first_step = ($u_start, 1);
1074 my @path = \@first_step; #I start from the user u_start...
1076 my ($res, $res_path) =
1077 $self->_get_path_recursive($u_start, $u_end, $stash, \%visited_nodes, \@path, 0, 1);
1079 #if I reached the end of recursion there is no direct path...
1080 return $res == 2 ? 0 : 1;
1083 sub _get_all_destinations_from_user{
1084 my ($self, $user, $max_reach_set, $stash) = @_;
1086 my $st = $stash->get_statement(GET_TRUSTS_FROM_USER, $self);
1087 $st->bind_param(1,$user);
1088 $st->bind_param(2,$user);
1089 $st->execute();
1091 #ok, now I get all the paths... from user
1092 my $u1;
1093 my $u2;
1094 my $t_u1_u2;
1095 my $t_u2_u1;
1096 $st->bind_columns(undef, \$u1, \$u2, \$t_u1_u2, \$t_u2_u1);
1098 my @destinations = ();
1100 while ( defined($st->fetch()) ) {
1102 my @dest;
1104 if ($u1 == $user){
1105 if ( defined($max_reach_set) && !exists($max_reach_set->{$u2})){
1106 next; #this ant does not belong to our maximum set
1108 push (@dest, $u2);
1109 push (@dest, $t_u1_u2);
1110 } else {
1111 if ( defined($max_reach_set) && !exists($max_reach_set->{$u1})){
1112 next; #this ant does not belong to our maximum set
1114 push (@dest, $u1);
1115 push (@dest, $t_u2_u1);
1118 push(@destinations, \@dest);
1120 $st->finish();
1122 return \@destinations;
1126 use Data::Dumper;
1128 #this function calculates the path from a user to another
1129 #returns a list of ids... it is recursive, but maybe it is not
1130 #very efficient.
1132 #return 0 No_path 1 Ok 2 Reached recursion limit
1133 sub _get_path_recursive{
1135 my ( $class, $u_start, $u_end, $stash, $visited_nodes, $path_so_far, $recursion_level, $recursion_limit) = @_;
1138 # print ">>>>>>>>>>>>> recursion u_start $u_start end $u_end level $recursion_level limit $recursion_limit\n";
1139 # print "nodes : ";
1140 # print Dumper($visited_nodes);
1141 # print "path so far : ";
1142 # print Dumper ($path_so_far);
1144 if ( $u_start == $u_end){
1145 return (1, $path_so_far); #ok, end of recursion.
1148 if ($recursion_level >= $recursion_limit){
1149 #ok, I have reached the end of recursion
1150 #print " END OF RECURSION... \n";
1151 return (2, $path_so_far);
1154 $visited_nodes->{$u_start} = 1; #I visit this node...
1155 my $st = $stash->get_statement(GET_TRUSTS_FROM_USER, $class);
1156 $st->bind_param(1,$u_start);
1157 $st->bind_param(2,$u_start);
1158 $st->execute();
1160 #ok, now I get all the paths... from u_start...
1161 my $u1;
1162 my $u2;
1163 my $t_u1_u2;
1164 my $t_u2_u1;
1165 $st->bind_columns(undef, \$u1, \$u2, \$t_u1_u2, \$t_u2_u1);
1167 my @destinations = ();
1168 my @trusts = ();
1170 while ( defined($st->fetch()) ) {
1172 if ($u1 == $u_start){
1173 if (exists ($visited_nodes->{$u2})){
1174 next;
1176 push (@destinations, $u2);
1177 push (@trusts, $t_u1_u2);
1178 } else {
1179 if (exists ($visited_nodes->{$u1})){
1180 next;
1182 push (@destinations, $u1);
1183 push (@trusts, $t_u2_u1);
1186 $st->finish();
1188 #print "Destinations from here:\n";
1189 #print Dumper(\@destinations);
1191 my $end_because_of_recursion_limit_flag = 0;
1193 my $index = 0;
1194 foreach(@destinations){
1195 #I try to reach every destination
1196 my $res;
1197 my $res_path;
1199 #test step
1200 my @test_step = ($_, $trusts[$index]);
1201 push(@{$path_so_far}, \@test_step);
1203 #let's try to reach the destination
1204 #print "pause press ENTER\n";
1205 #<STDIN>;
1206 ($res, $res_path) = $class->_get_path_recursive($_, $u_end, $stash, $visited_nodes, $path_so_far,
1207 $recursion_level+1, $recursion_limit);
1210 if ($res == 1){
1211 #ok, end of recursion
1212 return ($res, $path_so_far);
1213 } elsif ($res == 2){
1214 $end_because_of_recursion_limit_flag = 1;
1217 #no good...
1218 pop(@{$path_so_far});
1219 $index++;
1223 #no success...
1224 delete $visited_nodes->{$u_start};
1225 if ($end_because_of_recursion_limit_flag == 0){
1226 #print " *** KO DEAD END *** \n";
1227 return (0, $path_so_far);
1228 } else {
1229 #print " *** KO BECAUSE OF RECURSION LIMIT *** \n";
1230 return (2, $path_so_far);