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
21 # Contact: lino.ferrentino@yahoo.it (in Italian, English or German).
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",
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",
53 This method should return the backupped trusts
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);
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;
79 This method should simply commit the trust changes
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);
93 This method should rollback the trust changes made by a certain user.
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);
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];
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);
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);
131 $st = $stash->get_statement(DELETE_TRUST_BACKUPS
, $self);
132 $st->bind_param(1, $user);
138 This method should change a trust, making a backup, just in case
139 If a backup exists already it is overwritten
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.
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);
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);
174 sub _create_or_update_trust_backup
{
175 my ($self, $stash, $user_1, $user_2, $old_trust, $is_user_second) = @_;
179 my $st = $stash->get_statement(SELECT_TRUST_BACKUP
, $self);
181 $st->bind_param(1, $user_1);
182 $st->bind_param(2, $user_2);
185 my $row = $st->fetchrow_arrayref();
189 if (! defined ($row)){
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);
202 #The backup exists already, do nothing.
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);
215 sub _get_trust_between
{
216 my ($self, $stash, $user_1, $user_2) = @_;
221 my $st = $stash->get_statement(SELECT_TRUST_DIRECT
, $self);
222 $st->bind_param(1, $user_1);
223 $st->bind_param(2, $user_2);
226 my $row = $st->fetchrow_arrayref();
228 if ( ! defined($row)){
232 $st->bind_param(1, $user_2);
233 $st->bind_param(2, $user_1);
236 $row = $st->fetchrow_arrayref();
245 return ($trust, $am_i_second);
251 This method should simply see if there is already a booking
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);
263 my $row = $st->fetchrow_arrayref();
275 =head1 create_new_trust
276 This method should create a new trust between two users. The
277 booking must already be existing
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);
290 my $row = $st->fetchrow_arrayref();
292 my $trust_u1_u2 = $row->[2];
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);
307 =head1 create_new_trust_booking
308 This method simply creates a new trust
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);
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)){
335 sub is_valid_trust_bb
{
337 my ($self, $trust) = @_;
339 #the trust in bb is simply a number < 100.
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);
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);
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
425 ($res, $res_path) = $self->get_path($u_start, $u_end, $stash);
428 return 0; #no path, no trust
431 #ok, now I calculate the trust
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;
462 #This function calculates the trust from a user to another... in bBel
464 my ($self, $u_start, $u_end, $stash) = @_;
465 my $trust = $self->get_trust_decimal($u_start, $u_end, $stash);
469 #this function returns the trust in bBel.
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
483 my $trust_bB = shift;
485 my $coefficient = $trust_bB / 10;
486 my $trust = exp ( $coefficient * log (10));
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
502 $st->bind_columns(undef, \
$alfa, \
$bias);
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
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);
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;
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) = @_;
574 if (scalar(keys(%{$set_to_reach})) == 0){
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.
585 my %building_outgoing_net;
587 foreach(keys(%{$current_level_set})){
588 #print "I am $_ ! \n";
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);
667 if (scalar(keys(%{$set_to_reach})) == 0){
668 #print "END OF RECURSION...\n";
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 = {};
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...
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
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
724 #first of all, if this is the first time let's get the alpha bias for this user...
725 my $compare_needed = 1;
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!
734 #print "this is the first time for $user, no compare needed\n";
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);
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;
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
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";
835 #print Dumper($tentative_path);
836 #print Dumper($cache_alfa_bias);
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";
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;
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);
878 #ok, now I get all the paths... from user
883 $st->bind_columns(undef, \
$u1, \
$u2, \
$t_u1_u2, \
$t_u2_u1);
887 while ( defined($st->fetch()) ) {
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});
898 push (@path, $t_u2_u1);
900 push (@path, $t_u1_u2);
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});
910 push (@path, $t_u1_u2);
912 push (@path, $t_u2_u1);
916 push(@paths, \
@path);
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";
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;
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";
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);
1040 #print "I COULD reach $_->[0] with trust $test_trust... NO SUFFICIENT t lim is $t_lim\n";
1047 my ($self, $u_start, $u_end, $stash) = @_;
1049 #I initialize the set of the visited nodes
1052 my $recursion_limit = 0;
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,
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;
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);
1091 #ok, now I get all the paths... from user
1096 $st->bind_columns(undef, \
$u1, \
$u2, \
$t_u1_u2, \
$t_u2_u1);
1098 my @destinations = ();
1100 while ( defined($st->fetch()) ) {
1105 if ( defined($max_reach_set) && !exists($max_reach_set->{$u2})){
1106 next; #this ant does not belong to our maximum set
1109 push (@dest, $t_u1_u2);
1111 if ( defined($max_reach_set) && !exists($max_reach_set->{$u1})){
1112 next; #this ant does not belong to our maximum set
1115 push (@dest, $t_u2_u1);
1118 push(@destinations, \
@dest);
1122 return \
@destinations;
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
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";
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);
1160 #ok, now I get all the paths... from u_start...
1165 $st->bind_columns(undef, \
$u1, \
$u2, \
$t_u1_u2, \
$t_u2_u1);
1167 my @destinations = ();
1170 while ( defined($st->fetch()) ) {
1172 if ($u1 == $u_start){
1173 if (exists ($visited_nodes->{$u2})){
1176 push (@destinations, $u2);
1177 push (@trusts, $t_u1_u2);
1179 if (exists ($visited_nodes->{$u1})){
1182 push (@destinations, $u1);
1183 push (@trusts, $t_u2_u1);
1188 #print "Destinations from here:\n";
1189 #print Dumper(\@destinations);
1191 my $end_because_of_recursion_limit_flag = 0;
1194 foreach(@destinations){
1195 #I try to reach every destination
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";
1206 ($res, $res_path) = $class->_get_path_recursive($_, $u_end, $stash, $visited_nodes, $path_so_far,
1207 $recursion_level+1, $recursion_limit);
1211 #ok, end of recursion
1212 return ($res, $path_so_far);
1213 } elsif ($res == 2){
1214 $end_because_of_recursion_limit_flag = 1;
1218 pop(@
{$path_so_far});
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);
1229 #print " *** KO BECAUSE OF RECURSION LIMIT *** \n";
1230 return (2, $path_so_far);